How to securely manage credentials to multiple AWS accounts

Problem space

As soon as you your start working with more than one project or organization at AWS cloud, the first question you may have, is how to manage awscli credentials and have an ability to use them in easy and secure way to get access to all your AWS accounts and environments.

I always was not a big fan of ~/.aws/credentials file, because every single time I was coming to a new customer, I had a need to open this file for edit to add new credentials. As a result, I constantly had a feeling, that I displayed all my existing credentials to all security cameras in the office. God, bless the inventor of the privacy screens!

The second problem with credentials, is that they need to be renewed from time to time. More accounts you have, more efforts you spend on credentials rotation.

And the third problem - it is assuming roles in a terminal sessions and working in several different environments at the same time.

Solution

As a solution for the first two problems, not too far ago I started using:

As a solution for last two problems, I found that the following tooling stack suits most of my needs:

Managing AWS credentials

Here’s quick getting started guide.

Installation

I’m assuming here, that you already have zsh and oh-my-zsh installed. 😎

Let’s install aws-vault. Here’s the complete list of installation steps for most available platforms.

We’ll be doing everything for OS X:

brew cask install aws-vault

Choosing aws-vault backend

aws-vault supports several backends to store your credentials. My personal prefference is encrypted file. So, you need to add the following variable to your ~/.zshrc:

export AWS_VAULT_BACKEND="file"

Moving credentials

Now open your ~/.aws/credentials file. For every existing profile add credentials to aws-vault

cat ~/.aws/credentials

aws-vault add <profile_1>
aws-vault add <profile_2>

Now, add the following variable to your ~/.zshrc file, to prevent aws-vault for asking for your password every single time:

export AWS_VAULT_FILE_PASSPHRASE="my_strong_password"

You may rename ~/.aws/credentials and later on completely delete it as soon as you test everything.

Switching AWS profiles

To list all your AWS profiles, just type:

aws-vault list

Great, now you can easily switch your environment and see, where you’re working:

aws-vault exec <profile_name>

Here’s how it finally looks like:

zsh and aws vault integration

Role based approach

Well, ok, we just moved all our AWS credentials to a secure vault and configured our terminal to display our current aws-vault session. Now it’s time to discuss, how we can improve the solution even more.

Multi-account organization

One of best practices for organizing AWS users access to different AWS accounts - is managing all IAM users in one AWS account and providing access to another AWS accounts by allowing them to consume roles (sts:AssumeRole call) from that accounts.

Here’s the the typical AWS Organization example:

AWS Organizations structure example

AWS provided a great explanation of How to Use a Single IAM User to Easily Access All Your Accounts by Using the AWS CLI in their blog post, where they describing role consuming process and awscli configuration. I’ll not copy-paste them. Instead, we’ll concentrate on aws-vault configuration to do the similar thing, but without ~/.aws/credentials file.

Assuming you already have all necessary grants and permissions between your accounts.. If not, here’s the great article on that topic - Tutorial: Delegate Access Across AWS Accounts Using IAM Roles.

Default profile setup

You should already have your default profile setup in place at ~/.aws/config file. Probably, it looks something like that:

[profile default]
region = us-east-1

Let’s configure aws-vault as a credential source for our default profile:

[profile default]
region = us-east-1
credential_process = /usr/local/bin/aws-vault exec -j default

Now, if you grant permissions to your user or role from default profile to assume AWS role from another account, you’ll be able to specify new profiles configuration like that:

[profile default]
region = us-east-1
credential_process = /usr/local/bin/aws-vault exec -j default
mfa_serial = arn:aws:iam::012850762433:mfa/admin

[profile account_1_role_admin]
region = us-east-1
role_arn = arn:aws:iam::<account_id>:role/admin
source_profile = default

[profile account_2_role_qa]
region = us-east-1
role_arn = arn:aws:iam::<account_id>:role/qa
source_profile = default

source_profile configuration option will tell awscli, which account to use to grab role for any given profile.

AWS STS Assume Role

Testing

The fastest way to test, that you’re able to assume role, is to call:

aws sts get-caller-identify

You should see something similar for your default profile:

{
    "UserId": "AIDDRCTFVGBHNJMGF3WI7R",
    "Account": "01234567890",
    "Arn": "arn:aws:iam::01234567890:user/admin"
}

To test any other profile call:

aws sts get-caller-identity --profile account_1_role_admin

You should see output similar to the following:

{
    "UserId": "AROALKJHGFGDFV3IR2VSI:botocore-session-1584897134",
    "Account": "012345678901",
    "Arn": "arn:aws:sts::012345678901:assumed-role/admin/botocore-session-1584897134"
}

Bonus: Passwordless AWS Web console login

As a small bonus to those of you, who came to the end, here’s how to login to AWS web console for every given profile:

aws-vault login <profile name>

Summary

Using zsh, aws-vault and AWS sts:AssumeRole feature together can significantly simplify and make more secure management of multiple AWS accounts and their credentials.

If you like the article, please, feel free to spread it to the worl.

And of cause, if you have any questions, suggestions or comments, feel free to use Disqus below.

Authors


Author avatar
Andrei Maksimov

I’m a passionate Cloud Infrastructure Architect with more than 10 years of experience in IT.

This post represents my personal experience and opinion around the topic.