Posted on 15 July 2020, updated on 21 December 2023.

Software that interacts with the AWS API needs to perform authentication before sending any meaningful requests. On larger projects that have strong security requirements or that use multiple AWS accounts, handling intricate mechanisms like multi-factor authentication or chained role assumptions can make your code complex and harder to maintain.

Basic use of AWS profiles

AWS profiles exist in the ~/.aws/credentials on your machine. The simplest use-case is to write your AWS credentials like this:

This defines a profile called padok that you can use everywhere. In a bash script…

In a Go program…

In your Terraform code, to configure a state backend…

Or to configure a Terraform resource provider…

Or even multiple Terraform resource providers at once…

The whole point is that all your code ever needs is the name of your AWS profile. From there, AWS libraries automatically get all the information required to authenticate from the ~/.aws/credentials file.

Assuming AWS IAM roles

AWS IAM roles are often used to gain certain privileges on other AWS accounts. You can assume a role in many ways, but most involve doing it explicitly every time you need to use a certain role. This is absolutely feasible but AWS profiles allow you to configure authentication with role assumptions once and then forget about it.

Building on the padok profile from earlier, I can create two new profilespadok_staging and padok_production — that each uses a different role in a different AWS account.

Before you can assume a role, you need to be authenticated as a user. The source_profile field tells the AWS library which profile provides my user’s credentials. Once authenticated, the library assumes the role specified in the role_arn field.

I can use the padok_production profile in my code just as I used the padok profile in the examples above, and all my requests to the AWS API will seamlessly be made using the role specified in the ~/.aws/credentials file.

Did you know that once you have assumed an AWS IAM role, you can use that role to assume another one? This is called role chaining, and can be very useful in larger organisations where people require different sets of permissions on multiple projects.

With AWS profiles, role chaining is simple to set up. The source_profile and role_arn fields are all you need.

With this setup, my AWS IAM user has permission to assume a role in account 000011112222. I can then use this role to assume roles in accounts 333344445555 or 666677778888. I can use padok_production_alpha and padok_production_bravo interchangeably whenever I need to access different production environments.

Despite the complexity of the authentication method used, my code remains clean and simple: all I need to specify is the name of the profile to use.

Multi-factor authentication

When users have access to production environments, it is often best to set up multi-factor authentication — or MFA, for short — as an extra layer of security. However, when a developer wishes to run code that uses the AWS API, MFA can be an obstacle and slow the developer down.

To perform MFA, you need two things: your MFA device serial number and the seed used to generate one-time passwords. These parameters should have been provided to you by your system administrator when you were setting up your AWS user.

Useful tip: if you scanned a QR code to set up one-time passwords on an app, that QR code contained the seed to use.

You can add these parameters to your ~/.aws/credentials file in the same profile that contains the usual AWS credentials for your user.

Notice that we also added an empty profile called padok_mfa. This is important, so be sure to add it.

For one of our client’s projects, we wrote a simple shell script that reads the MFA serial number and seed from the padok profile, performs multi-factor authentication, and writes usable credentials in the padok_mfa profile. Feel free to use it by writing it to ~/.aws/update-credentials.sh. Remember to make the file executable.

For this script to work, you will need to have the aws, jq, and oathtool commands available. On OS X, you can install them by running brew install awscli jq oath-toolkit.

Once you have run this script, you should see that the padok_mfa profile has been updated in your ~/.aws/credentials file.

You can now use the padok_mfa profile as you would any other AWS profile. Whether or not you use multi-factor authentication will have no impact on your code beyond the name of the profile you use.

One drawback is that the credentials obtained when performing MFA expire after an hour. In order to avoid having to run the script manually over and over, you can add the following entry to your crontab so that it runs automatically every 30 minutes.

Now you never have to worry about MFA again.

Everything at once

What if you need to perform multi-factor authentication and then assume a role, or even chain roles? Can that be expressed inside your ~/.aws/credentials file? Absolutely.

You can use padok_mfa as the source_profile of another profile, and then chain role assumptions exactly like before.

While your ~/.aws/credentials file does have some added complexity, it provides a simple and powerful abstraction so that your software does not need to manage complex authentication mechanisms. All your code will ever need is the name of the AWS profile to use.

At Padok, we use abstractions like this one every day to make sure the code we write is maintainable and that our SREs are as productive as possible.