DLS fails with dynamic variable ${user.attrs.tenant_id} but works with static values

Hello OpenSearch Community,

I’m trying to implement Document Level Security (DLS) using a tenant_id claim from our OIDC provider’s JWT, but I’ve run into a specific issue. The DLS works perfectly when I hardcode a value, but fails as soon as I try to use the dynamic variable.

My Goal:
A user logs in via OIDC. Their JWT contains a tenant_id claim. Their searches should be automatically filtered to only show documents matching their tenant_id.

What I’ve Done & Tested:

I have successfully configured OIDC login. I then created a DLS role with the following query.

This WORKS:
When I set the DLS query with a static value (e.g., 1), the security works as expected. The user can log in, view dashboards, and only sees data where the tenant_id_field is 1.

{
  "term": {
    "my_tenant_id_field.keyword": 1 
  }
}

This FAILS:
The problem occurs when I switch to the dynamic variable to fetch the tenant_id from the JWT.

{
  "term": {
    "my_tenant_id_field.keyword": "${user.attrs.tenant_id}"
  }
}

and

{
  "term": {
    "my_tenant_id_field.keyword": "${user.attrs.tenant_id}"
  }
}

The Error:
When I use the dynamic ${user.attrs.tenant_id} variable, the user can still log in, but when they try to view data in Discover or on a dashboard, they receive a “Bad Request” error from the UI. This leads me to believe the ${user.attrs.tenant_id} variable is either not being populated or is being populated with a value that breaks the query syntax.

My Configuration Steps:

1. config.yml (Redacted):
I’ve configured my OIDC domain to map the tenant_id claim from the JWT to a user attribute.

_meta:
  type: "config"
  config_version: 2

config:
  dynamic:
    http:
      anonymous_auth_enabled: false
    authc:
      oidc_auth_domain:
        description: "Authenticate via OIDC (OpenID Connect)"
        http_enabled: true
        transport_enabled: true
        order: 0
        http_authenticator:
          type: "openid"
          challenge: true
          config:
            subject_key: "preferred_username"
            roles_key: "roles"
            openid_connect_url: "##################"
            client_id: "#############"
            client_secret: "###########" 
            user_mapping.attr_json_path.tenant_id: tenant_id
        authentication_backend:
          type: "noop"
      basic_internal_auth_domain:
        description: "Authenticate via HTTP Basic against internal users database"
        http_enabled: true
        transport_enabled: true
        order: 1
        http_authenticator:
          type: "basic"
          challenge: false
        authentication_backend:
          type: "internal"

2. OpenSearch DLS Role:
I created a role in the Dashboards UI with the necessary cluster and index permissions, and the DLS query mentioned above.

3. Role Mapping:
I mapped this DLS role to a “Backend Role” that corresponds to a role claim present in my user’s JWT.

My Question:

Since the DLS works with a hardcoded value, my role permissions and mappings seem to be correct. The issue appears to be isolated to the dynamic variable substitution.

Could there be something wrong with my user_mapping.attr_json_path.tenant_id: tenant_id configuration, or is there another place I should be looking to debug why ${user.attrs.tenant_id} is not resolving correctly?

Any help would be greatly appreciated. Thank you

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.