# Users unable to save items in private tenancy

**URL:** <https://forum.opensearch.org/t/users-unable-to-save-items-in-private-tenancy/26551>\
**Category:** Security\
**Created:** [August 29, 2025, 4:50am UTC](https://forum.opensearch.org/t/users-unable-to-save-items-in-private-tenancy/26551 "2025-08-29T04:50:03Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Evergreen1270](https://avatars.discourse-cdn.com/v4/letter/e/97f17d/32.png) [@Evergreen1270](https://forum.opensearch.org/u/Evergreen1270)\
**Post date:** [August 29, 2025, 4:50am UTC](https://forum.opensearch.org/t/users-unable-to-save-items-in-private-tenancy/26551/1 "2025-08-29T04:50:03Z")

</div>

**Versions** (relevant - OpenSearch/Dashboard/Server OS/Browser):

OpenSearch 3.2.0

Dashboard: 3.2.0

**Describe the issue** :

I have a Opensearch cluster that uses TLS authentication to authenticate Dashboards to OpenSearch, Users are authenticated via OpenID. I have enabled Multi tenancy and can see the private tenancy, however when I switch to the private tenant, and create an index / visualisation. It is saved to the global tenant instead of the private.

No index is created for each user

I have seen this post [Multitenancy - even with separated roles and tenants everything saved ends up in global - #9 by Anthony](https://forum.opensearch.org/t/multitenancy-even-with-separated-roles-and-tenants-everything-saved-ends-up-in-global/7143/9) however all of my values appear to have been updated, but it still isnt working.

Is anybody able to help troubleshoot this issue?

**Configuration** :

opensearch-dashboards.yml

> server:
> 
> name: os\_dashboards
> 
> host: “0.0.0.0”
> 
> basePath: “/search” #!!!This line only needed if using Nginx Reverse Proxy
> 
> rewriteBasePath: true #!!!This line only needed if using Nginx Reverse Proxy
> 
> opensearch:
> 
> requestHeadersAllowlist: [“securitytenant”, “Authorization”]
> 
> hosts:
> 
> ```auto
> - "https://os01:9200"
> 
> - "https://os02:9200"
> 
> - "https://os03:9200"
> 
> ```
> 
> ssl:
> 
> ```auto
> verificationMode: none
> 
> certificateAuthorities: \["/usr/share/opensearch-dashboards/config/certificates/ca/ca.pem"\]
> 
> certificate: "/usr/share/opensearch-dashboards/config/certificates/os-dashboards/os-dashboards.pem"
> 
> key: "/usr/share/opensearch-dashboards/config/certificates/os-dashboards/os-dashboards.key"
> 
> ```
> 
> #logging:
> 
> #dest: /usr/share/opensearch-dashboards/logs/opensearch\_dashboards.log
> 
> # Encrypt traffic between the browser and OpenSearch-Dashboards
> 
> server.ssl:
> 
> enabled: true
> 
> certificateAuthorities: [“/usr/share/opensearch-dashboards/config/certificates/ca/ca.pem”]
> 
> certificate: “/usr/share/opensearch-dashboards/config/certificates/os-dashboards/os-dashboards.pem”
> 
> key: “/usr/share/opensearch-dashboards/config/certificates/os-dashboards/os-dashboards.key”
> 
> #Enable Machine Learning Features
> 
> ml\_commons\_dashboards:
> 
> enabled: true
> 
> #Multi Tenancy Settings
> 
> opensearch\_security:
> 
> multitenancy:
> 
> ```auto
> enabled: true
> 
> tenants:
> 
> enable_global: true
> 
> enable_private: true
> 
> preferred: \["Private", "Global"\]
> 
> enable_filter: true
> 
> ```
> 
> readonly\_mode.roles: [“kibana\_read\_only”]
> 
> cookie:
> 
> ```auto
> secure: false
> 
> ```
> 
> allow\_client\_certificates: true
> 
> auth:
> 
> ```auto
> #type: \["basicauth", "openid"\]
> 
> #multiple_auth_enabled: true
> 
> type: "openid"
> 
> multiple_auth_enabled: false
> 
> ```
> 
> openid:
> 
> ```auto
> scope: "openid profile email"
> 
> client_id: ""
> 
> client_secret: ""
> 
> connect_url: "Auth URL"
> 
> base_redirect_url: "https://hostname/search/"
> 
> verify_hostnames: false
> 
> header: "Authorization"
> 
> ```

opensearch.yml

> cluster.name: opensearch-cluster
> 
> network.host: 0.0.0.0
> 
> bootstrap.memory\_lock: “true” # when combined with ulimits memlock settings, disables swapping.
> 
> cluster.routing.allocation.disk:
> 
> threshold\_enabled: true
> 
> watermark.low: 93%
> 
> watermark.high: 95%
> 
> discovery.seed\_hosts:
> 
> - ‘os01’
> 
> - ‘os02’
> 
> - ‘os03’
> 
> cluster.initial\_cluster\_manager\_nodes:
> 
> - ‘os01’
> 
> - ‘os02’
> 
> - ‘os03’
> 
> plugins.security:
> 
> # Uncomment the following two lines if you would like to store audit logs within OpenSearch.
> 
> # audit:
> 
> # type: internal\_opensearch
> 
> ssl:
> 
> ```auto
> http:
> 
> enabled: true
> 
> clientauth_mode: OPTIONAL #Could be OPTIONAL or REQUIRED
> 
> pemtrustedcas_filepath: certificates/ca/ca.pem
> 
> transport:
> 
> enabled: true
> 
> pemtrustedcas_filepath: certificates/ca/ca.pem
> 
> enforce_hostname_verification: false
> 
> ```
> 
> allow\_unsafe\_democertificates: false
> 
> allow\_default\_init\_securityindex: true
> 
> authcz.admin\_dn:
> 
> ```auto
> - 'CN=ADMIN'
> 
> ```
> 
> nodes\_dn:
> 
> ```auto
> - 'CN=os01'
> 
> - 'CN=os02'
> 
> - 'CN=os03,'
> 
> ```
> 
> restapi:
> 
> ```auto
> roles_enabled: \["all_access", "security_rest_api_access"\]
> 
> ```
> 
> system\_indices:
> 
> ```auto
> enabled: true
> 
> indices: \[".opendistro-alerting-config", ".opendistro-alerting-alert\*", ".opendistro-anomaly-results\*", ".opendistro-anomaly-detector\*", ".opendistro-anomaly-checkpoints", ".opendistro-anomaly-detection-state", ".opendistro-reports-\*", ".opendistro-notifications-\*", ".opendistro-notebooks", ".opendistro-asynchronous-search-response\*"\]
> 
> ```

config.yml

> -–
> 
> # This is the main OpenSearch Security configuration file where authentication
> 
> # and authorization is defined.
> 
> #
> 
> # You need to configure at least one authentication domain in the authc of this file.
> 
> # An authentication domain is responsible for extracting the user credentials from
> 
> # the request and for validating them against an authentication backend like Active Directory for example.
> 
> #
> 
> # If more than one authentication domain is configured the first one which succeeds wins.
> 
> # If all authentication domains fail then the request is unauthenticated.
> 
> # In this case an exception is thrown and/or the HTTP status is set to 401.
> 
> #
> 
> # After authentication authorization (authz) will be applied. There can be zero or more authorizers which collect
> 
> # the roles from a given backend for the authenticated user.
> 
> #
> 
> # Both, authc and auth can be enabled/disabled separately for REST and TRANSPORT layer. Default is true for both.
> 
> # http\_enabled: true
> 
> # transport\_enabled: true
> 
> #
> 
> # For HTTP it is possible to allow anonymous authentication. If that is the case then the HTTP authenticators try to
> 
> # find user credentials in the HTTP request. If credentials are found then the user gets regularly authenticated.
> 
> # If none can be found the user will be authenticated as an “anonymous” user. This user has always the username “anonymous”
> 
> # and one role named “anonymous\_backendrole”.
> 
> # If you enable anonymous authentication all HTTP authenticators will not challenge.
> 
> #
> 
> #
> 
> # Note: If you define more than one HTTP authenticators make sure to put non-challenging authenticators like “proxy” or “clientcert”
> 
> # first and the challenging one last.
> 
> # Because it’s not possible to challenge a client with two different authentication methods (for example
> 
> # Kerberos and Basic) only one can have the challenge flag set to true. You can cope with this situation
> 
> # by using pre-authentication, e.g. sending a HTTP Basic authentication header in the request.
> 
> #
> 
> # Default value of the challenge flag is true.
> 
> #
> 
> #
> 
> # HTTP
> 
> # basic (challenging)
> 
> # proxy (not challenging, needs xff)
> 
> # kerberos (challenging)
> 
> # clientcert (not challenging, needs https)
> 
> # jwt (not challenging)
> 
> # host (not challenging) #DEPRECATED, will be removed in a future version.
> 
> # host based authentication is configurable in roles\_mapping
> 
> # Authc
> 
> # internal
> 
> # noop
> 
> # ldap
> 
> # Authz
> 
> # ldap
> 
> # noop
> 
> \_meta:
> 
> type: “config”
> 
> config\_version: 2
> 
> config:
> 
> dynamic:
> 
> ```auto
> \# Set filtered_alias_mode to 'disallow' to forbid more than 2 filtered aliases per index
> 
> \# Set filtered_alias_mode to 'warn' to allow more than 2 filtered aliases per index but warns about it (default)
> 
> \# Set filtered_alias_mode to 'nowarn' to allow more than 2 filtered aliases per index silently
> 
> #filtered_alias_mode: warn
> 
> #do_not_fail_on_forbidden: false
> 
> kibana:
> 
> multitenancy_enabled: true
> 
> private_tenant_enabled: true
> 
> default_tenant: "Global"
> 
> server_username: os_dashboards
> 
> index: '.opensearch_dashboards'
> 
> authc:
> 
> basic_internal_auth_domain:
> 
> description: "Authenticate via HTTP Basic against internal users database"
> 
> http_enabled: true
> 
> transport_enabled: true
> 
> order: 4
> 
> http_authenticator:
> 
> type: basic
> 
> challenge: true
> 
> authentication_backend:
> 
> type: intern
> 
> clientcert_auth_domain:
> 
> description: "Authenticate via SSL client certificates"
> 
> http_enabled: true
> 
> transport_enabled: true
> 
> order: 2
> 
> http_authenticator:
> 
> type: clientcert
> 
> config:
> 
> username_attribute: cn #optional, if omitted DN becomes username
> 
> challenge: false
> 
> authentication_backend:
> 
> type: noop
> 
> openid_auth_domain:
> 
> http_enabled: true
> 
> transport_enabled: true
> 
> order: 1
> 
> http_authenticator:
> 
> type: openid
> 
> challenge: false
> 
> config:
> 
> subject_key: preferred_username
> 
> roles_key: groups
> 
> openid_connect_url: Auth URL
> 
> openid_connect_idp:
> 
> enable_ssl: false
> 
> verify_hostnames: false
> 
> authentication_backend:
> 
> type: noop
> 
> ```

roles\_mapping.yml

> \_meta:
> 
> type: “rolesmapping”
> 
> config\_version: 2
> 
> kibana\_server:
> 
> reserved: true
> 
> users:
> 
> ```auto
> - "os-dashboards"
> 
> ```

**Relevant Logs or Screenshots** :

---

<div class="post-metadata">

**Author:** ![sebastian-thorn](https://avatars.discourse-cdn.com/v4/letter/s/958977/32.png) [@sebastian-thorn](https://forum.opensearch.org/u/sebastian-thorn)\
**Post date:** [August 29, 2025, 7:43am UTC](https://forum.opensearch.org/t/users-unable-to-save-items-in-private-tenancy/26551/2 "2025-08-29T07:43:03Z")

</div>

Hi, when posting configurations, please use the code button and not the quote button.

Use yaml format in the dropdown.

 ![image](https://us1.discourse-cdn.com/flex019/uploads/mauve_hedgehog/original/2X/8/8549ee85afa537e61dd4660adf3240f97a716708.png)

That makes is possible to read your configuration.

```yaml
kibana_server:
  reserved: true
  users:
    - "os-dashboards"

```

Br Sebastian

---

<div class="post-metadata">

**Author:** ![Anthony](https://sea1.discourse-cdn.com/flex019/user_avatar/forum.opensearch.org/anthony/32/9939_2.png) [@Anthony](https://forum.opensearch.org/u/Anthony)\
**Post date:** [August 29, 2025, 9:22am UTC](https://forum.opensearch.org/t/users-unable-to-save-items-in-private-tenancy/26551/3 "2025-08-29T09:22:10Z")

</div>

@Evergreen1270 Its very difficult to read the above configuration blocks, as the indentation is incorrect. But in general, it would appear that opensearch\_dashboards is attempting to authenticate using certificate, however only openid is configured as possible authentication method. I would recommend to add [client\_auth](https://docs.opensearch.org/latest/security/authentication-backends/client-auth/#enabling-client-certificate-authentication) as secondary authentication method.

Can you then use curl with OSD certificate and key and check which role is assigned, using the following:

```auto
curl -k \
  --cert /path/client.crt \
  --key /path/client.key \
  --cacert /path/root-ca.pem \
  https://<opensearch>:9200/_plugins/_security/authinfo

```

A more thorough test would be to enable basic\_auth instead of openID/client\_auth, and test with basic authentication, to see if the issue persists. (using kibanaserver/kibanaserver as username/password for OSD)  
If this works, then add client\_auth, and then add openID and remove basic\_auth. This would indicate at which stage the issue is appearing.

---

<div class="post-metadata">

**Author:** ![Evergreen1270](https://avatars.discourse-cdn.com/v4/letter/e/97f17d/32.png) [@Evergreen1270](https://forum.opensearch.org/u/Evergreen1270)\
**Post date:** [August 30, 2025, 10:12pm UTC](https://forum.opensearch.org/t/users-unable-to-save-items-in-private-tenancy/26551/4 "2025-08-30T22:12:47Z")

</div>

I am sorry for the poor formatting. The code button doesnt appear for me in the menu.

I have managed to get this working. I made the following changes

In the config.yml for opensearch, updated the server\_username and index to be

> ```yaml
> server_username: os-dashboards  
> index: ".kibana"
> 
> ```

I also adjusted the order in which authentication is checked to have SSL auth first (Not sure if this made a difference)

Thanks for the tips, helped me better understand what is taking place under the hood which lead me in the right direction.
