Your single AWS account is a serious risk

Michael WittigUpdated 30 Aug 2016

Your AWS account is one of the most valuable things you own if you run a business on AWS. If you only own a single AWS account, you’re facing a serious security risk! The post will show you why this a problem and how you can solve it.

This post received over 300 points and 100 comments on Hacker News.

The risky default: a single AWS account

A single AWS account contains IAM users together with EC2 virtual servers, S3 buckets, RDS databases, and everything else you need to run your business. You have two ways to log in to your account: AWS Management Console (using username + password) or AWS access credentials used by the CLI and SDKs. The figure demonstrates how this works.

Single AWS account

When you type something like …

$ aws ec2 describe-instances

… into your terminal, your AWS access credentials (usually residing somewhere at ~/.aws/) are used to authenticate your request. You authenticate as an IAM user. The IAM user in most cases has AdministratorAccess, which means you can do anything. Why? You need to be able to administer all services. If someone gets access to your AWS access credentials, you’re in trouble.

You can improve this situation two ways.

1st improvement: Don’t use AdministratorAccess

To follow the principle of least privilege, it’s very unlikely that AdministratorAccess is what you need. PowerUserAccess is an improvement, because it doesn’t let you use the IAM service. Much better is having ReadOnlyAccess and using writing permissions only when needed. But that’s difficult to implement using IAM users. You need to create a user for each “least privilege,” and you need to generate access credentials for each user. Such a setup quickly becomes unmanageable if you aren’t the only user in your AWS account. I’ll call this security debt.

2nd improvement: Use multi-factor authentication

AWS provides excellent support for multi-factor authentication (MFA). You can use a hardware device or a software device to generate a token. Your password or access credentials together with the MFA token are then used to authenticate. Getting access to your account is now much more difficult.

Read on to learn how to implement these improvements.

Separating concerns with a bastion account

Instead of a single AWS account, you create another account. I’ll call this your bastion account. The bastion account contains only your IAM users — nothing else. The figure illustrates the idea.

Bastion AWS account

IAM users in the bastion account are very limited. They can only get temporary credentials and assume a role. Implement this by creating a group in the bastion account with an inline policy, as follows:

{
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "1",
        "Effect": "Allow",
        "Action": [
            "sts:AssumeRole"
        ],
        "Resource": "*",
        "Condition": {"Bool": {"aws:MultiFactorAuthPresent": "true"}}
    },
    {
        "Sid": "2",
        "Effect": "Allow",
        "Action": [
            "sts:GetSessionToken"
        ],
        "Resource": "*"
    }
]
}

Assign this group to all the IAM users in the bastion account. Make sure they don’t have any other policies attached!

The first Statement lets a user assume a role (but only if the request is authenticated using MFA). The second Statement lets a user get a temporary session by providing the MFA token. Let’s look at how this works.

The secure solution: MFA with role delegation

It’s time to summarize the setup: How does it work? The following figure shows the MFA authentication and role delegation flow.

MFA with role delegation

  1. You have AWS access credentials for your IAM user in the bastion account on your machine (usually in ~/.aws/ or in your environment variables). You make a call to the AWS API to get temporary credentials by providing an MFA token. If the MFA token is valid, you’ve created a short-lived session for your IAM user in the bastion account.

  2. You receive temporary credentials to authenticate as your IAM user.

  3. With the temporary credentials, you can assume a role in another account (this wasn’t possible before because assuming a role is only allowed for after authenticating with MFA). To assume a role in another account, the role must explicitly be allowed to be used with your account! The maximum permissions a role should have is PowerUserAccess. Don’t allow the role to interact with IAM!

  4. You receive temporary credentials and can begin working with your AWS account.

Implementation

The AWS CLI supports MFA authentication by default. Andreas has written up detailed instructions here.

This blog post has been translated into German: Ein einziger AWS Account ist ein ernsthaftes Risiko.

Michael Wittig

Michael Wittig

I’ve been building on AWS since 2012 together with my brother Andreas. We are sharing our insights into all things AWS on cloudonaut and have written the book AWS in Action. Besides that, we’re currently working on bucketAV, HyperEnv for GitHub Actions, and marbot.

Here are the contact options for feedback and questions.