LDAP multitenancy with no group name to index name relation

Hello,
this question is not related to any particular version of RoR or ES, so i omitted their versions.
Let’s assume the following situation:
We have a user usr1 who is a member of AD/LDAP groups grp1 and grp2, then we have a user usr2 that is a member of group grp2.
grp1 should have permissions to indices matching pattern ix-a*, grp2 should have permissions to indices matching ix-b* pattern (names of indices do not correspond in any way with the names of users or groups).
Since usr1 is a member of both groups grp1 and grp2, he should have permissions to indices matching patterns ix-a* and ix-b* while usr2 should have permissions only for indices matching ix-b* pattern.
It should be somehow possible to achieve it using external to local groups mapping and dynamic variables but I was not successful to make it work.
Please, any ideas how to achieve it?
Also we have multitenancy in Kibana (i.e. the possibility to change tenancy) and based on a chosen tenant we can see indices the specific tenant has permissions for. Does it have any REST counterpart, I mean can we specify/change a tenant in a REST call?
Best regards,
Pavel

Hi @pavelp

I will try to create a ROR sandbox-based PoC with this use case.
Please, give me a day or two.

Thanks a lot, I’m looking forward to seeing what you’ll come up with :slight_smile: .

Hi @pavelp

The example is ready: [Example] LDAP multitenancy with no group name to index name relation by coutoPL · Pull Request #64 · beshu-tech/ror-sandbox · GitHub
In the PR you have description how to run it. Also there, I show how to call ES directly with picked tenancy ID (you have to use id, not human readable name shown in the tenancy selector).

If you have any questions, please let me know :slight_smile:

Hi Mateusz,
thank you very much for the PoC, I have the sandbox up and running (it was surprisingly smooth, i just had to adjust permissions for ./ldap/data folder). I need some time to fully “digest” how it works and fully test it in our company environment.
Also thank you very much for mentioning the (afaik undocumented) x-ror-current-group header, that helps a lot, however it will need some more testing as well.
I’ll come back as soon as I have some results.
Best regards,
Pavel

Hi Mateusz,
I might be missing something but sadly I’m not getting exactly what we need.
RoR config is as follows (I did not edit the yaml you provided me with at all):

  - username: "*"
    groups:
      - local_group:
          id: "group_a"
          name: "Group A"
        external_group_ids: [ "grp1" ]
      - local_group:
          id: "group_b"
          name: "Group B"
        external_group_ids: [ "grp2" ]

I defined usr1 (LDAP membership grp1 and grp2) and usr2 (LDAP membership grp2) and there are 4 indices:

yellow open ix_a002 ijfCWsfiQGyZjAHIbhH6MQ 1 1 200 0 52.4kb 52.4kb 52.4kb
yellow open ix_a001 1rCcsOtZTZqdzRz0RoQoWA 1 1 200 0 45.9kb 45.9kb 45.9kb
yellow open ix_b002 aEsB399nT36MiKnE-yXpqw 1 1 120 0 74.7kb 74.7kb 74.7kb
yellow open ix_b001 CK8aexx0TEqENFbhlhl4Zw 1 1 100 0   59kb   59kb   59kb

With the x-ror-current-group header specified, I’m getting results as expected:

  1. for grp_a
curl -k -u usr1:pwd -XGET -H "x-ror-current-group: group_a" "https://localhost:19200/_cat/indices"
yellow open ix_a002 ijfCWsfiQGyZjAHIbhH6MQ 1 1 200 0 52.4kb 52.4kb 52.4kb
yellow open ix_a001 1rCcsOtZTZqdzRz0RoQoWA 1 1 200 0 45.9kb 45.9kb 45.9kb
  1. for grp_b
curl -k -u usr1:usr111111 -XGET -H "x-ror-current-group: group_b" "https://localhost:19200/_cat/indices"
yellow open ix_b001 CK8aexx0TEqENFbhlhl4Zw 1 1 100 0   59kb   59kb   59kb
yellow open ix_b002 aEsB399nT36MiKnE-yXpqw 1 1 120 0 74.7kb 74.7kb 74.7kb
  1. without the header
curl -k -u usr1:pwd -XGET  "https://localhost:19200/_cat/indices"
yellow open ix_b001 CK8aexx0TEqENFbhlhl4Zw 1 1 100 0   59kb   59kb   59kb
yellow open ix_b002 aEsB399nT36MiKnE-yXpqw 1 1 120 0 74.7kb 74.7kb 74.7kb

So with the header specified I’m getting (more or less) what I want but without the header I would expect getting all 4 indices but getting only ix_b001 and ix_b002 (also it’s not obvious which group RoR “chooses” as current group).
Another drawback is that the local group needs to be specified in the REST call (not the AD/LDAP group), so we can not recommend using the header even as a workaround because we would have to provide our users with our local mapping “alias”, which is kinda unacceptable.
So please, is there any way that the usr1 can get all 4 indices without the header specified and with the LDAP (not local-mapping) group specified in a header just the part related to the particular group?
Thanks a lot
Pavel

