Setting EC2 Volume Tags for Cost Tracking

Like many AWS users, our company needs to track our AWS costs by project and client for accounting purposes.  Amazon makes it pretty easy to do this using tags and some settings in the billing console.  In our case, we added a CostCenter tag to each instance and ELB to indicate how to allocate the cost. Because most of our instances have at least two volumes, setting the tags manually for the volumes would have been very tedious and error prone. Therefore, I put together this little Powershell script to do the work for us by copying the CostCenter tag from the instance to all its associated volumes:

$volumes = Get-EC2Volume

Write-Host "Setting cost center tag on " $volumes.Count " volumes"
foreach ($vol in $volumes) {
  $tags = $vol.Attachments | %{$_.InstanceId} | Select-Object -First 1 | Get-EC2Instance | %{ $_.Instances} | %{ $_.Tag}
  $name = ($tags | where {$_.Key -eq 'Name'} | %{$_.Value}) -join ','
  $costCenter = ($tags | where {$_.Key -eq 'CostCenter'} | %{$_.Value}) -join ','

  $tag = New-Object Amazon.EC2.Model.Tag
  $tag.Key = "CostCenter"
  $tag.Value = $costCenter
  New-EC2Tag -Resource $vol.VolumeId -Tag $tag
  Write-Host "Volume: " $vol.VolumeId " Cost Center Set To: " $costCenter
}

You will need the AWS Tools for Windows Powershell installed.

RabbitOperations Project Launched

An early preview release of my new open source project, RabbitOperations, is now available at https://github.com/SouthsideSoftware/RabbitOperations. The idea is to provide some tools for managing real-world applications that use RabbitMQ. It will support popular message buses like NServiceBus and Rebus with error replay, audit & error logging, sophisticated search capabilities and likely an integration with NewRelic to log stats about queue lengths etc. This very early release lacks a UI and is only suitable for experimentation and potential contributors.

Troubleshooting Assembly Binding Issues in .NET

I’ve been using fuslogvw.exe to troubleshoot assembly binding issues for several years so I was pretty surprised to find out that most of the guys on my team had not heard about it. Here’s a link to a great blog post that explains how to use it for those not in the know: http://www.meadow.se/wordpress/viewing-assembly-binding-logs-using-fuslogvw-exe/

Using Gulp with ASP.NET vNext and Visual Studio 2015 Preview

After playing with ASP.NET vNext and VS.NET 2015 a bit, I decided I wanted to switch from Grunt to my preferred build system for Node, Gulp. Although Gulp is supported, documentation is currently lacking and the VS.NET preview has some instability so it took me a few minutes to figure it out. Here are the steps that worked for me:

1) Make the package.json created by VS.NET complete so that npm will be able to add references.

npm init

2) Install gulp and uninstall grunt from the project

npm install -g gulp
npm install --save-dev gulp
npm uninstall --save-dev grunt

3) Install gulp-bower

npm install --save-dev gulp-bower

4) Add a gulpfile.js to the root of your web project with the following contents:

var gulp = require('gulp');
var bower = require('gulp-bower');

gulp.task('bower', function () {
    return bower({ layout: "byComponent"})
        .pipe(gulp.dest('wwwroot/lib'));
});

5) Modify project.json to use your new gulp task instead of grunt in the scripts section.

"scripts": {
        "postrestore": [ "npm install" ],
        "prepare": [ "gulp bower" ]
    }

6) Delete gruntfile.js

7) Close VS.NET and reopen and it should all work with gulp.

ASP.NET MVC Attribute Supporting SSL Terminated at Amazon Elastic Load Balancer

In my last post, I described an ASP.NET Web Api RequireHttps attribute that supports SSL terminated at a load balancer like Amazon’s ELB.  Here’s a RequireHttps attribute for ASP.NET MVC with load balancer support:

using System;
using System.Configuration;
using System.Web.Mvc;
using System.Web;
using System.Collections.Generic;

namespace MvcHelpers
{
    public class RequireHttpsSupportsLBAttibute : RequireHttpsAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext.HttpContext.Request.IsSecureConnectionConsideringLoadBalancer()) return;

            base.OnAuthorization(filterContext);
        }
    }

    public static class HttpRequestBaseHelper
    {
        public static bool IsSecureConnectionConsideringLoadBalancer(this HttpRequestBase request)
        {
            return request.IsSecureConnection || LoadBalancerSecured(request);
        }

        public static bool LoadBalancerSecured(HttpRequestBase request)
        {
            if (string.Equals(request.Headers["X-Forwarded-Proto"],
                "https"
                StringComparison.InvariantCultureIgnoreCase))
            {
                return true;
            }

            return false;
        }
    }
}

ASP.NET Web API 2 RequireSsl Attribute With Support For Terminating SSL At Load Balancer

Most modern load balancers, including Amazon’s Elastic Load Balancer (ELB), allow you to configure them to handle SSL. Although they can forward the request to your web nodes using SSL, it is more efficient to offload the SSL processing to the load balancer and forward requests from there to your web servers using plain HTTP on port 80. Load balancers that support offloading SSL generally inject a “X-Forwarded-Proto” header into the request with the value “http” or “https” to indicate the protocol of the original request. This approach is quite secure as the load balancer typically replaces any “X-Forwarded-Proto” header present in the original request. This is true for ELB.

You can use this header in ASP.NET Web API to make sure a request is secure. For example, here’s an attribute you can put on any controller or controller method to require SSL. It supports SSL terminated at the load balancer as well as plain old SSL straight to the server:

using System;
using System.Configuration;
using System.Linq;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;

namespace AspNetApiHelpers
{
    public class RequireHttpsAttribute : AuthorizationFilterAttribute
    {
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            if (actionContext.Request.RequestUri.Scheme != Uri.UriSchemeHttps && !IsForwardedSsl(actionContext))
            {
                actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
                {
                    ReasonPhrase = "HTTPS Required"
                };
            }
            else
            {
                base.OnAuthorization(actionContext);
            }
        }

        private static bool IsForwardedSsl(HttpActionContext actionContext)
        {
            var xForwardedProto = actionContext.Request.Headers.FirstOrDefault(x => x.Key == "X-Forwarded-Proto");
            var forwardedSsl = xForwardedProto.Value != null &&
                xForwardedProto.Value.Any(x => string.Equals(x, "https", StringComparison.InvariantCultureIgnoreCase));
            return forwardedSsl;
        }
    }
}