Skip to content

2025

IAM Users are a bad Idea

Image

Try the Cringy Podcast format of this post (NotebookLM):

Hallucinations are present in the AI generated Podcast

In AWS, IAM Users are just about everywhere, often seen as the primary means of ingress to an AWS environment, be it for getting access to the AWS Console, giving some sort of system access to AWS Resources, or setting up an automated workflow with AWS. If you've spent any amount of time tinkering on AWS, you will have, no doubt, seen countless tutorials, or forum examples on how to configure access to your environment utilizing IAM Users. Any time you see a the requirement for an ACCESS_KEY_ID or a SECRET_ACCESS_KEY, this implies that an IAM User is being used.

What's the problem with IAM Users

The problem...? Well, by nature IAM Users have long-lived access at whatever permission level is specified in the policies attached to that user. This means that by default, no matter the conditions, whatever systems make use of an IAM User's access keys, those systems will always need access at the level specified. Move the system to a new host? Access remains unchanged. Now, I know that there are work-arounds for this, where you can use Condition Statements in your IAM Policies to somewhat control the conditions for the permissions specified, but, this does assume, people are writing their own policies instead of simply using AWS Managed Policies, or copying them from ChatGPT.

It is also really hard to manage MFA Enforcement for IAM Users as an account wide policy. I believe that MFA should be enforced for any human users whenever they take action in AWS Accounts that I manage - regardless of access level. Although IAM Users can with relative ease make use of MFA, enforcing it, whilst allowing users to manage their own MFA Devices is challenging. If you get that right, its also significantly more complex present your MFA device when using the CLI.

Use IAM Roles wherever you can

Roles offer a far-superior mechanism for managing the permission scope (Attached Policies) and the "Who/What" and "Under what conditions" these permissions can be used (Trust Policy). This will hopefully help you avoid a lot of unnecessary risk exposure, if done right.

Don't Underestimate the importance of a Well-Defined Trust Policy

Most people put a lot more thought (if any) into the specific permissions applied to a role, when I would argue that it is more important to properly define Who or What and under What conditions the role may be assumed. I would feel far more comfortable giving my Terraform deployment role AdministratorAccess provided that I very carefully define which branch of which repository the Action Runner is allowed to run from to access the role, compared to if I had carefully scoped out very specific permissions, but left the Trust Policy vague.

TLDR

To avoid running on endlessly about why I don't much like IAM users, I have added summarized my dislikes regarding IAM Users below.

  • MFA Enforcement is challenging, and the use thereof is complicated with the CLI.
  • Access granted through IAM Users is permanent by default.
  • Access Keys need to be regularly rotated.
  • IAM Users are limited to 1 Account (yes, cross account roles are a thing, but they are gross).
  • In multi-account AWS Organizations, IAM Credentials need to be maintained in each individual account.
  • Unused Keys need to be deleted.
  • Handling Access Keys is risky.
  • In most cases, there are simply better ways to handle access to your aws environment than using IAM Users.

I will explore below some examples of ways to replace IAM Users in your AWS Estate.

For the Humans - IAM Identity Center

AWS Identity Center (formally AWS SSO) is AWS' implementation of Enterprise Single Sign-On, and allows you make use of temporary role-based access when assigning access to users in your AWS Estate. Identity Center can be configured to work in both the context of an AWS Organization or in a single AWS Account - although it is definitely optimized for an organization. Some of the features I really like are summarized below:

  • MFA Enforcement for all users is very easy.
  • Permissions can be centrally managed fro an entire AWS Organization from a single place.
  • Multiple Roles can be given to a single user or group in a single account - and with a bit of work, the roles can be conditional.
  • A single user or group can have differing permissions.
  • It can integrate with a multitude of Identity Sources (including Entra ID / Active Directory), or it can use it's own.
  • Any applications supporting OIDC or SAML integration can be integrated with IAm Identity Center to Manage User Access.
  • Its free to use.

The Management interface for IAM Identity Center is pretty intuitive to use. Managing things like Users, Groups, Permission Sets (Roles), and AWS Account Assignments is straightforward. Enforcing MFA for all users is literally a checkbox exercise.

User Access to the Console

Logging in to an AWS Account with IAM Identity Center is equally as straightforward as logging in to an AWS account with an IAM User. The only real difference is that instead of logging into an AWS Account directly, you will log in to a Single Sign-On Portal, from which you will have access to which ever accounts you have been granted access to with whichever Roles you have assigned to you. See the Screenshot below as an example.

SSO Roles SSO Roles

Clicking on any of the roles assigned to you under one of the accounts will open the AWS Console in that account, and with that Role, in a new tab in your browser.

User Programmatic Access

If you are already familiar with the AWS CLI, then switching to use IAM Identity Center is very straightforward. There is a slight difference in how you configure your credentials, and before making use of your configured credentials in the CLI, you will need to run an aws sso login command and present MFA when prompted in your browser (How often you need to do this depends on the session duration configured for the permission set you are using).

Here is a comparison of using an IAM User and an Identity Center User for the AWS CLI.

  • Configuring Credentials aws configure --profile <profile_name>
    • Here you will provide the Access Key ID and Secret Access Key of your IAM User.
  • Use the Credentials aws s3 ls --profile <profile_name>
  • Configuring Credentials aws configure sso --profile <profile_name>
    • Here you will need to provide a series
  • Login aws sso login --profile <profile_name>
    • Here you will need to present MFA in a pop-up in your web browser.
  • Use the Credentials aws s3 ls --profile <profile_name>

