How to contain a leaked cloud access key or compromised cloud identity
Disabling the credential, revoking the temporary sessions it already started, and scoping the principals, identity providers, and resources an attacker may have created for persistence, across AWS, Microsoft Entra, and Google Cloud.
How to contain a leaked cloud access key or compromised cloud identity
When you run this
A cloud credential or identity is known or strongly suspected to be under someone else's control. Common triggers:
- The provider or a secret scanner reports a long-lived access key committed to a public repository, a container image, or a build log.
- A threat-detection service raises a finding for anomalous API calls, credential use from an unexpected location, or instance credentials called from outside the instance.
- A user reports a phished console or single sign-on session, or you find an authenticated session you cannot account for.
- Another incident's investigation shows a workload credential being used from an address that is not the workload.
This procedure covers an identity you administer: an AWS IAM user or role, an AWS IAM Identity Center user, a Microsoft Entra user or service principal, or a Google Cloud user or service account. A compromised external identity provider is a wider problem: the containment step there is to break the federation trust and change the identity source, then run this procedure for every identity that provider could assert.
Before you start
- Use a responder identity that is separate from the one under investigation, ideally a break-glass account. It needs permission to disable credentials, edit directory and IAM objects, read the audit logs, and attach an organization-level deny (an AWS service control policy, an Entra Conditional Access policy, or a Google Cloud deny policy).
- Confirm the audit trail you will rely on was already running and centralized before the incident: AWS CloudTrail in every region delivering to a separate account, Entra diagnostic settings shipping sign-in and audit logs to a SIEM, Google Cloud Audit Logs with Data Access logging enabled where you need it. If audit logging was not on before the incident, you cannot reconstruct what the credential did; record that as a scoping limit and treat the identity's full permission set as exercised.
- Establish the identity's effective permissions now (IAM Access Analyzer and Access Advisor, Entra role assignments, the Google Cloud IAM policy). That is the ceiling on what you must assume the attacker could do.
Steps
-
Open an incident record and start a timeline. Fix the timestamp of the first suspicious event. You will use it as the session cutoff and as the start of every log query.
-
Preserve evidence before you change anything. Confirm audit logging is still running: a common early move is to stop it (
cloudtrail:StopLogging,cloudtrail:DeleteTrail,guardduty:DeleteDetector,config:StopConfigurationRecorder, or deleting an Entra diagnostic setting). Export or copy the relevant log range now, to storage the investigated identity cannot reach.Decision point: if logging was off or was tampered with, widen the scope. You must now assume the credential used its full permissions and treat every resource it could reach as suspect.
-
Disable the credential. Do not delete it yet.
- AWS long-lived access key: set it to Inactive. If AWS detected the
exposure it may have attached
AWSCompromisedKeyQuarantineV2; leave that in place and still deactivate the key. - Console or portal password: disable console access or block sign-in.
- Google Cloud service account key: disable the key. Deleting or disabling the key does not revoke short-lived access tokens already issued from it. To end those you must disable or delete the service account itself, then wait about 60 minutes for issued tokens to expire before re-enabling it. Plan for that outage.
- Entra application or service principal: set
accountEnabledtofalseon the service principal. Record thekeyIdof every credential first, then remove everypasswordCredentialandkeyCredential.
Deletion is kept for after rotation because a deleted access key also removes the ability to search some logs by its key ID.
- AWS long-lived access key: set it to Inactive. If AWS detected the
exposure it may have attached
-
Revoke active sessions and temporary credentials. A deactivated key does not end a session already established with temporary credentials.
- AWS IAM role: use Revoke active sessions, which attaches an inline
AWSRevokeOlderSessionspolicy that denies calls whoseaws:TokenIssueTimepredates the revocation. - AWS IAM Identity Center: disable the user, delete their active portal
sessions, then add an inline deny to the permission set (or a service
control policy) that denies all actions for that
identitystore:userIdwithaws:TokenIssueTimeearlier than now. - Entra user: revoke refresh tokens and sign-in sessions. For a service principal, disabling it and removing its credentials is the equivalent.
- Google Cloud: disabling the service account (step 3) covers workload identities. For a user, revoke the OAuth grant and force reauthentication.
- AWS IAM role: use Revoke active sessions, which attaches an inline
-
If the identity is privileged or you cannot yet bound what it did, apply an organization-level deny while you investigate. A service control policy denying all actions for the principal, a Conditional Access block, or a Google Cloud deny policy. This stops further action at the cost of breaking any legitimate automation that runs as the identity. Accept that for the investigation window.
-
Scope persistence and lateral movement from the audit log, starting at the first-suspicious timestamp:
- New IAM principals, access keys, login profiles, policy versions, attached
policies, and changed role trust policies (
iam:CreateUser,iam:CreateRole,iam:CreateAccessKey,iam:CreateLoginProfile,iam:AttachUserPolicy,iam:CreatePolicyVersion,iam:UpdateAssumeRolePolicy). - New or modified SAML and OIDC identity providers (
iam:CreateSAMLProvider,iam:UpdateSAMLProvider,iam:CreateOpenIDConnectProvider). This is a frequent persistence path. - Entra: new app registrations and service principals, credentials added under the audit activity "Update Application - Certificates and secrets management", new directory role assignments, new federation, new consent grants, new multi-factor methods, new inbox rules.
- Google Cloud: new service accounts and keys, added IAM policy bindings, new projects.
- Monitoring tampering: the logging and detection API calls listed in step 2.
- Resources created for abuse: compute instances in every region including stopped ones, serverless functions and layers.
- New IAM principals, access keys, login profiles, policy versions, attached
policies, and changed role trust policies (
-
Eradicate. Remove every attacker-created principal, key, policy, identity provider, trust relationship, and resource found in step 6. Check every region, not only the ones you use. Rotate any secret the identity could read: assume it called the secret-retrieval API for your secrets manager and key vault.
-
Rotate and re-issue the legitimate credential through the normal path. Create the replacement, deploy it to consumers, verify they work, then delete the old credential. Keep a record of every deleted key ID so you can keep searching logs for its use.
-
Recover. Restore any data or configuration the attacker changed from backups that predate the first-suspicious timestamp. Where integrity is uncertain, rebuild from a trusted source rather than clean in place.
-
Lift the temporary organization-level deny once eradication is verified. Re-enable a disabled Google Cloud service account only after its token-expiry window, and only with fresh credentials. Re-enable an Entra service principal only with new credentials.
Irreversible boundaries
- Deactivating a credential is reversible: reactivate it if you break a production consumer. Deleting a key is effectively permanent and also costs you some log-search ability, so delete only after rotation is confirmed.
- The Google Cloud service-account disable has a hard floor of about 60 minutes before already-issued access tokens expire. Nothing forces them to expire sooner.
- Changing an IAM Identity Center identity source away from a compromised external provider deletes all synchronized users and groups, and when moving away from Active Directory it also deletes permission-set assignments. Record the current state before you do it.
- If the attacker deleted the audit history for the incident window and you have no separate copy, that evidence is gone. Proceed on worst-case assumptions.
Verify
- The compromised credential shows Inactive or disabled, and a test API call with it is denied.
- The audit log shows no successful calls by the identity after the cutoff timestamp, allowing for the Google Cloud token-expiry window.
- A fresh audit-log query and a resource enumeration across all regions return none of the attacker-created principals, keys, policies, identity providers, or resources from step 6.
- IAM Access Analyzer, or the equivalent, shows no external-principal findings introduced during the incident window.
- Legitimate consumers run on rotated credentials; the old credential is deleted and its ID recorded.
- Detection is back on: audit logging active in every region, threat-detection service enabled.
Sources
- https://docs.aws.amazon.com/guardduty/latest/ug/compromised-creds.html
- https://github.com/aws-samples/aws-customer-playbook-framework/blob/main/docs/Compromised_IAM_Credentials.md
- https://docs.cloud.google.com/docs/security/compromised-credentials
- https://learn.microsoft.com/en-us/security/operations/incident-response-playbook-compromised-malicious-app
- https://learn.microsoft.com/en-us/azure/security/fundamentals/incident-response-overview
- https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_revoke-sessions.html
- https://csrc.nist.gov/pubs/sp/800/61/r2/final
