Right, let’s talk about the single most important tool for not accidentally deploying your resume to your production environment: named profiles. You’ve probably already used the default profile. You ran aws configure, shoved in your keys, and off you went. That’s fine for a single account, like your personal sandbox. But the moment you have more than one AWS account (and you will, because this is AWS and they give them out like candy), using the default profile is a one-way ticket to “oh god why is my production database in us-east-1 now?”

Think of a named profile as a specific persona you assume when using the AWS CLI. It’s not just a set of credentials; it’s a complete identity, bundling together the credentials, the default region, and the default output format for a specific AWS account and role. This is your mechanism for context switching without losing your mind.

The Basic Setup: It’s Just a File

Under the hood, profiles are just stashed in a plaintext file at ~/.aws/config (and the credentials live in ~/.aws/credentials). You can edit these with a text editor, and I often do because it’s faster. The CLI just provides a slightly more friendly way to manage them.

To create a profile the CLI way, you use the --profile flag. Let’s set up one for a dev account:

aws configure --profile dev-account
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: us-west-2
Default output format [None]: json

Now, peek inside your ~/.aws/config file. You’ll see something beautiful and structured:

[default]
region = us-east-1
output = json

[profile dev-account]
region = us-west-2
output = json

And in ~/.aws/credentials:

[default]
aws_access_key_id = AKIAI44QH8DHBEXAMPLE
aws_secret_access_key = je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY

[dev-account]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

Notice the subtle but crucial difference? The config file uses [profile profile-name] while the credentials file uses just [profile-name]. This is one of those charming, utterly pointless inconsistencies that you just have to memorize. I don’t make the rules.

Actually Using These Things

To use a profile, you slap that --profile flag onto any AWS CLI command.

aws s3 ls --profile dev-account

This command will list the S3 buckets in your dev account, using the credentials and region you defined for the dev-account profile. The magic is that it leaves your default profile completely untouched. This is how you avoid those heart-stopping mistakes.

Leveling Up: Assuming IAM Roles

Using long-term access keys (the ones you just configured) is better than nothing, but it’s not the pinnacle of security. The real power move is to have profiles that assume an IAM role in a target account. This is the AWS security best practice we should all be using. You configure a profile with short-term credentials that it automatically fetches and refreshes by assuming a role.

Here’s how the magic works. You have a “source” profile (with those long-term keys) that has permission to assume a role in a “target” account. You then create a new profile that knows how to perform that assumption.

Let’s say your long-term keys are in a “master” account, and you want to assume the AdminRole in a “production” account. Your config would look like this:

[profile master-user]
region = us-east-1
output = json

[profile prod-admin]
role_arn = arn:aws:iam::123456789012:role/AdminRole
source_profile = master-user
region = us-east-1

Now, when you run:

aws s3 ls --profile prod-admin

The CLI does this behind the curtains: it uses the credentials from master-user to call AssumeRole for the AdminRole in account 123456789012. It receives back a set of temporary credentials, uses those to make the S3 API call, and then caches those temp credentials so it doesn’t have to call AssumeRole again until they expire. It’s seamless, secure, and brilliant.

The Environment Variable Override

Here’s a pro tip that will save you from scripting headaches. The --profile flag is great for interactive use, but what about in a shell script where you want to be explicit? You can use the AWS_PROFILE environment variable to set the profile for every subsequent command in that shell session.

export AWS_PROFILE=prod-admin
aws s3 ls
aws ec2 describe-instances
# Both commands now use the prod-admin profile

This is incredibly useful. It also clearly demonstrates the precedence rules: an explicit --profile flag in a command will always win. Then AWS_PROFILE. Then, and only then, will it fall back to the default profile. This hierarchy is your friend. Use it to lock down dangerous commands.

The Gotchas and Rough Edges

  1. The Cached Credentials Problem: When assuming roles, the temp credentials are cached in ~/.aws/cli/cache. If you revoke the permissions of the master-user to assume the role, the cached credentials are still valid until they expire. This can lead to a confusing window where things seem to work but are actually broken. It’s a trade-off for not hammering the AssumeRole API.
  2. MFA is a Breeze (Once Configured): If your role requires MFA, the CLI will prompt you for the token code when it first assumes the role. It then caches the credentials with the MFA session, so you won’t be prompted again for a while. It’s actually a pretty elegant solution. You just have to remember your MFA device isn’t just for the web console anymore.
  3. The Profile Name Dance: The profile names in your config file are arbitrary. You can call [profile prod-admin] whatever you want. I recommend a naming convention that includes the account purpose and role, like prod-readonly or dev-ci-deploy. Your future self, frantically trying to figure out what profile-2 does, will thank you.