Always use names Profiles with the AWS CLI

Named Profiles allow for multiple sets of configurations for different AWS Accounts or Roles. If you work frequently with multiple AWS Accounts, or have different roles within an AWS Account, then named profiles also make it harder to accidentally run a command against the wrong account, or with dangerously elevated permissions. Named Profiles can also be used with the AWS SDK (any supported language) to authenticate with AWS.

Less-Human Users

Admittedly things tend to get slightly more complex when configuring system access to your aws environment, such as integrating a SIEM Tool with your aws account, or configuring a CI/CD Pipeline to authenticate with AWS. Things can get especially tricky when the system you are integrating does not natively support making use of an IAM Role directly. In most cases there will still be ways to work around this. I believe that the principle of only creating a User for an actual human should still stand.

To keep this discussion brief, I will go over an example of configuring authentication a CI/CD Pipeline built with GitHub Actions using OIDC (OpenID Connect). I will then also give a few brief mentions of solutions that may work for your system.

Example | CI/CD Pipeline with OIDC - GitHub Actions Workflow

Almost every blog post or online forum showing how to authenticate a Github Actions Workflow with AWS will show you how to do it using an AWS IAM User. Fortunately, there is some very good documentation on how to do this with OIDC if you turn to the github docs. AWS also has a handy blog post about how to do this.

The process is a three step one:

Read the documentation - please don't follow this blindly.

This is just one simple example. The documentation will give you a better idea of how to apply this to your environment.

  1. Create an OIDC Identity Provider
    • For the Provider use: https://token.actions.githubusercontent.com
    • For the Audience use: sts.amazonaws.com
  2. Create and IAM Role
    • Configure the Trust Policy as follows (Replace the items between the < >):
        {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "Federated": "<ARN_of_Identity_Provider_from_step_1>"
                    },
                    "Action": "sts:AssumeRoleWithWebIdentity",
                    "Condition": {
                        "StringLike": {
                            "token.actions.githubusercontent.com:sub": "repo:<github-org>/<repo-name>:*"
                        },
                        "StringEquals": {
                            "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
                        }
                    }
                }
            ]
        }
      
    • Set the Permissions to the minim,um required for your pipeline tasks.
  3. Configure the Github Actions Workflow
    • Below are the two examples illustrating what you might need to do differently to modify your Github Actions Workflow to make use of OIDC to authenticate with AWS.
name: Gross way with IAM User

on:
  push:
    branches:
      - main

jobs:
  aws-thing:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Configure aws credentials
      uses: aws-actions/configure-aws-credentials@v4
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: eu-west-1

    - name: Do the AWS Things
      run: |
        aws s3 sync / s3://${{ secrets.BUCKET_NAME }}/ --delete
name: Tasty way with OIDC

on:
  push:
    branches:
      - main

permissions:
  id-token: write
  contents: read

jobs:
  aws-thing:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Configure aws credentials
      uses: aws-actions/configure-aws-credentials@v4
      with:
        role-to-assume: ${{ secrets.DEPLOYMENT_ROLE }}
        aws-region: eu-west-1

    - name: Do the AWS Things
      run: |
        aws s3 sync / s3://${{ secrets.BUCKET_NAME }}/ --delete
Permissions Block

Note the additional permissions block that is required here for the OIDC Option. This is needed to facilitate the JWT Exchanged.

Honorable Mentions

IAM Roles Anywhere

AWS IAM Roles Anywhere enables workloads outside AWS, such as on-premises servers or applications, to securely access AWS resources using X.509 certificates from a trusted certificate authority (CA). The CA is registered with IAM Roles Anywhere as a trust anchor, allowing workloads to obtain temporary security credentials.

This method removes the need for long-term credentials, enhances security through short-lived credentials, and integrates seamlessly with IAM roles and policies. It's particularly useful for hybrid or multi-cloud environments requiring secure AWS access.

OIDC

OIDC (OpenID Connect), built on OAuth 2.0, enables secure authentication by relying on an external identity provider (IdP), like Google, to issue JSON Web Tokens (JWTs) after user authentication. In AWS, these tokens are used to request temporary security credentials via an IAM OIDC identity provider.

By setting up roles in IAM, AWS dynamically assigns temporary credentials to users based on the JWT's claims. This approach eliminates the need for static credentials, enhancing security and simplifying access to AWS resources for applications like web or mobile apps.

SAML

SAML enables systems to securely access AWS resources by using a trusted identity provider (IdP) for authentication. The system authenticates with the IdP, which verifies its identity and issues a SAML assertion containing key details like identity attributes and group memberships. This assertion is securely passed to AWS, where it is validated against pre-configured trust settings.

AWS then allows the system to assume a specific IAM role based on the information in the SAML assertion, granting temporary security credentials with defined permissions. This approach ensures access is both secure and dynamic, avoiding the need for long-term credentials while enforcing fine-grained access control aligned with organizational policies.

Conclusion

I don't completely dislike IAM Users, but hopefully I have illustrated the point that there are, in most cases better options. Please let me know in the comments bellow if you have any thoughts or examples of how you have purged IAM users from your estate - Or even if you have a case which proves IAM Users to be the very best option available. Also do feel free peruse the additional links I've added on the left pane of this blog post (Or at the bottom if you're reading this on your phone).

Lets all make sure we do out best to keep "Users" for Humans, and use better means for systems. Lets also do our best to use the best tools at our disposal to securely manage who and what has access to our environments. The world would be a better place for it.