Skip to content

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

Closed

Description

@bryans3c

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:

{
  "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": "<redacted>",
  "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:

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:

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

Activity

  1. infra-vault-gh-plugin-prod commented on Sep 2, 2026

    @infra-vault-gh-plugin-prod

    Pinging @elastic/security-service-integrations (Team:Security-Service Integrations)

  2. added
    Team:SDE-CrestCrest developers on the Security Integrations team [elastic/sit-crest-contractors]
    on Sep 10, 2026
  3. brijesh-elastic commented on Sep 21, 2026

    @brijesh-elastic
    Contributor

    Thanks for the detailed write-up @bryans3c.

    Taking a fresh look at the current CloudTrail data stream, both of the requested fields — along with the ECS aliases you suggested — are already mapped. This landed as of 7.4.0 via #20403, so a deployment on 8.1.0 should already have it.

    Field mapping (as requested):

    Source (CloudTrail) Mapped 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

    ECS alignment (also already done):

    • user.id is populated from onBehalfOf.userId for IdentityCenterUser events.
    • The same value is appended to related.user.

    Pipeline processors (data_stream/cloudtrail/elasticsearch/ingest_pipeline/default.yml):

    https://github.com/elastic/integrations/blob/main/packages/aws/data_stream/cloudtrail/elasticsearch/ingest_pipeline/default.yml#L1159-L1174

    - set:
        field: aws.cloudtrail.user_identity.on_behalf_of.user_id
        copy_from: json.userIdentity.onBehalfOf.userId
        ignore_empty_value: true
    - rename:
        field: json.userIdentity.onBehalfOf.identityStoreArn
        target_field: aws.cloudtrail.user_identity.on_behalf_of.identity_store_arn
        ignore_missing: true
    - rename:
        field: json.userIdentity.onBehalfOf.userId
        target_field: user.id
        ignore_missing: true
        if: ctx.aws?.cloudtrail?.user_identity?.type == 'IdentityCenterUser' && ctx.user?.id == null

    Verified output — feeding an IdentityCenterUser event with onBehalfOf through the pipeline produces:

    check - https://github.com/elastic/integrations/blob/main/packages/aws/data_stream/cloudtrail/_dev/test/pipeline/test-create-db-instance-json.log-expected.json

    This is covered by a pipeline test in the package, so the mapping is validated in CI.

  4. bryans3c commented on Oct 1, 2026

    @bryans3c
    ContributorAuthor

    Closing, confirmed fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Integration:awsAWSTeam:SDE-CrestCrest developers on the Security Integrations team [elastic/sit-crest-contractors]Team:Security-Service IntegrationsSecurity Service Integrations team [elastic/security-service-integrations]needs:triage

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions