/blog/

2025 1029 AWS account hygiene

I’ve been neglecting making security improvements to my AWS account, but a recent new project (announcement forthcoming) was a good opportunity to fix this.

The project will deploy via CI, and I’d like to limit the damage a compromised CI could do, particularly to my primary DNS zones. The best way to limit this is to create a separate AWS account scoped just to the project, which is described below, along with some other security improvements.

I’m happy to report that IAM Identity Center makes everything pretty smooth. I was afraid this would cause more disruption, but the new security speedbumps are manageable and don’t slow me down very much at all.

This post is mostly just a note to myself.

Removing tokens from root user

Amazon’s advice is to never use programmatic access tokens for the root user of an AWS account.

This never made sense to me, as for at least some work I use credentials with widely scoped access permissions. What is the benefit to creating an admin level user with the same permissions that the root user has and using that instead? But today I realized there is one way this makes sense: the root user can delete the account and affect billing settings, but an admin user with full CRUD permissions cannot.

I think this difference is prety minimal for my lab accounts, but not zero, so I went ahead and disabled my long-lived root access tokens for my primary account.

This is a one time task for each AWS account, so the best way to do it is in the CloudShell.

Creating sub accounts for CI

The easiest way to make sure a project’s wide resource creation and modification permissions cannot be used to affect existing infrastructure is to create a separate account per project. E.g. all my DNS for my primary domains are in Route53, and I want to add a new project that can also modify DNS records for the project’s own domain. The best separation is to just make a separate account for that project.

You can also do this with resource names, tags, etc, but this gets fragile. What’s going to be easy to understand when I come back to this project in 18 months is that all its resources are in a dedicated account.

Separate accounts are free.

You will need to create an IAM user that can manage accounts, though, because the main account root user cannot assume sub-account identities.

Organization hygiene

Creating separate accounts requires creating an AWS organization.

The account that creates the org is the account that will own the org, and this cannot be changed later.

Enable “Centralized root access for member accounts” in IAM from the org owner.

IAM and IAM Identity Center

  • These are entirely separate AWS products, lol
  • You have to IAM Identity Center in the console
  • IAM Identity Center is like a directory of users that can be assigned AWS permissions — conceptually, it’s like Active Directory for AWS

What I did

My starting place: me@micahrl.com was root user for my only AWS account, and it had programmatic access keys.

From there:

  • Create AWS organization
    • My current AWS account is now the owner of that organization
  • Modify my root AWS account
    • This is root for my primary AWS account — which is now also the organization owner
    • Deactivate its access keys, preventing programmatic access. (I found that these keys were created 3599 days ago - nearly 10 years!)
    • Change its email address from my primary me@micahrl.com address to an account root address me+aws-primary@micahrl.com
  • Create new account under the organization for my new project (TBD…)
    • The root email address for this account is me+aws-PROJECT@micahrl.com
    • Credentials are not created - neither username/password for logging in to the web console, nor access key for programmatic use
  • Enable IAM Identity Center
    • Created a new user with my primary me@micahrl.com address
    • Create a new permission set -> Predefined permission set -> AdministratorAccess
    • Assign my new user the new permission set for each account: AWS Organizations: AWS Accounts -> Select all accounts -> Assign users and groups -> Select the user and the permission set.
    • It sends that new user an email, and I log in and create my account.
    • Take note of the “start URL”, which this user will need to log in

To use the IAM Identity Center account to log in to the web console:

  • Visit the “Start URL”
  • Select the AWS account to log in to
  • It opens a new tab to the AWS console scoped to the account you selected

You can also copy credentials to be used on the command line after logging in to the Start URL, but the nicest way to use an IAM Identity Center account on the command line is to:

# Configure the account one time on each workstation
aws configure sso
# This launches an interactive command with the following prompts:
# SSO session name (Recommended): primary-micahrl # This doesn't matter, it just names the session we use to log in to IAM Identity Center
# SSO start URL [None]: https://SOMETHING.awsapps.com/start # This was provisioned with your IAM Identity Center instance
# SSO region [None]: us-east-2 # The region your IAM Identity Center instance is in
# SSO registration scopes [sso:account:access]: # Leave blank
# Attempting to automatically open the SSO authorization page in your default browser.
# If the browser does not open, open the following URL: ...
# (It waits for you to log in and authorize in a browser)
# There are 2 AWS accounts available to you.
#   Using the account ID XXXX # You can pick this by selecting with arrow keys
# The only role available to you is: AdministratorAccess
# Using the role name "AdministratorAccess"
# Default client Region [None]: us-east-2 # The default region you want to use when running the aws command etc
# CLI default output format (json if not specified) [None]: # Leaving as the default is fine
# Profile name [AdministratorAccess-379474500957]: primary-micahrl # Set a profile name, which is used below

# Log in whenever I need to use it, will launch a web browser and start a session
aws sso login --profile primary-micahrl

# For the duration of my session, execute commands with --profile
aws sts get-caller-identity --profile primary-micahrl
aws s3 ls ... --profile primary-micahrl # etc

# You can also inject AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY into your environment,
# which any AWS client can use directly, including 'hugo deploy' etc:
eval "$(aws configure export-credentials --profile primary-micahrl --format env)"

# After my session expires, I just have to reauthenticate with the same profile
aws sso login --profile primary-micahrl

# I use the same process to create profiles for all accounts that I added this IAM Identity Center user to
aws configure sso

You can also log in to the “start URL” on the web and get access to any account with delegated credentials

All of this is free!

Responses

Webmentions

Hosted on remote sites, and collected here via Webmention.io (thanks!).

Comments

Comments are hosted on this site and powered by Remark42 (thanks!).