From 3993b5b0200a4beaf8ad49949b90f9477e0091c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Goworko?= Date: Sun, 2 Aug 2026 19:15:56 +0200 Subject: [PATCH 1/5] qs --- details/impersonation.md | 170 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 165 insertions(+), 5 deletions(-) diff --git a/details/impersonation.md b/details/impersonation.md index 1db6788..48921d5 100644 --- a/details/impersonation.md +++ b/details/impersonation.md @@ -22,6 +22,44 @@ Both of the problems can be solved using the ROR's impersonation. Thanks to the Admin can add the new user configuration without worrying and then test it by impersonating the user. They can check if the user can log in without problems and if the user has access only to the Kibana features the admin wanted to grant. When the admin is sure that everything is configured correctly, they can promote the settings (test) to production. +## The impersonator/impersonated identity model + +Before diving into the configuration, it's worth understanding *what an impersonating request actually contains* and *what ROR does with it*, since this is the part of the configuration that is most error-prone. + +An impersonating request carries **two identities at once**: + +* the **impersonator** - the real, credentialed admin sitting behind the keyboard (e.g. `admin1`), proven by whatever credentials travel with the request (typically an HTTP Basic Auth header), +* the **impersonated user** - the identity the admin wants to "borrow" for the duration of the request (e.g. `dev2`), carried in an internal header ROR/Kibana attaches to the request (`x-ror-impersonating`). + +ROR has to answer two completely different questions before it lets the request through: + +1. **"Is the real caller actually who they claim to be, and are they allowed to impersonate anyone at all?"** - this is a question about the *impersonator's* identity. It has nothing to do with `dev2`. +2. **"Given that we trust the caller, are they allowed to become `dev2` specifically, and does `dev2` even exist?"** - this is a question about the *impersonated user*, answered using the `impersonation` section and, where needed, [service mocks](#defining-mocks-of-the-external-services-optional). + +This is why the `impersonation` section needs its own, explicit `authentication_rule`, separate from whatever rule authenticates users in `access_control_rules`. **It's not accidental duplication - the two rules answer different questions, for different identities, and they run at different times:** + +* The rule in `access_control_rules` authenticates whoever is trying to act as `dev2` during `dev2`'s own, non-impersonating session. During impersonation, ROR deliberately does **not** execute that rule's normal authentication logic - that's the entire point of impersonation: it lets an admin experience `dev2`'s permissions without needing `dev2`'s actual password, and without ROR having to make a call to `dev2`'s LDAP/external backend (that's also why [mocks](#defining-mocks-of-the-external-services-optional) exist - the impersonated identity's data is simulated, not fetched from the backend). +* The `authentication_rule` inside the matching `impersonation` entry authenticates the **real caller** (`admin1`) using the credentials that are actually present on the wire. It has to be spelled out explicitly because there is no other rule anywhere in the ACL whose job is "verify this is really `admin1`, right now, for the purpose of impersonation" - the block rules are all written with the *impersonated* users in mind, not the impersonator. + +In practice, admins usually configure the same credentials/mechanism for `admin1` in both places, because `admin1` authenticates the same way whether they're doing their own work or impersonating someone. That similarity is exactly what makes the two entries *look* like copy-pasted duplication - but they are checked by different execution paths, at different moments, and there's nothing stopping you from requiring a different (e.g. stronger) authentication method just for impersonation. + +### What actually happens, step by step + +1. The HTTP request arrives carrying the impersonator's own Basic Auth credentials (`Authorization: Basic ...`) plus the `x-ror-impersonating: ` header. +2. Before any ACL rule is evaluated, ROR decides which settings apply to the request. The mere presence of the `x-ror-impersonating` header makes ROR evaluate the request against **Test Settings** - never against Main Settings, even if Main Settings also happens to define an `impersonation` section of its own. If Test Settings aren't currently active (never applied, expired, or manually invalidated), the request is rejected immediately with `TEST_SETTINGS_NOT_CONFIGURED`, before any block gets a chance to run. See [Creating ROR's Test Settings](#creating-rors-test-settings) for how long Test Settings stay active. +3. ROR starts evaluating the Test Settings' `access_control_rules` blocks as usual, top to bottom. +4. The moment ROR reaches **any** authentication rule (`auth_key`, `ldap_authentication`, `external_authentication`, ...) inside a block, it notices the impersonation header and **does not run that rule's normal logic at all**. Instead, it switches into the impersonation flow below - the specific rule/type written in that block is irrelevant to this step; only the fact that it *is* an authentication rule matters. +5. ROR extracts the impersonator's username from the request's Basic Auth header, then searches the `impersonation` section, top to bottom, for the first entry where: + * the `impersonator` pattern matches that username, **and** + * the `users` pattern matches the target username from the `x-ror-impersonating` header. + + No match → the request is denied with `IMPERSONATION_NOT_ALLOWED`, regardless of whether `admin1` is a perfectly valid, authenticated user elsewhere in the ACL. +6. ROR authenticates the request's Basic Auth credentials against **that entry's own `authentication_rule`** - a fresh, independent check, unrelated to the block ROR happened to be evaluating. Failure → `IMPERSONATION_NOT_ALLOWED`. +7. ROR checks that the impersonator and the impersonated user aren't the same username (self-impersonation is rejected), and that the impersonated user actually exists - either because it's a statically configured user, or because a [service mock](#defining-mocks-of-the-external-services-optional) confirms it. If the existence check can't be performed at all (e.g. the rule doesn't support impersonation, or the required mock is missing), the request is denied with `IMPERSONATION_NOT_SUPPORTED`. +8. If everything checks out, ROR treats the impersonated user as logged in and continues evaluating the rest of the ACL (groups, indices, Kibana rules, etc.) exactly as it would for that user's real session - using mocked data wherever an external system would normally be consulted. + +One consequence worth calling out: steps 5-7 are re-run independently every time ROR reaches an authentication rule while trying to match a block, regardless of which authentication rule is written in that particular block. If your ACL has three blocks with three different auth rules (say `auth_key`, `ldap_authentication`, `external_authentication`), all three behave identically under impersonation - they all defer to the *same* `impersonation` section entry. Only the rules matching the impersonator's username/target-user pattern decide the outcome, not whichever rule happens to sit in the block. + ## Impersonation configuration Before an admin will be able to impersonate a user, they have to configure ROR properly. The configuration consists of several parts: @@ -36,10 +74,13 @@ When you call Elasticsearch directly or through ROR Kibana, ROR ACL is defined b ROR Kibana plugin provides a dedicated Test Settings UI. See our [Test Settings management guide](../examples/impersonation/test-settings-ui.md) for more information. -But copying Main Settings as Test Settings is not enough. We also have to instruct ROR which users can be considered as impersonators (the ones, who are allowed to impersonate other users): -1. In the `access_control_rules` section in ROR Settings, there must be a rule that authenticates the impersonator user. -2. The impersonator user must be defined in the `impersonation` section in ROR Settings -3. The impersonator's credentials in `impersonation` section must match the credentials, that the impersonator uses to authenticate in Kibana. +**This TTL gates impersonation directly.** As described in [step 2 above](#what-actually-happens-step-by-step), every impersonating request is evaluated exclusively against Test Settings - never against Main Settings. Once Test Settings expire or are invalidated, there are no Test Settings left to evaluate the request against, so impersonation stops working immediately with `TEST_SETTINGS_NOT_CONFIGURED`, regardless of how the `impersonation` section itself is configured. This is a distinct failure mode from a misconfigured `impersonation` entry, and it's worth ruling out first: re-apply Test Settings and retry before troubleshooting anything else. + +But copying Main Settings as Test Settings is not enough. We also have to instruct ROR which users can be considered as impersonators (the ones, who are allowed to impersonate other users). Concretely, three things have to line up, matching the three questions/checks described [above](#what-actually-happens-step-by-step): + +1. In the `access_control_rules` section in ROR Settings, there must be a rule that authenticates the impersonator user *for their own, normal (non-impersonating) session* - this is what grants `admin1` their everyday permissions, and it's a prerequisite for `admin1` being a legitimate ES/Kibana user at all. +2. The impersonator user must be defined in the `impersonation` section in ROR Settings, together with the list/pattern of users they're allowed to impersonate. **Being a valid, authenticated user in `access_control_rules` is not enough** - without a matching `impersonation` entry, ROR will refuse impersonation with `IMPERSONATION_NOT_ALLOWED`, even for a perfectly legitimate admin. +3. The impersonator's credentials must satisfy the `authentication_rule` configured *inside that `impersonation` entry* - this rule is evaluated completely independently of rule #1, using whatever credentials the impersonating request actually carries. It commonly mirrors rule #1 (same rule type, same credentials), but ROR never assumes that - it always re-checks. ```yaml readonlyrest: @@ -62,6 +103,13 @@ In the example above, we see that we have two impersonators: `admin1` and `admin When an impersonator passes wrong credentials ROR will tell Kibana that impersonation is not allowed. +A few structural rules ROR enforces when it loads this section (and that are worth knowing, since they explain some of the config-load errors you might see): + +* Exactly one authentication rule is allowed per `impersonation` entry - you can't stack several auth methods for a single impersonator. +* Only rules that are genuinely authentication rules (`auth_key*`, `ldap_authentication`, `external_authentication`, `proxy_auth`, ...) can be used here - authorization-only rules (like `ldap_authorization`) are rejected. +* The same exact username (no wildcards) cannot appear as both an `impersonator` and a member of `users` in the same entry - a user can't be declared as being able to impersonate themselves. +* If the `authentication_rule` has a statically known, fixed username (e.g. `auth_key: someone:pass`), ROR checks at load time that this username actually matches the `impersonator` pattern, and refuses to start otherwise. This check can't be done for dynamic identities (LDAP, external auth), since the username isn't known until request time. + #### Defining mocks of the external services (optional) ROR has many sophisticated authentication & authorization methods. Some of them are based on external systems like LDAP. The problem with such systems, in regard to to the impersonation feature, is that those systems either don't support it by default or don't support it at all and even if they do - the configuration is complex. @@ -82,6 +130,24 @@ In the impersonation case, it looks pretty much the same. The difference being t ROR Kibana plugin helps administrators to visually create and edit service mocks with a dedicated graphical UI. Follow our [service mock configuration guide](../examples/impersonation/external-services-mocks-ui.md) for more. +#### Which rules support impersonation + +Impersonation support isn't the same for every rule that can appear in an `access_control_rules` block. ROR checks this per rule and, when it applies Test Settings, reports a warning for each rule/block combination that won't work correctly during impersonation - these warnings surface through the Test Settings API and are shown by the ROR Kibana Test Settings UI. + +| Rule | Impersonation support | Notes | +|-------------------------------------------------------------------------------------------------------------------------------------------|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `auth_key`, `auth_key_unix`, `proxy_auth`, `token_authentication` | Full | Work as-is, no extra configuration needed | +| Group-membership rules (`groups_any_of`, `groups_all_of`, and other [groups logic](authorization-rules-details.md#checking-groups-logic)) | Full | Groups are supplied directly in settings, or by an authorization rule that's itself impersonation-aware; no external call is involved | +| `auth_key_sha1`, `auth_key_sha256`, `auth_key_sha512`, `auth_key_pbkdf2_hmac_sha512` | Full, with one condition | Only works when the rule is written in the `USER_NAME:hash(PASSWORD)` form. A fully hashed `hash(USER_NAME:PASSWORD)` blob can't be reversed back to a username, so it never matches during impersonation - see [limitations](#impersonation-limitations) | +| `ldap_authentication`, `ldap_authorization`, `ldap_auth` | Requires a mock | Needs a matching LDAP service mock (see [above](#defining-mocks-of-the-external-services-optional)); without it, denied with `IMPERSONATION_NOT_SUPPORTED` | +| `external_authentication` | Requires a mock | Needs an external authentication service mock | +| `external_authorization` | Requires a mock | Needs an external authorization service mock | +| `jwt_auth`, `jwt_authentication`, `jwt_authorization` | Not supported | Always denied with `IMPERSONATION_NOT_SUPPORTED`; there is no mock or workaround for this today | +| `ror_kbn_auth`, `ror_kbn_authentication`, `ror_kbn_authorization` | Not supported | Always denied with `IMPERSONATION_NOT_SUPPORTED`; there is no mock or workaround for this today | +| Everything else (`indices`, `actions`, `kibana_*`, `fields`, `filter`, `hosts`, `uri_re`, ...) | Not applicable | These rules don't authenticate or authorize an identity - they evaluate normally against whichever user, real or impersonated, is already logged in | + +A block only needs to be fully impersonation-capable if you intend to impersonate the users it applies to. A block built entirely around a "not supported" rule simply can't be exercised through impersonation - traffic that would otherwise match it falls through to later blocks, exactly as it would if the block rejected the request for any other reason. + #### Impersonating a chosen user Now that we have configured Test Settings and External Services Mocks, we can try to impersonate a user. In Elasticsearch ROR Settings, user can be: @@ -95,9 +161,102 @@ It means that we pick the users defined in Settings or Mocks, but also we can en Follow the instructions on how to [impersonate a user using the ROR Kibana plugin UI](../examples/impersonation/impersonate-user-ui.md). +## Full end-to-end examples + +### Example 1: local admin impersonating any local user + +Everything is defined statically, no mocks needed - the simplest possible setup. + +```yaml +readonlyrest: + access_control_rules: + + - name: "Admins" + auth_key: admin1:pass + groups_any_of: ["admins"] + + - name: "Devs" + auth_key: dev2:devpass + groups_any_of: ["devs"] + indices: ["dev-*"] + + users: + - username: admin1 + auth_key: admin1:pass + groups: ["admins"] + + - username: dev2 + auth_key: dev2:devpass + groups: ["devs"] + + impersonation: + - impersonator: admin1 + users: ["*"] + auth_key: admin1:pass # re-checks the SAME credentials admin1 used to authenticate - but independently +``` + +What happens when Kibana sends a request with `Authorization: Basic YWRtaW4xOnBhc3M=` (i.e. `admin1:pass`) and `x-ror-impersonating: dev2`: + +1. ROR reaches the "Admins" block first. Its `auth_key` rule notices the impersonation header and defers to the `impersonation` section instead of comparing `admin1:pass` against its own settings. +2. `admin1` matches the `impersonator` pattern, `dev2` matches `users: ["*"]`. +3. The `impersonation` entry's own `auth_key: admin1:pass` is checked against the request's credentials - it matches, so the caller is confirmed to really be `admin1`. +4. `dev2` is a statically defined local user, so its existence is confirmed without needing a mock. +5. ROR now evaluates the rest of the ACL as `dev2`: the "Admins" block's `groups_any_of: ["admins"]` doesn't match `dev2`'s groups, so it's skipped; the "Devs" block matches, and the response is scoped to `dev-*` indices - exactly what `dev2` would see in their own session. + +### Example 2: LDAP-authenticated admin impersonating an LDAP-authorized user + +Here the impersonated user's group membership comes from LDAP, so it needs a mock. + +```yaml +readonlyrest: + access_control_rules: + + - name: "LDAP admins can do everything" + ldap_authentication: "ldap1" + ldap_authorization: + name: "ldap1" + groups_any_of: ["admins"] + + - name: "LDAP devs see only their indices" + ldap_auth: + name: "ldap1" + groups_any_of: ["devs"] + indices: ["@{acl:user}_*"] + + ldaps: + - name: ldap1 + host: ldap.example.com + port: 389 + # ... rest of the connector settings + + impersonation: + - impersonator: admin1 + users: ["dev2"] + ldap_authentication: "ldap1" # admin1's own LDAP credentials, checked independently +``` + +For this to work during impersonation, a **Test Settings mock** for `ldap1` must define `dev2` as an existing user belonging to the `devs` group - see [Defining mocks of the external services](#defining-mocks-of-the-external-services-optional). Without it, both LDAP rules will refuse to evaluate `dev2` and the request is denied with `IMPERSONATION_NOT_SUPPORTED`, even though `admin1`'s own impersonator authentication succeeded. + +## Common misconfigurations + +Most support tickets about "impersonation isn't working" trace back to one of these. The middle column is what you'll typically see in the ES response/ROR logs (`USR` field, or the `causes`/reason returned to Kibana). + +| Symptom | What ROR reports | Most common root cause | Fix | +|-----------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------| +| Impersonation worked earlier in the session but every impersonating request now fails, though nothing in the config changed | `TEST_SETTINGS_NOT_CONFIGURED` | Test Settings expired (default TTL is 30 minutes) or were manually invalidated. Every impersonating request is evaluated exclusively against Test Settings (see [step 2](#what-actually-happens-step-by-step)), so once they're gone, impersonation stops working regardless of the `impersonation` section | Re-apply Test Settings (optionally with a longer TTL) and retry | +| Admin can log into Kibana fine, but impersonation is refused outright | `IMPERSONATION_NOT_ALLOWED` | There's no `impersonation` entry at all for this admin - being authenticated in `access_control_rules` does **not** automatically grant impersonation rights | Add an `impersonation` entry with an `impersonator` pattern matching the admin | +| Impersonation works for some target users but not others | `IMPERSONATION_NOT_ALLOWED` | The `users` pattern in the matching `impersonation` entry doesn't include the requested target username | Broaden the `users` pattern, or add a dedicated entry | +| Admin's password was recently changed and impersonation broke, even though normal login still works | `IMPERSONATION_NOT_ALLOWED` | The `authentication_rule` inside `impersonation` is checked completely independently of the rule in `access_control_rules` - updating one does not update the other | Keep both in sync, or point both at the same external identity source (LDAP/external auth) instead of hardcoding credentials twice | +| Config fails to load at startup, mentioning "should be either impersonator or a user to be impersonated" | Config validation error | The exact same username (no wildcards) appears in both `impersonator` and `users` in one entry | Remove the self-reference - a user can't be declared as able to impersonate themselves | +| Config fails to load at startup, mentioning "it's used in a context of user patterns" | Config validation error | The `impersonation` entry's `authentication_rule` has a fixed, statically known username that doesn't match the `impersonator` pattern (e.g. `impersonator: admin1` but `auth_key: someone_else:pass`) | Make the rule's username match the `impersonator` pattern | +| Impersonator authenticates fine, but the request is still denied, mentioning the impersonated user doesn't exist | Denied, logged as `AUTH_FAIL (Impersonated user does not exist)` | The target username isn't a statically configured user and isn't present in the relevant service mock | Add the user to the mock, or confirm the username matches exactly | +| Request denied with "impersonation not supported", even though the `impersonation` section looks correct | `IMPERSONATION_NOT_SUPPORTED` | An ACL block relies on a rule that either doesn't support impersonation at all (`jwt_auth`, `ror_kbn_auth` and their authentication/authorization variants), or needs a service mock (LDAP/external auth/external authz) that hasn't been configured yet, or uses `auth_key_sha*` with a fully-hashed `user:pass` blob (see [limitations](#impersonation-limitations)) | Add the missing mock, switch to the `USER_NAME:hash(PASSWORD)` form for hashed auth rules, or accept that the rule type isn't impersonable yet | +| Impersonation UI can't find/list the user you want to impersonate | N/A (UI limitation) | The target username is only reachable through a wildcard `users` pattern in the ACL, so ROR can't enumerate it upfront | Type the username manually in the impersonation UI, as described in [limitations](#impersonation-limitations) | +| Nothing happens / impersonation is silently ignored even though credentials and patterns look correct | Request is treated as a normal (non-impersonating) request | The impersonating client didn't send the impersonator's credentials as an HTTP Basic Auth header - ROR always identifies the impersonator from Basic Auth, regardless of which rule type is configured as the `authentication_rule` | Make sure the client authenticates with Basic Auth (this is what the ROR Kibana Test Settings UI does under the hood) | + ## Logs & audit -In Elasticsearch logs, in `USR` field, if an admin user finds something like this: `admin1 as (user1)` - it means that `admin1` was authenticated and they are the impersonator who is impersonating `user1`. +In Elasticsearch logs, in `USR` field, if an admin user finds something like this: `admin1 (as user1)` - it means that `admin1` was authenticated, and they are the impersonator who is impersonating `user1`. All logs of impersonated user in Kibana will have this format `[][plugins][ReadonlyREST][][impersonating ]` @@ -139,6 +298,7 @@ Impersonation mode has some limitations. Please check if they have an impact on * **Impersonator** - someone who imitates or copies the behavior or actions of another, * **Impersonation** - imitating behaviors or actions of a given user, +* **Impersonated user** - the identity being borrowed for the duration of an impersonation session; their permissions/data determine what the impersonator sees, but their own credentials are never needed or checked, * **Main Settings** - the ROR's settings that apply to ACL that handles requests during regular sessions (not the impersonation ones), * **Test Settings** - the ROR's settings that apply to ACL that handles impersonating requests (the ones during impersonation session), * **External Service Mock** - an imitation of an external service (the supported ones: LDAP, an external authentication service, an external authorization service). From c730a4861851daa66d0ea29b8f705bc0320581a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Goworko?= Date: Mon, 31 Aug 2026 00:29:04 +0200 Subject: [PATCH 2/5] qs --- details/impersonation.md | 52 +++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/details/impersonation.md b/details/impersonation.md index 48921d5..45aed6d 100644 --- a/details/impersonation.md +++ b/details/impersonation.md @@ -48,17 +48,20 @@ In practice, admins usually configure the same credentials/mechanism for `admin1 1. The HTTP request arrives carrying the impersonator's own Basic Auth credentials (`Authorization: Basic ...`) plus the `x-ror-impersonating: ` header. 2. Before any ACL rule is evaluated, ROR decides which settings apply to the request. The mere presence of the `x-ror-impersonating` header makes ROR evaluate the request against **Test Settings** - never against Main Settings, even if Main Settings also happens to define an `impersonation` section of its own. If Test Settings aren't currently active (never applied, expired, or manually invalidated), the request is rejected immediately with `TEST_SETTINGS_NOT_CONFIGURED`, before any block gets a chance to run. See [Creating ROR's Test Settings](#creating-rors-test-settings) for how long Test Settings stay active. 3. ROR starts evaluating the Test Settings' `access_control_rules` blocks as usual, top to bottom. -4. The moment ROR reaches **any** authentication rule (`auth_key`, `ldap_authentication`, `external_authentication`, ...) inside a block, it notices the impersonation header and **does not run that rule's normal logic at all**. Instead, it switches into the impersonation flow below - the specific rule/type written in that block is irrelevant to this step; only the fact that it *is* an authentication rule matters. -5. ROR extracts the impersonator's username from the request's Basic Auth header, then searches the `impersonation` section, top to bottom, for the first entry where: - * the `impersonator` pattern matches that username, **and** - * the `users` pattern matches the target username from the `x-ror-impersonating` header. +4. The moment ROR reaches an authentication rule that supports impersonation (`auth_key*`, `auth_key_unix`, `proxy_auth`, `token_authentication`, `ldap_authentication`, `external_authentication`, ...) inside a block, it notices the impersonation header and **does not run that rule's normal logic at all**. Instead, it switches into the impersonation flow below - which of those rules is written in the block doesn't change how the impersonator is identified. Rules that don't support impersonation (`jwt_*`, `ror_kbn_*` - see [Which rules support impersonation](#which-rules-support-impersonation)) never enter this flow: they evaluate the request exactly as they normally would, find no token in it, and their block simply doesn't match. +5. ROR extracts the impersonator's username from the request's Basic Auth header - this is always how the impersonator is identified, no matter which rule type the `impersonation` entry uses - and picks the **first entry whose `impersonator` pattern matches that username**. Only that one entry is then used: its `users` pattern is checked against the target username from the `x-ror-impersonating` header, and if it doesn't match, the request is denied with `IMPERSONATION_NOT_ALLOWED`. ROR does **not** continue scanning for a later entry that would allow the pair. - No match → the request is denied with `IMPERSONATION_NOT_ALLOWED`, regardless of whether `admin1` is a perfectly valid, authenticated user elsewhere in the ACL. + This makes the order of the `impersonation` entries significant. If two entries have overlapping `impersonator` patterns (e.g. `admin*` and `admin1`), only the first matching one is ever consulted for a given impersonator - the `users` list of the later entry is dead configuration. Prefer one entry per impersonator, and put the most specific patterns first. + + No entry matches the impersonator at all (or the request carries no Basic Auth header) → the same `IMPERSONATION_NOT_ALLOWED` denial, regardless of whether `admin1` is a perfectly valid, authenticated user elsewhere in the ACL. 6. ROR authenticates the request's Basic Auth credentials against **that entry's own `authentication_rule`** - a fresh, independent check, unrelated to the block ROR happened to be evaluating. Failure → `IMPERSONATION_NOT_ALLOWED`. -7. ROR checks that the impersonator and the impersonated user aren't the same username (self-impersonation is rejected), and that the impersonated user actually exists - either because it's a statically configured user, or because a [service mock](#defining-mocks-of-the-external-services-optional) confirms it. If the existence check can't be performed at all (e.g. the rule doesn't support impersonation, or the required mock is missing), the request is denied with `IMPERSONATION_NOT_SUPPORTED`. +7. ROR checks that the impersonator and the impersonated user aren't the same username (self-impersonation is rejected), and that the impersonated user actually exists. **The existence check is answered by the very rule ROR is currently evaluating**, using only what that rule knows: `auth_key: dev2:devpass` knows just `dev2`, an `ldap_authentication` rule asks the LDAP [service mock](#defining-mocks-of-the-external-services-optional), and so on. Three outcomes are possible: + * the rule confirms the user exists → the flow continues with step 8, + * the rule can answer, and the answer is "I don't know this user" → **this block** is rejected, logged as `AUTH_FAIL (Impersonated user does not exist)`, and ROR moves on to the next block. In a multi-block ACL this is completely normal - only the block that actually defines the impersonated user can match, + * the rule can't answer at all (a missing service mock, or `auth_key_sha*` with a fully hashed `user:pass` blob) → the request is denied with `IMPERSONATION_NOT_SUPPORTED`. 8. If everything checks out, ROR treats the impersonated user as logged in and continues evaluating the rest of the ACL (groups, indices, Kibana rules, etc.) exactly as it would for that user's real session - using mocked data wherever an external system would normally be consulted. -One consequence worth calling out: steps 5-7 are re-run independently every time ROR reaches an authentication rule while trying to match a block, regardless of which authentication rule is written in that particular block. If your ACL has three blocks with three different auth rules (say `auth_key`, `ldap_authentication`, `external_authentication`), all three behave identically under impersonation - they all defer to the *same* `impersonation` section entry. Only the rules matching the impersonator's username/target-user pattern decide the outcome, not whichever rule happens to sit in the block. +One consequence worth calling out: steps 5-7 are re-run independently every time ROR reaches an impersonation-aware authentication rule while trying to match a block. If your ACL has three blocks with three different auth rules (say `auth_key`, `ldap_authentication`, `external_authentication`), the impersonator side of the check behaves identically in all three - they all defer to the *same* `impersonation` section entry, and the rule written in the block has no say in who the impersonator is. What does differ from block to block is step 7: each rule answers the "does the impersonated user exist?" question with its own knowledge, and that is what makes one block match while the others fall through. ## Impersonation configuration @@ -76,7 +79,7 @@ ROR Kibana plugin provides a dedicated Test Settings UI. See our [Test Settings **This TTL gates impersonation directly.** As described in [step 2 above](#what-actually-happens-step-by-step), every impersonating request is evaluated exclusively against Test Settings - never against Main Settings. Once Test Settings expire or are invalidated, there are no Test Settings left to evaluate the request against, so impersonation stops working immediately with `TEST_SETTINGS_NOT_CONFIGURED`, regardless of how the `impersonation` section itself is configured. This is a distinct failure mode from a misconfigured `impersonation` entry, and it's worth ruling out first: re-apply Test Settings and retry before troubleshooting anything else. -But copying Main Settings as Test Settings is not enough. We also have to instruct ROR which users can be considered as impersonators (the ones, who are allowed to impersonate other users). Concretely, three things have to line up, matching the three questions/checks described [above](#what-actually-happens-step-by-step): +But copying Main Settings as Test Settings is not enough. We also have to instruct ROR which users can be considered as impersonators (the ones, who are allowed to impersonate other users). Concretely, three things have to line up, answering the two questions and the checks described [above](#what-actually-happens-step-by-step): 1. In the `access_control_rules` section in ROR Settings, there must be a rule that authenticates the impersonator user *for their own, normal (non-impersonating) session* - this is what grants `admin1` their everyday permissions, and it's a prerequisite for `admin1` being a legitimate ES/Kibana user at all. 2. The impersonator user must be defined in the `impersonation` section in ROR Settings, together with the list/pattern of users they're allowed to impersonate. **Being a valid, authenticated user in `access_control_rules` is not enough** - without a matching `impersonation` entry, ROR will refuse impersonation with `IMPERSONATION_NOT_ALLOWED`, even for a perfectly legitimate admin. @@ -142,8 +145,8 @@ Impersonation support isn't the same for every rule that can appear in an `acces | `ldap_authentication`, `ldap_authorization`, `ldap_auth` | Requires a mock | Needs a matching LDAP service mock (see [above](#defining-mocks-of-the-external-services-optional)); without it, denied with `IMPERSONATION_NOT_SUPPORTED` | | `external_authentication` | Requires a mock | Needs an external authentication service mock | | `external_authorization` | Requires a mock | Needs an external authorization service mock | -| `jwt_auth`, `jwt_authentication`, `jwt_authorization` | Not supported | Always denied with `IMPERSONATION_NOT_SUPPORTED`; there is no mock or workaround for this today | -| `ror_kbn_auth`, `ror_kbn_authentication`, `ror_kbn_authorization` | Not supported | Always denied with `IMPERSONATION_NOT_SUPPORTED`; there is no mock or workaround for this today | +| `jwt_auth`, `jwt_authentication`, `jwt_authorization` | Not supported | These rules ignore impersonation entirely: they evaluate the real request, find no JWT in it, fail authentication and their block doesn't match. No mock or workaround today - ROR reports a Test Settings warning for such blocks | +| `ror_kbn_auth`, `ror_kbn_authentication`, `ror_kbn_authorization` | Not supported | Same as above, with the ROR Kibana token: the block can't be exercised through impersonation, and ROR reports a Test Settings warning for it | | Everything else (`indices`, `actions`, `kibana_*`, `fields`, `filter`, `hosts`, `uri_re`, ...) | Not applicable | These rules don't authenticate or authorize an identity - they evaluate normally against whichever user, real or impersonated, is already logged in | A block only needs to be fully impersonation-capable if you intend to impersonate the users it applies to. A block built entirely around a "not supported" rule simply can't be exercised through impersonation - traffic that would otherwise match it falls through to later blocks, exactly as it would if the block rejected the request for any other reason. @@ -200,8 +203,8 @@ What happens when Kibana sends a request with `Authorization: Basic YWRtaW4xOnBh 1. ROR reaches the "Admins" block first. Its `auth_key` rule notices the impersonation header and defers to the `impersonation` section instead of comparing `admin1:pass` against its own settings. 2. `admin1` matches the `impersonator` pattern, `dev2` matches `users: ["*"]`. 3. The `impersonation` entry's own `auth_key: admin1:pass` is checked against the request's credentials - it matches, so the caller is confirmed to really be `admin1`. -4. `dev2` is a statically defined local user, so its existence is confirmed without needing a mock. -5. ROR now evaluates the rest of the ACL as `dev2`: the "Admins" block's `groups_any_of: ["admins"]` doesn't match `dev2`'s groups, so it's skipped; the "Devs" block matches, and the response is scoped to `dev-*` indices - exactly what `dev2` would see in their own session. +4. Finally, ROR asks the rule it is currently evaluating - the "Admins" block's `auth_key: admin1:pass` - whether `dev2` exists. That rule knows only `admin1`, so the answer is no: the **"Admins" block is rejected** (logged as `AUTH_FAIL (Impersonated user does not exist)`) and ROR moves on to the next block. That log line is expected here, not a misconfiguration - the "Admins" block is simply not the block that defines `dev2`. +5. In the "Devs" block, steps 1-3 repeat identically, and this time the block's own `auth_key: dev2:devpass` rule confirms that `dev2` exists (a statically defined local user, so no mock is needed). ROR marks the request as logged in as `dev2` and evaluates the remaining rules as `dev2`: `groups_any_of: ["devs"]` matches and the response is scoped to `dev-*` indices - exactly what `dev2` would see in their own session. ### Example 2: LDAP-authenticated admin impersonating an LDAP-authorized user @@ -241,18 +244,19 @@ For this to work during impersonation, a **Test Settings mock** for `ldap1` must Most support tickets about "impersonation isn't working" trace back to one of these. The middle column is what you'll typically see in the ES response/ROR logs (`USR` field, or the `causes`/reason returned to Kibana). -| Symptom | What ROR reports | Most common root cause | Fix | -|-----------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------| -| Impersonation worked earlier in the session but every impersonating request now fails, though nothing in the config changed | `TEST_SETTINGS_NOT_CONFIGURED` | Test Settings expired (default TTL is 30 minutes) or were manually invalidated. Every impersonating request is evaluated exclusively against Test Settings (see [step 2](#what-actually-happens-step-by-step)), so once they're gone, impersonation stops working regardless of the `impersonation` section | Re-apply Test Settings (optionally with a longer TTL) and retry | -| Admin can log into Kibana fine, but impersonation is refused outright | `IMPERSONATION_NOT_ALLOWED` | There's no `impersonation` entry at all for this admin - being authenticated in `access_control_rules` does **not** automatically grant impersonation rights | Add an `impersonation` entry with an `impersonator` pattern matching the admin | -| Impersonation works for some target users but not others | `IMPERSONATION_NOT_ALLOWED` | The `users` pattern in the matching `impersonation` entry doesn't include the requested target username | Broaden the `users` pattern, or add a dedicated entry | -| Admin's password was recently changed and impersonation broke, even though normal login still works | `IMPERSONATION_NOT_ALLOWED` | The `authentication_rule` inside `impersonation` is checked completely independently of the rule in `access_control_rules` - updating one does not update the other | Keep both in sync, or point both at the same external identity source (LDAP/external auth) instead of hardcoding credentials twice | -| Config fails to load at startup, mentioning "should be either impersonator or a user to be impersonated" | Config validation error | The exact same username (no wildcards) appears in both `impersonator` and `users` in one entry | Remove the self-reference - a user can't be declared as able to impersonate themselves | -| Config fails to load at startup, mentioning "it's used in a context of user patterns" | Config validation error | The `impersonation` entry's `authentication_rule` has a fixed, statically known username that doesn't match the `impersonator` pattern (e.g. `impersonator: admin1` but `auth_key: someone_else:pass`) | Make the rule's username match the `impersonator` pattern | -| Impersonator authenticates fine, but the request is still denied, mentioning the impersonated user doesn't exist | Denied, logged as `AUTH_FAIL (Impersonated user does not exist)` | The target username isn't a statically configured user and isn't present in the relevant service mock | Add the user to the mock, or confirm the username matches exactly | -| Request denied with "impersonation not supported", even though the `impersonation` section looks correct | `IMPERSONATION_NOT_SUPPORTED` | An ACL block relies on a rule that either doesn't support impersonation at all (`jwt_auth`, `ror_kbn_auth` and their authentication/authorization variants), or needs a service mock (LDAP/external auth/external authz) that hasn't been configured yet, or uses `auth_key_sha*` with a fully-hashed `user:pass` blob (see [limitations](#impersonation-limitations)) | Add the missing mock, switch to the `USER_NAME:hash(PASSWORD)` form for hashed auth rules, or accept that the rule type isn't impersonable yet | -| Impersonation UI can't find/list the user you want to impersonate | N/A (UI limitation) | The target username is only reachable through a wildcard `users` pattern in the ACL, so ROR can't enumerate it upfront | Type the username manually in the impersonation UI, as described in [limitations](#impersonation-limitations) | -| Nothing happens / impersonation is silently ignored even though credentials and patterns look correct | Request is treated as a normal (non-impersonating) request | The impersonating client didn't send the impersonator's credentials as an HTTP Basic Auth header - ROR always identifies the impersonator from Basic Auth, regardless of which rule type is configured as the `authentication_rule` | Make sure the client authenticates with Basic Auth (this is what the ROR Kibana Test Settings UI does under the hood) | +| Symptom | What ROR reports | Most common root cause | Fix | +|------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------| +| Impersonation worked earlier in the session but every impersonating request now fails, though nothing in the config changed | `TEST_SETTINGS_NOT_CONFIGURED` | Test Settings expired (default TTL is 30 minutes) or were manually invalidated. Every impersonating request is evaluated exclusively against Test Settings (see [step 2](#what-actually-happens-step-by-step)), so once they're gone, impersonation stops working regardless of the `impersonation` section | Re-apply Test Settings (optionally with a longer TTL) and retry | +| Admin can log into Kibana fine, but impersonation is refused outright | `IMPERSONATION_NOT_ALLOWED` | There's no `impersonation` entry at all for this admin - being authenticated in `access_control_rules` does **not** automatically grant impersonation rights | Add an `impersonation` entry with an `impersonator` pattern matching the admin | +| Impersonation works for some target users but not others | `IMPERSONATION_NOT_ALLOWED` | The `users` pattern of the **first** `impersonation` entry matching this impersonator doesn't include the requested target username. ROR uses only that first entry and never falls through to a later one, so a second entry added for the same admin is never consulted | Broaden the `users` pattern *in that first matching entry* - appending another entry below it won't help | +| Admin's password was recently changed and impersonation broke, even though normal login still works | `IMPERSONATION_NOT_ALLOWED` | The `authentication_rule` inside `impersonation` is checked completely independently of the rule in `access_control_rules` - updating one does not update the other | Keep both in sync, or point both at the same external identity source (LDAP/external auth) instead of hardcoding credentials twice | +| Config fails to load at startup, mentioning "should be either impersonator or a user to be impersonated" | Config validation error | The exact same username (no wildcards) appears in both `impersonator` and `users` in one entry | Remove the self-reference - a user can't be declared as able to impersonate themselves | +| Config fails to load at startup, mentioning "it's used in a context of user patterns" | Config validation error | The `impersonation` entry's `authentication_rule` has a fixed, statically known username that doesn't match the `impersonator` pattern (e.g. `impersonator: admin1` but `auth_key: someone_else:pass`) | Make the rule's username match the `impersonator` pattern | +| Impersonator authenticates fine, but the request is still denied, mentioning the impersonated user doesn't exist | Denied; `AUTH_FAIL (Impersonated user does not exist)` in the logs | **No** block could confirm the target user: they aren't statically configured in any block and aren't present in the relevant service mock. Note that this message is logged by every block whose authentication rule doesn't know the impersonated user, so seeing it in a healthy setup is normal - it's a problem only when no block ends up matching | Add the user to the mock, or confirm the username matches exactly | +| Request denied with "impersonation not supported", even though the `impersonation` section looks correct | `IMPERSONATION_NOT_SUPPORTED` | An ACL block needs a service mock (LDAP / external authentication / external authorization) that hasn't been configured yet, or uses `auth_key_sha*` with a fully-hashed `user:pass` blob (see [limitations](#impersonation-limitations)) | Add the missing mock, or switch to the `USER_NAME:hash(PASSWORD)` form for hashed auth rules | +| The block you wanted to test is never matched during impersonation, and it uses `jwt_auth` or `ror_kbn_auth` | No impersonation-specific error - the block just doesn't match | These rules don't take part in the impersonation flow: they look for a real JWT / ROR Kibana token in the request, don't find one, and reject the block. ROR reports it as a Test Settings warning | Not impersonable today - test such blocks with a real session, or authenticate the users with an impersonation-aware rule | +| Impersonation UI can't find/list the user you want to impersonate | N/A (UI limitation) | The target username is only reachable through a wildcard `users` pattern in the ACL, so ROR can't enumerate it upfront | Type the username manually in the impersonation UI, as described in [limitations](#impersonation-limitations) | +| Impersonation is refused for every target user, although the `impersonation` entry looks correct and the same credentials work elsewhere | `IMPERSONATION_NOT_ALLOWED` | The impersonating client didn't send the impersonator's credentials as an HTTP Basic Auth header - ROR always identifies the impersonator from Basic Auth, regardless of which rule type is configured as the `authentication_rule` | Make sure the client authenticates with Basic Auth (this is what the ROR Kibana Test Settings UI does under the hood) | ## Logs & audit From 2e65d59515567f0373f97623b07ec57bb68b8ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Goworko?= Date: Wed, 2 Sep 2026 23:25:01 +0200 Subject: [PATCH 3/5] qs --- details/impersonation.md | 151 +++++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 68 deletions(-) diff --git a/details/impersonation.md b/details/impersonation.md index 45aed6d..7bcaef6 100644 --- a/details/impersonation.md +++ b/details/impersonation.md @@ -22,46 +22,59 @@ Both of the problems can be solved using the ROR's impersonation. Thanks to the Admin can add the new user configuration without worrying and then test it by impersonating the user. They can check if the user can log in without problems and if the user has access only to the Kibana features the admin wanted to grant. When the admin is sure that everything is configured correctly, they can promote the settings (test) to production. -## The impersonator/impersonated identity model +## How ROR processes an impersonation request -Before diving into the configuration, it's worth understanding *what an impersonating request actually contains* and *what ROR does with it*, since this is the part of the configuration that is most error-prone. +An impersonating request is almost identical to the request the impersonated user would send themselves. It reaches the same cluster and is evaluated by the same ACL, block by block, in the same order. Rules like `indices`, `kibana_*`, `fields`, `filter` or `hosts` see exactly what they would see in that user's own session - which is what makes impersonation useful for testing a configuration in the first place. -An impersonating request carries **two identities at once**: +Two things are different: -* the **impersonator** - the real, credentialed admin sitting behind the keyboard (e.g. `admin1`), proven by whatever credentials travel with the request (typically an HTTP Basic Auth header), -* the **impersonated user** - the identity the admin wants to "borrow" for the duration of the request (e.g. `dev2`), carried in an internal header ROR/Kibana attaches to the request (`x-ror-impersonating`). +* **the authentication data the request carries** - the credentials on the wire belong to the *impersonator* (say, `alice`), while the identity to be evaluated - the *impersonated user* (say, `bob`) - travels separately, in an internal header managed by ROR and its Kibana plugin, +* **the way authentication and authorization rules behave** - and that is where the whole feature lives. -ROR has to answer two completely different questions before it lets the request through: +The rest of this section is about that second difference. -1. **"Is the real caller actually who they claim to be, and are they allowed to impersonate anyone at all?"** - this is a question about the *impersonator's* identity. It has nothing to do with `dev2`. -2. **"Given that we trust the caller, are they allowed to become `dev2` specifically, and does `dev2` even exist?"** - this is a question about the *impersonated user*, answered using the `impersonation` section and, where needed, [service mocks](#defining-mocks-of-the-external-services-optional). +### Impersonating requests use Test Settings -This is why the `impersonation` section needs its own, explicit `authentication_rule`, separate from whatever rule authenticates users in `access_control_rules`. **It's not accidental duplication - the two rules answer different questions, for different identities, and they run at different times:** +ROR keeps two independent sets of settings: -* The rule in `access_control_rules` authenticates whoever is trying to act as `dev2` during `dev2`'s own, non-impersonating session. During impersonation, ROR deliberately does **not** execute that rule's normal authentication logic - that's the entire point of impersonation: it lets an admin experience `dev2`'s permissions without needing `dev2`'s actual password, and without ROR having to make a call to `dev2`'s LDAP/external backend (that's also why [mocks](#defining-mocks-of-the-external-services-optional) exist - the impersonated identity's data is simulated, not fetched from the backend). -* The `authentication_rule` inside the matching `impersonation` entry authenticates the **real caller** (`admin1`) using the credentials that are actually present on the wire. It has to be spelled out explicitly because there is no other rule anywhere in the ACL whose job is "verify this is really `admin1`, right now, for the purpose of impersonation" - the block rules are all written with the *impersonated* users in mind, not the impersonator. +* **Main Settings** - the ACL that handles regular traffic, +* **Test Settings** - a separate ACL, used only for impersonation. They are a scratchpad: the admin can edit them freely, without any risk to the users working against Main Settings, and promote them to Main Settings once the result is satisfying. -In practice, admins usually configure the same credentials/mechanism for `admin1` in both places, because `admin1` authenticates the same way whether they're doing their own work or impersonating someone. That similarity is exactly what makes the two entries *look* like copy-pasted duplication - but they are checked by different execution paths, at different moments, and there's nothing stopping you from requiring a different (e.g. stronger) authentication method just for impersonation. +An impersonating request is always evaluated against Test Settings, never against Main Settings. Test Settings stay active only for a limited time and can be invalidated at any moment (see [Creating ROR's Test Settings](#creating-rors-test-settings)); when none are active, impersonation simply doesn't work, no matter how the rest of the configuration looks. -### What actually happens, step by step +### The impersonator and the impersonated user are authorized differently -1. The HTTP request arrives carrying the impersonator's own Basic Auth credentials (`Authorization: Basic ...`) plus the `x-ror-impersonating: ` header. -2. Before any ACL rule is evaluated, ROR decides which settings apply to the request. The mere presence of the `x-ror-impersonating` header makes ROR evaluate the request against **Test Settings** - never against Main Settings, even if Main Settings also happens to define an `impersonation` section of its own. If Test Settings aren't currently active (never applied, expired, or manually invalidated), the request is rejected immediately with `TEST_SETTINGS_NOT_CONFIGURED`, before any block gets a chance to run. See [Creating ROR's Test Settings](#creating-rors-test-settings) for how long Test Settings stay active. -3. ROR starts evaluating the Test Settings' `access_control_rules` blocks as usual, top to bottom. -4. The moment ROR reaches an authentication rule that supports impersonation (`auth_key*`, `auth_key_unix`, `proxy_auth`, `token_authentication`, `ldap_authentication`, `external_authentication`, ...) inside a block, it notices the impersonation header and **does not run that rule's normal logic at all**. Instead, it switches into the impersonation flow below - which of those rules is written in the block doesn't change how the impersonator is identified. Rules that don't support impersonation (`jwt_*`, `ror_kbn_*` - see [Which rules support impersonation](#which-rules-support-impersonation)) never enter this flow: they evaluate the request exactly as they normally would, find no token in it, and their block simply doesn't match. -5. ROR extracts the impersonator's username from the request's Basic Auth header - this is always how the impersonator is identified, no matter which rule type the `impersonation` entry uses - and picks the **first entry whose `impersonator` pattern matches that username**. Only that one entry is then used: its `users` pattern is checked against the target username from the `x-ror-impersonating` header, and if it doesn't match, the request is denied with `IMPERSONATION_NOT_ALLOWED`. ROR does **not** continue scanning for a later entry that would allow the pair. +`alice` can appear in ROR settings in two completely independent roles: - This makes the order of the `impersonation` entries significant. If two entries have overlapping `impersonator` patterns (e.g. `admin*` and `admin1`), only the first matching one is ever consulted for a given impersonator - the `users` list of the later entry is dead configuration. Prefer one entry per impersonator, and put the most specific patterns first. +* **as a regular user** - authenticated by an authentication rule, which is a part of a block, which is one of many in the ACL, exactly like anybody else. This is what lets `alice` log into Kibana and do her own work. +* **as an impersonator** - declared in the `impersonation` section, a separate part of ROR settings saying who may impersonate whom, and how such an impersonator is authenticated (see [Impersonation configuration](#impersonation-configuration)). - No entry matches the impersonator at all (or the request carries no Basic Auth header) → the same `IMPERSONATION_NOT_ALLOWED` denial, regardless of whether `admin1` is a perfectly valid, authenticated user elsewhere in the ACL. -6. ROR authenticates the request's Basic Auth credentials against **that entry's own `authentication_rule`** - a fresh, independent check, unrelated to the block ROR happened to be evaluating. Failure → `IMPERSONATION_NOT_ALLOWED`. -7. ROR checks that the impersonator and the impersonated user aren't the same username (self-impersonation is rejected), and that the impersonated user actually exists. **The existence check is answered by the very rule ROR is currently evaluating**, using only what that rule knows: `auth_key: dev2:devpass` knows just `dev2`, an `ldap_authentication` rule asks the LDAP [service mock](#defining-mocks-of-the-external-services-optional), and so on. Three outcomes are possible: - * the rule confirms the user exists → the flow continues with step 8, - * the rule can answer, and the answer is "I don't know this user" → **this block** is rejected, logged as `AUTH_FAIL (Impersonated user does not exist)`, and ROR moves on to the next block. In a multi-block ACL this is completely normal - only the block that actually defines the impersonated user can match, - * the rule can't answer at all (a missing service mock, or `auth_key_sha*` with a fully hashed `user:pass` blob) → the request is denied with `IMPERSONATION_NOT_SUPPORTED`. -8. If everything checks out, ROR treats the impersonated user as logged in and continues evaluating the rest of the ACL (groups, indices, Kibana rules, etc.) exactly as it would for that user's real session - using mocked data wherever an external system would normally be consulted. +Neither role implies the other, and that is deliberate: -One consequence worth calling out: steps 5-7 are re-run independently every time ROR reaches an impersonation-aware authentication rule while trying to match a block. If your ACL has three blocks with three different auth rules (say `auth_key`, `ldap_authentication`, `external_authentication`), the impersonator side of the check behaves identically in all three - they all defer to the *same* `impersonation` section entry, and the rule written in the block has no say in who the impersonator is. What does differ from block to block is step 7: each rule answers the "does the impersonated user exist?" question with its own knowledge, and that is what makes one block match while the others fall through. +* An impersonator who never logs into Kibana needs only an `impersonation` entry. They can impersonate users through the Elasticsearch REST API without being a regular ACL user at all. +* If `alice` should also log into Kibana as herself, some ACL block has to authenticate her as a regular user. The `impersonation` section grants no everyday access whatsoever. + +So, when a request comes in as `alice` herself, it is authorized by the ACL like any other request. When the same `alice` sends a request on behalf of `bob`, the authentication rules in the ACL blocks no longer answer the question "who is the caller?" - the `impersonation` section does. This is why the impersonator's authentication has to be spelled out there explicitly: it is the only place in the settings whose job is to verify that the caller really is `alice`, right now, for the purpose of impersonation. + +### Not every authentication rule supports impersonation + +The first thing an authentication rule does with an impersonating request is to check whether it supports impersonation at all (the full list is in [Which rules support impersonation](#which-rules-support-impersonation)). The two paths are completely different. + +**When the rule doesn't support impersonation** (`jwt_*`, `ror_kbn_*`), it takes no part in the impersonation flow. It evaluates the request the way it always does: it looks for a JWT or a ROR Kibana token, finds none (the request carries the impersonator's Basic Auth credentials instead), and doesn't match - so its block doesn't match either, and ROR moves on to the next block. A block built around such a rule cannot be exercised through impersonation at all; ROR points this out with a warning when Test Settings are applied. + +**When the rule does support impersonation**, it skips its normal authentication logic entirely and hands the request over to the impersonation flow, which answers three questions, in order: + +1. **Is `alice` allowed to impersonate `bob`?** The impersonator is identified by the Basic Auth credentials carried by the request, and looked up in the `impersonation` section. If nothing there allows this particular pair, the request is denied. +2. **Is the caller really `alice`?** Her credentials are verified against the authentication rule of the matching `impersonation` entry - independently of the block ROR happens to be evaluating, and independently of whatever rule authenticates `alice` as a regular user. Trying to impersonate oneself is rejected here as well. +3. **Does `bob` exist?** This one is answered by the very rule ROR is currently evaluating, using only what that rule knows. A rule holding static credentials knows the usernames written next to it. A rule backed by an external system (LDAP, an external authentication or authorization service) would normally have to ask that system - during impersonation it asks a [mock](#defining-mocks-of-the-external-services-optional) of it instead, so that no real account, no password and no connection to the production service are needed. + +The answer to the last question decides the fate of the block: + +* the rule knows `bob` → ROR treats the request as logged in as `bob`, and the rest of the block (groups, indices, Kibana rules, ...) is evaluated as `bob`, using mocked data wherever an external system would normally be consulted, +* the rule can answer, and the answer is "I don't know this user" → this block doesn't match, and ROR moves on to the next one. In a multi-block ACL this is perfectly normal: only the block that actually defines `bob` can match him, and the others log `AUTH_FAIL (Impersonated user does not exist)` along the way, +* the rule cannot answer at all - a missing service mock, or an `auth_key_sha*` rule whose whole `user:pass` pair is hashed and can't be reversed back to a username → the request is denied, and ROR reports that the impersonation is not supported. + +These three questions are asked from scratch in every block ROR tries. The first two always get the same answer - they depend only on the `impersonation` section, never on the block. The third one is what differs: each rule answers it with its own knowledge, and that is what makes exactly one block match while the others fall through. ## Impersonation configuration @@ -77,35 +90,37 @@ When you call Elasticsearch directly or through ROR Kibana, ROR ACL is defined b ROR Kibana plugin provides a dedicated Test Settings UI. See our [Test Settings management guide](../examples/impersonation/test-settings-ui.md) for more information. -**This TTL gates impersonation directly.** As described in [step 2 above](#what-actually-happens-step-by-step), every impersonating request is evaluated exclusively against Test Settings - never against Main Settings. Once Test Settings expire or are invalidated, there are no Test Settings left to evaluate the request against, so impersonation stops working immediately with `TEST_SETTINGS_NOT_CONFIGURED`, regardless of how the `impersonation` section itself is configured. This is a distinct failure mode from a misconfigured `impersonation` entry, and it's worth ruling out first: re-apply Test Settings and retry before troubleshooting anything else. +**This TTL gates impersonation directly.** As described [above](#impersonating-requests-use-test-settings), every impersonating request is evaluated exclusively against Test Settings. Once they expire or are invalidated, there is nothing left to evaluate such a request against, so impersonation stops working immediately, regardless of how the `impersonation` section itself is configured. This is a distinct failure mode from a misconfigured `impersonation` entry, and it's worth ruling out first: re-apply Test Settings and retry before troubleshooting anything else. -But copying Main Settings as Test Settings is not enough. We also have to instruct ROR which users can be considered as impersonators (the ones, who are allowed to impersonate other users). Concretely, three things have to line up, answering the two questions and the checks described [above](#what-actually-happens-step-by-step): +But copying Main Settings as Test Settings is not enough. We also have to instruct ROR which users can be considered as impersonators (the ones, who are allowed to impersonate other users). As described [above](#the-impersonator-and-the-impersonated-user-are-authorized-differently), this is what the `impersonation` section is for: -1. In the `access_control_rules` section in ROR Settings, there must be a rule that authenticates the impersonator user *for their own, normal (non-impersonating) session* - this is what grants `admin1` their everyday permissions, and it's a prerequisite for `admin1` being a legitimate ES/Kibana user at all. -2. The impersonator user must be defined in the `impersonation` section in ROR Settings, together with the list/pattern of users they're allowed to impersonate. **Being a valid, authenticated user in `access_control_rules` is not enough** - without a matching `impersonation` entry, ROR will refuse impersonation with `IMPERSONATION_NOT_ALLOWED`, even for a perfectly legitimate admin. -3. The impersonator's credentials must satisfy the `authentication_rule` configured *inside that `impersonation` entry* - this rule is evaluated completely independently of rule #1, using whatever credentials the impersonating request actually carries. It commonly mirrors rule #1 (same rule type, same credentials), but ROR never assumes that - it always re-checks. +1. The impersonator must be declared in the `impersonation` section of ROR Settings, together with the list/pattern of users they are allowed to impersonate. **Being a valid, authenticated user in `access_control_rules` is not enough** - without a matching entry here, ROR refuses the impersonation, even for a perfectly legitimate admin. +2. The impersonator's credentials must satisfy the authentication rule configured *inside that entry*. It is evaluated completely independently of anything in `access_control_rules`, using whatever credentials the impersonating request actually carries. +3. Only if the impersonator is also supposed to work with Kibana as themselves, `access_control_rules` needs a block authenticating them as a regular user. Such a block plays no part in impersonation - it's what grants them their everyday access. ```yaml readonlyrest: access_control_rules: - - name: "Authenticate admin1" - auth_key: admin1:pass - - name: "Authenticate admin2" + - name: "Authenticate alice" + auth_key: alice:pass + - name: "Authenticate carol" ldap_authentication: "ldap1" impersonation: - - impersonator: admin1 // Who can impersonate? (user name or pattern) + - impersonator: alice // Who can impersonate? (user name or pattern) users: ["*"] // Who can be impersonated? (user names or patterns) - auth_key: admin1:pass // Authentication rule required to impersonate (any authentication rule can be used here) - - impersonator: admin2 - users: ["dev2"] + auth_key: alice:pass // Authentication rule required to impersonate (any authentication rule can be used here) + - impersonator: carol + users: ["bob"] ldap_authentication: "ldap1" ``` -In the example above, we see that we have two impersonators: `admin1` and `admin2`. The first one can impersonate any user (`*`) and they are able to authenticate using basic auth (`admin1:pass`). The second impersonator can impersonate only `dev2` user. They will be authenticated using `ldap1` connector. +In the example above, we see that we have two impersonators: `alice` and `carol`. The first one can impersonate any user (`*`) and they are able to authenticate using basic auth (`alice:pass`). The second impersonator can impersonate only `bob` user. They will be authenticated using `ldap1` connector. When an impersonator passes wrong credentials ROR will tell Kibana that impersonation is not allowed. +The order of the entries matters. ROR uses the **first** entry whose `impersonator` pattern matches the caller, and only that one - it never falls through to a later entry, even if that one would allow the requested impersonated user. With overlapping patterns (e.g. `admin*` before `alice`), the `users` list of the later entry is dead configuration. Prefer one entry per impersonator, and put the most specific patterns first. + A few structural rules ROR enforces when it loads this section (and that are worth knowing, since they explain some of the config-load errors you might see): * Exactly one authentication rule is allowed per `impersonation` entry - you can't stack several auth methods for a single impersonator. @@ -142,7 +157,7 @@ Impersonation support isn't the same for every rule that can appear in an `acces | `auth_key`, `auth_key_unix`, `proxy_auth`, `token_authentication` | Full | Work as-is, no extra configuration needed | | Group-membership rules (`groups_any_of`, `groups_all_of`, and other [groups logic](authorization-rules-details.md#checking-groups-logic)) | Full | Groups are supplied directly in settings, or by an authorization rule that's itself impersonation-aware; no external call is involved | | `auth_key_sha1`, `auth_key_sha256`, `auth_key_sha512`, `auth_key_pbkdf2_hmac_sha512` | Full, with one condition | Only works when the rule is written in the `USER_NAME:hash(PASSWORD)` form. A fully hashed `hash(USER_NAME:PASSWORD)` blob can't be reversed back to a username, so it never matches during impersonation - see [limitations](#impersonation-limitations) | -| `ldap_authentication`, `ldap_authorization`, `ldap_auth` | Requires a mock | Needs a matching LDAP service mock (see [above](#defining-mocks-of-the-external-services-optional)); without it, denied with `IMPERSONATION_NOT_SUPPORTED` | +| `ldap_authentication`, `ldap_authorization`, `ldap_auth` | Requires a mock | Needs a matching LDAP service mock (see [above](#defining-mocks-of-the-external-services-optional)); without it, ROR reports that impersonation is not supported | | `external_authentication` | Requires a mock | Needs an external authentication service mock | | `external_authorization` | Requires a mock | Needs an external authorization service mock | | `jwt_auth`, `jwt_authentication`, `jwt_authorization` | Not supported | These rules ignore impersonation entirely: they evaluate the real request, find no JWT in it, fail authentication and their block doesn't match. No mock or workaround today - ROR reports a Test Settings warning for such blocks | @@ -175,36 +190,36 @@ readonlyrest: access_control_rules: - name: "Admins" - auth_key: admin1:pass + auth_key: alice:pass groups_any_of: ["admins"] - name: "Devs" - auth_key: dev2:devpass + auth_key: bob:bobpass groups_any_of: ["devs"] indices: ["dev-*"] users: - - username: admin1 - auth_key: admin1:pass + - username: alice + auth_key: alice:pass groups: ["admins"] - - username: dev2 - auth_key: dev2:devpass + - username: bob + auth_key: bob:bobpass groups: ["devs"] impersonation: - - impersonator: admin1 + - impersonator: alice users: ["*"] - auth_key: admin1:pass # re-checks the SAME credentials admin1 used to authenticate - but independently + auth_key: alice:pass # re-checks the SAME credentials alice used to authenticate - but independently ``` -What happens when Kibana sends a request with `Authorization: Basic YWRtaW4xOnBhc3M=` (i.e. `admin1:pass`) and `x-ror-impersonating: dev2`: +What happens when Kibana sends a request with `Authorization: Basic YWxpY2U6cGFzcw==` (i.e. `alice:pass`) and `x-ror-impersonating: bob`: -1. ROR reaches the "Admins" block first. Its `auth_key` rule notices the impersonation header and defers to the `impersonation` section instead of comparing `admin1:pass` against its own settings. -2. `admin1` matches the `impersonator` pattern, `dev2` matches `users: ["*"]`. -3. The `impersonation` entry's own `auth_key: admin1:pass` is checked against the request's credentials - it matches, so the caller is confirmed to really be `admin1`. -4. Finally, ROR asks the rule it is currently evaluating - the "Admins" block's `auth_key: admin1:pass` - whether `dev2` exists. That rule knows only `admin1`, so the answer is no: the **"Admins" block is rejected** (logged as `AUTH_FAIL (Impersonated user does not exist)`) and ROR moves on to the next block. That log line is expected here, not a misconfiguration - the "Admins" block is simply not the block that defines `dev2`. -5. In the "Devs" block, steps 1-3 repeat identically, and this time the block's own `auth_key: dev2:devpass` rule confirms that `dev2` exists (a statically defined local user, so no mock is needed). ROR marks the request as logged in as `dev2` and evaluates the remaining rules as `dev2`: `groups_any_of: ["devs"]` matches and the response is scoped to `dev-*` indices - exactly what `dev2` would see in their own session. +1. ROR reaches the "Admins" block first. Its `auth_key` rule notices the impersonation header and defers to the `impersonation` section instead of comparing `alice:pass` against its own settings. +2. `alice` matches the `impersonator` pattern, `bob` matches `users: ["*"]`. +3. The `impersonation` entry's own `auth_key: alice:pass` is checked against the request's credentials - it matches, so the caller is confirmed to really be `alice`. +4. Finally, ROR asks the rule it is currently evaluating - the "Admins" block's `auth_key: alice:pass` - whether `bob` exists. That rule knows only `alice`, so the answer is no: the **"Admins" block is rejected** (logged as `AUTH_FAIL (Impersonated user does not exist)`) and ROR moves on to the next block. That log line is expected here, not a misconfiguration - the "Admins" block is simply not the block that defines `bob`. +5. In the "Devs" block, steps 1-3 repeat identically, and this time the block's own `auth_key: bob:bobpass` rule confirms that `bob` exists (a statically defined local user, so no mock is needed). ROR marks the request as logged in as `bob` and evaluates the remaining rules as `bob`: `groups_any_of: ["devs"]` matches and the response is scoped to `dev-*` indices - exactly what `bob` would see in their own session. ### Example 2: LDAP-authenticated admin impersonating an LDAP-authorized user @@ -233,34 +248,34 @@ readonlyrest: # ... rest of the connector settings impersonation: - - impersonator: admin1 - users: ["dev2"] - ldap_authentication: "ldap1" # admin1's own LDAP credentials, checked independently + - impersonator: alice + users: ["bob"] + ldap_authentication: "ldap1" # alice's own LDAP credentials, checked independently ``` -For this to work during impersonation, a **Test Settings mock** for `ldap1` must define `dev2` as an existing user belonging to the `devs` group - see [Defining mocks of the external services](#defining-mocks-of-the-external-services-optional). Without it, both LDAP rules will refuse to evaluate `dev2` and the request is denied with `IMPERSONATION_NOT_SUPPORTED`, even though `admin1`'s own impersonator authentication succeeded. +For this to work during impersonation, a **Test Settings mock** for `ldap1` must define `bob` as an existing user belonging to the `devs` group - see [Defining mocks of the external services](#defining-mocks-of-the-external-services-optional). Without it, both LDAP rules will refuse to evaluate `bob` and the request is denied as not supported, even though `alice`'s own impersonator authentication succeeded. ## Common misconfigurations -Most support tickets about "impersonation isn't working" trace back to one of these. The middle column is what you'll typically see in the ES response/ROR logs (`USR` field, or the `causes`/reason returned to Kibana). +Most support tickets about "impersonation isn't working" trace back to one of these. The middle column is what you'll typically see in Kibana, in the ES response, or in the ROR logs. | Symptom | What ROR reports | Most common root cause | Fix | |------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------| -| Impersonation worked earlier in the session but every impersonating request now fails, though nothing in the config changed | `TEST_SETTINGS_NOT_CONFIGURED` | Test Settings expired (default TTL is 30 minutes) or were manually invalidated. Every impersonating request is evaluated exclusively against Test Settings (see [step 2](#what-actually-happens-step-by-step)), so once they're gone, impersonation stops working regardless of the `impersonation` section | Re-apply Test Settings (optionally with a longer TTL) and retry | -| Admin can log into Kibana fine, but impersonation is refused outright | `IMPERSONATION_NOT_ALLOWED` | There's no `impersonation` entry at all for this admin - being authenticated in `access_control_rules` does **not** automatically grant impersonation rights | Add an `impersonation` entry with an `impersonator` pattern matching the admin | -| Impersonation works for some target users but not others | `IMPERSONATION_NOT_ALLOWED` | The `users` pattern of the **first** `impersonation` entry matching this impersonator doesn't include the requested target username. ROR uses only that first entry and never falls through to a later one, so a second entry added for the same admin is never consulted | Broaden the `users` pattern *in that first matching entry* - appending another entry below it won't help | -| Admin's password was recently changed and impersonation broke, even though normal login still works | `IMPERSONATION_NOT_ALLOWED` | The `authentication_rule` inside `impersonation` is checked completely independently of the rule in `access_control_rules` - updating one does not update the other | Keep both in sync, or point both at the same external identity source (LDAP/external auth) instead of hardcoding credentials twice | +| Impersonation worked earlier in the session but every impersonating request now fails, though nothing in the config changed | Kibana reports that no Test Settings are configured | Test Settings expired (default TTL is 30 minutes) or were manually invalidated. Every impersonating request is evaluated exclusively against Test Settings (see [above](#impersonating-requests-use-test-settings)), so once they're gone, impersonation stops working regardless of the `impersonation` section | Re-apply Test Settings (optionally with a longer TTL) and retry | +| Admin can log into Kibana fine, but impersonation is refused outright | Impersonation not allowed | There's no `impersonation` entry at all for this admin - being authenticated in `access_control_rules` does **not** automatically grant impersonation rights | Add an `impersonation` entry with an `impersonator` pattern matching the admin | +| Impersonation works for some target users but not others | Impersonation not allowed | The `users` pattern of the **first** `impersonation` entry matching this impersonator doesn't include the requested target username. ROR uses only that first entry and never falls through to a later one, so a second entry added for the same admin is never consulted | Broaden the `users` pattern *in that first matching entry* - appending another entry below it won't help | +| Admin's password was recently changed and impersonation broke, even though normal login still works | Impersonation not allowed | The `authentication_rule` inside `impersonation` is checked completely independently of the rule in `access_control_rules` - updating one does not update the other | Keep both in sync, or point both at the same external identity source (LDAP/external auth) instead of hardcoding credentials twice | | Config fails to load at startup, mentioning "should be either impersonator or a user to be impersonated" | Config validation error | The exact same username (no wildcards) appears in both `impersonator` and `users` in one entry | Remove the self-reference - a user can't be declared as able to impersonate themselves | -| Config fails to load at startup, mentioning "it's used in a context of user patterns" | Config validation error | The `impersonation` entry's `authentication_rule` has a fixed, statically known username that doesn't match the `impersonator` pattern (e.g. `impersonator: admin1` but `auth_key: someone_else:pass`) | Make the rule's username match the `impersonator` pattern | +| Config fails to load at startup, mentioning "it's used in a context of user patterns" | Config validation error | The `impersonation` entry's `authentication_rule` has a fixed, statically known username that doesn't match the `impersonator` pattern (e.g. `impersonator: alice` but `auth_key: someone_else:pass`) | Make the rule's username match the `impersonator` pattern | | Impersonator authenticates fine, but the request is still denied, mentioning the impersonated user doesn't exist | Denied; `AUTH_FAIL (Impersonated user does not exist)` in the logs | **No** block could confirm the target user: they aren't statically configured in any block and aren't present in the relevant service mock. Note that this message is logged by every block whose authentication rule doesn't know the impersonated user, so seeing it in a healthy setup is normal - it's a problem only when no block ends up matching | Add the user to the mock, or confirm the username matches exactly | -| Request denied with "impersonation not supported", even though the `impersonation` section looks correct | `IMPERSONATION_NOT_SUPPORTED` | An ACL block needs a service mock (LDAP / external authentication / external authorization) that hasn't been configured yet, or uses `auth_key_sha*` with a fully-hashed `user:pass` blob (see [limitations](#impersonation-limitations)) | Add the missing mock, or switch to the `USER_NAME:hash(PASSWORD)` form for hashed auth rules | +| Request denied with "impersonation not supported", even though the `impersonation` section looks correct | Impersonation not supported | An ACL block needs a service mock (LDAP / external authentication / external authorization) that hasn't been configured yet, or uses `auth_key_sha*` with a fully-hashed `user:pass` blob (see [limitations](#impersonation-limitations)) | Add the missing mock, or switch to the `USER_NAME:hash(PASSWORD)` form for hashed auth rules | | The block you wanted to test is never matched during impersonation, and it uses `jwt_auth` or `ror_kbn_auth` | No impersonation-specific error - the block just doesn't match | These rules don't take part in the impersonation flow: they look for a real JWT / ROR Kibana token in the request, don't find one, and reject the block. ROR reports it as a Test Settings warning | Not impersonable today - test such blocks with a real session, or authenticate the users with an impersonation-aware rule | | Impersonation UI can't find/list the user you want to impersonate | N/A (UI limitation) | The target username is only reachable through a wildcard `users` pattern in the ACL, so ROR can't enumerate it upfront | Type the username manually in the impersonation UI, as described in [limitations](#impersonation-limitations) | -| Impersonation is refused for every target user, although the `impersonation` entry looks correct and the same credentials work elsewhere | `IMPERSONATION_NOT_ALLOWED` | The impersonating client didn't send the impersonator's credentials as an HTTP Basic Auth header - ROR always identifies the impersonator from Basic Auth, regardless of which rule type is configured as the `authentication_rule` | Make sure the client authenticates with Basic Auth (this is what the ROR Kibana Test Settings UI does under the hood) | +| Impersonation is refused for every target user, although the `impersonation` entry looks correct and the same credentials work elsewhere | Impersonation not allowed | The impersonating client didn't send the impersonator's credentials as an HTTP Basic Auth header - ROR always identifies the impersonator from Basic Auth, regardless of which rule type is configured as the `authentication_rule` | Make sure the client authenticates with Basic Auth (this is what the ROR Kibana Test Settings UI does under the hood) | ## Logs & audit -In Elasticsearch logs, in `USR` field, if an admin user finds something like this: `admin1 (as user1)` - it means that `admin1` was authenticated, and they are the impersonator who is impersonating `user1`. +In Elasticsearch logs, in `USR` field, if an admin user finds something like this: `alice (as bob)` - it means that `alice` was authenticated, and they are the impersonator who is impersonating `bob`. All logs of impersonated user in Kibana will have this format `[][plugins][ReadonlyREST][][impersonating ]` From 52097c7bd9bdf8f50a5f105022f7146356785792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Goworko?= Date: Wed, 2 Sep 2026 23:31:24 +0200 Subject: [PATCH 4/5] qs --- SUMMARY.md | 1 - details/impersonation.md | 323 -------------------- elasticsearch.md | 32 +- examples/impersonation/README.md | 327 ++++++++++++++++++++- examples/impersonation/test-settings-ui.md | 2 +- kibana.md | 2 +- 6 files changed, 339 insertions(+), 348 deletions(-) delete mode 100644 details/impersonation.md diff --git a/SUMMARY.md b/SUMMARY.md index 2634fa3..b3eb026 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -10,7 +10,6 @@ * [Indices rule - Index not found scenario](details/index-not-found-examples.md) * [Indices rule - ES Templates handling](details/indices-rule-templates.md) * [For Kibana](kibana.md) - * [Impersonation (Enterprise)](details/impersonation.md) * [Kibana 7.8.x and older](details/kibana-7.8.x-and-older.md) * [ReadonlyREST API](kibana/readonlyrest-api.md) * [ReadonlyREST DISA STIG Compliance](kibana/readonlyrest-disa-stig-compliance.md) diff --git a/details/impersonation.md b/details/impersonation.md deleted file mode 100644 index 7bcaef6..0000000 --- a/details/impersonation.md +++ /dev/null @@ -1,323 +0,0 @@ -# Impersonation -([Enterprise](https://readonlyrest.com/enterprise)) - -After describing what [the impersonation is](../kibana.md#impersonation), it's high time to see how ROR supports it and who and when could be interested in using this feature. Let's start with the latter. - -## Use cases - -The impersonation feature is intended for ROR administrators, rather than users. We can point out the two most obvious use cases when the admin could take advantage of the feature: - -#### Debugging users' problems: - -Let's imagine that some user has a problem with their ROR configuration (eg. the user doesn't have access to some feature that was blocked at ROR's level by you, the admin). And they are not able to clearly describe what the issue is (sounds familiar?). As an administrator, it would be extremely beneficial if you could see what the user sees. Thanks to the impersonation feature, an admin is allowed to impersonate the user and experience exactly what the user experiences. - -#### Configuring a new user: - -When an admin configures a new user in ROR settings, they face two problems: - -1. `Will the updated configuration break the production cluster?` -2. `How do I know that the new user is correctly configured? Did I configure all their permissions correctly??` - -Both of the problems can be solved using the ROR's impersonation. Thanks to the fact that the impersonation feature always uses its own Test Settings, that is completely independent from the main production settings, the admin can alter it without worries that their actions will break something and users won't be able to do their job. - -Admin can add the new user configuration without worrying and then test it by impersonating the user. They can check if the user can log in without problems and if the user has access only to the Kibana features the admin wanted to grant. When the admin is sure that everything is configured correctly, they can promote the settings (test) to production. - -## How ROR processes an impersonation request - -An impersonating request is almost identical to the request the impersonated user would send themselves. It reaches the same cluster and is evaluated by the same ACL, block by block, in the same order. Rules like `indices`, `kibana_*`, `fields`, `filter` or `hosts` see exactly what they would see in that user's own session - which is what makes impersonation useful for testing a configuration in the first place. - -Two things are different: - -* **the authentication data the request carries** - the credentials on the wire belong to the *impersonator* (say, `alice`), while the identity to be evaluated - the *impersonated user* (say, `bob`) - travels separately, in an internal header managed by ROR and its Kibana plugin, -* **the way authentication and authorization rules behave** - and that is where the whole feature lives. - -The rest of this section is about that second difference. - -### Impersonating requests use Test Settings - -ROR keeps two independent sets of settings: - -* **Main Settings** - the ACL that handles regular traffic, -* **Test Settings** - a separate ACL, used only for impersonation. They are a scratchpad: the admin can edit them freely, without any risk to the users working against Main Settings, and promote them to Main Settings once the result is satisfying. - -An impersonating request is always evaluated against Test Settings, never against Main Settings. Test Settings stay active only for a limited time and can be invalidated at any moment (see [Creating ROR's Test Settings](#creating-rors-test-settings)); when none are active, impersonation simply doesn't work, no matter how the rest of the configuration looks. - -### The impersonator and the impersonated user are authorized differently - -`alice` can appear in ROR settings in two completely independent roles: - -* **as a regular user** - authenticated by an authentication rule, which is a part of a block, which is one of many in the ACL, exactly like anybody else. This is what lets `alice` log into Kibana and do her own work. -* **as an impersonator** - declared in the `impersonation` section, a separate part of ROR settings saying who may impersonate whom, and how such an impersonator is authenticated (see [Impersonation configuration](#impersonation-configuration)). - -Neither role implies the other, and that is deliberate: - -* An impersonator who never logs into Kibana needs only an `impersonation` entry. They can impersonate users through the Elasticsearch REST API without being a regular ACL user at all. -* If `alice` should also log into Kibana as herself, some ACL block has to authenticate her as a regular user. The `impersonation` section grants no everyday access whatsoever. - -So, when a request comes in as `alice` herself, it is authorized by the ACL like any other request. When the same `alice` sends a request on behalf of `bob`, the authentication rules in the ACL blocks no longer answer the question "who is the caller?" - the `impersonation` section does. This is why the impersonator's authentication has to be spelled out there explicitly: it is the only place in the settings whose job is to verify that the caller really is `alice`, right now, for the purpose of impersonation. - -### Not every authentication rule supports impersonation - -The first thing an authentication rule does with an impersonating request is to check whether it supports impersonation at all (the full list is in [Which rules support impersonation](#which-rules-support-impersonation)). The two paths are completely different. - -**When the rule doesn't support impersonation** (`jwt_*`, `ror_kbn_*`), it takes no part in the impersonation flow. It evaluates the request the way it always does: it looks for a JWT or a ROR Kibana token, finds none (the request carries the impersonator's Basic Auth credentials instead), and doesn't match - so its block doesn't match either, and ROR moves on to the next block. A block built around such a rule cannot be exercised through impersonation at all; ROR points this out with a warning when Test Settings are applied. - -**When the rule does support impersonation**, it skips its normal authentication logic entirely and hands the request over to the impersonation flow, which answers three questions, in order: - -1. **Is `alice` allowed to impersonate `bob`?** The impersonator is identified by the Basic Auth credentials carried by the request, and looked up in the `impersonation` section. If nothing there allows this particular pair, the request is denied. -2. **Is the caller really `alice`?** Her credentials are verified against the authentication rule of the matching `impersonation` entry - independently of the block ROR happens to be evaluating, and independently of whatever rule authenticates `alice` as a regular user. Trying to impersonate oneself is rejected here as well. -3. **Does `bob` exist?** This one is answered by the very rule ROR is currently evaluating, using only what that rule knows. A rule holding static credentials knows the usernames written next to it. A rule backed by an external system (LDAP, an external authentication or authorization service) would normally have to ask that system - during impersonation it asks a [mock](#defining-mocks-of-the-external-services-optional) of it instead, so that no real account, no password and no connection to the production service are needed. - -The answer to the last question decides the fate of the block: - -* the rule knows `bob` → ROR treats the request as logged in as `bob`, and the rest of the block (groups, indices, Kibana rules, ...) is evaluated as `bob`, using mocked data wherever an external system would normally be consulted, -* the rule can answer, and the answer is "I don't know this user" → this block doesn't match, and ROR moves on to the next one. In a multi-block ACL this is perfectly normal: only the block that actually defines `bob` can match him, and the others log `AUTH_FAIL (Impersonated user does not exist)` along the way, -* the rule cannot answer at all - a missing service mock, or an `auth_key_sha*` rule whose whole `user:pass` pair is hashed and can't be reversed back to a username → the request is denied, and ROR reports that the impersonation is not supported. - -These three questions are asked from scratch in every block ROR tries. The first two always get the same answer - they depend only on the `impersonation` section, never on the block. The third one is what differs: each rule answers it with its own knowledge, and that is what makes exactly one block match while the others fall through. - -## Impersonation configuration - -Before an admin will be able to impersonate a user, they have to configure ROR properly. The configuration consists of several parts: - -1. creating ROR's Test Settings, -2. defining mocks of the external services (like [LDAP](../elasticsearch.md#ldap-connector), [External Basic Auth](../elasticsearch.md#external-basic-auth) or [Custom groups provider](../elasticsearch.md#custom-groups-providers)), -3. impersonating a chosen user. - -#### Creating ROR's Test Settings - -When you call Elasticsearch directly or through ROR Kibana, ROR ACL is defined by Settings (we can assume they are Main Settings). The Test Settings define another ACL, that is taken into consideration by ROR ES only when a proper impersonation header is passed. The header is managed by ROR internally. The Test Settings are active only for a strictly defined amount of time (by default it's _30 minutes_, but the admin can change it before applying Test Settings). After the time has expired, they are automatically invalidated (for security reasons). Obviously, the admin is allowed to invalidate the configured Test Settings in any time. There is no way to have more than one Test Settings configured at time. - -ROR Kibana plugin provides a dedicated Test Settings UI. See our [Test Settings management guide](../examples/impersonation/test-settings-ui.md) for more information. - -**This TTL gates impersonation directly.** As described [above](#impersonating-requests-use-test-settings), every impersonating request is evaluated exclusively against Test Settings. Once they expire or are invalidated, there is nothing left to evaluate such a request against, so impersonation stops working immediately, regardless of how the `impersonation` section itself is configured. This is a distinct failure mode from a misconfigured `impersonation` entry, and it's worth ruling out first: re-apply Test Settings and retry before troubleshooting anything else. - -But copying Main Settings as Test Settings is not enough. We also have to instruct ROR which users can be considered as impersonators (the ones, who are allowed to impersonate other users). As described [above](#the-impersonator-and-the-impersonated-user-are-authorized-differently), this is what the `impersonation` section is for: - -1. The impersonator must be declared in the `impersonation` section of ROR Settings, together with the list/pattern of users they are allowed to impersonate. **Being a valid, authenticated user in `access_control_rules` is not enough** - without a matching entry here, ROR refuses the impersonation, even for a perfectly legitimate admin. -2. The impersonator's credentials must satisfy the authentication rule configured *inside that entry*. It is evaluated completely independently of anything in `access_control_rules`, using whatever credentials the impersonating request actually carries. -3. Only if the impersonator is also supposed to work with Kibana as themselves, `access_control_rules` needs a block authenticating them as a regular user. Such a block plays no part in impersonation - it's what grants them their everyday access. - -```yaml -readonlyrest: - access_control_rules: - - name: "Authenticate alice" - auth_key: alice:pass - - name: "Authenticate carol" - ldap_authentication: "ldap1" - - impersonation: - - impersonator: alice // Who can impersonate? (user name or pattern) - users: ["*"] // Who can be impersonated? (user names or patterns) - auth_key: alice:pass // Authentication rule required to impersonate (any authentication rule can be used here) - - impersonator: carol - users: ["bob"] - ldap_authentication: "ldap1" -``` - -In the example above, we see that we have two impersonators: `alice` and `carol`. The first one can impersonate any user (`*`) and they are able to authenticate using basic auth (`alice:pass`). The second impersonator can impersonate only `bob` user. They will be authenticated using `ldap1` connector. - -When an impersonator passes wrong credentials ROR will tell Kibana that impersonation is not allowed. - -The order of the entries matters. ROR uses the **first** entry whose `impersonator` pattern matches the caller, and only that one - it never falls through to a later entry, even if that one would allow the requested impersonated user. With overlapping patterns (e.g. `admin*` before `alice`), the `users` list of the later entry is dead configuration. Prefer one entry per impersonator, and put the most specific patterns first. - -A few structural rules ROR enforces when it loads this section (and that are worth knowing, since they explain some of the config-load errors you might see): - -* Exactly one authentication rule is allowed per `impersonation` entry - you can't stack several auth methods for a single impersonator. -* Only rules that are genuinely authentication rules (`auth_key*`, `ldap_authentication`, `external_authentication`, `proxy_auth`, ...) can be used here - authorization-only rules (like `ldap_authorization`) are rejected. -* The same exact username (no wildcards) cannot appear as both an `impersonator` and a member of `users` in the same entry - a user can't be declared as being able to impersonate themselves. -* If the `authentication_rule` has a statically known, fixed username (e.g. `auth_key: someone:pass`), ROR checks at load time that this username actually matches the `impersonator` pattern, and refuses to start otherwise. This check can't be done for dynamic identities (LDAP, external auth), since the username isn't known until request time. - -#### Defining mocks of the external services (optional) - -ROR has many sophisticated authentication & authorization methods. Some of them are based on external systems like LDAP. The problem with such systems, in regard to to the impersonation feature, is that those systems either don't support it by default or don't support it at all and even if they do - the configuration is complex. - -That's why we decided to solve it totally differently - using mocks. [Wikipedia](https://en.wiktionary.org/wiki/mock) defines `mock` as `an imitation, usually of lesser quality.` And in the case of external authentication systems we are going provide an imitation of it that will tell ACL which users should be successfully authenticated by it. When we consider an authorization service, a mock of it will return the ACL users with their roles in the service. And this is enough for ROR to support impersonation. - -How does ROR use the mocks? Let's suppose we have an `ldap_auth` rule. When ROR processes the rule, it: - -* asks the given LDAP service if the username can be authenticated with a given password, and if they can ... -* asks LDAP to list what groups the user belongs to - -In the impersonation case, it looks pretty much the same. The difference being that ROR won't call any LDAP server - the mock will provide the required information instead (no password required). During impersonating, when ROR processes an LDAP rule, it: - -* asks the mock if the username exists, and if it does ... -* asks the mock to tell what groups the user belongs to - -**⚠️ IMPORTANT:** If one or more of the external services are not mocked, ROR might inform Kibana that the impersonation is not supported. It's better to always define all mocks, to avoid the "Impersonation not supported" Elasticsearch response. - -ROR Kibana plugin helps administrators to visually create and edit service mocks with a dedicated graphical UI. Follow our [service mock configuration guide](../examples/impersonation/external-services-mocks-ui.md) for more. - -#### Which rules support impersonation - -Impersonation support isn't the same for every rule that can appear in an `access_control_rules` block. ROR checks this per rule and, when it applies Test Settings, reports a warning for each rule/block combination that won't work correctly during impersonation - these warnings surface through the Test Settings API and are shown by the ROR Kibana Test Settings UI. - -| Rule | Impersonation support | Notes | -|-------------------------------------------------------------------------------------------------------------------------------------------|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `auth_key`, `auth_key_unix`, `proxy_auth`, `token_authentication` | Full | Work as-is, no extra configuration needed | -| Group-membership rules (`groups_any_of`, `groups_all_of`, and other [groups logic](authorization-rules-details.md#checking-groups-logic)) | Full | Groups are supplied directly in settings, or by an authorization rule that's itself impersonation-aware; no external call is involved | -| `auth_key_sha1`, `auth_key_sha256`, `auth_key_sha512`, `auth_key_pbkdf2_hmac_sha512` | Full, with one condition | Only works when the rule is written in the `USER_NAME:hash(PASSWORD)` form. A fully hashed `hash(USER_NAME:PASSWORD)` blob can't be reversed back to a username, so it never matches during impersonation - see [limitations](#impersonation-limitations) | -| `ldap_authentication`, `ldap_authorization`, `ldap_auth` | Requires a mock | Needs a matching LDAP service mock (see [above](#defining-mocks-of-the-external-services-optional)); without it, ROR reports that impersonation is not supported | -| `external_authentication` | Requires a mock | Needs an external authentication service mock | -| `external_authorization` | Requires a mock | Needs an external authorization service mock | -| `jwt_auth`, `jwt_authentication`, `jwt_authorization` | Not supported | These rules ignore impersonation entirely: they evaluate the real request, find no JWT in it, fail authentication and their block doesn't match. No mock or workaround today - ROR reports a Test Settings warning for such blocks | -| `ror_kbn_auth`, `ror_kbn_authentication`, `ror_kbn_authorization` | Not supported | Same as above, with the ROR Kibana token: the block can't be exercised through impersonation, and ROR reports a Test Settings warning for it | -| Everything else (`indices`, `actions`, `kibana_*`, `fields`, `filter`, `hosts`, `uri_re`, ...) | Not applicable | These rules don't authenticate or authorize an identity - they evaluate normally against whichever user, real or impersonated, is already logged in | - -A block only needs to be fully impersonation-capable if you intend to impersonate the users it applies to. A block built entirely around a "not supported" rule simply can't be exercised through impersonation - traffic that would otherwise match it falls through to later blocks, exactly as it would if the block rejected the request for any other reason. - -#### Impersonating a chosen user - -Now that we have configured Test Settings and External Services Mocks, we can try to impersonate a user. In Elasticsearch ROR Settings, user can be: - -* provided statically (defined in the settings), -* provided dynamically: - * from external, dependant systems (like LDAP) - we mock them - * from upstream systems (eg. through headers) - they are not known upfront - -It means that we pick the users defined in Settings or Mocks, but also we can enter the username and try to impersonate such user. - -Follow the instructions on how to [impersonate a user using the ROR Kibana plugin UI](../examples/impersonation/impersonate-user-ui.md). - -## Full end-to-end examples - -### Example 1: local admin impersonating any local user - -Everything is defined statically, no mocks needed - the simplest possible setup. - -```yaml -readonlyrest: - access_control_rules: - - - name: "Admins" - auth_key: alice:pass - groups_any_of: ["admins"] - - - name: "Devs" - auth_key: bob:bobpass - groups_any_of: ["devs"] - indices: ["dev-*"] - - users: - - username: alice - auth_key: alice:pass - groups: ["admins"] - - - username: bob - auth_key: bob:bobpass - groups: ["devs"] - - impersonation: - - impersonator: alice - users: ["*"] - auth_key: alice:pass # re-checks the SAME credentials alice used to authenticate - but independently -``` - -What happens when Kibana sends a request with `Authorization: Basic YWxpY2U6cGFzcw==` (i.e. `alice:pass`) and `x-ror-impersonating: bob`: - -1. ROR reaches the "Admins" block first. Its `auth_key` rule notices the impersonation header and defers to the `impersonation` section instead of comparing `alice:pass` against its own settings. -2. `alice` matches the `impersonator` pattern, `bob` matches `users: ["*"]`. -3. The `impersonation` entry's own `auth_key: alice:pass` is checked against the request's credentials - it matches, so the caller is confirmed to really be `alice`. -4. Finally, ROR asks the rule it is currently evaluating - the "Admins" block's `auth_key: alice:pass` - whether `bob` exists. That rule knows only `alice`, so the answer is no: the **"Admins" block is rejected** (logged as `AUTH_FAIL (Impersonated user does not exist)`) and ROR moves on to the next block. That log line is expected here, not a misconfiguration - the "Admins" block is simply not the block that defines `bob`. -5. In the "Devs" block, steps 1-3 repeat identically, and this time the block's own `auth_key: bob:bobpass` rule confirms that `bob` exists (a statically defined local user, so no mock is needed). ROR marks the request as logged in as `bob` and evaluates the remaining rules as `bob`: `groups_any_of: ["devs"]` matches and the response is scoped to `dev-*` indices - exactly what `bob` would see in their own session. - -### Example 2: LDAP-authenticated admin impersonating an LDAP-authorized user - -Here the impersonated user's group membership comes from LDAP, so it needs a mock. - -```yaml -readonlyrest: - access_control_rules: - - - name: "LDAP admins can do everything" - ldap_authentication: "ldap1" - ldap_authorization: - name: "ldap1" - groups_any_of: ["admins"] - - - name: "LDAP devs see only their indices" - ldap_auth: - name: "ldap1" - groups_any_of: ["devs"] - indices: ["@{acl:user}_*"] - - ldaps: - - name: ldap1 - host: ldap.example.com - port: 389 - # ... rest of the connector settings - - impersonation: - - impersonator: alice - users: ["bob"] - ldap_authentication: "ldap1" # alice's own LDAP credentials, checked independently -``` - -For this to work during impersonation, a **Test Settings mock** for `ldap1` must define `bob` as an existing user belonging to the `devs` group - see [Defining mocks of the external services](#defining-mocks-of-the-external-services-optional). Without it, both LDAP rules will refuse to evaluate `bob` and the request is denied as not supported, even though `alice`'s own impersonator authentication succeeded. - -## Common misconfigurations - -Most support tickets about "impersonation isn't working" trace back to one of these. The middle column is what you'll typically see in Kibana, in the ES response, or in the ROR logs. - -| Symptom | What ROR reports | Most common root cause | Fix | -|------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------| -| Impersonation worked earlier in the session but every impersonating request now fails, though nothing in the config changed | Kibana reports that no Test Settings are configured | Test Settings expired (default TTL is 30 minutes) or were manually invalidated. Every impersonating request is evaluated exclusively against Test Settings (see [above](#impersonating-requests-use-test-settings)), so once they're gone, impersonation stops working regardless of the `impersonation` section | Re-apply Test Settings (optionally with a longer TTL) and retry | -| Admin can log into Kibana fine, but impersonation is refused outright | Impersonation not allowed | There's no `impersonation` entry at all for this admin - being authenticated in `access_control_rules` does **not** automatically grant impersonation rights | Add an `impersonation` entry with an `impersonator` pattern matching the admin | -| Impersonation works for some target users but not others | Impersonation not allowed | The `users` pattern of the **first** `impersonation` entry matching this impersonator doesn't include the requested target username. ROR uses only that first entry and never falls through to a later one, so a second entry added for the same admin is never consulted | Broaden the `users` pattern *in that first matching entry* - appending another entry below it won't help | -| Admin's password was recently changed and impersonation broke, even though normal login still works | Impersonation not allowed | The `authentication_rule` inside `impersonation` is checked completely independently of the rule in `access_control_rules` - updating one does not update the other | Keep both in sync, or point both at the same external identity source (LDAP/external auth) instead of hardcoding credentials twice | -| Config fails to load at startup, mentioning "should be either impersonator or a user to be impersonated" | Config validation error | The exact same username (no wildcards) appears in both `impersonator` and `users` in one entry | Remove the self-reference - a user can't be declared as able to impersonate themselves | -| Config fails to load at startup, mentioning "it's used in a context of user patterns" | Config validation error | The `impersonation` entry's `authentication_rule` has a fixed, statically known username that doesn't match the `impersonator` pattern (e.g. `impersonator: alice` but `auth_key: someone_else:pass`) | Make the rule's username match the `impersonator` pattern | -| Impersonator authenticates fine, but the request is still denied, mentioning the impersonated user doesn't exist | Denied; `AUTH_FAIL (Impersonated user does not exist)` in the logs | **No** block could confirm the target user: they aren't statically configured in any block and aren't present in the relevant service mock. Note that this message is logged by every block whose authentication rule doesn't know the impersonated user, so seeing it in a healthy setup is normal - it's a problem only when no block ends up matching | Add the user to the mock, or confirm the username matches exactly | -| Request denied with "impersonation not supported", even though the `impersonation` section looks correct | Impersonation not supported | An ACL block needs a service mock (LDAP / external authentication / external authorization) that hasn't been configured yet, or uses `auth_key_sha*` with a fully-hashed `user:pass` blob (see [limitations](#impersonation-limitations)) | Add the missing mock, or switch to the `USER_NAME:hash(PASSWORD)` form for hashed auth rules | -| The block you wanted to test is never matched during impersonation, and it uses `jwt_auth` or `ror_kbn_auth` | No impersonation-specific error - the block just doesn't match | These rules don't take part in the impersonation flow: they look for a real JWT / ROR Kibana token in the request, don't find one, and reject the block. ROR reports it as a Test Settings warning | Not impersonable today - test such blocks with a real session, or authenticate the users with an impersonation-aware rule | -| Impersonation UI can't find/list the user you want to impersonate | N/A (UI limitation) | The target username is only reachable through a wildcard `users` pattern in the ACL, so ROR can't enumerate it upfront | Type the username manually in the impersonation UI, as described in [limitations](#impersonation-limitations) | -| Impersonation is refused for every target user, although the `impersonation` entry looks correct and the same credentials work elsewhere | Impersonation not allowed | The impersonating client didn't send the impersonator's credentials as an HTTP Basic Auth header - ROR always identifies the impersonator from Basic Auth, regardless of which rule type is configured as the `authentication_rule` | Make sure the client authenticates with Basic Auth (this is what the ROR Kibana Test Settings UI does under the hood) | - -## Logs & audit - -In Elasticsearch logs, in `USR` field, if an admin user finds something like this: `alice (as bob)` - it means that `alice` was authenticated, and they are the impersonator who is impersonating `bob`. - -All logs of impersonated user in Kibana will have this format `[][plugins][ReadonlyREST][][impersonating ]` - -When auditing is enabled, the audit document is going to contain an `impersonated_by` field. - -## Impersonation limitations - -Impersonation mode has some limitations. Please check if they have an impact on your use cases: - -* Not all features available in the ROR configuration are testable with impersonation mode. Some rules used in ROR ACL do not support impersonation. For example, auth rule with hashed credentials (e.g. `auth_key_sha512`) can be used in impersonation mode only when credentials follow the format `USER_NAME: HASH(PASSWORD)`; A fully hashed username and password don't allow fetching a username. The auth rule in such a format won't match during impersonation. In the [rules description](../elasticsearch.md#rules) section you can find information about each rules impersonation support. -* Test Settings are stored in the memory of the node that handled the saving request sent by ROR Kibana plugin. Impersonation support will be limited to this node. We are going to improve it in the future, but for now your Kibana should only communicate with one Elasticsearch node. -* Sometimes it is impossible to fetch usernames defined in the Test Settings. If a `users` rule contains a username pattern with a wildcard, to impersonate a user matching the pattern, you need to enter the username manually. - - ```yaml - readonlyrest: - - access_control_rules: - - name: "LDAP group g1" - type: allow - groups_any_of: ["g1"] - - users: - - username: "admin*" // To impersonate a user with a username matching 'admin*' you need to enter the username manually, like 'admin123' - groups: - - g1: group1 - ldap_auth: - name: "ldap1" - groups_any_of: ["group1"] - - ldaps: - - name: ldap1 - [..] - - impersonation: - [...] - ``` - -## Glossary - -* **Impersonator** - someone who imitates or copies the behavior or actions of another, -* **Impersonation** - imitating behaviors or actions of a given user, -* **Impersonated user** - the identity being borrowed for the duration of an impersonation session; their permissions/data determine what the impersonator sees, but their own credentials are never needed or checked, -* **Main Settings** - the ROR's settings that apply to ACL that handles requests during regular sessions (not the impersonation ones), -* **Test Settings** - the ROR's settings that apply to ACL that handles impersonating requests (the ones during impersonation session), -* **External Service Mock** - an imitation of an external service (the supported ones: LDAP, an external authentication service, an external authorization service). diff --git a/elasticsearch.md b/elasticsearch.md index efabfda..6ee8745 100644 --- a/elasticsearch.md +++ b/elasticsearch.md @@ -842,7 +842,7 @@ It's an authentication rule that accepts [HTTP Basic Auth](https://en.wikipedia. **⚠️IMPORTANT**: this rule is handy just for tests, replace it with another rule that hashes credentials, like: `auth_key_sha512`, or `auth_key_unix`. -[Impersonation](details/impersonation.md) is supported by this rule without an extra configuration. +[Impersonation](examples/impersonation/README.md) is supported by this rule without an extra configuration. ##### `auth_key_sha512` @@ -858,7 +858,7 @@ The rules support also alternative syntax, where only password is hashed, eg: In the example below `admin` is the username and `280ac6f...94bf9` is the hashed secret. -[Impersonation](details/impersonation.md) is supported by these rules by default. +[Impersonation](examples/impersonation/README.md) is supported by these rules by default. ##### `auth_key_pbkdf2` @@ -877,7 +877,7 @@ The authentication rule that accepts [HTTP Basic Auth](https://en.wikipedia.org/ The hash can be calculated using [this calculator](https://8gwifi.org/pbkdf.jsp) \(notice that the salt has to base Base64 encoded\). -[Impersonation](details/impersonation.md) is supported by this rule without an extra configuration. +[Impersonation](examples/impersonation/README.md) is supported by this rule without an extra configuration. ##### `auth_key_unix` @@ -939,7 +939,7 @@ if __name__ == '__main__': For example, `test` is the username and `$6$rounds=65535$d07dnv4N$QeErsDT9Mz.ZoEPXW3dwQGL7tzwRz.eOrTBepIwfGEwdUAYSy/NirGoOaNyPx8lqiR6DYRSsDzVvVbhP4Y9wf0` is the hash for `test` \(the password is identical to the username in this example\). -[Impersonation](details/impersonation.md) is supported by this rule without an extra configuration. +[Impersonation](examples/impersonation/README.md) is supported by this rule without an extra configuration. ##### `token_authentication` @@ -977,7 +977,7 @@ For a complete Fleet setup — including the required `forbid` block for token/A For a complete walkthrough including credential flow, the `forbid` block rationale, and a runnable example, see the [Elastic Fleet guide](examples/fleet/README.md). -[Impersonation](details/impersonation.md) is supported by this rule without an extra configuration. +[Impersonation](examples/impersonation/README.md) is supported by this rule without an extra configuration. ##### `proxy_auth: "*"` @@ -991,7 +991,7 @@ If you are using this technique for authentication using our **Kibana** plugins, So that Kibana will forward the necessary headers to Elasticsearch. -[Impersonation](details/impersonation.md) is supported by this rule without an extra configuration. +[Impersonation](examples/impersonation/README.md) is supported by this rule without an extra configuration. ##### Groups rules @@ -1129,7 +1129,7 @@ In general it looks like this: For details see [User management](elasticsearch.md#users-and-groups). -[Impersonation](details/impersonation.md) support depends on +[Impersonation](examples/impersonation/README.md) support depends on authentication and authorization rules used in `users` section. For more information on the ROR's authorization rules, see [Authorization rules details](details/authorization-rules-details.md) @@ -1202,7 +1202,7 @@ ldap_authorization: See the dedicated [LDAP section](elasticsearch.md#ldap-connector) -[Impersonation](details/impersonation.md) support by LDAP rules requires to add [an extra configuration](details/impersonation.md#defining-mocks-of-the-external-services-optional). +[Impersonation](examples/impersonation/README.md) support by LDAP rules requires to add [an extra configuration](examples/impersonation/README.md#defining-mocks-of-the-external-services-optional). * Groups logic syntax can be uses as part of this rule, as described in the [Checking groups logic section](details/authorization-rules-details.md#checking-groups-logic) * For more information on the ROR's authorization rules, see [Authorization rules details](details/authorization-rules-details.md) @@ -1211,7 +1211,7 @@ See the dedicated [LDAP section](elasticsearch.md#ldap-connector) See below, the dedicated [JSON Web Tokens section](elasticsearch.md#json-web-token-jwt-auth). It's an authentication rule. -[Impersonation](details/impersonation.md) is not currently supported by this rule. +[Impersonation](examples/impersonation/README.md) is not currently supported by this rule. ```yaml readonlyrest: @@ -1232,7 +1232,7 @@ readonlyrest: See below, the dedicated [JSON Web Tokens section](elasticsearch.md#json-web-token-jwt-auth). It's an authorization rule. -[Impersonation](details/impersonation.md) is not currently supported by this rule. +[Impersonation](examples/impersonation/README.md) is not currently supported by this rule. * Groups logic syntax can be uses as part of this rule, as described in the [Checking groups logic section](details/authorization-rules-details.md#checking-groups-logic) * For more information on the ROR's authorization rules, see [Authorization rules details](details/authorization-rules-details.md) @@ -1264,7 +1264,7 @@ readonlyrest: See below, the dedicated [JSON Web Tokens section](elasticsearch.md#json-web-token-jwt-auth). It's an authentication and authorization rule at the same time. -[Impersonation](details/impersonation.md) is not currently supported by this rule. +[Impersonation](examples/impersonation/README.md) is not currently supported by this rule. * Groups logic syntax can be uses as part of this rule, as described in the [Checking groups logic section](details/authorization-rules-details.md#checking-groups-logic) * For more information on the ROR's authorization rules, see [Authorization rules details](details/authorization-rules-details.md) @@ -1290,7 +1290,7 @@ readonlyrest: Used to delegate authentication to another server that supports HTTP Basic Auth. See below, the dedicated [External BASIC Auth section](elasticsearch.md#external-basic-auth) -[Impersonation](details/impersonation.md) support by this rule requires to add [an extra configuration](details/impersonation.md#defining-mocks-of-the-external-services-optional). +[Impersonation](examples/impersonation/README.md) support by this rule requires to add [an extra configuration](examples/impersonation/README.md#defining-mocks-of-the-external-services-optional). For more information on the ROR's authorization rules, see [Authorization rules details](details/authorization-rules-details.md) @@ -1298,7 +1298,7 @@ For more information on the ROR's authorization rules, see [Authorization rules Used to delegate groups resolution for a user to a JSON microservice. See below, the dedicated [Groups Provider Authorization section](elasticsearch.md#custom-groups-providers) -[Impersonation](details/impersonation.md) support by this rule requires to add [an extra configuration](details/impersonation.md#defining-mocks-of-the-external-services-optional). +[Impersonation](examples/impersonation/README.md) support by this rule requires to add [an extra configuration](examples/impersonation/README.md#defining-mocks-of-the-external-services-optional). * Groups logic syntax can be uses as part of this rule, as described in the [Checking groups logic section](details/authorization-rules-details.md#checking-groups-logic) * For more information on the ROR's authorization rules, see [Authorization rules details](details/authorization-rules-details.md) @@ -1322,7 +1322,7 @@ readonlyrest: It handles authentication only using the configured ROR KBN connector (here `kbn1`). Continue reading about this in the kibana plugin documentation, in the dedicated [SAML section](kibana.md#saml) -[Impersonation](details/impersonation.md) is currently not supported by this rule. +[Impersonation](examples/impersonation/README.md) is currently not supported by this rule. ##### `ror_kbn_authorization` ([Enterprise](https://readonlyrest.com/enterprise)) @@ -1353,7 +1353,7 @@ readonlyrest: It handles authorization only using the configured ROR KBN connector (here `kbn1` and `kbn2`). Continue reading about this in the kibana plugin documentation, in the dedicated [SAML section](kibana.md#saml) -[Impersonation](details/impersonation.md) is currently not supported by this rule. +[Impersonation](examples/impersonation/README.md) is currently not supported by this rule. * Groups logic syntax can be uses as part of this rule, as described in the [Checking groups logic section](details/authorization-rules-details.md#checking-groups-logic) * For more information on the ROR's authorization rules, see [Authorization rules details](details/authorization-rules-details.md) @@ -1389,7 +1389,7 @@ This authentication and authorization connector represents the secure channel \( Continue reading about this in the kibana plugin documentation, in the dedicated [SAML section](kibana.md#saml) -[Impersonation](details/impersonation.md) is currently not supported by this rule. +[Impersonation](examples/impersonation/README.md) is currently not supported by this rule. * Groups logic syntax can be uses as part of this rule, as described in the [Checking groups logic section](details/authorization-rules-details.md#checking-groups-logic) * For more information on the ROR's authorization rules, see [Authorization rules details](details/authorization-rules-details.md) diff --git a/examples/impersonation/README.md b/examples/impersonation/README.md index 9030438..c784d63 100644 --- a/examples/impersonation/README.md +++ b/examples/impersonation/README.md @@ -9,10 +9,325 @@ According to [Wikipedia](https://en.wikipedia.org/wiki/Impersonator): > An impersonator is someone who imitates or copies the behavior or actions of another. -So, an impersonation can be understood as imitating behaviors or actions. -In the context of ReadonlyREST: one user could imitate an action -of another user. Why would we want it? Let's suppose the first user is -an admin, who has just configured access for a new user. They would like -to know if the rule(s) are configured correctly. And here comes the impersonation feature. The admin can impersonate a given user in Kibana and see what the user would see if they logged in themselves. +So, an impersonation can be understood as imitating behaviors or actions. In the context of ReadonlyREST: one user could imitate an action of another user. Let's suppose the first user is an admin, who has just configured access for a new user. They would like to know if the rules are configured correctly. And here comes the impersonation feature: the admin can impersonate the given user and see exactly what that user would see if they logged in themselves. -ROR plugins support impersonation and provide UI for configuring the cluster before using it. Visit the [impersonation details page](../../details/impersonation.md) to know more. +Impersonation is, first and foremost, a Kibana feature. The ROR Kibana plugin drives the whole workflow - preparing a safe copy of the settings, mocking the external services and switching in and out of an impersonation session - from the ROR menu, and this page describes it that way. Everything the plugin does is backed by ROR for Elasticsearch, so impersonating through the Elasticsearch REST API alone is possible as well, but it means driving ROR's internal APIs by hand and is not covered here. + +## Use cases + +The impersonation feature is intended for ROR administrators, rather than users. We can point out the two most obvious use cases when the admin could take advantage of the feature: + +#### Debugging users' problems: + +Let's imagine that some user has a problem with their ROR configuration (eg. the user doesn't have access to some feature that was blocked at ROR's level by you, the admin). And they are not able to clearly describe what the issue is (sounds familiar?). As an administrator, it would be extremely beneficial if you could see what the user sees. Thanks to the impersonation feature, an admin is allowed to impersonate the user and experience exactly what the user experiences. + +#### Configuring a new user: + +When an admin configures a new user in ROR settings, they face two problems: + +1. `Will the updated configuration break the production cluster?` +2. `How do I know that the new user is correctly configured? Did I configure all their permissions correctly??` + +Both of the problems can be solved using the ROR's impersonation. Thanks to the fact that the impersonation feature always uses its own Test Settings, that is completely independent from the main production settings, the admin can alter it without worries that their actions will break something and users won't be able to do their job. + +Admin can add the new user configuration without worrying and then test it by impersonating the user. They can check if the user can log in without problems and if the user has access only to the Kibana features the admin wanted to grant. When the admin is sure that everything is configured correctly, they can promote the settings (test) to production. + +## Impersonating a user in Kibana + +The whole workflow lives in the ROR menu, under **Edit security settings**, and consists of three steps. Only the first one is mandatory. + +1. **Create Test Settings.** Impersonation never touches your production configuration: it runs against a separate, temporary copy of the ACL called Test Settings, which you can edit freely and promote to the main settings once you're happy with it. See [Creating Test Settings](test-settings-ui.md), and [Test Settings](#creating-rors-test-settings) below for what they are and how long they last. +2. **Define mocks of the external services** - needed only when the users you want to impersonate come from LDAP or another external service. Instead of connecting to the real system, ROR asks a mock which users exist and what groups they belong to, so no real account or password is required. See [Defining external services mock configurations](external-services-mocks-ui.md) and [the section below](#defining-mocks-of-the-external-services-optional). +3. **Start the impersonation session.** Pick the user from the list, or type the username by hand when ROR can't enumerate it, and Kibana reloads as that user. See [Impersonating users](impersonate-user-ui.md). + +The list of users offered by the UI is built from what ROR can enumerate in the settings and in the mocks: + +* users provided statically (defined in the settings), +* users provided dynamically: + * from external, dependant systems (like LDAP) - the ones taken from the mocks, + * from upstream systems (eg. through headers) - these are not known upfront, so the username has to be entered manually. + +Before any of this works, the settings have to say who is allowed to impersonate whom - see [Impersonation configuration](#impersonation-configuration). + +## How ROR processes an impersonation request + +An impersonating request is almost identical to the request the impersonated user would send themselves. It reaches the same cluster and is evaluated by the same ACL, block by block, in the same order. Rules like `indices`, `kibana_*`, `fields`, `filter` or `hosts` see exactly what they would see in that user's own session - which is what makes impersonation useful for testing a configuration in the first place. + +Two things are different: + +* **the authentication data the request carries** - the credentials on the wire belong to the *impersonator* (say, `alice`), while the identity to be evaluated - the *impersonated user* (say, `bob`) - travels separately, in an internal header managed by ROR and its Kibana plugin, +* **the way authentication and authorization rules behave** - and that is where the whole feature lives. + +The rest of this section is about that second difference. + +### Impersonating requests use Test Settings + +ROR keeps two independent sets of settings: + +* **Main Settings** - the ACL that handles regular traffic, +* **Test Settings** - a separate ACL, used only for impersonation. They are a scratchpad: the admin can edit them freely, without any risk to the users working against Main Settings, and promote them to Main Settings once the result is satisfying. + +An impersonating request is always evaluated against Test Settings, never against Main Settings. Test Settings stay active only for a limited time and can be invalidated at any moment (see [Creating ROR's Test Settings](#creating-rors-test-settings)); when none are active, impersonation simply doesn't work, no matter how the rest of the configuration looks. + +### The impersonator and the impersonated user are authorized differently + +`alice` can appear in ROR settings in two completely independent roles: + +* **as a regular user** - authenticated by an authentication rule, which is a part of a block, which is one of many in the ACL, exactly like anybody else. This is what lets `alice` log into Kibana and do her own work. +* **as an impersonator** - declared in the `impersonation` section, a separate part of ROR settings saying who may impersonate whom, and how such an impersonator is authenticated (see [Impersonation configuration](#impersonation-configuration)). + +Neither role implies the other, and that is deliberate: + +* An impersonator who never logs into Kibana needs only an `impersonation` entry. They can impersonate users through the Elasticsearch REST API without being a regular ACL user at all. +* If `alice` should also log into Kibana as herself, some ACL block has to authenticate her as a regular user. The `impersonation` section grants no everyday access whatsoever. + +So, when a request comes in as `alice` herself, it is authorized by the ACL like any other request. When the same `alice` sends a request on behalf of `bob`, the authentication rules in the ACL blocks no longer answer the question "who is the caller?" - the `impersonation` section does. This is why the impersonator's authentication has to be spelled out there explicitly: it is the only place in the settings whose job is to verify that the caller really is `alice`, right now, for the purpose of impersonation. + +### Not every authentication rule supports impersonation + +The first thing an authentication rule does with an impersonating request is to check whether it supports impersonation at all (the full list is in [Which rules support impersonation](#which-rules-support-impersonation)). The two paths are completely different. + +**When the rule doesn't support impersonation** (`jwt_*`, `ror_kbn_*`), it takes no part in the impersonation flow. It evaluates the request the way it always does: it looks for a JWT or a ROR Kibana token, finds none (the request carries the impersonator's Basic Auth credentials instead), and doesn't match - so its block doesn't match either, and ROR moves on to the next block. A block built around such a rule cannot be exercised through impersonation at all; ROR points this out with a warning when Test Settings are applied. + +**When the rule does support impersonation**, it skips its normal authentication logic entirely and hands the request over to the impersonation flow, which answers three questions, in order: + +1. **Is `alice` allowed to impersonate `bob`?** The impersonator is identified by the Basic Auth credentials carried by the request, and looked up in the `impersonation` section. If nothing there allows this particular pair, the request is denied. +2. **Is the caller really `alice`?** Her credentials are verified against the authentication rule of the matching `impersonation` entry - independently of the block ROR happens to be evaluating, and independently of whatever rule authenticates `alice` as a regular user. Trying to impersonate oneself is rejected here as well. +3. **Does `bob` exist?** This one is answered by the very rule ROR is currently evaluating, using only what that rule knows. A rule holding static credentials knows the usernames written next to it. A rule backed by an external system (LDAP, an external authentication or authorization service) would normally have to ask that system - during impersonation it asks a [mock](#defining-mocks-of-the-external-services-optional) of it instead, so that no real account, no password and no connection to the production service are needed. + +The answer to the last question decides the fate of the block: + +* the rule knows `bob` → ROR treats the request as logged in as `bob`, and the rest of the block (groups, indices, Kibana rules, ...) is evaluated as `bob`, using mocked data wherever an external system would normally be consulted, +* the rule can answer, and the answer is "I don't know this user" → this block doesn't match, and ROR moves on to the next one. In a multi-block ACL this is perfectly normal: only the block that actually defines `bob` can match him, and the others log `AUTH_FAIL (Impersonated user does not exist)` along the way, +* the rule cannot answer at all - a missing service mock, or an `auth_key_sha*` rule whose whole `user:pass` pair is hashed and can't be reversed back to a username → the request is denied, and ROR reports that the impersonation is not supported. + +These three questions are asked from scratch in every block ROR tries. The first two always get the same answer - they depend only on the `impersonation` section, never on the block. The third one is what differs: each rule answers it with its own knowledge, and that is what makes exactly one block match while the others fall through. + +## Impersonation configuration + +This is the reference for the two things the [Kibana workflow](#impersonating-a-user-in-kibana) sets up - Test Settings and the mocks of the external services (like [LDAP](../../elasticsearch.md#ldap-connector), [External Basic Auth](../../elasticsearch.md#external-basic-auth) or [Custom groups provider](../../elasticsearch.md#custom-groups-providers)) - plus the `impersonation` section, which says who is allowed to impersonate whom. + +#### Creating ROR's Test Settings + +When you call Elasticsearch directly or through ROR Kibana, ROR ACL is defined by Settings (we can assume they are Main Settings). The Test Settings define another ACL, that is taken into consideration by ROR ES only when a proper impersonation header is passed. The header is managed by ROR internally. The Test Settings are active only for a strictly defined amount of time (by default it's _30 minutes_, but the admin can change it before applying Test Settings). After the time has expired, they are automatically invalidated (for security reasons). Obviously, the admin is allowed to invalidate the configured Test Settings in any time. There is no way to have more than one Test Settings configured at time. + +ROR Kibana plugin provides a dedicated Test Settings UI. See our [Test Settings management guide](test-settings-ui.md) for more information. + +**This TTL gates impersonation directly.** As described [above](#impersonating-requests-use-test-settings), every impersonating request is evaluated exclusively against Test Settings. Once they expire or are invalidated, there is nothing left to evaluate such a request against, so impersonation stops working immediately, regardless of how the `impersonation` section itself is configured. This is a distinct failure mode from a misconfigured `impersonation` entry, and it's worth ruling out first: re-apply Test Settings and retry before troubleshooting anything else. + +But copying Main Settings as Test Settings is not enough. We also have to instruct ROR which users can be considered as impersonators (the ones, who are allowed to impersonate other users). As described [above](#the-impersonator-and-the-impersonated-user-are-authorized-differently), this is what the `impersonation` section is for: + +1. The impersonator must be declared in the `impersonation` section of ROR Settings, together with the list/pattern of users they are allowed to impersonate. **Being a valid, authenticated user in `access_control_rules` is not enough** - without a matching entry here, ROR refuses the impersonation, even for a perfectly legitimate admin. +2. The impersonator's credentials must satisfy the authentication rule configured *inside that entry*. It is evaluated completely independently of anything in `access_control_rules`, using whatever credentials the impersonating request actually carries. +3. Only if the impersonator is also supposed to work with Kibana as themselves, `access_control_rules` needs a block authenticating them as a regular user. Such a block plays no part in impersonation - it's what grants them their everyday access. + +```yaml +readonlyrest: + access_control_rules: + - name: "Authenticate alice" + auth_key: alice:pass + - name: "Authenticate carol" + ldap_authentication: "ldap1" + + impersonation: + - impersonator: alice // Who can impersonate? (user name or pattern) + users: ["*"] // Who can be impersonated? (user names or patterns) + auth_key: alice:pass // Authentication rule required to impersonate (any authentication rule can be used here) + - impersonator: carol + users: ["bob"] + ldap_authentication: "ldap1" +``` + +In the example above, we see that we have two impersonators: `alice` and `carol`. The first one can impersonate any user (`*`) and they are able to authenticate using basic auth (`alice:pass`). The second impersonator can impersonate only `bob` user. They will be authenticated using `ldap1` connector. + +When an impersonator passes wrong credentials ROR will tell Kibana that impersonation is not allowed. + +The order of the entries matters. ROR uses the **first** entry whose `impersonator` pattern matches the caller, and only that one - it never falls through to a later entry, even if that one would allow the requested impersonated user. With overlapping patterns (e.g. `admin*` before `alice`), the `users` list of the later entry is dead configuration. Prefer one entry per impersonator, and put the most specific patterns first. + +A few structural rules ROR enforces when it loads this section (and that are worth knowing, since they explain some of the config-load errors you might see): + +* Exactly one authentication rule is allowed per `impersonation` entry - you can't stack several auth methods for a single impersonator. +* Only rules that are genuinely authentication rules (`auth_key*`, `ldap_authentication`, `external_authentication`, `proxy_auth`, ...) can be used here - authorization-only rules (like `ldap_authorization`) are rejected. +* The same exact username (no wildcards) cannot appear as both an `impersonator` and a member of `users` in the same entry - a user can't be declared as being able to impersonate themselves. +* If the `authentication_rule` has a statically known, fixed username (e.g. `auth_key: someone:pass`), ROR checks at load time that this username actually matches the `impersonator` pattern, and refuses to start otherwise. This check can't be done for dynamic identities (LDAP, external auth), since the username isn't known until request time. + +#### Defining mocks of the external services (optional) + +ROR has many sophisticated authentication & authorization methods. Some of them are based on external systems like LDAP. The problem with such systems, in regard to to the impersonation feature, is that those systems either don't support it by default or don't support it at all and even if they do - the configuration is complex. + +That's why we decided to solve it totally differently - using mocks. [Wikipedia](https://en.wiktionary.org/wiki/mock) defines `mock` as `an imitation, usually of lesser quality.` And in the case of external authentication systems we are going provide an imitation of it that will tell ACL which users should be successfully authenticated by it. When we consider an authorization service, a mock of it will return the ACL users with their roles in the service. And this is enough for ROR to support impersonation. + +How does ROR use the mocks? Let's suppose we have an `ldap_auth` rule. When ROR processes the rule, it: + +* asks the given LDAP service if the username can be authenticated with a given password, and if they can ... +* asks LDAP to list what groups the user belongs to + +In the impersonation case, it looks pretty much the same. The difference being that ROR won't call any LDAP server - the mock will provide the required information instead (no password required). During impersonating, when ROR processes an LDAP rule, it: + +* asks the mock if the username exists, and if it does ... +* asks the mock to tell what groups the user belongs to + +**⚠️ IMPORTANT:** If one or more of the external services are not mocked, ROR might inform Kibana that the impersonation is not supported. It's better to always define all mocks, to avoid the "Impersonation not supported" Elasticsearch response. + +ROR Kibana plugin helps administrators to visually create and edit service mocks with a dedicated graphical UI. Follow our [service mock configuration guide](external-services-mocks-ui.md) for more. + +#### Which rules support impersonation + +Impersonation support isn't the same for every rule that can appear in an `access_control_rules` block. ROR checks this per rule and, when it applies Test Settings, reports a warning for each rule/block combination that won't work correctly during impersonation - these warnings surface through the Test Settings API and are shown by the ROR Kibana Test Settings UI. + +| Rule | Impersonation support | Notes | +|-------------------------------------------------------------------------------------------------------------------------------------------|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `auth_key`, `auth_key_unix`, `proxy_auth`, `token_authentication` | Full | Work as-is, no extra configuration needed | +| Group-membership rules (`groups_any_of`, `groups_all_of`, and other [groups logic](../../details/authorization-rules-details.md#checking-groups-logic)) | Full | Groups are supplied directly in settings, or by an authorization rule that's itself impersonation-aware; no external call is involved | +| `auth_key_sha1`, `auth_key_sha256`, `auth_key_sha512`, `auth_key_pbkdf2_hmac_sha512` | Full, with one condition | Only works when the rule is written in the `USER_NAME:hash(PASSWORD)` form. A fully hashed `hash(USER_NAME:PASSWORD)` blob can't be reversed back to a username, so it never matches during impersonation - see [limitations](#impersonation-limitations) | +| `ldap_authentication`, `ldap_authorization`, `ldap_auth` | Requires a mock | Needs a matching LDAP service mock (see [above](#defining-mocks-of-the-external-services-optional)); without it, ROR reports that impersonation is not supported | +| `external_authentication` | Requires a mock | Needs an external authentication service mock | +| `external_authorization` | Requires a mock | Needs an external authorization service mock | +| `jwt_auth`, `jwt_authentication`, `jwt_authorization` | Not supported | These rules ignore impersonation entirely: they evaluate the real request, find no JWT in it, fail authentication and their block doesn't match. No mock or workaround today - ROR reports a Test Settings warning for such blocks | +| `ror_kbn_auth`, `ror_kbn_authentication`, `ror_kbn_authorization` | Not supported | Same as above, with the ROR Kibana token: the block can't be exercised through impersonation, and ROR reports a Test Settings warning for it | +| Everything else (`indices`, `actions`, `kibana_*`, `fields`, `filter`, `hosts`, `uri_re`, ...) | Not applicable | These rules don't authenticate or authorize an identity - they evaluate normally against whichever user, real or impersonated, is already logged in | + +A block only needs to be fully impersonation-capable if you intend to impersonate the users it applies to. A block built entirely around a "not supported" rule simply can't be exercised through impersonation - traffic that would otherwise match it falls through to later blocks, exactly as it would if the block rejected the request for any other reason. + +## Full end-to-end examples + +### Example 1: local admin impersonating any local user + +Everything is defined statically, no mocks needed - the simplest possible setup. + +```yaml +readonlyrest: + access_control_rules: + + - name: "Admins" + auth_key: alice:pass + groups_any_of: ["admins"] + + - name: "Devs" + auth_key: bob:bobpass + groups_any_of: ["devs"] + indices: ["dev-*"] + + users: + - username: alice + auth_key: alice:pass + groups: ["admins"] + + - username: bob + auth_key: bob:bobpass + groups: ["devs"] + + impersonation: + - impersonator: alice + users: ["*"] + auth_key: alice:pass # re-checks the SAME credentials alice used to authenticate - but independently +``` + +What happens when Kibana sends a request with `Authorization: Basic YWxpY2U6cGFzcw==` (i.e. `alice:pass`) and `x-ror-impersonating: bob`: + +1. ROR reaches the "Admins" block first. Its `auth_key` rule notices the impersonation header and defers to the `impersonation` section instead of comparing `alice:pass` against its own settings. +2. `alice` matches the `impersonator` pattern, `bob` matches `users: ["*"]`. +3. The `impersonation` entry's own `auth_key: alice:pass` is checked against the request's credentials - it matches, so the caller is confirmed to really be `alice`. +4. Finally, ROR asks the rule it is currently evaluating - the "Admins" block's `auth_key: alice:pass` - whether `bob` exists. That rule knows only `alice`, so the answer is no: the **"Admins" block is rejected** (logged as `AUTH_FAIL (Impersonated user does not exist)`) and ROR moves on to the next block. That log line is expected here, not a misconfiguration - the "Admins" block is simply not the block that defines `bob`. +5. In the "Devs" block, steps 1-3 repeat identically, and this time the block's own `auth_key: bob:bobpass` rule confirms that `bob` exists (a statically defined local user, so no mock is needed). ROR marks the request as logged in as `bob` and evaluates the remaining rules as `bob`: `groups_any_of: ["devs"]` matches and the response is scoped to `dev-*` indices - exactly what `bob` would see in their own session. + +### Example 2: LDAP-authenticated admin impersonating an LDAP-authorized user + +Here the impersonated user's group membership comes from LDAP, so it needs a mock. + +```yaml +readonlyrest: + access_control_rules: + + - name: "LDAP admins can do everything" + ldap_authentication: "ldap1" + ldap_authorization: + name: "ldap1" + groups_any_of: ["admins"] + + - name: "LDAP devs see only their indices" + ldap_auth: + name: "ldap1" + groups_any_of: ["devs"] + indices: ["@{acl:user}_*"] + + ldaps: + - name: ldap1 + host: ldap.example.com + port: 389 + # ... rest of the connector settings + + impersonation: + - impersonator: alice + users: ["bob"] + ldap_authentication: "ldap1" # alice's own LDAP credentials, checked independently +``` + +For this to work during impersonation, a **Test Settings mock** for `ldap1` must define `bob` as an existing user belonging to the `devs` group - see [Defining mocks of the external services](#defining-mocks-of-the-external-services-optional). Without it, both LDAP rules will refuse to evaluate `bob` and the request is denied as not supported, even though `alice`'s own impersonator authentication succeeded. + +## Common misconfigurations + +Most support tickets about "impersonation isn't working" trace back to one of these. The middle column is what you'll typically see in Kibana, in the ES response, or in the ROR logs. + +| Symptom | What ROR reports | Most common root cause | Fix | +|------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------| +| Impersonation worked earlier in the session but every impersonating request now fails, though nothing in the config changed | Kibana reports that no Test Settings are configured | Test Settings expired (default TTL is 30 minutes) or were manually invalidated. Every impersonating request is evaluated exclusively against Test Settings (see [above](#impersonating-requests-use-test-settings)), so once they're gone, impersonation stops working regardless of the `impersonation` section | Re-apply Test Settings (optionally with a longer TTL) and retry | +| Admin can log into Kibana fine, but impersonation is refused outright | Impersonation not allowed | There's no `impersonation` entry at all for this admin - being authenticated in `access_control_rules` does **not** automatically grant impersonation rights | Add an `impersonation` entry with an `impersonator` pattern matching the admin | +| Impersonation works for some target users but not others | Impersonation not allowed | The `users` pattern of the **first** `impersonation` entry matching this impersonator doesn't include the requested target username. ROR uses only that first entry and never falls through to a later one, so a second entry added for the same admin is never consulted | Broaden the `users` pattern *in that first matching entry* - appending another entry below it won't help | +| Admin's password was recently changed and impersonation broke, even though normal login still works | Impersonation not allowed | The `authentication_rule` inside `impersonation` is checked completely independently of the rule in `access_control_rules` - updating one does not update the other | Keep both in sync, or point both at the same external identity source (LDAP/external auth) instead of hardcoding credentials twice | +| Config fails to load at startup, mentioning "should be either impersonator or a user to be impersonated" | Config validation error | The exact same username (no wildcards) appears in both `impersonator` and `users` in one entry | Remove the self-reference - a user can't be declared as able to impersonate themselves | +| Config fails to load at startup, mentioning "it's used in a context of user patterns" | Config validation error | The `impersonation` entry's `authentication_rule` has a fixed, statically known username that doesn't match the `impersonator` pattern (e.g. `impersonator: alice` but `auth_key: someone_else:pass`) | Make the rule's username match the `impersonator` pattern | +| Impersonator authenticates fine, but the request is still denied, mentioning the impersonated user doesn't exist | Denied; `AUTH_FAIL (Impersonated user does not exist)` in the logs | **No** block could confirm the target user: they aren't statically configured in any block and aren't present in the relevant service mock. Note that this message is logged by every block whose authentication rule doesn't know the impersonated user, so seeing it in a healthy setup is normal - it's a problem only when no block ends up matching | Add the user to the mock, or confirm the username matches exactly | +| Request denied with "impersonation not supported", even though the `impersonation` section looks correct | Impersonation not supported | An ACL block needs a service mock (LDAP / external authentication / external authorization) that hasn't been configured yet, or uses `auth_key_sha*` with a fully-hashed `user:pass` blob (see [limitations](#impersonation-limitations)) | Add the missing mock, or switch to the `USER_NAME:hash(PASSWORD)` form for hashed auth rules | +| The block you wanted to test is never matched during impersonation, and it uses `jwt_auth` or `ror_kbn_auth` | No impersonation-specific error - the block just doesn't match | These rules don't take part in the impersonation flow: they look for a real JWT / ROR Kibana token in the request, don't find one, and reject the block. ROR reports it as a Test Settings warning | Not impersonable today - test such blocks with a real session, or authenticate the users with an impersonation-aware rule | +| Impersonation UI can't find/list the user you want to impersonate | N/A (UI limitation) | The target username is only reachable through a wildcard `users` pattern in the ACL, so ROR can't enumerate it upfront | Type the username manually in the impersonation UI, as described in [limitations](#impersonation-limitations) | +| Impersonation is refused for every target user, although the `impersonation` entry looks correct and the same credentials work elsewhere | Impersonation not allowed | The impersonating client didn't send the impersonator's credentials as an HTTP Basic Auth header - ROR always identifies the impersonator from Basic Auth, regardless of which rule type is configured as the `authentication_rule` | Make sure the client authenticates with Basic Auth (this is what the ROR Kibana Test Settings UI does under the hood) | + +## Logs & audit + +In Elasticsearch logs, in `USR` field, if an admin user finds something like this: `alice (as bob)` - it means that `alice` was authenticated, and they are the impersonator who is impersonating `bob`. + +All logs of impersonated user in Kibana will have this format `[][plugins][ReadonlyREST][][impersonating ]` + +When auditing is enabled, the audit document is going to contain an `impersonated_by` field. + +## Impersonation limitations + +Impersonation mode has some limitations. Please check if they have an impact on your use cases: + +* Not all features available in the ROR configuration are testable with impersonation mode. Some rules used in ROR ACL do not support impersonation. For example, auth rule with hashed credentials (e.g. `auth_key_sha512`) can be used in impersonation mode only when credentials follow the format `USER_NAME: HASH(PASSWORD)`; A fully hashed username and password don't allow fetching a username. The auth rule in such a format won't match during impersonation. In the [rules description](../../elasticsearch.md#rules) section you can find information about each rules impersonation support. +* Test Settings are stored in the memory of the node that handled the saving request sent by ROR Kibana plugin. Impersonation support will be limited to this node. We are going to improve it in the future, but for now your Kibana should only communicate with one Elasticsearch node. +* Sometimes it is impossible to fetch usernames defined in the Test Settings. If a `users` rule contains a username pattern with a wildcard, to impersonate a user matching the pattern, you need to enter the username manually. + + ```yaml + readonlyrest: + + access_control_rules: + - name: "LDAP group g1" + type: allow + groups_any_of: ["g1"] + + users: + - username: "admin*" // To impersonate a user with a username matching 'admin*' you need to enter the username manually, like 'admin123' + groups: + - g1: group1 + ldap_auth: + name: "ldap1" + groups_any_of: ["group1"] + + ldaps: + - name: ldap1 + [..] + + impersonation: + [...] + ``` + +## Glossary + +* **Impersonator** - someone who imitates or copies the behavior or actions of another, +* **Impersonation** - imitating behaviors or actions of a given user, +* **Impersonated user** - the identity being borrowed for the duration of an impersonation session; their permissions/data determine what the impersonator sees, but their own credentials are never needed or checked, +* **Main Settings** - the ROR's settings that apply to ACL that handles requests during regular sessions (not the impersonation ones), +* **Test Settings** - the ROR's settings that apply to ACL that handles impersonating requests (the ones during impersonation session), +* **External Service Mock** - an imitation of an external service (the supported ones: LDAP, an external authentication service, an external authorization service). diff --git a/examples/impersonation/test-settings-ui.md b/examples/impersonation/test-settings-ui.md index 03e0874..0b2337a 100644 --- a/examples/impersonation/test-settings-ui.md +++ b/examples/impersonation/test-settings-ui.md @@ -19,4 +19,4 @@ For impersonation to work, some valid Test Settings should be created and saved. ![test settings tab](<../../.gitbook/assets/test_settings_tab.png>) -Read more about [configuring impersonation in the ROR settings](../../details/impersonation.md#creating-rors-test-settings). +Read more about [configuring impersonation in the ROR settings](README.md#creating-rors-test-settings). diff --git a/kibana.md b/kibana.md index 2637cec..20af5a5 100644 --- a/kibana.md +++ b/kibana.md @@ -1164,7 +1164,7 @@ According to [Wikipedia](https://en.wikipedia.org/wiki/Impersonator): So, an impersonation can be understood as imitating behaviors or actions. In the context of ReadonlyREST: one user could imitate an action of another user. Why would we want it? Let's suppose the first user is an admin, who has just configured access for a new user. They would like to know if the rule(s) are configured correctly. And here comes the impersonation feature. The admin can impersonate the given user in Kibana and see what the user would see if they logged in themselves. -ROR plugins support impersonation and provide UI for configuring a cluster before using it. Visit the [impersonation details page](details/impersonation.md) to know more. +The ROR Kibana plugin drives the whole workflow, from preparing a safe copy of the settings to switching in and out of an impersonation session. See the [impersonation guide](examples/impersonation/README.md) for how to use and configure it. ## Multi-tenancy From ea42fa7f5ae2625c5bbd031dbdffc624a29e6f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Goworko?= Date: Fri, 11 Sep 2026 00:20:17 +0200 Subject: [PATCH 5/5] qs --- SUMMARY.md | 1 + details/impersonation.md | 4 + examples/impersonation/README.md | 288 +++++++++++++++---------------- kibana.md | 8 +- 4 files changed, 145 insertions(+), 156 deletions(-) create mode 100644 details/impersonation.md diff --git a/SUMMARY.md b/SUMMARY.md index b3eb026..55da0aa 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -10,6 +10,7 @@ * [Indices rule - Index not found scenario](details/index-not-found-examples.md) * [Indices rule - ES Templates handling](details/indices-rule-templates.md) * [For Kibana](kibana.md) + * [Impersonation (Enterprise)](details/impersonation.md) * [Kibana 7.8.x and older](details/kibana-7.8.x-and-older.md) * [ReadonlyREST API](kibana/readonlyrest-api.md) * [ReadonlyREST DISA STIG Compliance](kibana/readonlyrest-disa-stig-compliance.md) diff --git a/details/impersonation.md b/details/impersonation.md new file mode 100644 index 0000000..f0f506e --- /dev/null +++ b/details/impersonation.md @@ -0,0 +1,4 @@ +# Impersonation +([Enterprise](https://readonlyrest.com/enterprise)) + +This page has moved. Impersonation is now described in the [Impersonation guide](../examples/impersonation/README.md), which explains how to configure it and how to use it in Kibana. For known limitations, see [Impersonation limitations](../examples/impersonation/README.md#impersonation-limitations). diff --git a/examples/impersonation/README.md b/examples/impersonation/README.md index c784d63..0647b14 100644 --- a/examples/impersonation/README.md +++ b/examples/impersonation/README.md @@ -9,117 +9,119 @@ According to [Wikipedia](https://en.wikipedia.org/wiki/Impersonator): > An impersonator is someone who imitates or copies the behavior or actions of another. -So, an impersonation can be understood as imitating behaviors or actions. In the context of ReadonlyREST: one user could imitate an action of another user. Let's suppose the first user is an admin, who has just configured access for a new user. They would like to know if the rules are configured correctly. And here comes the impersonation feature: the admin can impersonate the given user and see exactly what that user would see if they logged in themselves. +In ReadonlyREST, impersonation means that one user acts as another user. For example, an admin who has just configured access for a new user can impersonate that user and see what the user would see after logging in. -Impersonation is, first and foremost, a Kibana feature. The ROR Kibana plugin drives the whole workflow - preparing a safe copy of the settings, mocking the external services and switching in and out of an impersonation session - from the ROR menu, and this page describes it that way. Everything the plugin does is backed by ROR for Elasticsearch, so impersonating through the Elasticsearch REST API alone is possible as well, but it means driving ROR's internal APIs by hand and is not covered here. +Impersonation is mainly a Kibana feature, and this page describes it from the Kibana point of view. The ROR Kibana plugin handles the whole workflow in the ROR menu: it prepares a copy of the settings for testing, lets you mock external services, and starts and ends impersonation sessions. The plugin relies on ROR for Elasticsearch, so you can also impersonate users with the Elasticsearch REST API alone. That requires calling ROR's internal APIs directly and is not described here. ## Use cases -The impersonation feature is intended for ROR administrators, rather than users. We can point out the two most obvious use cases when the admin could take advantage of the feature: +Impersonation is a tool for ROR administrators rather than for regular users. The two most common use cases are described below. -#### Debugging users' problems: +### Debugging users' problems -Let's imagine that some user has a problem with their ROR configuration (eg. the user doesn't have access to some feature that was blocked at ROR's level by you, the admin). And they are not able to clearly describe what the issue is (sounds familiar?). As an administrator, it would be extremely beneficial if you could see what the user sees. Thanks to the impersonation feature, an admin is allowed to impersonate the user and experience exactly what the user experiences. +A user reports a problem with their access, for example a Kibana feature they can't use because of a ROR rule, but they can't clearly describe what is wrong. If you impersonate that user, you see what they see, which makes the problem much easier to find. -#### Configuring a new user: +### Configuring a new user -When an admin configures a new user in ROR settings, they face two problems: +When you add a new user to the ROR settings, you usually have two questions: -1. `Will the updated configuration break the production cluster?` -2. `How do I know that the new user is correctly configured? Did I configure all their permissions correctly??` +1. Will the updated settings break anything on the production cluster? +2. Is the new user configured correctly, with all the permissions they need and no more? -Both of the problems can be solved using the ROR's impersonation. Thanks to the fact that the impersonation feature always uses its own Test Settings, that is completely independent from the main production settings, the admin can alter it without worries that their actions will break something and users won't be able to do their job. - -Admin can add the new user configuration without worrying and then test it by impersonating the user. They can check if the user can log in without problems and if the user has access only to the Kibana features the admin wanted to grant. When the admin is sure that everything is configured correctly, they can promote the settings (test) to production. +Impersonation answers both. It always uses its own Test Settings, which are separate from the production settings, so you can change them without affecting other users. You add the new user to the Test Settings, impersonate them, and check that they can log in and see only the Kibana features you meant to give them. When everything is correct, you promote the Test Settings to production. ## Impersonating a user in Kibana -The whole workflow lives in the ROR menu, under **Edit security settings**, and consists of three steps. Only the first one is mandatory. +The workflow is available in the ROR menu, under **Edit security settings**. It has three steps: + +1. **Create Test Settings.** Impersonation doesn't use your production settings. It uses Test Settings: a separate, temporary ACL that you can edit freely and later promote to Main Settings. See [Creating Test Settings](test-settings-ui.md) for the UI, and [Creating ROR's Test Settings](#creating-rors-test-settings) for how Test Settings work. +2. **Define mocks of external services (optional).** This step is needed only if the users you want to impersonate come from LDAP or another external service. During impersonation, ROR doesn't connect to that service. Instead, it asks a mock which users exist and which groups they belong to, so you don't need a real account or password. See [Defining external services mock configurations](external-services-mocks-ui.md) and [Defining mocks of the external services](#defining-mocks-of-the-external-services-optional). +3. **Start impersonating.** Pick a user from the list, or type the username if it isn't listed. Kibana reloads as that user. See [Impersonating users](impersonate-user-ui.md). -1. **Create Test Settings.** Impersonation never touches your production configuration: it runs against a separate, temporary copy of the ACL called Test Settings, which you can edit freely and promote to the main settings once you're happy with it. See [Creating Test Settings](test-settings-ui.md), and [Test Settings](#creating-rors-test-settings) below for what they are and how long they last. -2. **Define mocks of the external services** - needed only when the users you want to impersonate come from LDAP or another external service. Instead of connecting to the real system, ROR asks a mock which users exist and what groups they belong to, so no real account or password is required. See [Defining external services mock configurations](external-services-mocks-ui.md) and [the section below](#defining-mocks-of-the-external-services-optional). -3. **Start the impersonation session.** Pick the user from the list, or type the username by hand when ROR can't enumerate it, and Kibana reloads as that user. See [Impersonating users](impersonate-user-ui.md). +The list of users contains: -The list of users offered by the UI is built from what ROR can enumerate in the settings and in the mocks: +* users defined statically in the settings, +* users defined in the mocks of external services, such as LDAP. -* users provided statically (defined in the settings), -* users provided dynamically: - * from external, dependant systems (like LDAP) - the ones taken from the mocks, - * from upstream systems (eg. through headers) - these are not known upfront, so the username has to be entered manually. +Users that come from upstream systems, for example through HTTP headers, aren't known in advance. To impersonate such a user, type their username. -Before any of this works, the settings have to say who is allowed to impersonate whom - see [Impersonation configuration](#impersonation-configuration). +The settings must also define who can impersonate whom. See [The impersonation section](#the-impersonation-section). ## How ROR processes an impersonation request -An impersonating request is almost identical to the request the impersonated user would send themselves. It reaches the same cluster and is evaluated by the same ACL, block by block, in the same order. Rules like `indices`, `kibana_*`, `fields`, `filter` or `hosts` see exactly what they would see in that user's own session - which is what makes impersonation useful for testing a configuration in the first place. +ROR handles an impersonation request almost the same way as a request sent by the impersonated user. It checks the request against the same ACL, block by block, in the same order. Rules such as `indices`, `kibana_*`, `fields`, `filter` or `hosts` work the same way as in that user's own session. This is what makes impersonation useful for testing settings. -Two things are different: +There are two differences: -* **the authentication data the request carries** - the credentials on the wire belong to the *impersonator* (say, `alice`), while the identity to be evaluated - the *impersonated user* (say, `bob`) - travels separately, in an internal header managed by ROR and its Kibana plugin, -* **the way authentication and authorization rules behave** - and that is where the whole feature lives. +* The credentials in the request belong to the impersonator, for example `alice`. The name of the impersonated user, for example `bob`, is sent separately, in an internal header set by ROR and the ROR Kibana plugin. +* Authentication and authorization rules behave differently. -The rest of this section is about that second difference. +The sections below explain how. ### Impersonating requests use Test Settings -ROR keeps two independent sets of settings: +ROR has two separate sets of settings: -* **Main Settings** - the ACL that handles regular traffic, -* **Test Settings** - a separate ACL, used only for impersonation. They are a scratchpad: the admin can edit them freely, without any risk to the users working against Main Settings, and promote them to Main Settings once the result is satisfying. +* **Main Settings**: the ACL used for regular requests. +* **Test Settings**: a separate ACL used only for impersonation. You can change Test Settings without affecting users who work with Main Settings, and promote them to Main Settings when you're done. -An impersonating request is always evaluated against Test Settings, never against Main Settings. Test Settings stay active only for a limited time and can be invalidated at any moment (see [Creating ROR's Test Settings](#creating-rors-test-settings)); when none are active, impersonation simply doesn't work, no matter how the rest of the configuration looks. +ROR always checks impersonation requests against Test Settings, never against Main Settings. Test Settings are active only for a limited time and can be invalidated at any moment (see [Creating ROR's Test Settings](#creating-rors-test-settings)). When no Test Settings are active, impersonation doesn't work. ### The impersonator and the impersonated user are authorized differently -`alice` can appear in ROR settings in two completely independent roles: +`alice` can appear in the ROR settings in two independent roles: -* **as a regular user** - authenticated by an authentication rule, which is a part of a block, which is one of many in the ACL, exactly like anybody else. This is what lets `alice` log into Kibana and do her own work. -* **as an impersonator** - declared in the `impersonation` section, a separate part of ROR settings saying who may impersonate whom, and how such an impersonator is authenticated (see [Impersonation configuration](#impersonation-configuration)). +* **As a regular user.** She is authenticated by the authentication rule of one of the ACL blocks, like any other user. This lets `alice` log into Kibana and do her own work. +* **As an impersonator.** She is listed in the `impersonation` section, a separate part of the settings that defines who can impersonate whom and how each impersonator is authenticated (see [The impersonation section](#the-impersonation-section)). -Neither role implies the other, and that is deliberate: +One role doesn't require the other: -* An impersonator who never logs into Kibana needs only an `impersonation` entry. They can impersonate users through the Elasticsearch REST API without being a regular ACL user at all. -* If `alice` should also log into Kibana as herself, some ACL block has to authenticate her as a regular user. The `impersonation` section grants no everyday access whatsoever. +* An impersonator who never logs into Kibana needs only an entry in the `impersonation` section. They can still impersonate users through the Elasticsearch REST API. +* If `alice` should also be able to log into Kibana as herself, an ACL block must authenticate her as a regular user. The `impersonation` section doesn't give her any access of her own. -So, when a request comes in as `alice` herself, it is authorized by the ACL like any other request. When the same `alice` sends a request on behalf of `bob`, the authentication rules in the ACL blocks no longer answer the question "who is the caller?" - the `impersonation` section does. This is why the impersonator's authentication has to be spelled out there explicitly: it is the only place in the settings whose job is to verify that the caller really is `alice`, right now, for the purpose of impersonation. +When `alice` sends a request as herself, the ACL handles it like any other request. When she sends a request as `bob`, the authentication rules in the ACL blocks no longer check who the caller is. The `impersonation` section does that instead. This is why each entry in the `impersonation` section needs its own authentication rule: it is the only place in the settings that verifies the impersonator. ### Not every authentication rule supports impersonation -The first thing an authentication rule does with an impersonating request is to check whether it supports impersonation at all (the full list is in [Which rules support impersonation](#which-rules-support-impersonation)). The two paths are completely different. +When an authentication rule receives an impersonation request, what happens next depends on whether the rule supports impersonation. The full list is in [Which rules support impersonation](#which-rules-support-impersonation). -**When the rule doesn't support impersonation** (`jwt_*`, `ror_kbn_*`), it takes no part in the impersonation flow. It evaluates the request the way it always does: it looks for a JWT or a ROR Kibana token, finds none (the request carries the impersonator's Basic Auth credentials instead), and doesn't match - so its block doesn't match either, and ROR moves on to the next block. A block built around such a rule cannot be exercised through impersonation at all; ROR points this out with a warning when Test Settings are applied. +**Rules that don't support impersonation** (`jwt_*`, `ror_kbn_*`) handle the request as usual. They look for a JWT or a ROR Kibana token, don't find one (the request contains the impersonator's Basic Auth credentials instead), and fail. The block doesn't match, and ROR moves on to the next block. Such blocks can't be tested with impersonation, and ROR shows a warning about them when Test Settings are applied. -**When the rule does support impersonation**, it skips its normal authentication logic entirely and hands the request over to the impersonation flow, which answers three questions, in order: +**Rules that support impersonation** skip their normal authentication. Instead, ROR answers three questions, in this order: -1. **Is `alice` allowed to impersonate `bob`?** The impersonator is identified by the Basic Auth credentials carried by the request, and looked up in the `impersonation` section. If nothing there allows this particular pair, the request is denied. -2. **Is the caller really `alice`?** Her credentials are verified against the authentication rule of the matching `impersonation` entry - independently of the block ROR happens to be evaluating, and independently of whatever rule authenticates `alice` as a regular user. Trying to impersonate oneself is rejected here as well. -3. **Does `bob` exist?** This one is answered by the very rule ROR is currently evaluating, using only what that rule knows. A rule holding static credentials knows the usernames written next to it. A rule backed by an external system (LDAP, an external authentication or authorization service) would normally have to ask that system - during impersonation it asks a [mock](#defining-mocks-of-the-external-services-optional) of it instead, so that no real account, no password and no connection to the production service are needed. +1. **Can `alice` impersonate `bob`?** ROR takes the impersonator's username from the Basic Auth credentials of the request and looks for a matching entry in the `impersonation` section. If no entry allows `alice` to impersonate `bob`, the block doesn't match. +2. **Is the caller really `alice`?** ROR checks the credentials with the authentication rule of the matching `impersonation` entry. This check doesn't depend on the current block, or on the rule that authenticates `alice` as a regular user. Users who try to impersonate themselves are rejected at this step. +3. **Does `bob` exist?** The rule that ROR is currently evaluating answers this, based on what it knows. A rule with static credentials knows only the usernames written in it. A rule that uses an external system, such as LDAP or an external authentication or authorization service, doesn't contact that system during impersonation. It asks a [mock](#defining-mocks-of-the-external-services-optional) of the system instead, so no real account, password or connection to the production service is needed. -The answer to the last question decides the fate of the block: +The answer to the third question decides what happens to the block: -* the rule knows `bob` → ROR treats the request as logged in as `bob`, and the rest of the block (groups, indices, Kibana rules, ...) is evaluated as `bob`, using mocked data wherever an external system would normally be consulted, -* the rule can answer, and the answer is "I don't know this user" → this block doesn't match, and ROR moves on to the next one. In a multi-block ACL this is perfectly normal: only the block that actually defines `bob` can match him, and the others log `AUTH_FAIL (Impersonated user does not exist)` along the way, -* the rule cannot answer at all - a missing service mock, or an `auth_key_sha*` rule whose whole `user:pass` pair is hashed and can't be reversed back to a username → the request is denied, and ROR reports that the impersonation is not supported. +* **The rule knows `bob`.** ROR treats the request as sent by `bob` and evaluates the rest of the block (groups, indices, Kibana rules and so on) as `bob`. Where the block would normally call an external system, ROR uses data from the mocks. +* **The rule doesn't know `bob`.** The block doesn't match, and ROR moves on to the next block. This is normal when the ACL has many blocks, because only the blocks that define `bob` can match. Blocks that don't define `bob` log `AUTH_FAIL (Impersonated user does not exist)`. +* **The rule can't check.** This happens when a mock is missing, or when an `auth_key_sha*` rule hashes the whole `user:pass` pair, so the username can't be read from it. The block doesn't match, and ROR moves on to the next block. If no block matches `bob`, ROR reports that impersonation is not supported. -These three questions are asked from scratch in every block ROR tries. The first two always get the same answer - they depend only on the `impersonation` section, never on the block. The third one is what differs: each rule answers it with its own knowledge, and that is what makes exactly one block match while the others fall through. +A negative answer to any of the questions affects only the current block. ROR moves on to the next block, as it does for a regular request, and asks the questions again. The answers to the first two questions depend only on the `impersonation` section, so they are the same in every block. If one of them is negative, every block whose authentication rule supports impersonation fails, and the request is refused as not allowed, unless a block with no authentication rule matches it. The answer to the third question depends on the rule in each block, and it decides which block matches first. ## Impersonation configuration -This is the reference for the two things the [Kibana workflow](#impersonating-a-user-in-kibana) sets up - Test Settings and the mocks of the external services (like [LDAP](../../elasticsearch.md#ldap-connector), [External Basic Auth](../../elasticsearch.md#external-basic-auth) or [Custom groups provider](../../elasticsearch.md#custom-groups-providers)) - plus the `impersonation` section, which says who is allowed to impersonate whom. +This part describes the settings that the [Kibana workflow](#impersonating-a-user-in-kibana) depends on: Test Settings, the `impersonation` section, and mocks of external services such as [LDAP](../../elasticsearch.md#ldap-connector), [External Basic Auth](../../elasticsearch.md#external-basic-auth) or [Custom groups provider](../../elasticsearch.md#custom-groups-providers). + +### Creating ROR's Test Settings -#### Creating ROR's Test Settings +When you call Elasticsearch directly or through Kibana, ROR uses the ACL from Main Settings. Test Settings define a second ACL, which ROR for Elasticsearch uses only for requests that carry the impersonation header. ROR manages this header internally. -When you call Elasticsearch directly or through ROR Kibana, ROR ACL is defined by Settings (we can assume they are Main Settings). The Test Settings define another ACL, that is taken into consideration by ROR ES only when a proper impersonation header is passed. The header is managed by ROR internally. The Test Settings are active only for a strictly defined amount of time (by default it's _30 minutes_, but the admin can change it before applying Test Settings). After the time has expired, they are automatically invalidated (for security reasons). Obviously, the admin is allowed to invalidate the configured Test Settings in any time. There is no way to have more than one Test Settings configured at time. +Test Settings are active only for a limited time: 30 minutes by default, but you can set a different time before you apply them. When the time runs out, ROR invalidates the Test Settings automatically, for security reasons. You can also invalidate them yourself at any time. Only one set of Test Settings can be active at a time. -ROR Kibana plugin provides a dedicated Test Settings UI. See our [Test Settings management guide](test-settings-ui.md) for more information. +The ROR Kibana plugin has a dedicated UI for Test Settings. See the [Test Settings management guide](test-settings-ui.md). -**This TTL gates impersonation directly.** As described [above](#impersonating-requests-use-test-settings), every impersonating request is evaluated exclusively against Test Settings. Once they expire or are invalidated, there is nothing left to evaluate such a request against, so impersonation stops working immediately, regardless of how the `impersonation` section itself is configured. This is a distinct failure mode from a misconfigured `impersonation` entry, and it's worth ruling out first: re-apply Test Settings and retry before troubleshooting anything else. +When Test Settings expire or are invalidated, impersonation stops working immediately, whatever the `impersonation` section contains. If impersonation suddenly stops working, check this first: apply the Test Settings again and retry. -But copying Main Settings as Test Settings is not enough. We also have to instruct ROR which users can be considered as impersonators (the ones, who are allowed to impersonate other users). As described [above](#the-impersonator-and-the-impersonated-user-are-authorized-differently), this is what the `impersonation` section is for: +### The impersonation section -1. The impersonator must be declared in the `impersonation` section of ROR Settings, together with the list/pattern of users they are allowed to impersonate. **Being a valid, authenticated user in `access_control_rules` is not enough** - without a matching entry here, ROR refuses the impersonation, even for a perfectly legitimate admin. -2. The impersonator's credentials must satisfy the authentication rule configured *inside that entry*. It is evaluated completely independently of anything in `access_control_rules`, using whatever credentials the impersonating request actually carries. -3. Only if the impersonator is also supposed to work with Kibana as themselves, `access_control_rules` needs a block authenticating them as a regular user. Such a block plays no part in impersonation - it's what grants them their everyday access. +Test Settings alone are not enough. ROR also needs to know which users can impersonate others, and whom they can impersonate. This is defined in the `impersonation` section (see [The impersonator and the impersonated user are authorized differently](#the-impersonator-and-the-impersonated-user-are-authorized-differently)): + +1. Every impersonator must have an entry in the `impersonation` section, with the usernames or username patterns of the users they can impersonate. Being authenticated in `access_control_rules` is not enough. Without a matching entry, ROR refuses impersonation, whatever access the user has otherwise. +2. The impersonator's credentials must pass the authentication rule defined in that entry. ROR checks this rule separately from `access_control_rules`, using the credentials sent with the impersonation request. +3. If the impersonator should also use Kibana as themselves, `access_control_rules` needs a block that authenticates them as a regular user. That block isn't used for impersonation. ```yaml readonlyrest: @@ -130,110 +132,98 @@ readonlyrest: ldap_authentication: "ldap1" impersonation: - - impersonator: alice // Who can impersonate? (user name or pattern) - users: ["*"] // Who can be impersonated? (user names or patterns) - auth_key: alice:pass // Authentication rule required to impersonate (any authentication rule can be used here) + - impersonator: alice # who can impersonate (a username or pattern) + users: ["*"] # who can be impersonated (usernames or patterns) + auth_key: alice:pass # how the impersonator is authenticated (any authentication rule) - impersonator: carol users: ["bob"] ldap_authentication: "ldap1" ``` -In the example above, we see that we have two impersonators: `alice` and `carol`. The first one can impersonate any user (`*`) and they are able to authenticate using basic auth (`alice:pass`). The second impersonator can impersonate only `bob` user. They will be authenticated using `ldap1` connector. +In this example there are two impersonators. `alice` can impersonate any user (`*`) and is authenticated with Basic Auth (`alice:pass`). `carol` can impersonate only `bob` and is authenticated with the `ldap1` LDAP connector. + +If an impersonator sends wrong credentials, ROR tells Kibana that impersonation is not allowed. -When an impersonator passes wrong credentials ROR will tell Kibana that impersonation is not allowed. +The order of the entries matters. ROR uses only the first entry whose `impersonator` pattern matches the caller. It doesn't check later entries, even if one of them would allow the requested user. For example, if an entry for `a*` comes before an entry for `alice`, the `users` list of the `alice` entry is never used. Use one entry per impersonator where possible, and put the most specific patterns first. -The order of the entries matters. ROR uses the **first** entry whose `impersonator` pattern matches the caller, and only that one - it never falls through to a later entry, even if that one would allow the requested impersonated user. With overlapping patterns (e.g. `admin*` before `alice`), the `users` list of the later entry is dead configuration. Prefer one entry per impersonator, and put the most specific patterns first. +When ROR loads this section, it checks that: -A few structural rules ROR enforces when it loads this section (and that are worth knowing, since they explain some of the config-load errors you might see): +* each entry has exactly one authentication rule, +* the rule is an authentication rule (`auth_key*`, `ldap_authentication`, `external_authentication`, `proxy_auth` and so on), not an authorization-only rule such as `ldap_authorization`, +* no username (without wildcards) appears in both `impersonator` and `users` of the same entry, because users can't impersonate themselves, +* a fixed username in the rule (for example `auth_key: someone:pass`) matches the `impersonator` pattern. ROR can't check this for LDAP or external authentication, because the username is known only when a request arrives. -* Exactly one authentication rule is allowed per `impersonation` entry - you can't stack several auth methods for a single impersonator. -* Only rules that are genuinely authentication rules (`auth_key*`, `ldap_authentication`, `external_authentication`, `proxy_auth`, ...) can be used here - authorization-only rules (like `ldap_authorization`) are rejected. -* The same exact username (no wildcards) cannot appear as both an `impersonator` and a member of `users` in the same entry - a user can't be declared as being able to impersonate themselves. -* If the `authentication_rule` has a statically known, fixed username (e.g. `auth_key: someone:pass`), ROR checks at load time that this username actually matches the `impersonator` pattern, and refuses to start otherwise. This check can't be done for dynamic identities (LDAP, external auth), since the username isn't known until request time. +If any of these checks fails, ROR doesn't load the settings. -#### Defining mocks of the external services (optional) +### Defining mocks of the external services (optional) -ROR has many sophisticated authentication & authorization methods. Some of them are based on external systems like LDAP. The problem with such systems, in regard to to the impersonation feature, is that those systems either don't support it by default or don't support it at all and even if they do - the configuration is complex. +Some ROR authentication and authorization methods rely on external systems such as LDAP. These systems usually don't support impersonation, and when they do, it's complex to configure. -That's why we decided to solve it totally differently - using mocks. [Wikipedia](https://en.wiktionary.org/wiki/mock) defines `mock` as `an imitation, usually of lesser quality.` And in the case of external authentication systems we are going provide an imitation of it that will tell ACL which users should be successfully authenticated by it. When we consider an authorization service, a mock of it will return the ACL users with their roles in the service. And this is enough for ROR to support impersonation. +ROR solves this with mocks. [Wiktionary](https://en.wiktionary.org/wiki/mock) defines a mock as "an imitation, usually of lesser quality". A mock of an external authentication service tells ROR which users exist. A mock of an authorization service also tells ROR which groups each user belongs to. This is enough for ROR to support impersonation. -How does ROR use the mocks? Let's suppose we have an `ldap_auth` rule. When ROR processes the rule, it: +For example, when ROR evaluates an `ldap_auth` rule for a regular request, it: -* asks the given LDAP service if the username can be authenticated with a given password, and if they can ... -* asks LDAP to list what groups the user belongs to +* asks the LDAP server whether the user can log in with the given password, and if so, +* asks the LDAP server which groups the user belongs to. -In the impersonation case, it looks pretty much the same. The difference being that ROR won't call any LDAP server - the mock will provide the required information instead (no password required). During impersonating, when ROR processes an LDAP rule, it: +During impersonation, ROR doesn't contact the LDAP server, and no password is needed. Instead, it: -* asks the mock if the username exists, and if it does ... -* asks the mock to tell what groups the user belongs to +* asks the mock whether the user exists, and if so, +* asks the mock which groups the user belongs to. -**⚠️ IMPORTANT:** If one or more of the external services are not mocked, ROR might inform Kibana that the impersonation is not supported. It's better to always define all mocks, to avoid the "Impersonation not supported" Elasticsearch response. +**⚠️ IMPORTANT:** If an external service used in the ACL has no mock, ROR may report that impersonation is not supported. To avoid this, define mocks for all external services. -ROR Kibana plugin helps administrators to visually create and edit service mocks with a dedicated graphical UI. Follow our [service mock configuration guide](external-services-mocks-ui.md) for more. +The ROR Kibana plugin has a UI for creating and editing mocks. See the [service mock configuration guide](external-services-mocks-ui.md). -#### Which rules support impersonation +### Which rules support impersonation -Impersonation support isn't the same for every rule that can appear in an `access_control_rules` block. ROR checks this per rule and, when it applies Test Settings, reports a warning for each rule/block combination that won't work correctly during impersonation - these warnings surface through the Test Settings API and are shown by the ROR Kibana Test Settings UI. +Rules differ in how they support impersonation. When Test Settings are applied, ROR checks every rule and reports a warning for each block with a rule that won't work during impersonation. The ROR Kibana plugin shows these warnings in the Test Settings UI. -| Rule | Impersonation support | Notes | -|-------------------------------------------------------------------------------------------------------------------------------------------|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `auth_key`, `auth_key_unix`, `proxy_auth`, `token_authentication` | Full | Work as-is, no extra configuration needed | -| Group-membership rules (`groups_any_of`, `groups_all_of`, and other [groups logic](../../details/authorization-rules-details.md#checking-groups-logic)) | Full | Groups are supplied directly in settings, or by an authorization rule that's itself impersonation-aware; no external call is involved | -| `auth_key_sha1`, `auth_key_sha256`, `auth_key_sha512`, `auth_key_pbkdf2_hmac_sha512` | Full, with one condition | Only works when the rule is written in the `USER_NAME:hash(PASSWORD)` form. A fully hashed `hash(USER_NAME:PASSWORD)` blob can't be reversed back to a username, so it never matches during impersonation - see [limitations](#impersonation-limitations) | -| `ldap_authentication`, `ldap_authorization`, `ldap_auth` | Requires a mock | Needs a matching LDAP service mock (see [above](#defining-mocks-of-the-external-services-optional)); without it, ROR reports that impersonation is not supported | -| `external_authentication` | Requires a mock | Needs an external authentication service mock | -| `external_authorization` | Requires a mock | Needs an external authorization service mock | -| `jwt_auth`, `jwt_authentication`, `jwt_authorization` | Not supported | These rules ignore impersonation entirely: they evaluate the real request, find no JWT in it, fail authentication and their block doesn't match. No mock or workaround today - ROR reports a Test Settings warning for such blocks | -| `ror_kbn_auth`, `ror_kbn_authentication`, `ror_kbn_authorization` | Not supported | Same as above, with the ROR Kibana token: the block can't be exercised through impersonation, and ROR reports a Test Settings warning for it | -| Everything else (`indices`, `actions`, `kibana_*`, `fields`, `filter`, `hosts`, `uri_re`, ...) | Not applicable | These rules don't authenticate or authorize an identity - they evaluate normally against whichever user, real or impersonated, is already logged in | +| Rule | Impersonation support | Notes | +|------|-----------------------|-------| +| `auth_key`, `auth_key_unix`, `proxy_auth`, `token_authentication` | Full | No extra configuration needed | +| Group rules (`groups_any_of`, `groups_all_of` and other [groups logic](../../details/authorization-rules-details.md#checking-groups-logic)) | Depends on the `users` section | The rules in the matching `users` entry decide. Static groups work without extra configuration. Groups from an external system, for example through `ldap_auth`, need a mock of that system | +| `auth_key_sha1`, `auth_key_sha256`, `auth_key_sha512`, `auth_key_pbkdf2_hmac_sha512` | Partial | Work only in the `USER_NAME:hash(PASSWORD)` form. In the `hash(USER_NAME:PASSWORD)` form, ROR can't read the username, so the rule never matches during impersonation. See [limitations](#impersonation-limitations) | +| `ldap_authentication`, `ldap_authorization`, `ldap_auth` | Requires a mock | Need an LDAP mock (see [Defining mocks of the external services](#defining-mocks-of-the-external-services-optional)). Without it, ROR reports that impersonation is not supported | +| `external_authentication` | Requires a mock | Needs a mock of the external authentication service | +| `external_authorization` | Requires a mock | Needs a mock of the external authorization service | +| `jwt_auth`, `jwt_authentication`, `jwt_authorization` | Not supported | These rules look for a JWT in the request, don't find one, and fail, so the block doesn't match. ROR shows a Test Settings warning for such blocks | +| `ror_kbn_auth`, `ror_kbn_authentication`, `ror_kbn_authorization` | Not supported | Same as the JWT rules, but with the ROR Kibana token | +| All other rules (`indices`, `actions`, `kibana_*`, `fields`, `filter`, `hosts`, `uri_re` and so on) | Not applicable | These rules don't identify users. They work the same way for an impersonated user as for a regular user | -A block only needs to be fully impersonation-capable if you intend to impersonate the users it applies to. A block built entirely around a "not supported" rule simply can't be exercised through impersonation - traffic that would otherwise match it falls through to later blocks, exactly as it would if the block rejected the request for any other reason. +Only blocks for users you want to impersonate need to support impersonation. A block that relies on an unsupported rule can't be tested with impersonation. Requests that would match it go on to the next blocks, as they would if the block didn't match for any other reason. ## Full end-to-end examples -### Example 1: local admin impersonating any local user +### Example 1: a local user impersonating other local users -Everything is defined statically, no mocks needed - the simplest possible setup. +All users are defined in the settings, so no mocks are needed. This is the simplest setup. ```yaml readonlyrest: access_control_rules: - - name: "Admins" + - name: "Alice" auth_key: alice:pass - groups_any_of: ["admins"] - - name: "Devs" + - name: "Developers" auth_key: bob:bobpass - groups_any_of: ["devs"] indices: ["dev-*"] - users: - - username: alice - auth_key: alice:pass - groups: ["admins"] - - - username: bob - auth_key: bob:bobpass - groups: ["devs"] - impersonation: - impersonator: alice users: ["*"] - auth_key: alice:pass # re-checks the SAME credentials alice used to authenticate - but independently + auth_key: alice:pass # checked separately from the "Alice" block ``` -What happens when Kibana sends a request with `Authorization: Basic YWxpY2U6cGFzcw==` (i.e. `alice:pass`) and `x-ror-impersonating: bob`: +When `alice` impersonates `bob` in Kibana, the first two questions have the same answers in both blocks: `alice` can impersonate any user, and her credentials match the `impersonation` entry. The answers to the third question differ: -1. ROR reaches the "Admins" block first. Its `auth_key` rule notices the impersonation header and defers to the `impersonation` section instead of comparing `alice:pass` against its own settings. -2. `alice` matches the `impersonator` pattern, `bob` matches `users: ["*"]`. -3. The `impersonation` entry's own `auth_key: alice:pass` is checked against the request's credentials - it matches, so the caller is confirmed to really be `alice`. -4. Finally, ROR asks the rule it is currently evaluating - the "Admins" block's `auth_key: alice:pass` - whether `bob` exists. That rule knows only `alice`, so the answer is no: the **"Admins" block is rejected** (logged as `AUTH_FAIL (Impersonated user does not exist)`) and ROR moves on to the next block. That log line is expected here, not a misconfiguration - the "Admins" block is simply not the block that defines `bob`. -5. In the "Devs" block, steps 1-3 repeat identically, and this time the block's own `auth_key: bob:bobpass` rule confirms that `bob` exists (a statically defined local user, so no mock is needed). ROR marks the request as logged in as `bob` and evaluates the remaining rules as `bob`: `groups_any_of: ["devs"]` matches and the response is scoped to `dev-*` indices - exactly what `bob` would see in their own session. +* The `auth_key` rule in the "Alice" block knows only `alice`. For this block, `bob` doesn't exist, so the block doesn't match and logs `AUTH_FAIL (Impersonated user does not exist)`. This is expected. +* The `auth_key` rule in the "Developers" block knows `bob`, so this block matches. ROR evaluates the request as `bob` and limits it to the `dev-*` indices, as in `bob`'s own session. -### Example 2: LDAP-authenticated admin impersonating an LDAP-authorized user +### Example 2: an LDAP user impersonating another LDAP user -Here the impersonated user's group membership comes from LDAP, so it needs a mock. +In this example, the impersonated user's groups come from LDAP, so a mock is needed. ```yaml readonlyrest: @@ -260,44 +250,44 @@ readonlyrest: impersonation: - impersonator: alice users: ["bob"] - ldap_authentication: "ldap1" # alice's own LDAP credentials, checked independently + ldap_authentication: "ldap1" # alice's own LDAP credentials, checked separately ``` -For this to work during impersonation, a **Test Settings mock** for `ldap1` must define `bob` as an existing user belonging to the `devs` group - see [Defining mocks of the external services](#defining-mocks-of-the-external-services-optional). Without it, both LDAP rules will refuse to evaluate `bob` and the request is denied as not supported, even though `alice`'s own impersonator authentication succeeded. +For impersonation to work, an LDAP mock for `ldap1` must define `bob` as a user in the `devs` group (see [Defining mocks of the external services](#defining-mocks-of-the-external-services-optional)). Without the mock, neither LDAP rule can check whether `bob` exists, and the request is refused as not supported, even though `alice` was authenticated as an impersonator. ## Common misconfigurations -Most support tickets about "impersonation isn't working" trace back to one of these. The middle column is what you'll typically see in Kibana, in the ES response, or in the ROR logs. - -| Symptom | What ROR reports | Most common root cause | Fix | -|------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------| -| Impersonation worked earlier in the session but every impersonating request now fails, though nothing in the config changed | Kibana reports that no Test Settings are configured | Test Settings expired (default TTL is 30 minutes) or were manually invalidated. Every impersonating request is evaluated exclusively against Test Settings (see [above](#impersonating-requests-use-test-settings)), so once they're gone, impersonation stops working regardless of the `impersonation` section | Re-apply Test Settings (optionally with a longer TTL) and retry | -| Admin can log into Kibana fine, but impersonation is refused outright | Impersonation not allowed | There's no `impersonation` entry at all for this admin - being authenticated in `access_control_rules` does **not** automatically grant impersonation rights | Add an `impersonation` entry with an `impersonator` pattern matching the admin | -| Impersonation works for some target users but not others | Impersonation not allowed | The `users` pattern of the **first** `impersonation` entry matching this impersonator doesn't include the requested target username. ROR uses only that first entry and never falls through to a later one, so a second entry added for the same admin is never consulted | Broaden the `users` pattern *in that first matching entry* - appending another entry below it won't help | -| Admin's password was recently changed and impersonation broke, even though normal login still works | Impersonation not allowed | The `authentication_rule` inside `impersonation` is checked completely independently of the rule in `access_control_rules` - updating one does not update the other | Keep both in sync, or point both at the same external identity source (LDAP/external auth) instead of hardcoding credentials twice | -| Config fails to load at startup, mentioning "should be either impersonator or a user to be impersonated" | Config validation error | The exact same username (no wildcards) appears in both `impersonator` and `users` in one entry | Remove the self-reference - a user can't be declared as able to impersonate themselves | -| Config fails to load at startup, mentioning "it's used in a context of user patterns" | Config validation error | The `impersonation` entry's `authentication_rule` has a fixed, statically known username that doesn't match the `impersonator` pattern (e.g. `impersonator: alice` but `auth_key: someone_else:pass`) | Make the rule's username match the `impersonator` pattern | -| Impersonator authenticates fine, but the request is still denied, mentioning the impersonated user doesn't exist | Denied; `AUTH_FAIL (Impersonated user does not exist)` in the logs | **No** block could confirm the target user: they aren't statically configured in any block and aren't present in the relevant service mock. Note that this message is logged by every block whose authentication rule doesn't know the impersonated user, so seeing it in a healthy setup is normal - it's a problem only when no block ends up matching | Add the user to the mock, or confirm the username matches exactly | -| Request denied with "impersonation not supported", even though the `impersonation` section looks correct | Impersonation not supported | An ACL block needs a service mock (LDAP / external authentication / external authorization) that hasn't been configured yet, or uses `auth_key_sha*` with a fully-hashed `user:pass` blob (see [limitations](#impersonation-limitations)) | Add the missing mock, or switch to the `USER_NAME:hash(PASSWORD)` form for hashed auth rules | -| The block you wanted to test is never matched during impersonation, and it uses `jwt_auth` or `ror_kbn_auth` | No impersonation-specific error - the block just doesn't match | These rules don't take part in the impersonation flow: they look for a real JWT / ROR Kibana token in the request, don't find one, and reject the block. ROR reports it as a Test Settings warning | Not impersonable today - test such blocks with a real session, or authenticate the users with an impersonation-aware rule | -| Impersonation UI can't find/list the user you want to impersonate | N/A (UI limitation) | The target username is only reachable through a wildcard `users` pattern in the ACL, so ROR can't enumerate it upfront | Type the username manually in the impersonation UI, as described in [limitations](#impersonation-limitations) | -| Impersonation is refused for every target user, although the `impersonation` entry looks correct and the same credentials work elsewhere | Impersonation not allowed | The impersonating client didn't send the impersonator's credentials as an HTTP Basic Auth header - ROR always identifies the impersonator from Basic Auth, regardless of which rule type is configured as the `authentication_rule` | Make sure the client authenticates with Basic Auth (this is what the ROR Kibana Test Settings UI does under the hood) | +Most impersonation problems are caused by one of the misconfigurations below. The "What ROR reports" column shows what you typically see in Kibana, in the Elasticsearch response or in the ROR logs. + +| Symptom | What ROR reports | Cause | Fix | +|---------|------------------|-------|-----| +| Impersonation worked earlier, but now every impersonation request fails, and the settings haven't changed | Kibana reports that no Test Settings are configured | The Test Settings expired (after 30 minutes by default) or were invalidated | Apply the Test Settings again, optionally with a longer expiration time | +| The impersonator can log into Kibana, but impersonation is refused | Impersonation not allowed | There is no `impersonation` entry for this user. Being authenticated in `access_control_rules` doesn't give the right to impersonate | Add an `impersonation` entry whose `impersonator` pattern matches the user | +| Impersonation works for some users but not for others | Impersonation not allowed | The first `impersonation` entry that matches the impersonator doesn't include the requested user in `users`. ROR ignores later entries for the same impersonator | Add the user to `users` in that first matching entry. Adding a new entry below it won't help | +| Impersonation stopped working after the impersonator's password changed, but normal login still works | Impersonation not allowed | The authentication rule in the `impersonation` entry is separate from the one in `access_control_rules`. Changing one doesn't change the other | Update both, or use the same external source (LDAP or external authentication) in both instead of hardcoded credentials | +| The settings fail to load with "should be either impersonator or a user to be impersonated" | Settings validation error | The same username (without wildcards) is in both `impersonator` and `users` of one entry | Remove the username from one of them. Users can't impersonate themselves | +| The settings fail to load with "it's used in a context of user patterns" | Settings validation error | The authentication rule of an `impersonation` entry has a fixed username that doesn't match the `impersonator` pattern, for example `impersonator: alice` with `auth_key: someone_else:pass` | Change the username in the rule so that it matches the `impersonator` pattern | +| The impersonator is authenticated, but the request is refused because the impersonated user doesn't exist | `AUTH_FAIL (Impersonated user does not exist)` in the logs | No block knows the user: they aren't defined in any block and aren't in the mock. Blocks that don't know the user always log this message, so it's a problem only if no block matches | Add the user to the mock, or check the spelling of the username | +| The request is refused as not supported, although the `impersonation` section looks correct | Impersonation not supported | A block uses LDAP, external authentication or external authorization without a mock, or an `auth_key_sha*` rule in the `hash(USER_NAME:PASSWORD)` form (see [limitations](#impersonation-limitations)) | Add the missing mock, or use the `USER_NAME:hash(PASSWORD)` form | +| A block that uses `jwt_auth` or `ror_kbn_auth` never matches during impersonation | No impersonation error, the block just doesn't match | These rules don't support impersonation. They look for a JWT or ROR Kibana token, don't find one, and fail. ROR shows a Test Settings warning for such blocks | Test these blocks in a real user session, or use a rule that supports impersonation | +| The user you want to impersonate isn't on the list in Kibana | None (UI limitation) | The user matches only a wildcard pattern in the `users` section, so ROR can't list them | Type the username manually (see [limitations](#impersonation-limitations)) | +| Impersonation is refused for every user, although the `impersonation` entry looks correct and the credentials work elsewhere | Impersonation not allowed | ROR identifies the impersonator only by HTTP Basic Auth credentials, whatever rule the `impersonation` entry uses. Credentials sent in any other form don't match any entry | Make sure the impersonator authenticates with a username and password (HTTP Basic Auth) | ## Logs & audit -In Elasticsearch logs, in `USR` field, if an admin user finds something like this: `alice (as bob)` - it means that `alice` was authenticated, and they are the impersonator who is impersonating `bob`. +In the Elasticsearch logs, a `USR` field value such as `alice (as bob)` means that `alice` was authenticated and is impersonating `bob`. -All logs of impersonated user in Kibana will have this format `[][plugins][ReadonlyREST][][impersonating ]` +In Kibana, all logs of the impersonated user have this format: `[][plugins][ReadonlyREST][][impersonating ]` -When auditing is enabled, the audit document is going to contain an `impersonated_by` field. +When audit is enabled, the audit document contains an `impersonated_by` field. ## Impersonation limitations -Impersonation mode has some limitations. Please check if they have an impact on your use cases: +Check whether these limitations affect your use cases: -* Not all features available in the ROR configuration are testable with impersonation mode. Some rules used in ROR ACL do not support impersonation. For example, auth rule with hashed credentials (e.g. `auth_key_sha512`) can be used in impersonation mode only when credentials follow the format `USER_NAME: HASH(PASSWORD)`; A fully hashed username and password don't allow fetching a username. The auth rule in such a format won't match during impersonation. In the [rules description](../../elasticsearch.md#rules) section you can find information about each rules impersonation support. -* Test Settings are stored in the memory of the node that handled the saving request sent by ROR Kibana plugin. Impersonation support will be limited to this node. We are going to improve it in the future, but for now your Kibana should only communicate with one Elasticsearch node. -* Sometimes it is impossible to fetch usernames defined in the Test Settings. If a `users` rule contains a username pattern with a wildcard, to impersonate a user matching the pattern, you need to enter the username manually. +* Not everything in the ROR settings can be tested with impersonation, because some rules don't support it. For example, a rule with hashed credentials (such as `auth_key_sha512`) works during impersonation only in the `USER_NAME:HASH(PASSWORD)` form. If the username and password are hashed together, ROR can't read the username, and the rule won't match during impersonation. The [rules description](../../elasticsearch.md#rules) says which rules support impersonation. +* Test Settings are stored in the memory of the Elasticsearch node that received the save request from the ROR Kibana plugin, so impersonation works only on that node. For now, Kibana should communicate with only one Elasticsearch node. We plan to improve this in the future. +* ROR can't always list the users defined in Test Settings. If the `users` section contains a username pattern with a wildcard, you have to type the username of a user that matches the pattern manually. ```yaml readonlyrest: @@ -308,7 +298,7 @@ Impersonation mode has some limitations. Please check if they have an impact on groups_any_of: ["g1"] users: - - username: "admin*" // To impersonate a user with a username matching 'admin*' you need to enter the username manually, like 'admin123' + - username: "admin*" # to impersonate a user matching 'admin*', type the username manually, for example 'admin123' groups: - g1: group1 ldap_auth: @@ -325,9 +315,9 @@ Impersonation mode has some limitations. Please check if they have an impact on ## Glossary -* **Impersonator** - someone who imitates or copies the behavior or actions of another, -* **Impersonation** - imitating behaviors or actions of a given user, -* **Impersonated user** - the identity being borrowed for the duration of an impersonation session; their permissions/data determine what the impersonator sees, but their own credentials are never needed or checked, -* **Main Settings** - the ROR's settings that apply to ACL that handles requests during regular sessions (not the impersonation ones), -* **Test Settings** - the ROR's settings that apply to ACL that handles impersonating requests (the ones during impersonation session), -* **External Service Mock** - an imitation of an external service (the supported ones: LDAP, an external authentication service, an external authorization service). +* **Impersonator** - a user who acts as another user. +* **Impersonation** - acting as another user. +* **Impersonated user** - the user whose identity is used during an impersonation session. Their permissions decide what the impersonator sees, but their credentials are never needed. +* **Main Settings** - the ROR settings with the ACL that handles regular requests. +* **Test Settings** - the ROR settings with the ACL that handles impersonation requests. +* **External Service Mock** - an imitation of an external service. Mocks are supported for LDAP, external authentication services and external authorization services. diff --git a/kibana.md b/kibana.md index 20af5a5..23e49a7 100644 --- a/kibana.md +++ b/kibana.md @@ -1158,13 +1158,7 @@ readonlyrest_kbn.auth: ### Impersonation -According to [Wikipedia](https://en.wikipedia.org/wiki/Impersonator): - -> An impersonator is someone who imitates or copies the behavior or actions of another. - -So, an impersonation can be understood as imitating behaviors or actions. In the context of ReadonlyREST: one user could imitate an action of another user. Why would we want it? Let's suppose the first user is an admin, who has just configured access for a new user. They would like to know if the rule(s) are configured correctly. And here comes the impersonation feature. The admin can impersonate the given user in Kibana and see what the user would see if they logged in themselves. - -The ROR Kibana plugin drives the whole workflow, from preparing a safe copy of the settings to switching in and out of an impersonation session. See the [impersonation guide](examples/impersonation/README.md) for how to use and configure it. +Impersonation lets you use Kibana as another user, so you can check what that user can see and do. The [impersonation guide](examples/impersonation/README.md) explains how to configure and use it. ## Multi-tenancy