IAM User credentials with MFA
Tags: aws, iam, mfa, commandline
Published: 2023-01-02 08:15:38

When you use IAM user for programmatic access. You have an `ACCESS_KEY` and a `SECRET_ACCESS_KEY`. With these credentials you are able to interact with AWS. A common pattern is that you will use the IAM User to assume roles in the same or even in different AWS accounts.
The CLI configuration would look something like this:

```ini
[profile my-role]
source_profile = default
role_arn = arn:aws:iam::111122223333:role/Administrator
mfa_serial = arn:aws:iam::111122223333:mfa/my-iam-user
```

But when you use this role for the first time. Or when the cached credentials are expired it will prompt for MFA token. When you use many accounts and profiles this becomes annoying. You could configure and use a longer session time on your roles. But you still need to enter your MFA token per role.
In this blog post I will explain why this is and what you can do to avoid it!

How does it work?
-----------------

So what happens under the hood? When you perform an cli command like:

```bash
aws s3 ls --profile=my-role
```

It will first check in the `~/.aws/cli/cache/` folder if there are credentials cached. If not or if the credentials are expired an `assume-role` call is executed. Because we configured the `default` source profile. It will use the `default` credentials found in the `~/.aws/credentials` file.

```ini
[default]
aws_access_key_id = AKIAXXXXXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

Because we configured an `mfa_serial` under our profile in our `~/.aws/config` file. The AWS cli will prompt for the token and once given it will do the assume-role API call. If everything is fine temporary credentials are returned and these are cached.

![Assume role using MFA Token](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kkaos9caeg8kgtm8k4fq.png)

The problem with this approach is that it will be executed each time you need to assume a role. Therefor triggering an MFA prompt each time you use a role. For the first time or if the cached credentials are expired.

How can I avoid it?
-------------------

You can avoid the MFA prompts by first fetching the temporary credentials of the IAM User using MFA. This will give you credentials that are MFA authenticated. And because they are already MFA authenticated. There is no need to provide the token during the assume-role API call.


![Fetch STS Credentials then assume role](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kfzxsjdt0a83n7glz5ye.png)

As you can see we split the process into 2 parts:

1. Fetch the temporary credentials for the IAM User using MFA.
2. Use the temporary credentials to assume the `my-role` role.
The magic behind this approach is because we have split them. You are able to repeat step 2 with other roles. This removes the MFA token prompt because we are already authenticated using MFA.
To make this easier I wrote a small cli tool called [aws-iam-login](https://github.com/Nr18/aws-iam-login) that helps you with this!
It only needs to know the `mfa_serial` and `username`. You can retrieve these if you execute:

```bash
aws-iam-login default init
```

This command will fetch the ARN of the caller identity. Based on this identity we will determine the username and mfa\_serial of the IAM User. These will then be stored in the `~/.aws/credentials` file. For example:

```ini
[default]
aws_access_key_id = AKIAXXXXXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
mfa_serial = arn:aws:iam::111122223333:mfa/my-iam-user
username = my-iam-user
```

Now you can use the tool as followed:

```bash
aws-iam-login default
```

This authenticates against the AWS API. And request temporary credentials from AWS using your MFA Token. These credentials are then stored as `<profile-name>-sts`. For example:

```ini
[default-sts]
aws_access_key_id = ASIAXXXXXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
aws_session_token = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
expiration = 2022-07-25 19:00:00+00:00
```

So if you now use the following in your `~/.aws/config` file:

```ini
[profile my-role]
source_profile = default-sts
role_arn = arn:aws:iam::111122223333:role/Administrator
```

You will now use the temporary credentials defined in the `~/.aws/credentials` file. When the temporary credentials become invalid. Re-run the `aws-iam-login default` command and new credentials will be fetched.

### Rotating your credentials

Next to helping you assume roles [aws-iam-login](https://github.com/Nr18/aws-iam-login) can help you with more! It can rotate your credentials for you! You can do this with the following command:

```bash
aws-iam-login default rotate
```

And the tool will:

1. List all available keys for the user, when 1 key is active rotation is possible!
2. Create a new **AccessKey** and **SecretAccessKey**.
3. Use the created keys to deactivate the old keys.
4. Write the new keys to the `~/.aws/configuration` file.
5. Delete the old keys.

Conclusion
----------

By using the temporary credentials of the IAM user. You are not prompted to enter your MFA token every time.
And [aws-iam-login](https://github.com/Nr18/aws-iam-login) can help you with that!