Implementing the sudo access pattern for AWS IAM Users

When you create an AWS account from scratch, you also create an omnipotent “root” account. AWS recommends against using it for everyday tasks and encourages you to create an IAM user. By default, IAM users don’t have credentials or access; it’s up to you to configure them. The complexity of AWS IAM authentication and access control can make it tough to design a good usability and security tradeoff for the regular AWS “human” user.

One design patten to consider is sudo. Sudo is a Unix feature that lets users impersonate another user of the system, by default the superuser account, but if you consider the sudo pattern as “re-establish trust before I elevate privileges”, it’s commonly used outside of operating systems.

You will see a sudo-like pattern for accessing the Google Administrator Console:

Re-authentication for Google

And on Github when you edit security settings:

Github re-authentication dialog

What makes this design useful is that the friction of authentication ceremonies and permission negotiation are aligned with the risk of trust decisions. I think it’s also becoming more familiar to developers, and because familiarity is usability, it should be easier to roll out then tactical access restrictions that can be hard to intuit.

The setup described below puts sensitive functionality behind a sudo-like prompt for MFA for web and API access, and offers some protection from malware designed to steal AWS API credentials.

Access Control

When you create IAM users, AWS recommends you consider the concept of least privilege — and the first step is to “determine what users need to do”. AWS has many services, each with dozens of different actions, and each account has a potentially large number of different resources. Like configuring a file system for least privilege, it can be difficult to know a priori what user needs which kind of access to particular resources.

Let’s assume, for now, read access by an adversary is less bad than write access, which may make sense if your primary concern is credential theft and someone spinning up a bunch of cryptocurrency mining EC2 instances.

Create your IAM User

Create an IAM home user. Create the password, and add an MFA device. We’ll add access keys later.

Assign a read-only policy

Give the IAM user the managed policy of ReadOnlyAccess, which grants access to all read operations.

Create sudo role

Create a role named sudo that can be assumed by the home user with an MFA condition. The assume role policy should look something like this:

{
"Version": "2012–10–17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::YOUR_ACCOUNT_NUMBER:user/home"
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}

While in practice you may want to use more tailored permissions, here we’ll attach the AdministratorAccess managed policy to the sudo role.

You should now be able to assume the sudo role in the web console using the “Switch Role” functionality. You’ll be prompted for an MFA code.

Credentials

IAM users can have three authentication factors: a password for the web console, access keys for the API, and an MFA device. There are some generic guidelines to stick with: generate and store the password with a password vault, enable MFA. If you’re concerned about your phone account security or SMS attacks, you may even want to use a hardware key or burner SMS for MFA.

What about access keys? There are a variety of command line tools for assuming roles when using the AWS API, but the one I’ve been recommending is aws-vault, which has the extra feature of storing AWS access keys in an OS-level keychain, which means you’re prompted for a password when they’re used by a new process. It works fairly well for macOS, although I get the sense the system keychain API is overly aggressive with password prompts. The Windows/Linux support appears to be even less polished, but if a piece of malware sweeps your environment variables and configuration files for AWS access keys, aws-vault will keep you in the clear. Plus, you can configure your bash profile with some simple commands to make web and API access with the sudo pattern fast.

Install aws-vault

You can install aws-vault using a package manager or build it from source. Add the home users AWS credentials by running aws-vault add home and entering your access key ID and secret. You’ll also create a keychain password that you’ll need to enter when you use these credentials. This should be a type-able, memorized password, since copy/paste for the macOS keychain isn’t well-supported.

Then you can remove any existing credentials and setup your sudo profile in ~/.aws/config:

[profile home]
region=us-west-1
[profile sudo]
mfa_serial=arn:aws:iam:YOUR_ACCOUNT_NUMBER:mfa/home
source_profile=home
role_arn=arn:aws:iam::YOUR_ACCOUNT_NUMBER:role/sudo

Use aws-vault

You can see that the AWS CLI can’t find your credentials:

$ aws sts get-caller-identity
Unable to locate credentials. You can configure credentials by running “aws configure”.

Then you can verify that you can use aws-vault to expose your credentials:

$ aws-vault exec home
$ aws sts get-caller-identity
{
"Account": "…",
"UserId": "…",
"Arn": “arn:aws:iam::...:user/home"
}
$ echo $AWS_ACCESS_KEY_ID
ASIAIX...

Set up fast AWS access

To make it lightning fast to use aws-vault for both web and CLI login, add something like this to your bash profile:

function av {
echo 'Opening console...'
PS1="\[\e[32m\]\$AWS_VAULT_SESSION_NAME\[\e[m\] $ " AWS_VAULT_SESSION_NAME=home aws-vault exec home --
}
function avconsole {
echo 'Opening web console...'
aws-vault login home
}
function avsudo {
echo 'Opening sudo console…'
PS1="\[\e[32m\]\$AWS_VAULT_SESSION_NAME\[\e[m\] $ " AWS_VAULT_SESSION_NAME=sudo aws-vault exec sudo --
}
function avsudoconsole {
echo 'Opening sudo web console…'
aws-vault login sudo
}

Now, you can type av to start a command line sub-shell with an updated bash prompt:

$ av
Opening console...
home $

avsudo will prompt for MFA and then give you a command line session using the sudo role:

$ avsudo
Opening sudo console...
Enter MFA creds: XXXXX
sudo $

Similarly, you can run avconsole or avsudoconsole to open a web console with home or sudo, using the aws-vault login command.

Follow-up

You can customize the read-only policy to allow whatever actions you want in non-sudo mode, if you want to restrict certain reads or allow certain writes without MFA. Similarly, you can limit the sudo permissions to a set list of services and resources. For an organization, you’ll likely want Federation or automation to sync IAM users with a corporate directory.

This pattern allows you to create a blast radius using MFA that may even block unsophisticated malware. The world of threat models is large and varied, so in practice this model is just a baseline for more sophisticated configuration.

Essentially, this simple system demonstrates a user-friendly workflow. I can check up on things without digging out my phone, but to modify settings, I avsudoconsole, enter my MFA, and use the temporary elevated permission role credentials.