elastic / elastic/integrations

[AWS]: Map userIdentity.onBehalfOf for IAM Identity Center events

Open
#21,018 1 comment 0 reactions 1 assignee Claimed by @brijesh-elastic View on GitHub
Integration:aws needs:triage Team:SDE-Crest Team:Security-Service Integrations
Dominant language
Handlebars
Stars
333
Forks
647
Avg merge
3d 4h
Merged PRs (30d)
209

Description

### Integration Name

AWS [packages/aws]

### Dataset Name

aws.cloudtrail

### Integration Version

8.1.0

### Agent Version

9.6.0

### OS Version and Architecture

Not host specific

### User Goal

When writing detection rules for AWS IAM Identity Center (AWS SSO). Several high-value detections need to identify, group, and baseline the specific Identity Center user that acted in or was the subject of an event: administrator password resets, portal sign-ins, forced first-login password changes, and directory user or group changes.

For every event whose `userIdentity.type` is `IdentityCenterUser`, the acting Identity Center user is present in the raw record only as `userIdentity.onBehalfOf.userId` (a directory UUID) and `userIdentity.onBehalfOf.identityStoreArn`. I need those two values mapped to queryable fields so a rule can:

- group or run a New Terms baseline on the acting Identity Center user
- name the affected user in the alert
- build aggregation detections such as one principal forcing password changes across many distinct users

### Existing Features

The integration maps `userIdentity.type` but, for `IdentityCenterUser` events, leaves `userIdentity.arn` empty and `user.name` null, and does not map `userIdentity.onBehalfOf` at all. There is no `aws.cloudtrail.user_identity.onBehalfOf.*` field. The only surviving copy of the acting user is inside `event.original`.

Because of that:

- KQL detection rules can only wildcard-match `event.original` to test the *presence* of `onBehalfOf`; they cannot extract the value into a field, so New Terms and grouping on the Identity Center user are impossible.
- The value can be recovered with an ES|QL `GROK` over `event.original`, but that forces the rule to be an ES|QL rule, scans the full raw event on every run, and is fragile to JSON key ordering. It is a workaround, not a stable field.

### What did you see?

Ingested `UpdatePassword` document (forced first-login change). The mapped identity fields are empty and the acting user is only inside `event.original`:

```json
{
"userIdentity": {
"type": "IdentityCenterUser",
"arn": "",
"accountId": "x",
"accessKeyId": "",
"onBehalfOf": {
"userId": "y",
"identityStoreArn": "arn:aws:identitystore::x:identitystore/d-9067e0196b"
},
"credentialId": "z"
},
"eventTime": "2026-09-01T14:33:25Z",
"eventSource": "sso-directory.amazonaws.com",
"eventName": "UpdatePassword",
"awsRegion": "us-east-1",
"sourceIPAddress": "",
"requestParameters": null,
"responseElements": null
}
```

Mapped-field view of the same document, showing the value is not queryable:

```
aws.cloudtrail.user_identity.type = "IdentityCenterUser"
aws.cloudtrail.user_identity.arn = null
user.name = null
aws.cloudtrail.user_identity.onBehalfOf.* = (field does not exist)
```

Confirmation that the value exists and is recoverable only from `event.original`, via ES|QL `GROK`:

```esql
FROM logs-aws.cloudtrail-*
| WHERE event.provider == "sso-directory.amazonaws.com" AND event.action == "UpdatePassword"
AND event.original LIKE "*onBehalfOf*"
| GROK event.original """"onBehalfOf":\{"userId":"%{DATA:obo_user_id}","identityStoreArn":"%{DATA:obo_identity_store}"\}"""
| KEEP @timestamp, aws.cloudtrail.user_identity.type, obo_user_id, obo_identity_store
```

Result:

```
@timestamp user_identity.type obo_user_id obo_identity_store
2026-09-01T14:33:25Z IdentityCenterUser y arn:aws:identitystore::x:identitystore/d-9067e0196b
```

### Anything else?

Requested mapping:

| Source (CloudTrail) | Requested field | Type |
| --- | --- | --- |
| `userIdentity.onBehalfOf.userId` | `aws.cloudtrail.user_identity.on_behalf_of.user_id` | keyword |
| `userIdentity.onBehalfOf.identityStoreArn` | `aws.cloudtrail.user_identity.on_behalf_of.identity_store_arn` | keyword |

Note: 7.4.0 (PR #20403) added previously-dropped CloudTrail fields and populated `related.*`, but `userIdentity.onBehalfOf` was not among them. It remains unmapped through 8.1.0, `aws.cloudtrail.user_identity.on_behalf_of.*` and `.onBehalfOf.*` both return `Unknown column` at query time.

Suggested ECS alignment, so the acting Identity Center user is usable by generic rules and entity analytics:

- populate `user.id` with `onBehalfOf.userId` for `IdentityCenterUser` events;
- add it to `related.user` as well, consistent with how 7.1.0 (PR #20318) already uses `related.user` for assumed-role session names for cross-source correlation.

Reference: AWS CloudTrail `userIdentity` element, `onBehalfOf` object — https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference-user-identity.html

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.