@pavelp

TBH x-ror-current-group is an internal API - it’s used by ROR KBN plugin. Thats why it’s not documented.

But it seems you can use your own header in the same way.

About the issue: when no x-ror-current-group is passed, ROR ES picks one of the available groups and makes it the current group. I hope that explains the behaviour you saw.

TBH it was a tricky thing to do, but I improved the ACL to meet your business requirements. Please take a look (see the updated Github PR) and tell me if it’s clear or you want me to explain it. If you want, I can also show you how to use a custom header to pass the info about tenancy/group instead of relying on ROR internal API.

let me know what you think

Hi Mateusz,
thank you very much for the update, it looks so far that you nailed it this time :slight_smile: . I’m gonna do some more testing (so far I tested it only on my local playground) however I have a feeling that this is exactly what we were looking for. Only one thing makes me slightly confused, if the kibana setting is “ro”, I cannot execute any REST calls in Dev Tools. Could you please confirm that this is the intended behaviour (RoR documentation is not so clear)?
I think I understand what you mean with a custom header (haven’t tested it yet though but I believe I can use it with the headers_or key the same way you used it in the sample config).
Regards,
Pavel

one thing makes me slightly confused, if the kibana setting is “ro”, I cannot execute any REST calls in Dev Tools. Could you please confirm that this is the intended behaviour (RoR documentation is not so clear)?

I’ve just tested ES 8.8.0 and 8.17.2. And for the second one, I don’t see the “run” button in the Dev Tools (for the first one everything is ok). We are checking what’s the problem. You (as a RO user) should be able to use Dev Tools.

I think I understand what you mean with a custom header (haven’t tested it yet though but I believe I can use it with the headers_or key the same way you used it in the sample config).

Yes, correct. You will probably need also the header dynamic variable to extract the header value in the ACL.

I’ve just realised that we should also have a dynamic variable for the query parameters and query_params rule. Once we have that, we could do the same at the HTTP request query parameter level.

Hi Mateusz,
it took a while to wrap my head around it but I think I even simplified the config as I’m directly mapping available external groups to local groups = permitted index patterns and since there is no replacement, it should be slightly more efficient as well (I took just the relevant parts of the config file).

readonlyrest:
  ssl:
    enable: true
    keystore_file: "ror-keystore.jks"
    keystore_pass: readonlyrest
    key_pass: readonlyrest

  access_control_rules:

    - name: "My users (no tenancy picked)"
      groups_or: [ "*" ]
      headers_or: [ "~x-ror-current-group:*" ]
      #original @explode
      #indices: [ 'ix_@explode{acl:available_groups}#{replace_all("group_", "")}*' ]
      indices: [ '@explode{acl:available_groups}' ]
      kibana:
        access: ro

  users:
  
  - username: "*"
    groups:
      - local_group:
          id: "ix_a*"
          name: "Group A"
        external_group_ids: [ "grp1" ]
      - local_group:
          id: "ix_b*"
          name: "Group B"
        external_group_ids: [ "grp2" ]
    ldap_auth: 
      name: "ldap1"
      groups: [ "*" ]

  ldaps:

So far it does exactly what it’s supposed to do but I might be missing some (obvious) gotchas. Audit log looks like this

KIBANA-> RULES:[auth_key->false] RESOLVED:[indices=*]], [Admins-> RULES:[groups_or->false] RESOLVED:[indices=*]], [My users (tenancy picked)-> RULES:[groups_or->false] RESOLVED:[indices=*]], [My users (no tenancy picked)-> RULES:[groups_or->true, kibana->true, headers_or->true, indices->true] RESOLVED:[user=usr1;group=ix_b*;av_groups=ix_b*, ix_a*;indices=ix_b002, ix_b001, ix_a002, ix_a001;kibana_idx=.kibana]]

so in my opinion it should be OK, however I’d like to make sure that I’m not missig something.
Regards,
Pavel

Pavel, if this is a complete ACL, it doesn’t work exactly like the one in the example I created.

First of all request like this:

 curl -k -u usr1:password -XGET -H "x-ror-current-group: ix_a*" "https://localhost:19200/_cat/indices"

won’t be matched.

Secondly, you won’t be able to log in using Kibana.

Maybe, this is what you want, but I thought the requirements were different.

We’ve confirmed it’s a bug (affected versions KBN 8.15+). We are working on the fix. It should be a part of the ROR 1.63.0 release.

ROR 1.63.0 with the fix is released

Thank you very much :slight_smile:

1 Like