Cake on .NET Core 2.0! – A simpler Docker build for CircleCI 2.0

Previously I wrote about having a Docker container with .NET Core 1 and 2 specifically to run a build with Cake on Circle CI 2.0. This was because Cake had been only able to run on .NET Core 1 while the rest of the .NET Core world had moved on to 2. I’m happy to say this is no longer the case.

Cake is now targeting .NET Standard 2.0 (and net46 for Omnisharp reasons) which allows me to drop the custom container I made just for Cake builds.

Now my CircleCI 2.0 uses the official Microsoft build .NET Core 2.0 SDK container with a small addition: unzip. Maybe I’ll figure out how to drop this too one day:

version: 2
      - image: microsoft/dotnet:2.0.5-sdk-2.1.4
      - checkout
      - run:
          name: Install unzip
          command: |
            apt-get update
            apt-get install -y unzip
      - run:
          name: Build
          command: ./

It’s nice to be simple and rely on other people to maintain stuff for you instead of making my own container.

Terraform, API Gateway and Cognito

I’d like to control API Gateway as an HTTP Proxy to an ALB for an ECS Task.

Unfortunately, Terraform’s support of Cognito isn’t quite there.

There are some features missing:

In this context, I need to add a Cognito Authorizer for an existing User Client Pool.

Currently, Terraform only supports making an authorizer for a lambda only. So creating an authorizer for cognito is a manual step. Creating a cognito authorizer is documented but creating it with the AWS console is easy. Just make it of type COGNITO then select the pool you want.

Next you need to attach the authorizer to the aws_api_gateway_method resources desired. Your methods would look similar to this:

resource "aws_api_gateway_method" "api-gateway-method-post" {
  rest_api_id   = "${}"
  resource_id   = "${}"
  http_method   = "POST"
  authorization = "COGNITO_USER_POOLS"
  authorizer_id = "${var.cognito-authorizer-id}"

variable "cognito-authorizer-id" {
  default = "9rvrci"

Setting authorization to COGNITO_USER_POOLS isn’t documented but it currently works.

The hard part here is finding the authorizer id. I found this by setting using it manually in the AWS console then running terraform plan to see what terrafrom would change the value of a current method from to empty. I’m sure there are better ways.


Process for API Gateway with Cognito Authorizer

  • Create API Gateway (minus authorizer) with Terraform
  • Create Cognito User Pool (maybe without Terraform)
  • Create Cognito Authorizer on the API Gateway (without Terraform)
  • Add Cognito Authorizer details to the Terraform configuration then apply

One day soon, Terraform will support all this 🙂

SharpCompress 0.19 – .NET Standard 2.0

New Features:

Bug Fixes:
Opening 7zip archive with invalid win32 date
eliminate spurious rar crc exception
create new memorystream to allow proper resizing as memorystream could be a user provided buffer


Docker Container with .NET Core 1 and 2 for Cake builds

Cake build container

I love Cake but it doesn’t run on .NET Core 2 yet. Actually, I’m trying to fix that issue:

Unfortunately, the official Docker images don’t have both runtimes installed. So it should be easy to make an image with both right? Well, it wasn’t as easy as I thought it would but I managed to do it!

Uses a Ubuntu 16.04 base image with a .NET Core 1 runtime installed then .NET Core 2 SDK installed. This should be enough to build any .NET Core 2 project using Cake.

CircleCI is my build service of choice and it is Docker all the way!

Sample CircleCI 2.0 Config

version: 2
      - image: adamhathcock/cake-build:latest
      - checkout
      - run:
          name: Build
          command: ./

Actually, this config isn’t that interesting 🙂

Using the AWS SDK to login with MFA and Assume Role

A new-ish thing to me is having my IAM account on a centralized AWS account then switching roles to a role in another AWS account. It’s a good way to manage users across a lot of accounts: Cross-Account Access in the AWS Management Console

What is definitely is having to do this programmatically for a script. I’m using C# for this but the guts are the same for any language I’m sure.


1) Load main credentials – either hard-coded or from ~/.aws/credentials
2) Get a Session Token from STS
3) Setup MFA callback
4) Use Session Token creds and MFA call back on an AssumeRole credential set then to do work.


//needed info from target account
var targetRoleAccount = "<account id>";
var targetRoleName = "<role name>";
//needed info from main account about my user
var mainAccount = "<account id>";
var mainAccountUser = "<my user name>";
//my user creds
var mainAccountUserAccessToken = "<aws access token>";
var mainAccountUserSecretToken = "<aws secret token>";
//make some ARNs
var roleArn = $"arn:aws:iam::{targetRoleAccount}:role/{targetRoleName}";
var mfaArn = $"arn:aws:iam::{mainAccount}:mfa/{mainAccountUser}";

var basicCreds = new BasicAWSCredentials(mainAccountUserAccessToken, mainAccountUserSecretToken);

var stsClient = new AmazonSecurityTokenServiceClient(basicCreds);
var sessionResponse = await stsClient.GetSessionTokenAsync();

var sessionCreds = new SessionAWSCredentials(sessionResponse.Credentials.AccessKeyId,
    sessionResponse.Credentials.SecretAccessKey, sessionResponse.Credentials.SessionToken);

var options = new AssumeRoleAWSCredentialsOptions()
    MfaSerialNumber = mfaArn,
    MfaTokenCodeCallback = () =>
        Console.WriteLine("Enter MFA");
        return Console.ReadLine();

var assumeRoleCredentials = new AssumeRoleAWSCredentials(sessionCreds, roleArn, targetRoleName, options);

//time to work!
var client = new AmazonEC2Client(assumeRoleCredentials, RegionEndpoint.EUWest1);

The code roughly follows the steps I listed before. The trick is getting your MFA code in.

Here, I just have a console app so I can just ReadLine() and enter the numbers from my phone which I use for the two-factor code.

Took some figuring out as I didn’t know the AWS termology and had to dig the into the AWS SDK integration tests for STS to get it right. Wasn’t too bad.

SharpCompress 0.18

GitHub Release

* Breaking change – Remove ArchiveEncoding static class in favor of instance on OptionsArchiveEncoding is now on the Options base class. This now allows for more Encoding class options as well as a custom Func for decoding for more custom options. Being instance based avoids multi-threading issues. See

* LeaveStreamOpen doesn’t work with TarWriter
* If Zip file has normal file header AND a post-descriptor header AND the file is attempted to be skipped by a ZipReader, then the data is attempted to be skipped twice.
* AbstractReader.Skip() does not fully read bytes from non-local streams