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/09/18"
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 "Noise: Low",
76 "Performance: Fast",
77 "Rule Type: ES|QL",
78 "Platform: AWS",
79 "Service: AWS IAM",
80]
81timestamp_override = "event.ingested"
82type = "esql"
83
84query = '''
85FROM logs-aws.cloudtrail-*
86| WHERE data_stream.dataset == "aws.cloudtrail"
87 AND (
88 (
89 event.provider == "iam.amazonaws.com"
90 AND event.action == "CreateAccessKey"
91 AND event.outcome == "success"
92 AND aws.cloudtrail.user_identity.type == "IAMUser"
93 )
94 OR (
95 aws.cloudtrail.user_identity.type == "IAMUser"
96 AND aws.cloudtrail.user_identity.access_key_id LIKE "AKIA*"
97 AND NOT (
98 event.provider == "iam.amazonaws.com"
99 AND event.action == "CreateAccessKey"
100 )
101 )
102 )
103| GROK aws.cloudtrail.response_elements """.*accessKeyId=(?<Esql_priv.aws_cloudtrail_response_elements_access_key_access_key_id>AKIA[A-Z0-9]{16}).*"""
104| EVAL
105 Esql.aws_cloudtrail_self_access_key_creation_flag = CASE(
106 event.provider == "iam.amazonaws.com"
107 AND event.action == "CreateAccessKey"
108 AND event.outcome == "success"
109 AND aws.cloudtrail.user_identity.type == "IAMUser"
110 AND (
111 user.target.name IS NULL
112 OR user.name == user.target.name
113 )
114 AND Esql_priv.aws_cloudtrail_response_elements_access_key_access_key_id IS NOT NULL,
115 1,
116 0
117 ),
118 Esql.aws_cloudtrail_created_access_key_use_flag = CASE(
119 aws.cloudtrail.user_identity.type == "IAMUser"
120 AND aws.cloudtrail.user_identity.access_key_id LIKE "AKIA*"
121 AND NOT (
122 event.provider == "iam.amazonaws.com"
123 AND event.action == "CreateAccessKey"
124 ),
125 1,
126 0
127 )
128| EVAL
129 Esql_priv.aws_cloudtrail_user_identity_access_key_id_creator = CASE(
130 Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
131 aws.cloudtrail.user_identity.access_key_id,
132 null
133 ),
134 Esql_priv.aws_cloudtrail_access_key_id_correlation = CASE(
135 Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
136 Esql_priv.aws_cloudtrail_response_elements_access_key_access_key_id,
137 aws.cloudtrail.user_identity.access_key_id
138 )
139| WHERE Esql_priv.aws_cloudtrail_access_key_id_correlation IS NOT NULL
140 AND aws.cloudtrail.user_identity.arn IS NOT NULL
141| STATS
142 Esql.aws_cloudtrail_self_access_key_creation_count =
143 COUNT(*) WHERE Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
144 Esql.aws_cloudtrail_created_access_key_use_count =
145 COUNT(*) WHERE Esql.aws_cloudtrail_created_access_key_use_flag == 1,
146 Esql_priv.aws_cloudtrail_user_identity_access_key_id_creator_values =
147 VALUES(Esql_priv.aws_cloudtrail_user_identity_access_key_id_creator)
148 WHERE Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
149 Esql_priv.aws_cloudtrail_response_elements_access_key_access_key_id_values =
150 VALUES(Esql_priv.aws_cloudtrail_response_elements_access_key_access_key_id)
151 WHERE Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
152 Esql_priv.aws_cloudtrail_user_identity_access_key_id_created_key_use_values =
153 VALUES(aws.cloudtrail.user_identity.access_key_id)
154 WHERE Esql.aws_cloudtrail_created_access_key_use_flag == 1,
155 Esql.timestamp_self_access_key_creation_min =
156 MIN(@timestamp)
157 WHERE Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
158 Esql.timestamp_created_access_key_use_min =
159 MIN(@timestamp)
160 WHERE Esql.aws_cloudtrail_created_access_key_use_flag == 1,
161 Esql.source_ip_self_access_key_creation_values =
162 VALUES(source.ip)
163 WHERE Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
164 Esql.source_ip_created_access_key_use_values =
165 VALUES(source.ip)
166 WHERE Esql.aws_cloudtrail_created_access_key_use_flag == 1,
167 Esql.user_agent_original_self_access_key_creation_values =
168 VALUES(user_agent.original)
169 WHERE Esql.aws_cloudtrail_self_access_key_creation_flag == 1,
170 Esql.user_agent_original_created_access_key_use_values =
171 VALUES(user_agent.original)
172 WHERE Esql.aws_cloudtrail_created_access_key_use_flag == 1,
173 Esql.event_action_created_access_key_use_values =
174 VALUES(event.action)
175 WHERE Esql.aws_cloudtrail_created_access_key_use_flag == 1
176 BY cloud.account.id,
177 aws.cloudtrail.user_identity.arn,
178 Esql_priv.aws_cloudtrail_access_key_id_correlation
179| WHERE Esql.aws_cloudtrail_self_access_key_creation_count > 0
180 AND Esql.aws_cloudtrail_created_access_key_use_count > 0
181 AND Esql.timestamp_created_access_key_use_min >
182 Esql.timestamp_self_access_key_creation_min
183 AND DATE_DIFF(
184 "seconds",
185 Esql.timestamp_self_access_key_creation_min,
186 Esql.timestamp_created_access_key_use_min
187 ) <= 3600
188| KEEP
189 cloud.account.id,
190 aws.cloudtrail.user_identity.arn,
191 Esql.*,
192 Esql_priv.*
193'''
194
195
196[[rule.threat]]
197framework = "MITRE ATT&CK"
198[[rule.threat.technique]]
199id = "T1098"
200name = "Account Manipulation"
201reference = "https://attack.mitre.org/techniques/T1098/"
202[[rule.threat.technique.subtechnique]]
203id = "T1098.001"
204name = "Additional Cloud Credentials"
205reference = "https://attack.mitre.org/techniques/T1098/001/"
206
207
208
209[rule.threat.tactic]
210id = "TA0003"
211name = "Persistence"
212reference = "https://attack.mitre.org/tactics/TA0003/"
213
214[rule.alert_suppression]
215group_by = ["aws.cloudtrail.user_identity.arn","cloud.account.id"]
216missing_fields_strategy = "suppress"
217[rule.alert_suppression.duration]
218unit = "m"
219value = 35
220
221[rule.investigation_fields]
222field_names = [
223 "cloud.account.id",
224 "aws.cloudtrail.user_identity.arn",
225 "Esql_priv.aws_cloudtrail_user_identity_access_key_id_creator_values",
226 "Esql_priv.aws_cloudtrail_response_elements_access_key_access_key_id_values",
227 "Esql_priv.aws_cloudtrail_user_identity_access_key_id_created_key_use_values",
228 "Esql.timestamp_self_access_key_creation_min",
229 "Esql.timestamp_created_access_key_use_min",
230 "Esql.source_ip_self_access_key_creation_values",
231 "Esql.source_ip_created_access_key_use_values",
232 "Esql.user_agent_original_self_access_key_creation_values",
233 "Esql.user_agent_original_created_access_key_use_values",
234 "Esql.event_action_created_access_key_use_values",
235]
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 Login Profile Created or Modified for an IAM User
- AWS IAM SAML Provider Created
- AWS Access Token Used from Multiple Addresses
- AWS IAM AdministratorAccess Policy Attached to Group
- AWS IAM AdministratorAccess Policy Attached to User