Résumé
ONYEDIKACHI BERNARDCLOUD · DEVSECOPS · AI
RésuméGet in touch
CASE 03IDENTITY & ACCESS

AWS IAM Compromise Investigation

A deployment user had picked up AdministratorAccess and a new access key. I removed both, confirmed they were gone, and built an EventBridge to SNS alert so the next high-risk IAM change does not go unnoticed.

Status: REMEDIATED · DETECTION ADDED

DOMAIN
Identity & access
PLATFORM
AWS IAM, CloudTrail, EventBridge, SNS
SEVERITY
High
OUTCOME
Contained and monitored

TOOLS

AWS IAMAWS CLIAWS CloudShellAWS CloudTrailAmazon EventBridgeAmazon SNSIAM access keysJSON event patterns
RESULT
BEFOREAdmin policy and a rogue key
AFTERBoth removed, 13 IAM events alerted
01

Objective

I set out to find and undo unauthorized IAM changes on a deployment user, remove the excess admin access and the rogue credential, and add event-driven monitoring for high-risk IAM changes.

02

Scenario

The IAM user app-deployer showed two signs of unauthorized change: the AWS-managed AdministratorAccess policy was attached to it, and it had a recently created access key that nobody could account for. My plan was to investigate the user and its credentials, remove the privileges, deactivate and delete the key, then add detection and test it with a controlled event.

03

What I found

FINDING 01HIGH

AdministratorAccess on a deployment user

app-deployer had AdministratorAccess attached. For an application deployment identity that is a privilege boundary failure: if its credentials leaked, an attacker could act on almost anything in the account.

FINDING 02HIGH

A rogue access key

The user had a newly created access key that was not part of the expected deployment workflow. An unexpected key is a second way into the account that works outside the application.

FINDING 03MEDIUM

No alerting on high-risk IAM changes

Nothing raised an alert when the policy was attached or the key was created. Changes like AttachUserPolicy and CreateAccessKey could happen without anyone being told.

04

What I did

  1. Identified the rogue key

    I stored the account ID and found the most recently created access key on app-deployer. The key value is never written down.

  2. Removed admin access

    I detached AdministratorAccess and confirmed the user had no attached policies left.

  3. Disabled, then deleted the key

    I set the key to inactive first, deleted it, and confirmed the user had no access keys left.

  4. Set up notifications

    I created an SNS topic, iam-change-alerts, with an email subscription and a topic policy that lets EventBridge publish to it.

  5. Built the detection rule

    I created the EventBridge rule iam-high-risk-changes to match 13 high-risk IAM API calls recorded by CloudTrail, and pointed it at the SNS topic.

  6. Tested it with a controlled event

    I created a test access key to trigger a CreateAccessKey event, then deleted the test key straight away.

In production I would investigate an unauthorized change before rolling it back, to tell a legitimate admin action from a malicious or accidental one.

EVIDENCE

BASH
# Find the newest access key on the user (value never printed)
ROGUE_KEY_ID=$(aws iam list-access-keys --user-name app-deployer \
  --query "sort_by(AccessKeyMetadata, &CreateDate)[-1].AccessKeyId" --output text)

# Remove admin access, then disable and delete the key
aws iam detach-user-policy --user-name app-deployer \
  --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
aws iam update-access-key --user-name app-deployer --access-key-id $ROGUE_KEY_ID --status Inactive
aws iam delete-access-key --user-name app-deployer --access-key-id $ROGUE_KEY_ID

# Detection: EventBridge rule to SNS
aws events put-rule --name iam-high-risk-changes \
  --event-pattern file://iam-event-pattern.json --state ENABLED
aws events put-targets --rule iam-high-risk-changes --targets "Id=sns-iam-alerts,Arn=$SNS_ARN"

Event pattern for the rule:

iam-event-pattern.json
{
  "source": ["aws.iam"],
  "detail-type": ["AWS API Call via CloudTrail"],
  "detail": {
    "eventSource": ["iam.amazonaws.com"],
    "eventName": [
      "AttachUserPolicy", "AttachRolePolicy", "AttachGroupPolicy",
      "PutUserPolicy", "PutRolePolicy", "PutGroupPolicy",
      "CreateUser", "CreateAccessKey", "CreateLoginProfile",
      "UpdateAssumeRolePolicy", "DeactivateMFADevice",
      "DeleteUser", "DeleteAccessKey"
    ]
  }
}
05

Validation

After the changes, the user had no attached policies and no access keys. The rule target was added with FailedEntryCount: 0, and the controlled CreateAccessKey call matched the rule's pattern.

CHECKRESULT
Attached policies on app-deployerNone
Access keys on app-deployerNone
EventBridge ruleEnabled
SNS targetAdded, 0 failed entries
Test keyCreated, then deleted
06

Before and after

CONTROLBEFOREAFTER
Administrative policyAdministratorAccess attachedRemoved
Rogue access keyPresentDeactivated and deleted
IAM change monitoringNo alertingEventBridge rule
High-risk IAM eventsNot watched13 API calls matched
NotificationNot configuredSNS topic
Detection testNot runControlled CreateAccessKey
07

What I recommend

  1. 01Do not give application identities AdministratorAccess without a documented reason.
  2. 02Alert on high-risk IAM changes: policy attachments, access key creation, trust policy edits and MFA changes.
  3. 03Review access keys regularly and remove unused or unexpected ones.
  4. 04Prefer roles and temporary credentials for workloads over long-lived user keys.
  5. 05Investigate before reverting suspicious changes.
  6. 06Test detections with controlled events instead of assuming a rule works.

“IAM incident response is not finished when the bad permission is gone. You also have to remove the compromised credential and put detection in place for the next change like it.”

WHAT I LEARNED

SKILLS IT PROVES

  • Cloud Security Incident Response
  • AWS IAM
  • Access Key Management
  • Credential Lifecycle Management
  • Privilege Remediation
  • AWS CloudTrail
  • Amazon EventBridge
  • Amazon SNS
  • Event-Driven Detection
  • Security Monitoring and Alerting
  • Security Control Validation
View my labs on GitHub