Skip to content

Add user profile ID to audit log events#141092

Merged
thomheymann merged 16 commits intoelastic:mainfrom
thomheymann:audit-profile-id
Oct 3, 2022
Merged

Add user profile ID to audit log events#141092
thomheymann merged 16 commits intoelastic:mainfrom
thomheymann:audit-profile-id

Conversation

@thomheymann
Copy link
Copy Markdown
Contributor

@thomheymann thomheymann commented Sep 20, 2022

Resolves #125932

Release notes

Adds user.id field to audit log.

Testing

  1. Add the following config to kibana.dev.yml:
xpack.security.audit.enabled: true
xpack.security.audit.appender:
  type: console
  layout:
    type: json
  1. You should now see all audit events logged with user.id property:
{
  "message": "User [elastic] has logged in using basic provider [name=basic1]"
  "user": {
    "id": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0",
    "name": "elastic",
  },
}

@github-actions
Copy link
Copy Markdown
Contributor

Documentation preview:

@thomheymann thomheymann added release_note:enhancement v8.5.0 Team:Security Platform Security: Auth, Users, Roles, Spaces, Audit Logging, etc t// Feature:Security/Audit Platform Security - Audit Logging feature backport:skip This PR does not require backporting labels Sep 20, 2022
@azasypkin azasypkin self-requested a review September 22, 2022 13:57
@azasypkin azasypkin removed their assignment Sep 22, 2022
@spalger
Copy link
Copy Markdown
Contributor

spalger commented Sep 22, 2022

@elasticmachine merge upstream

(to resolve ci issues caused by Github outage)

@thomheymann thomheymann added v8.6.0 and removed v8.5.0 labels Sep 26, 2022
@thomheymann thomheymann marked this pull request as ready for review September 27, 2022 13:34
@thomheymann thomheymann requested a review from a team as a code owner September 27, 2022 13:34
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/kibana-security (Team:Security)

@azasypkin
Copy link
Copy Markdown
Contributor

ACK: will review today or tomorrow at the latest

@azasypkin azasypkin self-requested a review September 29, 2022 06:09
Copy link
Copy Markdown
Contributor

@azasypkin azasypkin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks and works great! I just left two small proposals to improve unit/API integration test coverage a bit before we merge the PR.

Thanks!

authentication_provider: { type: 'kerberos', name: 'kerberos' },
authentication_type: 'token',
elastic_cloud_user: false,
profile_uid: jestExpect.any(String),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: Since the user profile UID isn't part of the ES authentication response and we have a custom logic to enrich user with it, it'd be great if instead of jestExpect.any(String) here and in similar API integration tests for other major authentication providers, we could check that profile uid is indeed correct (e.g. fetching it from /internal/security/user_profile before this assertion).

What do you think?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it's worth having an end to end test for the enrichment logic but I don't think it's correct to clutter this in with the authentication providers since the logic is independent of provider logic. I have added an end to end test for the enrichment logic to the user profile related functional test suite instead.

}
}

function enrichWithUserProfileId(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

concern: since we updated authenticated user mock to always populate profile_uid we might not really test this method in Authenticator unit tests. Would you mind adding a few tests for login/authenticate/re-authenticate that explicitly test this logic (e.g. create user mock returned by the provider without profile_uid)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I've added unit tests for this method.

@kibana-ci
Copy link
Copy Markdown

💚 Build Succeeded

Metrics [docs]

Unknown metric groups

API count

id before after diff
security 247 250 +3

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@thomheymann thomheymann merged commit c1d0b93 into elastic:main Oct 3, 2022
WafaaNasr pushed a commit to WafaaNasr/kibana that referenced this pull request Oct 11, 2022
* Add user profile ID to audit log events

* Fix merge conflict

* Fix integration tests

* Fix integration tests

* Fix type

* Refactor

* updated functional tests

* updated functional tests

* Added tests for enrichment logic

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
WafaaNasr pushed a commit to WafaaNasr/kibana that referenced this pull request Oct 14, 2022
* Add user profile ID to audit log events

* Fix merge conflict

* Fix integration tests

* Fix integration tests

* Fix type

* Refactor

* updated functional tests

* updated functional tests

* Added tests for enrichment logic

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
csr added a commit that referenced this pull request Mar 20, 2026
…258866)

