AWS IAM User Self-Created Access Key Subsequently Used
Detects an AWS IAM user using an existing credential to create a new access key for itself and subsequently using the new key within one hour. This behavior can indicate an adversary converting compromised credentials into an additional long-term credential for persistence. Unlike a standalone self-service key creation alert, requiring subsequent use of the new key reduces noise from unused or abandoned credential-rotation operations.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2026/07/13"
3integration = ["aws"]
4maturity = "production"
5updated_date = "2026/07/13"
6
7[rule]
8author = ["Elastic"]
9description = """
10Detects an AWS IAM user using an existing credential to create a new access key for itself and subsequently using the
11new key within one hour. This behavior can indicate an adversary converting compromised credentials into an additional
12long-term credential for persistence. Unlike a standalone self-service key creation alert, requiring subsequent use of
13the new key reduces noise from unused or abandoned credential-rotation operations.
14"""
15false_positives = [
16 """
17 Approved credential-rotation automation may create and immediately validate or use a replacement access key. Confirm
18 the principal, source addresses, user agents, timing, and change records. Exclude only verified rotation workflows.
19 """,
20]
21from = "now-35m"
22language = "esql"
23license = "Elastic License v2"
24name = "AWS IAM User Self-Created Access Key Subsequently Used"
25note = """## Triage and analysis
26
27### Investigating AWS IAM User Self-Created Access Key Subsequently Used
28
29This rule detects an IAM user using an existing access key (Token A) to create a new access key for itself (Token B), followed by an AWS API request authenticated with Token B within one hour. The creation event proves that Token A was used to request the additional credential, while the subsequent CloudTrail event confirms that Token B became active.
30
31This sequence can indicate persistence after an IAM user's credentials are compromised. An adversary can use the compromised key to create another long-term credential, then continue accessing the account through the new key even after the original credential is identified and disabled.
32
33### Possible investigation steps
34
35- Identify the IAM user and AWS account using `aws.cloudtrail.user_identity.arn` and `cloud.account.id`.
36- Review Token A in `Esql_priv.aws_cloudtrail_user_identity_access_key_id_creator_values`. Determine whether it is an expected credential for the IAM user and whether it was previously observed from unusual infrastructure.
37- Confirm that the key in `Esql_priv.aws_cloudtrail_response_elements_access_key_access_key_id_values` matches the subsequently used key in `Esql_priv.aws_cloudtrail_user_identity_access_key_id_created_key_use_values`.
38- Compare `Esql.source_ip_self_access_key_creation_values` with `Esql.source_ip_created_access_key_use_values`. A rapid change in source IP, ASN, geography, or hosting provider increases suspicion.
39- Compare `Esql.user_agent_original_self_access_key_creation_values` with `Esql.user_agent_original_created_access_key_use_values` to identify changes between the creation and use clients.
40- Review `Esql.event_action_created_access_key_use_values` to determine what Token B accessed or modified after creation.
41- Examine nearby CloudTrail activity for IAM reconnaissance, MFA changes, login-profile changes, policy modifications, or attempts to create additional credentials.
42- Confirm whether the activity corresponds to an approved credential-rotation workflow and whether the user is permitted to create its own long-term access keys.
43
44### False positive analysis
45
46- Approved credential-rotation automation may create and immediately test or use a replacement access key.
47- Developer onboarding or recovery workflows may create a key and validate it with an initial AWS API request.
48- Validate the principal, source addresses, user agents, timing, and change records before excluding the activity. Prefer narrowly scoped exceptions for verified automation rather than excluding the IAM user broadly.
49
50### Response and remediation
51
52- If unauthorized, deactivate or delete Token B immediately.
53- Rotate or disable Token A and investigate how it was exposed or compromised.
54- Review every CloudTrail event authenticated with Token B and determine whether it accessed data, changed IAM permissions, created resources, or established additional persistence.
55- Review the IAM user's policies and remove unnecessary `iam:CreateAccessKey` permissions.
56- Prefer temporary credentials and IAM Identity Center for human access instead of long-term IAM user access keys.
57- Preserve the relevant CloudTrail events, access key IDs, source addresses, and user-agent values for incident response.
58"""
59references = [
60 "https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/#iamcreateaccesskey",
61 "https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateAccessKey.html",
62 "https://github.com/RhinoSecurityLabs/pacu/tree/master/pacu/modules/iam__backdoor_users_keys",
63]
64risk_score = 47
65rule_id = "dfb7dc0b-2caf-4186-9b59-5752bc59bc19"
66severity = "medium"
67tags = [
68 "Domain: Cloud",
69 "Data Source: AWS",
70 "Data Source: Amazon Web Services",
71 "Data Source: AWS IAM",
72 "Use Case: Identity and Access Audit",
73 "Tactic: Persistence",
74 "Resources: Investigation Guide",
75]
76timestamp_override = "event.ingested"
77type = "esql"
78
79query = '''
80FROM logs-aws.cloudtrail-*
81| WHERE data_stream.dataset == "aws.cloudtrail"
82 AND (
83 (
84 event.provider == "iam.amazonaws.com"
85 AND event.action == "CreateAccessKey"
86 AND event.outcome == "success"
87 AND aws.cloudtrail.user_identity.type == "IAMUser"
88 )
89 OR (
90 aws.cloudtrail.user_identity.type == "IAMUser"
91 AND aws.cloudtrail.user_identity.access_key_id LIKE "AKIA*"
92 AND NOT (
93 event.provider == "iam.amazonaws.com"
94 AND event.action == "CreateAccessKey"
95 )
96 )
97 )
98| GROK aws.cloudtrail.response_elements """.*accessKeyId=(?<Esql_priv.aws_cloudtrail_response_elements_access_key_access_key_id>AKIA[A-Z0-9]{16}).*"""
99| EVAL
100 Esql.aws_cloudtrail_self_access_key_creation_flag = CASE(
101 event.provider == "iam.amazonaws.com"
102 AND event.action == "CreateAccessKey"
103 AND event.outcome == "success"
104 AND aws.cloudtrail.user_identity.type == "IAMUser"
105 AND (
106 user.target.name IS NULL
107 OR user.name == user.target.name
108 )
109 AND Esql_priv.aws_cloudtrail_response_elements_access_key_access_key_id IS NOT NULL,
110 1,
111 0
112 ),
113 Esql.aws_cloudtrail_created_access_key_use_flag = CASE(
114 aws.cloudtrail.user_identity.type == "IAMUser"
115 AND aws.cloudtrail.user_identity.access_key_id LIKE "AKIA*"
116 AND NOT (
117 event.provider == "iam.amazonaws.com"
118 AND event.action == "CreateAccessKey"
119 ),
120 1,
121 0
122 )
123| EVAL
124 Esql_priv.aws_cloudtrail_user_identity_access_key_id_creator = CASE(
125 Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
126 aws.cloudtrail.user_identity.access_key_id,
127 null
128 ),
129 Esql_priv.aws_cloudtrail_access_key_id_correlation = CASE(
130 Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
131 Esql_priv.aws_cloudtrail_response_elements_access_key_access_key_id,
132 aws.cloudtrail.user_identity.access_key_id
133 )
134| WHERE Esql_priv.aws_cloudtrail_access_key_id_correlation IS NOT NULL
135 AND aws.cloudtrail.user_identity.arn IS NOT NULL
136| STATS
137 Esql.aws_cloudtrail_self_access_key_creation_count =
138 COUNT(*) WHERE Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
139 Esql.aws_cloudtrail_created_access_key_use_count =
140 COUNT(*) WHERE Esql.aws_cloudtrail_created_access_key_use_flag == 1,
141 Esql_priv.aws_cloudtrail_user_identity_access_key_id_creator_values =
142 VALUES(Esql_priv.aws_cloudtrail_user_identity_access_key_id_creator)
143 WHERE Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
144 Esql_priv.aws_cloudtrail_response_elements_access_key_access_key_id_values =
145 VALUES(Esql_priv.aws_cloudtrail_response_elements_access_key_access_key_id)
146 WHERE Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
147 Esql_priv.aws_cloudtrail_user_identity_access_key_id_created_key_use_values =
148 VALUES(aws.cloudtrail.user_identity.access_key_id)
149 WHERE Esql.aws_cloudtrail_created_access_key_use_flag == 1,
150 Esql.timestamp_self_access_key_creation_min =
151 MIN(@timestamp)
152 WHERE Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
153 Esql.timestamp_created_access_key_use_min =
154 MIN(@timestamp)
155 WHERE Esql.aws_cloudtrail_created_access_key_use_flag == 1,
156 Esql.source_ip_self_access_key_creation_values =
157 VALUES(source.ip)
158 WHERE Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
159 Esql.source_ip_created_access_key_use_values =
160 VALUES(source.ip)
161 WHERE Esql.aws_cloudtrail_created_access_key_use_flag == 1,
162 Esql.user_agent_original_self_access_key_creation_values =
163 VALUES(user_agent.original)
164 WHERE Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
165 Esql.user_agent_original_created_access_key_use_values =
166 VALUES(user_agent.original)
167 WHERE Esql.aws_cloudtrail_created_access_key_use_flag == 1,
168 Esql.event_action_created_access_key_use_values =
169 VALUES(event.action)
170 WHERE Esql.aws_cloudtrail_created_access_key_use_flag == 1
171 BY cloud.account.id,
172 aws.cloudtrail.user_identity.arn,
173 Esql_priv.aws_cloudtrail_access_key_id_correlation
174| WHERE Esql.aws_cloudtrail_self_access_key_creation_count > 0
175 AND Esql.aws_cloudtrail_created_access_key_use_count > 0
176 AND Esql.timestamp_created_access_key_use_min >
177 Esql.timestamp_self_access_key_creation_min
178 AND DATE_DIFF(
179 "seconds",
180 Esql.timestamp_self_access_key_creation_min,
181 Esql.timestamp_created_access_key_use_min
182 ) <= 3600
183| KEEP
184 cloud.account.id,
185 aws.cloudtrail.user_identity.arn,
186 Esql.*,
187 Esql_priv.*
188'''
189
190
191[[rule.threat]]
192framework = "MITRE ATT&CK"
193[[rule.threat.technique]]
194id = "T1098"
195name = "Account Manipulation"
196reference = "https://attack.mitre.org/techniques/T1098/"
197[[rule.threat.technique.subtechnique]]
198id = "T1098.001"
199name = "Additional Cloud Credentials"
200reference = "https://attack.mitre.org/techniques/T1098/001/"
201
202
203
204[rule.threat.tactic]
205id = "TA0003"
206name = "Persistence"
207reference = "https://attack.mitre.org/tactics/TA0003/"
208
209[rule.alert_suppression]
210group_by = ["aws.cloudtrail.user_identity.arn","cloud.account.id"]
211missing_fields_strategy = "suppress"
212[rule.alert_suppression.duration]
213unit = "m"
214value = 35
215
216[rule.investigation_fields]
217field_names = [
218 "cloud.account.id",
219 "aws.cloudtrail.user_identity.arn",
220 "Esql_priv.aws_cloudtrail_user_identity_access_key_id_creator_values",
221 "Esql_priv.aws_cloudtrail_response_elements_access_key_access_key_id_values",
222 "Esql_priv.aws_cloudtrail_user_identity_access_key_id_created_key_use_values",
223 "Esql.timestamp_self_access_key_creation_min",
224 "Esql.timestamp_created_access_key_use_min",
225 "Esql.source_ip_self_access_key_creation_values",
226 "Esql.source_ip_created_access_key_use_values",
227 "Esql.user_agent_original_self_access_key_creation_values",
228 "Esql.user_agent_original_created_access_key_use_values",
229 "Esql.event_action_created_access_key_use_values",
230]
Triage and analysis
Investigating AWS IAM User Self-Created Access Key Subsequently Used
This rule detects an IAM user using an existing access key (Token A) to create a new access key for itself (Token B), followed by an AWS API request authenticated with Token B within one hour. The creation event proves that Token A was used to request the additional credential, while the subsequent CloudTrail event confirms that Token B became active.
This sequence can indicate persistence after an IAM user's credentials are compromised. An adversary can use the compromised key to create another long-term credential, then continue accessing the account through the new key even after the original credential is identified and disabled.
Possible investigation steps
- Identify the IAM user and AWS account using
aws.cloudtrail.user_identity.arnandcloud.account.id. - Review Token A in
Esql_priv.aws_cloudtrail_user_identity_access_key_id_creator_values. Determine whether it is an expected credential for the IAM user and whether it was previously observed from unusual infrastructure. - Confirm that the key in
Esql_priv.aws_cloudtrail_response_elements_access_key_access_key_id_valuesmatches the subsequently used key inEsql_priv.aws_cloudtrail_user_identity_access_key_id_created_key_use_values. - Compare
Esql.source_ip_self_access_key_creation_valueswithEsql.source_ip_created_access_key_use_values. A rapid change in source IP, ASN, geography, or hosting provider increases suspicion. - Compare
Esql.user_agent_original_self_access_key_creation_valueswithEsql.user_agent_original_created_access_key_use_valuesto identify changes between the creation and use clients. - Review
Esql.event_action_created_access_key_use_valuesto determine what Token B accessed or modified after creation. - Examine nearby CloudTrail activity for IAM reconnaissance, MFA changes, login-profile changes, policy modifications, or attempts to create additional credentials.
- Confirm whether the activity corresponds to an approved credential-rotation workflow and whether the user is permitted to create its own long-term access keys.
False positive analysis
- Approved credential-rotation automation may create and immediately test or use a replacement access key.
- Developer onboarding or recovery workflows may create a key and validate it with an initial AWS API request.
- Validate the principal, source addresses, user agents, timing, and change records before excluding the activity. Prefer narrowly scoped exceptions for verified automation rather than excluding the IAM user broadly.
Response and remediation
- If unauthorized, deactivate or delete Token B immediately.
- Rotate or disable Token A and investigate how it was exposed or compromised.
- Review every CloudTrail event authenticated with Token B and determine whether it accessed data, changed IAM permissions, created resources, or established additional persistence.
- Review the IAM user's policies and remove unnecessary
iam:CreateAccessKeypermissions. - Prefer temporary credentials and IAM Identity Center for human access instead of long-term IAM user access keys.
- Preserve the relevant CloudTrail events, access key IDs, source addresses, and user-agent values for incident response.
References
Related rules
- AWS IAM Virtual MFA Device Registration Attempt with Session Token
- AWS IAM AdministratorAccess Policy Attached to User
- AWS IAM Create User via Assumed Role on EC2 Instance
- AWS IAM OIDC Provider Created by Rare User
- AWS IAM Roles Anywhere Profile Creation