How to migrate from access keys to IAM roles
Topic: Accounts access
Summary
Migrate applications from IAM user access keys to IAM roles so workloads use temporary credentials and keys can be removed. Use instance profiles for EC2, execution roles for Lambda, and OIDC or assume-role for external/on-prem; then rotate off and delete the old keys.
Intent: How-to
Quick answer
- Identify where the app runs (EC2, Lambda, ECS, external); create an IAM role with the same (or reduced) permissions the app needs and the correct trust policy for that environment.
- Deploy the role (instance profile, Lambda execution role, OIDC role) and update the app to use the default credential chain—remove access key from config or environment.
- Verify the app works with the role; then deactivate and delete the IAM user's access keys and optionally remove or restrict the user.
Prerequisites
Steps
-
Audit current key usage
Identify the IAM user and policies used by the app; list the actions and resources the app actually uses (CloudTrail, code review) so the new role has least privilege, not more.
-
Create the IAM role and attach policies
Create a role with trust for the right principal (ec2, lambda, OIDC, etc.); attach policies that grant only the required actions and resources; do not attach the same broad policy as the user unless necessary.
-
Deploy the role and switch the app
Attach the role to the resource (instance profile, Lambda execution role, etc.); update the app to stop using static credentials (remove AWS_ACCESS_KEY_ID, etc.) and use the default credential chain so it picks up the role.
-
Remove the old keys
Verify the app runs correctly with the role; then deactivate and delete the IAM user's access keys used by this app; document and repeat for other apps still on keys.
Summary
You will migrate applications from IAM user access keys to IAM roles by creating a role with the correct trust and permissions, attaching it to the workload (EC2, Lambda, etc.), switching the app to the default credential chain, and then removing the old keys. Use this to eliminate long-lived keys and reduce blast radius.
Prerequisites
- Application(s) currently using IAM user access keys (stored in config, env, or secrets manager). See How to create access for applications without IAM users, How to create an IAM role for EC2, and How to create an IAM role for Lambda.
- IAM permissions to create roles, attach policies, and delete access keys.
Steps
Step 1: Audit current key usage
- Identify the IAM user and its attached policies (and group memberships). List the access keys used by the app.
- Use CloudTrail (filter by access key ID or user) to see which APIs the app actually calls and on which resources. Design the new role to grant only those actions and resources (least privilege). Avoid copying AdministratorAccess to the role.
Step 2: Create the IAM role and attach policies
- EC2: Create a role with trust
Service: ec2.amazonaws.com, attach the minimal policies, create an instance profile and add the role to it. - Lambda: Create a role with trust
Service: lambda.amazonaws.com, attach the minimal policies. - External/on-prem/CI: Use OIDC (e.g. GitHub Actions) or an IAM user/role that can assume this role; create a role with trust for the OIDC provider or the assuming principal. Attach the same minimal policies.
Attach only the permissions the app needs; do not attach the user’s full policy set unless required.
Step 3: Deploy the role and switch the app
- EC2: Attach the instance profile to the instance(s) running the app. In the app config or environment, remove AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and any profile that used the key. Restart the app so it uses the instance metadata credentials (default chain).
- Lambda: Set the function’s execution role to the new role. Remove any layer or env that injected the old key. Redeploy and test.
- External: Configure the external system to assume the role (e.g. OIDC flow or assume-role with temporary credentials). Remove the static key from the external config.
Verify the app can perform its normal AWS operations (e.g. S3, DynamoDB). Use get-caller-identity from the app to confirm the role ARN.
Step 4: Remove the old keys
- Confirm no other system uses the same access key (search configs, CI, secrets manager). If the key is shared, migrate all consumers to roles or a single new key before removal.
- Deactivate the access key:
aws iam update-access-key --user-name USER --access-key-id KEY_ID --status Inactive - Monitor for errors; then delete the key:
aws iam delete-access-key --user-name USER --access-key-id KEY_ID - If the IAM user is no longer used for anything, consider revoking and deleting the user (see revoke guide).
Verification
- The application runs without static credentials and uses the role (get-caller-identity shows the role ARN).
- The old access key is deactivated and deleted; list-access-keys for the user shows no key or only keys for other uses.
- No other workload or script is broken by the key removal.
Troubleshooting
App fails with no credentials after switch — Ensure the role is attached to the resource (instance profile on EC2, execution role on Lambda). Ensure the app uses the default credential chain and does not still read key from a config file or env. Restart the app after attaching the role.
Role has less permission than the user — Add the missing action or resource to the role’s policies. Use CloudTrail from the old key period to see what was called and align the role policy.
Shared key used by multiple apps — Migrate one app at a time to a role (or to a new key), or create one role per app and migrate all, then delete the key when no consumer remains.