I'm working on adding Scout API tests
(#258534) and noticed that
`created_by_profile_uid` and `updated_by_profile_uid` fields are absent
from all Osquery API responses on ECH (Elastic Cloud Hosted), even
though the authenticated user clearly has a `profile_uid` available.

## Test it yourself on ECH (dev console)

Confirm the user has a `profile_uid`:

```bash
GET kbn:/internal/security/me
```

This returns `{ "profile_uid": "u_..." }`.

Now create a saved query and check the response keys:

```bash
POST kbn:/api/osquery/saved_queries
{"id":"profile-uid-test","query":"select 1;","interval":"3600"}
```

The `created_by_profile_uid` and `updated_by_profile_uid` fields are
missing from the response on ECH. On local stateful they appear just
fine.

## Hypothesis (LLM-assisted)

`getUserInfo()` has two code paths for resolving user identity:

1. **Primary**: `userProfiles.getCurrent()` — returns `profile_uid` from
the user profile service
2. **Fallback**: `authc.getCurrentUser()` — used when the primary fails
or returns `null`

The fallback hardcodes `profile_uid: null` instead of reading
`user.profile_uid` from the `AuthenticatedUser` object (available since
2022, PR #141092).

On ECH (Elastic Cloud Hosted), `userProfiles.getCurrent()` returns
`null`, so the fallback is always used. The hardcoded `null` then
cascades through route handlers:
- Converted to `undefined` via `?? undefined`
- Stripped by `JSON.stringify` (packs) or `pickBy` (saved queries)

## Why didn't we spot this sooner and why Scout comes to the rescue

The existing FTR API tests
[[1](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/saved_queries.ts#L90-L126)]
[[2](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/packs.ts#L191-L251)]
covering this ground aren't run on ECH. Scout is designed to be
[deployment-agnostic](https://www.elastic.co/docs/extend/kibana/scout/best-practices#design-tests-with-a-cloud-first-mindset),
so we're easily able to run the same set of tests on different testing
surfaces :-)
csr added a commit to csr/kibana that referenced this pull request Mar 24, 2026
…lastic#258866)

I'm working on adding Scout API tests
(elastic#258534) and noticed that
`created_by_profile_uid` and `updated_by_profile_uid` fields are absent
from all Osquery API responses on ECH (Elastic Cloud Hosted), even
though the authenticated user clearly has a `profile_uid` available.

## Test it yourself on ECH (dev console)

Confirm the user has a `profile_uid`:

```bash
GET kbn:/internal/security/me
```

This returns `{ "profile_uid": "u_..." }`.

Now create a saved query and check the response keys:

```bash
POST kbn:/api/osquery/saved_queries
{"id":"profile-uid-test","query":"select 1;","interval":"3600"}
```

The `created_by_profile_uid` and `updated_by_profile_uid` fields are
missing from the response on ECH. On local stateful they appear just
fine.

## Hypothesis (LLM-assisted)

`getUserInfo()` has two code paths for resolving user identity:

1. **Primary**: `userProfiles.getCurrent()` — returns `profile_uid` from
the user profile service
2. **Fallback**: `authc.getCurrentUser()` — used when the primary fails
or returns `null`

The fallback hardcodes `profile_uid: null` instead of reading
`user.profile_uid` from the `AuthenticatedUser` object (available since
2022, PR elastic#141092).

On ECH (Elastic Cloud Hosted), `userProfiles.getCurrent()` returns
`null`, so the fallback is always used. The hardcoded `null` then
cascades through route handlers:
- Converted to `undefined` via `?? undefined`
- Stripped by `JSON.stringify` (packs) or `pickBy` (saved queries)

## Why didn't we spot this sooner and why Scout comes to the rescue

The existing FTR API tests
[[1](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/saved_queries.ts#L90-L126)]
[[2](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/packs.ts#L191-L251)]
covering this ground aren't run on ECH. Scout is designed to be
[deployment-agnostic](https://www.elastic.co/docs/extend/kibana/scout/best-practices#design-tests-with-a-cloud-first-mindset),
so we're easily able to run the same set of tests on different testing
surfaces :-)

(cherry picked from commit fe7e247)

# Conflicts:
#	x-pack/platform/plugins/shared/osquery/server/lib/get_user_info.test.ts
jeramysoucy pushed a commit to jeramysoucy/kibana that referenced this pull request Mar 26, 2026
…lastic#258866)

I'm working on adding Scout API tests
(elastic#258534) and noticed that
`created_by_profile_uid` and `updated_by_profile_uid` fields are absent
from all Osquery API responses on ECH (Elastic Cloud Hosted), even
though the authenticated user clearly has a `profile_uid` available.

## Test it yourself on ECH (dev console)

Confirm the user has a `profile_uid`:

```bash
GET kbn:/internal/security/me
```

This returns `{ "profile_uid": "u_..." }`.

Now create a saved query and check the response keys:

```bash
POST kbn:/api/osquery/saved_queries
{"id":"profile-uid-test","query":"select 1;","interval":"3600"}
```

The `created_by_profile_uid` and `updated_by_profile_uid` fields are
missing from the response on ECH. On local stateful they appear just
fine.

## Hypothesis (LLM-assisted)

`getUserInfo()` has two code paths for resolving user identity:

1. **Primary**: `userProfiles.getCurrent()` — returns `profile_uid` from
the user profile service
2. **Fallback**: `authc.getCurrentUser()` — used when the primary fails
or returns `null`

The fallback hardcodes `profile_uid: null` instead of reading
`user.profile_uid` from the `AuthenticatedUser` object (available since
2022, PR elastic#141092).

On ECH (Elastic Cloud Hosted), `userProfiles.getCurrent()` returns
`null`, so the fallback is always used. The hardcoded `null` then
cascades through route handlers:
- Converted to `undefined` via `?? undefined`
- Stripped by `JSON.stringify` (packs) or `pickBy` (saved queries)

## Why didn't we spot this sooner and why Scout comes to the rescue

The existing FTR API tests
[[1](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/saved_queries.ts#L90-L126)]
[[2](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/packs.ts#L191-L251)]
covering this ground aren't run on ECH. Scout is designed to be
[deployment-agnostic](https://www.elastic.co/docs/extend/kibana/scout/best-practices#design-tests-with-a-cloud-first-mindset),
so we're easily able to run the same set of tests on different testing
surfaces :-)
csr added a commit that referenced this pull request Apr 1, 2026
…back (#258866) (#259258)

# Backport

This will backport the following commits from `main` to `9.3`:
- [[Osquery] Fix `profile_uid` dropped in `getUserInfo` authc fallback
(#258866)](#258866)

<!--- Backport version: 11.0.1 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Cesare de
Cal","email":"cesare.decal@elastic.co"},"sourceCommit":{"committedDate":"2026-03-20T16:39:00Z","message":"[Osquery]
Fix `profile_uid` dropped in `getUserInfo` authc fallback
(#258866)\n\nI'm working on adding Scout API
tests\n(#258534) and noticed
that\n`created_by_profile_uid` and `updated_by_profile_uid` fields are
absent\nfrom all Osquery API responses on ECH (Elastic Cloud Hosted),
even\nthough the authenticated user clearly has a `profile_uid`
available.\n\n## Test it yourself on ECH (dev console)\n\nConfirm the
user has a `profile_uid`:\n\n```bash\nGET
kbn:/internal/security/me\n```\n\nThis returns `{ \"profile_uid\":
\"u_...\" }`.\n\nNow create a saved query and check the response
keys:\n\n```bash\nPOST
kbn:/api/osquery/saved_queries\n{\"id\":\"profile-uid-test\",\"query\":\"select
1;\",\"interval\":\"3600\"}\n```\n\nThe `created_by_profile_uid` and
`updated_by_profile_uid` fields are\nmissing from the response on ECH.
On local stateful they appear just\nfine.\n\n## Hypothesis
(LLM-assisted)\n\n`getUserInfo()` has two code paths for resolving user
identity:\n\n1. **Primary**: `userProfiles.getCurrent()` — returns
`profile_uid` from\nthe user profile service\n2. **Fallback**:
`authc.getCurrentUser()` — used when the primary fails\nor returns
`null`\n\nThe fallback hardcodes `profile_uid: null` instead of
reading\n`user.profile_uid` from the `AuthenticatedUser` object
(available since\n2022, PR #141092).\n\nOn ECH (Elastic Cloud Hosted),
`userProfiles.getCurrent()` returns\n`null`, so the fallback is always
used. The hardcoded `null` then\ncascades through route handlers:\n-
Converted to `undefined` via `?? undefined`\n- Stripped by
`JSON.stringify` (packs) or `pickBy` (saved queries)\n\n## Why didn't we
spot this sooner and why Scout comes to the rescue\n\nThe existing FTR
API
tests\n[[1](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/saved_queries.ts#L90-L126)]\n[[2](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/packs.ts#L191-L251)]\ncovering
this ground aren't run on ECH. Scout is designed to
be\n[deployment-agnostic](https://www.elastic.co/docs/extend/kibana/scout/best-practices#design-tests-with-a-cloud-first-mindset),\nso
we're easily able to run the same set of tests on different
testing\nsurfaces
:-)","sha":"fe7e2477ddd0d89e13e5a8ff594a22eb4b8e2d5c","branchLabelMapping":{"^v9.4.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","backport
missing","backport:version","v9.4.0","v9.3.3"],"title":"[Osquery] Fix
`profile_uid` dropped in `getUserInfo` authc
fallback","number":258866,"url":"https://github.com/elastic/kibana/pull/258866","mergeCommit":{"message":"[Osquery]
Fix `profile_uid` dropped in `getUserInfo` authc fallback
(#258866)\n\nI'm working on adding Scout API
tests\n(#258534) and noticed
that\n`created_by_profile_uid` and `updated_by_profile_uid` fields are
absent\nfrom all Osquery API responses on ECH (Elastic Cloud Hosted),
even\nthough the authenticated user clearly has a `profile_uid`
available.\n\n## Test it yourself on ECH (dev console)\n\nConfirm the
user has a `profile_uid`:\n\n```bash\nGET
kbn:/internal/security/me\n```\n\nThis returns `{ \"profile_uid\":
\"u_...\" }`.\n\nNow create a saved query and check the response
keys:\n\n```bash\nPOST
kbn:/api/osquery/saved_queries\n{\"id\":\"profile-uid-test\",\"query\":\"select
1;\",\"interval\":\"3600\"}\n```\n\nThe `created_by_profile_uid` and
`updated_by_profile_uid` fields are\nmissing from the response on ECH.
On local stateful they appear just\nfine.\n\n## Hypothesis
(LLM-assisted)\n\n`getUserInfo()` has two code paths for resolving user
identity:\n\n1. **Primary**: `userProfiles.getCurrent()` — returns
`profile_uid` from\nthe user profile service\n2. **Fallback**:
`authc.getCurrentUser()` — used when the primary fails\nor returns
`null`\n\nThe fallback hardcodes `profile_uid: null` instead of
reading\n`user.profile_uid` from the `AuthenticatedUser` object
(available since\n2022, PR #141092).\n\nOn ECH (Elastic Cloud Hosted),
`userProfiles.getCurrent()` returns\n`null`, so the fallback is always
used. The hardcoded `null` then\ncascades through route handlers:\n-
Converted to `undefined` via `?? undefined`\n- Stripped by
`JSON.stringify` (packs) or `pickBy` (saved queries)\n\n## Why didn't we
spot this sooner and why Scout comes to the rescue\n\nThe existing FTR
API
tests\n[[1](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/saved_queries.ts#L90-L126)]\n[[2](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/packs.ts#L191-L251)]\ncovering
this ground aren't run on ECH. Scout is designed to
be\n[deployment-agnostic](https://www.elastic.co/docs/extend/kibana/scout/best-practices#design-tests-with-a-cloud-first-mindset),\nso
we're easily able to run the same set of tests on different
testing\nsurfaces
:-)","sha":"fe7e2477ddd0d89e13e5a8ff594a22eb4b8e2d5c"}},"sourceBranch":"main","suggestedTargetBranches":["9.3"],"targetPullRequestStates":[{"branch":"main","label":"v9.4.0","branchLabelMappingKey":"^v9.4.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/258866","number":258866,"mergeCommit":{"message":"[Osquery]
Fix `profile_uid` dropped in `getUserInfo` authc fallback
(#258866)\n\nI'm working on adding Scout API
tests\n(#258534) and noticed
that\n`created_by_profile_uid` and `updated_by_profile_uid` fields are
absent\nfrom all Osquery API responses on ECH (Elastic Cloud Hosted),
even\nthough the authenticated user clearly has a `profile_uid`
available.\n\n## Test it yourself on ECH (dev console)\n\nConfirm the
user has a `profile_uid`:\n\n```bash\nGET
kbn:/internal/security/me\n```\n\nThis returns `{ \"profile_uid\":
\"u_...\" }`.\n\nNow create a saved query and check the response
keys:\n\n```bash\nPOST
kbn:/api/osquery/saved_queries\n{\"id\":\"profile-uid-test\",\"query\":\"select
1;\",\"interval\":\"3600\"}\n```\n\nThe `created_by_profile_uid` and
`updated_by_profile_uid` fields are\nmissing from the response on ECH.
On local stateful they appear just\nfine.\n\n## Hypothesis
(LLM-assisted)\n\n`getUserInfo()` has two code paths for resolving user
identity:\n\n1. **Primary**: `userProfiles.getCurrent()` — returns
`profile_uid` from\nthe user profile service\n2. **Fallback**:
`authc.getCurrentUser()` — used when the primary fails\nor returns
`null`\n\nThe fallback hardcodes `profile_uid: null` instead of
reading\n`user.profile_uid` from the `AuthenticatedUser` object
(available since\n2022, PR #141092).\n\nOn ECH (Elastic Cloud Hosted),
`userProfiles.getCurrent()` returns\n`null`, so the fallback is always
used. The hardcoded `null` then\ncascades through route handlers:\n-
Converted to `undefined` via `?? undefined`\n- Stripped by
`JSON.stringify` (packs) or `pickBy` (saved queries)\n\n## Why didn't we
spot this sooner and why Scout comes to the rescue\n\nThe existing FTR
API
tests\n[[1](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/saved_queries.ts#L90-L126)]\n[[2](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/packs.ts#L191-L251)]\ncovering
this ground aren't run on ECH. Scout is designed to
be\n[deployment-agnostic](https://www.elastic.co/docs/extend/kibana/scout/best-practices#design-tests-with-a-cloud-first-mindset),\nso
we're easily able to run the same set of tests on different
testing\nsurfaces
:-)","sha":"fe7e2477ddd0d89e13e5a8ff594a22eb4b8e2d5c"}},{"branch":"9.3","label":"v9.3.3","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting Feature:Security/Audit Platform Security - Audit Logging feature release_note:enhancement Team:Security Platform Security: Auth, Users, Roles, Spaces, Audit Logging, etc t// v8.6.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add user profile ID to audit log events

6 participants