Date Category Blog

Today I'm mapping out a brief set of requirements for bringing up and stopping an instance on-demand using MFA and the AWS CLI tools. I need it for work anyway, and it's a common use-case besides.

After that, I want to take a look at using saving state for a complex app and jailing the stateless bits. For this, for fun, I'll be targeting a running Minecraft server. Reasonably complex, a little more unique, but consistent and ... "useful", at least for my own purposes.

Step One: awscli & MFA

  • Start by activating MFA on the root account
  • Next, set up a secondary IAM user with MFA & CLI access (leeron@qbsd)

After going through the guide on MFA CLI access, it became quickly clear that the most useful mechanism wasn't clearly outlined: a global "Deny" response when MFA is not in use. Requiring a condition key for every Allow statemetn is not very efficient, and strangely there's no easy managed policy available to attach to an IAM user group, so I had to roll my own.

Thankfully this wasn't actually very difficult, but it did lead me through a couple of pages of documentation before I was able to identify the specific boolean value to use for the global condition key here. What I came up with is actually quite simple; create a custom policy RequireMFA on an IAM group for your users, and set the following:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "*",
      "Effect": "Deny",
      "Resource": "*",
      "Condition": {
        "BoolIfExists": {
          "aws:MultiFactorAuthPresent": "false"
        }
      }
    }
  ]
}

The key here is that "BoolIfExists" is necessary, or if the MFA token doesn't exist it will return true, and allow all access anyway. But with this in place, no request to the API will succeed (other than the essential sts get-session-token) without first authenticating the session like this:

$ aws --profile leeron sts get-session-token --serial-number arn:aws:iam::640959109915:mfa/leeron --token-code 269036
{
    "Credentials": {
        "SecretAccessKey": "gSgMEbXYx/2rGuwEQDT4SuuGdcDTM1t22FYLvb1x", 
        "SessionToken": "FQoGZXIvYXdzEB0aDIv4enPpahc3ypCr8SKwAWfa28Ef65L73yxuQ6a1ylIOeYM/3k9e1z2PYX0qx6NqMdEdPxSFlFgKSVPvdYAx/tCMs2mI038ofMuMPhFOCrEE36XaXrKAgzOUPOWI1zdZJqvxPZzJ4Z+HBLAd/ujlWlKDVh77OgG3OjK6i4ruQkHUNaGpZUiZZdOixTI44Tvh46v+oyEMd0HyBluXIurh2RLyys3YYngUTFkE0PRx8s3w7m9pbl7b7Y5uDtGHhNpmKLqNr9wF", 
        "Expiration": "2018-09-02T23:17:14Z", 
        "AccessKeyId": "ASIAZKJBD3MNRZBDIQH4"
    }
}
$ export AWS_ACCESS_KEY_ID=ASIAZKJBD3MNRZBDIQH4
$ export AWS_SECRET_ACCESS_KEY='gSgMEbXYx/2rGuwEQDT4SuuGdcDTM1t22FYLvb1x'
$ export AWS_SESSION_TOKEN="FQoGZXIvYXdzEB0aDIv4enPpahc3ypCr8SKwAWfa28Ef65L73yxuQ6a1ylIOeYM/3k9e1z2PYX0qx6NqMdEdPxSFlFgKSVPvdYAx/tCMs2mI038ofMuMPhFOCrEE36XaXrKAgzOUPOWI1zdZJqvxPZzJ4Z+HBLAd/ujlWlKDVh77OgG3OjK6i4ruQkHUNaGpZUiZZdOixTI44Tvh46v+oyEMd0HyBluXIurh2RLyys3YYngUTFkE0PRx8s3w7m9pbl7b7Y5uDtGHhNpmKLqNr9wF"

The shell variables usefully take precedence to the configured [default] profile in your .aws/config or .aws/credentials settings, and so this will continue to work until your session token expires.

The Problem: Persistent Backend Storage

Minecraft is a good use-case scenario for test-running the new Condominium setup as it presents the basic common issue with any application: how to separate the stateless running code (for different versions of the Minecraft server), and the persistent storage that serves the backend.

In the Docker universe, this appears to be solved using "volumes" which contain datasets made available to running containers.

... ran out of time. Will have to touch up this post later.