Skip to main content

IAM User Long-Lived Credentials

Overview

This check identifies IAM users who rely on long-lived access keys (static credentials) instead of temporary, role-based credentials when accessing AWS services other than IAM or STS.

Long-lived access keys never expire on their own. If they are stolen or leaked, an attacker can use them indefinitely until you manually rotate or delete them.

Risk

If this check fails, your IAM users are using static access keys that:

  • Never expire - Unlike temporary credentials, access keys remain valid until you manually deactivate them
  • Enable persistent access - A stolen key can be used from anywhere in the world to access your AWS resources
  • Are difficult to contain - Without automatic expiration, compromised keys require manual intervention to revoke
  • Can lead to data theft, privilege escalation, or destructive actions - Attackers can use leaked keys to access sensitive data or spin up expensive resources

Remediation Steps

Prerequisites

You need:

  • AWS Console access with IAM permissions, OR
  • AWS CLI configured with appropriate IAM permissions
Setting up AWS CLI (if needed)
  1. Install the AWS CLI: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
  2. Configure credentials: aws configure
  3. Verify access: aws sts get-caller-identity

AWS Console Method

This is the recommended approach for most users.

Step 1: Navigate to IAM Users

  1. Sign in to the AWS Console
  2. Go to IAM (search for "IAM" in the top search bar)
  3. Click Users in the left sidebar

Step 2: Review the affected user

  1. Click on the user name flagged by Prowler
  2. Select the Security credentials tab
  3. Scroll down to the Access keys section

Step 3: Deactivate the access key

Before deleting, deactivate the key first to ensure nothing breaks:

  1. Find the active access key
  2. Click Actions next to the key
  3. Select Deactivate
  4. Wait 24-48 hours and monitor for any application failures

Step 4: Delete the access key

Once you have confirmed nothing depends on the key:

  1. Click Actions next to the deactivated key
  2. Select Delete
  3. Confirm the deletion

Step 5: Transition to temporary credentials

Instead of creating a new access key, set up the user to assume an IAM role:

  1. Create an IAM role with the permissions the user needs
  2. Grant the user permission to assume that role
  3. Have the user use aws sts assume-role or configure their application to use role-based credentials
AWS CLI Method

List access keys for a user:

aws iam list-access-keys \
--user-name <your-username> \
--region us-east-1

Deactivate an access key:

aws iam update-access-key \
--user-name <your-username> \
--access-key-id <access-key-id> \
--status Inactive \
--region us-east-1

Delete an access key (after confirming it is safe to remove):

aws iam delete-access-key \
--user-name <your-username> \
--access-key-id <access-key-id> \
--region us-east-1

Apply a deny policy for long-lived credentials (alternative approach):

If you cannot immediately remove access keys, you can apply a policy that denies access to non-IAM/STS services when using long-lived credentials:

aws iam put-user-policy \
--user-name <your-username> \
--policy-name DenyLongLivedCredentialsForNonIAMSTS \
--policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyAccessWithLongTermCredentials",
"Effect": "Deny",
"NotAction": ["iam:*", "sts:*"],
"Resource": "*",
"Condition": {
"Null": {
"aws:TokenIssueTime": "true"
}
}
}
]
}' \
--region us-east-1

This policy uses the aws:TokenIssueTime condition key. When this key is null (not present), it means the request is using long-lived credentials rather than temporary credentials from STS.

CloudFormation Template

This template creates an inline policy that denies access to non-IAM/STS services when using long-lived credentials:

AWSTemplateFormatVersion: '2010-09-09'
Description: Deny long-lived credentials for non-IAM/STS services

Parameters:
UserName:
Type: String
Description: The IAM user to apply the policy to

Resources:
DenyLongLivedCredentialsPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: DenyLongLivedCredentialsForNonIAMSTS
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: DenyAccessWithLongTermCredentials
Effect: Deny
NotAction:
- iam:*
- sts:*
Resource: '*'
Condition:
'Null':
aws:TokenIssueTime: 'true'
Users:
- !Ref UserName

Outputs:
PolicyName:
Description: Name of the created policy
Value: !Ref DenyLongLivedCredentialsPolicy

Deploy the template:

aws cloudformation create-stack \
--stack-name deny-long-lived-creds-<your-username> \
--template-body file://template.yaml \
--parameters ParameterKey=UserName,ParameterValue=<your-username> \
--region us-east-1
Terraform Configuration
variable "user_name" {
description = "The IAM user to apply the policy to"
type = string
}

resource "aws_iam_user_policy" "deny_long_lived_credentials" {
name = "DenyLongLivedCredentialsForNonIAMSTS"
user = var.user_name

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "DenyAccessWithLongTermCredentials"
Effect = "Deny"
NotAction = ["iam:*", "sts:*"]
Resource = "*"
Condition = {
"Null" = {
"aws:TokenIssueTime" = "true"
}
}
}
]
})
}

Apply the configuration:

terraform init
terraform apply -var="user_name=<your-username>"

Verification

After remediation, verify the fix:

  1. Go to IAM > Users > select the user > Security credentials
  2. Confirm the Access keys section shows no active keys
CLI Verification
# List access keys - should return empty or show no Active keys
aws iam list-access-keys \
--user-name <your-username> \
--region us-east-1

# If you applied the deny policy, verify it exists
aws iam get-user-policy \
--user-name <your-username> \
--policy-name DenyLongLivedCredentialsForNonIAMSTS \
--region us-east-1

Re-run the Prowler check to confirm the finding is resolved:

prowler aws --check iam_user_with_temporary_credentials

Additional Resources

Notes

  • Deactivate before deleting: Always deactivate access keys for 24-48 hours before deleting to catch any applications that depend on them
  • Update applications first: If applications use the access key, update them to use IAM roles or instance profiles before removing the key
  • Consider federation: For human users, consider using AWS IAM Identity Center (SSO) instead of IAM users with access keys
  • EC2 and Lambda: Workloads running on EC2 or Lambda should use IAM roles attached to the resource, not access keys
  • The deny policy is a stopgap: Applying the deny policy restricts long-lived credentials but does not eliminate them. The best practice is to delete the keys entirely and transition to temporary credentials