Back to Checks
aws

IAM user does not use long-lived credentials to access services other than IAM or STS

iam_user_with_temporary_credentials
Service: iamSeverity: high
OfficialBuilt-inVerified
Categories:identity-accesssecrets
Resource Type:AwsIamUser

IAM users are assessed for activity using long-lived access keys. Use of static credentials to access services other than IAM or STS indicates reliance on permanent keys instead of temporary role-based credentials.

Risk

Persistent access keys enable attacker persistence and replay. Stolen keys allow off-network API calls for data exfiltration, privilege changes, and destructive actions, impacting confidentiality, integrity, and availability. Without expiry, the blast radius grows and containment is harder.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks iam_user_with_temporary_credentials

Recommendation

Adopt temporary credentials via IAM roles and federation for humans and workloads. Remove or restrict long-term keys; if unavoidable, apply least privilege, require MFA, rotate aggressively, and monitor usage. Prefer short session durations and session conditions to limit blast radius.

Remediation

CLI

aws iam put-user-policy --user-name <example_resource_name> --policy-name deny-non-iam-sts-with-long-term-creds --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Deny","NotAction":["iam:*","sts:*"],"Resource":"*","Condition":{"Null":{"aws:TokenIssueTime":"true"}}}]}'

Terraform

# Attach an inline policy to block long-term creds from non-IAM/STS services
resource "aws_iam_user_policy" "deny_non_iam_sts_longterm" {
  name = "DenyNonIamStsWithLongTermCreds"
  user = "<example_resource_name>"  # Critical: target the affected IAM user

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Deny"
      NotAction = ["iam:*", "sts:*"]
      Resource  = "*"
      Condition = {
        Null = { "aws:TokenIssueTime" = "true" } # Critical: denies when no session token (long-lived creds)
      }
    }]
  })
}

NativeIaC

# Attach a policy to block long-term creds from accessing non-IAM/STS services
Resources:
  DenyLongTermNonIamSts:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: DenyNonIamStsWithLongTermCreds
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Deny
            NotAction:
              - iam:*
              - sts:*
            Resource: "*"
            Condition:
              Null:
                aws:TokenIssueTime: "true"  # Critical: denies when no session token (i.e., long-lived creds)
      Users:
        - <example_resource_name>  # Critical: attach to the affected IAM user

Other

1In AWS Console, go to IAM > Users and select <example_resource_name>
2Open the Security credentials tab
3Under Access keys, deactivate and delete all active access keys
4Save changes
5Re-test: the user no longer has long-lived credentials to access non-IAM/STS services

Check Code

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.iam.iam_client import iam_client


class iam_user_with_temporary_credentials(Check):
    def execute(self) -> Check_Report_AWS:
        findings = []

        for (
            user_data,
            last_accessed_services,
        ) in iam_client.user_temporary_credentials_usage.items():
            user_name = user_data[0]
            user_arn = user_data[1]

            report = Check_Report_AWS(
                metadata=self.metadata(),
                resource={"name": user_name, "arn": user_arn},
            )
            report.resource_id = user_name
            report.resource_arn = user_arn
            report.region = iam_client.region
            # Search user in iam_client.users to get tags
            for iam_user in iam_client.users:
                if iam_user.arn == user_arn:
                    report.resource_tags = iam_user.tags
                    break

            report.status = "PASS"
            report.status_extended = f"User {user_name} doesn't have long lived credentials with access to other services than IAM or STS."

            if last_accessed_services:
                report.status = "FAIL"
                report.status_extended = f"User {user_name} has long lived credentials with access to other services than IAM or STS."

            findings.append(report)

        return findings