I've been digging into Amazon Web Services (AWS)1 user administration. One of my first goals was to create a user, send them their password, and let them manage the rest of their credentials without me.

The various credential types are located under the "My Security Credentials2" section for each user. They are:

  1. IAM Password for console access
  2. Access keys for CLI, SDK, & API access
  3. Multi-factor authentication (MFA)
  4. X.509 certificate
  5. SSH Keys
  6. HTTPS Git credentials for AWS CodeCommit

Amazon provides five built-in IAM policies that provide access to the credential sets. The first one, IAMFullAccess, provides full admin control over the Identity and Access Management (IAM) service. Not only does it allow users to manage their own details, it allows them to create, delete, and otherwise mess with any other user, group, policy, role, etc… Not something to give a non-admin user.

A second built-in AWS policy is IAMReadOnlyAccess. It does just what it says on the tin, providing read-only access to the various parts of the IAM dashboard. So, no help there when it comes to letting users set their credentials.

The last three built-in policies (and what they correspond to) are:

  1. IAMSelfManageServiceSpecificCredentials - allows users to update their HTTPS Git credentials for AWS CodeCommit
  2. IAMUserChangePassword - allows users to update their IAM Password for console access
  3. IAMUserSSHKeys - allows users to update their SSH Keys

Half way there, but we're still left without the ability to manage "Access keys for CLI, SDK, & API access", "Multi-factor authentication (MFA)", and "X.509 certificate". Since what I was looking for wasn't built-in, I went about building a custom policy myself.

After referencing a half dozen web pages, IAM docs3 and just as many StackOverflow4 pages, I came up with the following policy definition. It provides users with control of all six sets of credentials. It also required Multi-Factor Authentication (MFA)5 and locks users out of all AWS services until it's set up.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["iam:ListVirtualMFADevices"],
      "Resource": "*"
    },
    {
      "Sid": "AllowUsersToManageCoreCredentials",
      "Effect": "Allow",
      "Action": [
        "iam:*AccessKey*",
        "iam:ChangePassword",
        "iam:GetUser",
        "iam:*ServiceSpecificCredential*",
        "iam:*SigningCertificate*"
      ],
      "Resource": ["arn:aws:iam::*:user/${aws:username}"]
    },
    {
      "Sid": "AllowIndividualUserToListOnlyTheirOwnMFA",
      "Effect": "Allow",
      "Action": ["iam:ListMFADevices"],
      "Resource": [
        "arn:aws:iam::*:mfa/*",
        "arn:aws:iam::*:user/${aws:username}"
      ]
    },
    {
      "Sid": "AllowIndividualUserToManageTheirOwnMFA",
      "Effect": "Allow",
      "Action": [
        "iam:CreateVirtualMFADevice",
        "iam:DeleteVirtualMFADevice",
        "iam:EnableMFADevice",
        "iam:ResyncMFADevice"
      ],
      "Resource": [
        "arn:aws:iam::*:mfa/${aws:username}",
        "arn:aws:iam::*:user/${aws:username}"
      ]
    },
    {
      "Sid": "AllowIndividualUserToDeactivateOnlyTheirOwnMFAOnlyWhenUsingMFA",
      "Effect": "Allow",
      "Action": ["iam:DeactivateMFADevice"],
      "Resource": [
        "arn:aws:iam::*:mfa/${aws:username}",
        "arn:aws:iam::*:user/${aws:username}"
      ],
      "Condition": {"Bool": {"aws:MultiFactorAuthPresent": "true"}}
    },
    {
      "Sid": "AllowIndividualUserToManageTheirSSHCredentials",
      "Effect": "Allow",
      "Action": [
        "iam:DeleteSSHPublicKey",
        "iam:GetSSHPublicKey",
        "iam:ListSSHPublicKeys",
        "iam:UpdateSSHPublicKey",
        "iam:UploadSSHPublicKey"
      ],
      "Resource": "arn:aws:iam::*:user/${aws:username}"
    },
    {
      "Sid": "BlockMostAccessUnlessSignedInWithMFA",
      "Effect": "Deny",
      "NotAction": [
        "iam:CreateVirtualMFADevice",
        "iam:EnableMFADevice",
        "iam:ListMFADevices",
        "iam:ListUsers",
        "iam:ListVirtualMFADevices",
        "iam:ResyncMFADevice"
      ],
      "Resource": "*",
      "Condition": {"BoolIfExists": {"aws:MultiFactorAuthPresent": "false"}}
    }
  ]
}

Speaking of MFA, it's easy to use in the web console. Using it on the command line isn't as straight forward. For details on the basic process check out this video from Amazon. (If you're like me, this looks like a prime opportunity to write a little script to help automate the process. That's left as an exercise for the reader.)


Footnotes

  1. One of the marvels of the modern world, Amazon Web Services is the "Cloud Computing" platform that's eating the software world.
  2. Every user has a My Security Credentials section they can use to manage their various credentials, assuming they have permissions to do so. Which, of course, is what this post is all about.
  3. Amazon's documentation is some of the best I've ever seen. The IAM docs are no exception (despite not having the specific thing I was after).
  4. Another marvel of the modern world, StackOverflow is the place to go for all your programming question wants and needs. (Though, again, they didn't have what I was looking for. At least, not until I post this there as well.)
  5. Multi-factor Authentication is the way to go. The basic idea is that logging in requires "something you have and something you know". The thing you know is your password. The thing you have is some type of device (or app on your phone) that spits out random numbers every 30 seconds. If you don't have the proper numbers to go along with your password, you can't login. The reason this is important is if your password gets stolen, the bad guys can't get in but you still can with your MFA device.