DEV Community

Rocky
Rocky

Posted on

Revoking The Key Didn't Kill The Session

2am, the pager fires: CloudTrail flagged an AssumeRole call from an ASN nobody on the team recognizes, using an access key that hasn't shown activity in four months. The instinct that kicks in first, for almost everyone the first time this happens, is to revoke the access key immediately and call it handled.

It isn't handled. AssumeRole doesn't hand out the long-term access key to whoever called it, it hands out a temporary session: an access key ID, a secret key, and a session token, valid for however long the role's session duration allows, often up to an hour, sometimes longer if someone configured it generously. Once that session exists, it exists independently of the credentials used to create it. Revoking or deleting the original IAM user's access key does nothing to a session that's already been issued. If the attacker got in with an old key, assumed a role, and is now operating on that temporary session, disabling the key you found stops them from doing it again. It does not stop what's happening right now.

What actually kills an active session is revoking the role's temporary credentials directly, which in AWS means attaching a deny-all inline policy scoped to that session (using the aws:TokenIssueTime condition to invalidate anything issued before the moment you respond) or, if you can afford the blast radius, deleting the role itself. That's the step that gets skipped when the first reaction is "rotate the key and move on," and it's the difference between an incident that's actually contained and one that looks contained on a dashboard while the session quietly keeps working for another forty minutes.

The harder part comes after containment, when you try to figure out if this happens the same way on the next cloud provider your org runs, because it doesn't. AWS logs this as an AssumeRole event in CloudTrail with a specific set of fields. Azure's equivalent identity assumption shows up in the Activity Log under a completely different event schema, tied to Azure AD token issuance rather than an IAM role session. GCP's short-lived credentials, issued through its Security Token Service, land in Admin Activity audit logs under yet another naming convention. Write a detection rule against CloudTrail's exact field names and it catches nothing anywhere else, which means the org either writes and maintains three separate rule sets by hand, one per provider, or someone eventually doesn't, and the next provider added to the environment ships with a detection gap nobody planned on.

This is the actual argument for detection-as-code: write the logic once, in a provider-agnostic format like Sigma, describing the behavior you care about (temporary credential issuance from an unfamiliar network location, followed by API activity inconsistent with that identity's history) rather than one cloud's specific field names, and translate it to each provider's log schema instead of hand-writing it three times and hoping the second and third copies stay current with the first.

Codelivly's Cloud Detection and Response Book covers exactly this: detection-as-code and Sigma rules built to work across AWS, Azure, GCP and Kubernetes, plus the incident response steps that actually contain a session instead of just the credential that created it.

Top comments (0)