No permissions for user

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

Describe the issue:
I have an error indicating that the user “client1” does not have the necessary permissions to perform the “indices:data/read/search” action in OpenSearch. The user is associated with the “client1_role” backend role.

Configuration:
here’s my opensearch.yml file :
plugins.security.disabled: “false”

plugins.security.ssl.transport.pemcert_filepath: node1.pem
plugins.security.ssl.transport.pemkey_filepath: node1-key.pem
plugins.security.ssl.transport.pemtrustedcas_filepath: root-ca.pem
plugins.security.ssl.transport.enforce_hostname_verification: false
plugins.security.ssl.http.enabled: false
plugins.security.ssl.http.pemcert_filepath: node1.pem
plugins.security.ssl.http.pemkey_filepath: node1-key.pem
plugins.security.ssl.http.pemtrustedcas_filepath: root-ca.pem
plugins.security.authcz.admin_dn:

  • ‘CN=A,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA’
    plugins.security.nodes_dn:
  • ‘CN=node1.dns.a-record,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA’
  • ‘CN=node2.dns.a-record,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA’

plugins.security.restapi.roles_enabled: [“all_access”, “security_rest_api_access”, “client1_role”]

And here’s my opensearch_dashboards.yml file
opensearch.hosts: [“http://localhost:9200”]
opensearch.ssl.verificationMode: none
opensearch.username: “admin”
opensearch.password: “admin”
#opensearch.requestHeadersAllowlist: [ authorization,securitytenant ]
server.ssl.enabled: false
#server.ssl.certificate: “path/to///client.pem”
#server.ssl.key: “path/to/client-key.pem”
#opensearch.ssl.certificateAuthorities: [“path/to/root-ca.pem”]
opensearch_security.multitenancy.enabled: true
opensearch_security.multitenancy.tenants.preferred: [“Private”, “Global”]
opensearch_security.readonly_mode.roles: [“kibana_read_only”]
opensearch_security.cookie.secure: false

Relevant Logs or Screenshots:

log [13:22:01.337] [error][plugins][securityDashboards] StatusCodeError: Authorization Exception
at respond (C:\Users\w133790\dashboard\opensearch-dashboards-2.7.0\node_modules\elasticsearch\src\lib\transport.js:349:15)
at checkRespForFailure (C:\Users\w133790\dashboard\opensearch-dashboards-2.7.0\node_modules\elasticsearch\src\lib\transport.js:306:7)
at HttpConnector. (C:\Users\w133790\dashboard\opensearch-dashboards-2.7.0\node_modules\elasticsearch\src\lib\connectors\http.js:173:7)
at IncomingMessage.wrapper (C:\Users\w133790\dashboard\opensearch-dashboards-2.7.0\node_modules\lodash\lodash.js:4991:19)
at IncomingMessage.emit (events.js:412:35)
at IncomingMessage.emit (domain.js:475:12)
at endReadableNT (internal/streams/readable.js:1333:12)
at processTicksAndRejections (internal/process/task_queues.js:82:21) {
status: 403,
displayName: ‘AuthorizationException’,
path: ‘/_plugins/_security/tenantinfo’,
query: {},
body: undefined,
statusCode: 403,
response: ‘’,
toString: [Function (anonymous)],
toJSON: [Function (anonymous)]
}
log [13:22:01.344] [warning][environment] Detected an unhandled Promise rejection.
Authorization Exception :: {“path”:“/_plugins/_security/tenantinfo”,“query”:{},“statusCode”:403,“response”:“”}
log [13:22:01.346] [info][server][OpenSearchDashboards][http] http server running at http://localhost:5601

…(then when i login with the client user i get this)

log [13:22:35.489] [error][data][opensearch] [security_exception]: no permissions for [indices:data/read/search] and User [name=client1, backend_roles=[client1_role], requestedTenant=null]

@zakaria Please share corresponding entries from roles.yml and roles_mapping.yml.

Also, please share the config.yml file content.

here’s roles.yml : (the part when i define the client user)

client1_role:
  cluster_permissions:
    - "cluster_monitor"
    - "cluster:admin/opensearch/observability/get"
    - "cluster_composite_ops"
  index_permissions:
    - index_patterns:
        - "filebeat-*"
      allowed_actions:
        - "read"
        - "indices:data/read/get"
        - "indices:data/read/search"
      dls: '{"term": {"type": "getSession"}}'
  tenant_permissions:
    - tenant_patterns:
        - "client1_tenant"
      allowed_actions:
        - "kibana_all_write"

And here’s roles_mapping.yml :

# Define your roles mapping here

client1_role:
  reserved: false
  backend_roles:
    - "client1_role"
  users:
    - "client1"  
  description: "Maps client1_role backend role to client1_role OpenSearch role"

and here’s config.yml file :

---

# 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:
    # 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: true
    kibana:
    # Kibana multitenancy
    #multitenancy_enabled: true
    #private_tenant_enabled: true
    #default_tenant: ""
    #server_username: kibanaserver
    #index: '.kibana'
    http:
      anonymous_auth_enabled: false
      xff:
        enabled: false
        internalProxies: '192\.168\.0\.10|192\.168\.0\.11' # regex pattern
        #internalProxies: '.*' # trust all internal proxies, regex pattern
        #remoteIpHeader:  'x-forwarded-for'
        ###### see https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html for regex help
        ###### more information about XFF https://en.wikipedia.org/wiki/X-Forwarded-For
        ###### and here https://tools.ietf.org/html/rfc7239
        ###### and https://tomcat.apache.org/tomcat-8.0-doc/config/valve.html#Remote_IP_Valve
    authc:
      kerberos_auth_domain:
        http_enabled: false
        transport_enabled: false
        order: 6
        http_authenticator:
          type: kerberos
          challenge: true
          config:
            # If true a lot of kerberos/security related debugging output will be logged to standard out
            krb_debug: false
            # If true then the realm will be stripped from the user name
            strip_realm_from_principal: true
        authentication_backend:
          type: noop
      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
      proxy_auth_domain:
        description: "Authenticate via proxy"
        http_enabled: false
        transport_enabled: false
        order: 3
        http_authenticator:
          type: proxy
          challenge: false
          config:
            user_header: "x-proxy-user"
            roles_header: "x-proxy-roles"
        authentication_backend:
          type: noop
      jwt_auth_domain:
        description: "Authenticate via Json Web Token"
        http_enabled: false
        transport_enabled: false
        order: 0
        http_authenticator:
          type: jwt
          challenge: false
          config:
            signing_key: "base64 encoded HMAC key or public RSA/ECDSA pem key"
            jwt_header: "Authorization"
            jwt_url_parameter: null
            jwt_clock_skew_tolerance_seconds: 30
            roles_key: null
            subject_key: null
        authentication_backend:
          type: noop
      clientcert_auth_domain:
        description: "Authenticate via SSL client certificates"
        http_enabled: false
        transport_enabled: false
        order: 2
        http_authenticator:
          type: clientcert
          config:
            username_attribute: cn #optional, if omitted DN becomes username
          challenge: false
        authentication_backend:
          type: noop
      ldap:
        description: "Authenticate via LDAP or Active Directory"
        http_enabled: false
        transport_enabled: false
        order: 5
        http_authenticator:
          type: basic
          challenge: false
        authentication_backend:
          # LDAP authentication backend (authenticate users against a LDAP or Active Directory)
          type: ldap
          config:
            # enable ldaps
            enable_ssl: false
            # enable start tls, enable_ssl should be false
            enable_start_tls: false
            # send client certificate
            enable_ssl_client_auth: false
            # verify ldap hostname
            verify_hostnames: true
            hosts:
            - localhost:8389
            bind_dn: null
            password: null
            userbase: 'ou=people,dc=example,dc=com'
            # Filter to search for users (currently in the whole subtree beneath userbase)
            # {0} is substituted with the username
            usersearch: '(sAMAccountName={0})'
            # Use this attribute from the user as username (if not set then DN is used)
            username_attribute: null
    authz:
      roles_from_myldap:
        description: "Authorize via LDAP or Active Directory"
        http_enabled: false
        transport_enabled: false
        authorization_backend:
          # LDAP authorization backend (gather roles from a LDAP or Active Directory, you have to configure the above LDAP authentication backend settings too)
          type: ldap
          config:
            # enable ldaps
            enable_ssl: false
            # enable start tls, enable_ssl should be false
            enable_start_tls: false
            # send client certificate
            enable_ssl_client_auth: false
            # verify ldap hostname
            verify_hostnames: true
            hosts:
            - localhost:8389
            bind_dn: null
            password: null
            rolebase: 'ou=groups,dc=example,dc=com'
            # Filter to search for roles (currently in the whole subtree beneath rolebase)
            # {0} is substituted with the DN of the user
            # {1} is substituted with the username
            # {2} is substituted with an attribute value from user's directory entry, of the authenticated user. Use userroleattribute to specify the name of the attribute
            rolesearch: '(member={0})'
            # Specify the name of the attribute which value should be substituted with {2} above
            userroleattribute: null
            # Roles as an attribute of the user entry
            userrolename: disabled
            #userrolename: memberOf
            # The attribute in a role entry containing the name of that role, Default is "name".
            # Can also be "dn" to use the full DN as rolename.
            rolename: cn
            # Resolve nested roles transitive (roles which are members of other roles and so on ...)
            resolve_nested_roles: true
            userbase: 'ou=people,dc=example,dc=com'
            # Filter to search for users (currently in the whole subtree beneath userbase)
            # {0} is substituted with the username
            usersearch: '(uid={0})'
            # Skip users matching a user name, a wildcard or a regex pattern
            #skip_users:
            #  - 'cn=Michael Jackson,ou*people,o=TEST'
            #  - '/\S*/'
      roles_from_another_ldap:
        description: "Authorize via another Active Directory"
        http_enabled: false
        transport_enabled: false
        authorization_backend:
          type: ldap
          #config goes here ...
  #    auth_failure_listeners:
  #      ip_rate_limiting:
  #        type: ip
  #        allowed_tries: 10
  #        time_window_seconds: 3600
  #        block_expiry_seconds: 600
  #        max_blocked_clients: 100000
  #        max_tracked_clients: 100000
  #      internal_authentication_backend_limiting:
  #        type: username
  #        authentication_backend: intern
  #        allowed_tries: 10
  #        time_window_seconds: 3600
  #        block_expiry_seconds: 600
  #        max_blocked_clients: 100000
  #        max_tracked_clients: 100000

Please let me know if you need any other configuration file, i can provide
Thank you

@zakaria What action did you perform when you got this message?

When i log in with the client1 user, i get this error

 log   [13:59:28.113] [error][data][opensearch] [security_exception]: no permissions for [indices:data/read/search] and User [name=client1, backend_roles=[client1_role], requestedTenant=null]

And also when i try to visualize the dashboard i get the same error in the terminal, and when i go to Discover the page is blank so i can’t really see my logs. I defined the permissions in the configuration file but it still says that i have no permissions.

PS : with the admin account i can see the logs.

@zakaria Do you get the same error when you remove dls from the role?

Do you see .kibana_<ID>_client1tenant_1 index in your OpenSearch cluster?

GET _cat/indices

I just tried, and i still have the same error

@zakaria I’ve noticed in your log the following information.

 User [name=client1, backend_roles=[client1_role], 

According to your config.yml, you are using basicauth as an authentication domain. Also in your roles_mapping.yml, you’ve configured client1_role as the backend role.

The user client1 is an internal user. For internal users roles are not mapped as backend roles.
Instead, you should assign the user directly to the role.

client1_role:
  hosts: []
  users:
  - "client1"
  reserved: false
  hidden: false
  backend_roles: []
  and_backend_roles: []

The backend_roles are reserved for external IdP authentication i.e. LDAP, SAML, OpenID etc.

1 Like

@zakaria Did you select the correct tenant after logging into OpenSearch Dashboards?

image

Do you see .kibana_<ID>_client1tenant_1 index in your OpenSearch cluster?

GET _cat/indices
1 Like

No @pablo , I could not select the client1_tenant because i can’t select nothing at all when i log in with the client1 user. It says that I have an Authorization Exception so i can’t switch tenants or add a dashboard or visualize a saved one.

Is this normal even if i’m using basicauth? If not, how can i resolve this problem, please ?

Thank you very much :slight_smile:

@pablo and yes i do see .kibana_<ID>_client1tenant_1 index in my opensearch cluster :

green open .kibana_1408398659_client1tenant_1

@zakaria Could you share a screenshot of the OpenSearch Dashboards UI after login?
Did you upload the configuration to the cluster with securityadmin.sh once you’ve updated the yaml files?

@pablo First, when i run the dashboard in the terminal i get this error, but i can login with the admin account :

 log   [12:16:20.524] [error][plugins][securityDashboards] StatusCodeError: Authorization Exception
    at respond (C:\Users\dashboard\opensearch-dashboards-2.7.0\node_modules\elasticsearch\src\lib\transport.js:349:15)
    at checkRespForFailure (C:\Users\dashboard\opensearch-dashboards-2.7.0\node_modules\elasticsearch\src\lib\transport.js:306:7)
    at HttpConnector.<anonymous> (C:\Users\dashboard\opensearch-dashboards-2.7.0\node_modules\elasticsearch\src\lib\connectors\http.js:173:7)
    at IncomingMessage.wrapper (C:\Users\dashboard\opensearch-dashboards-2.7.0\node_modules\lodash\lodash.js:4991:19)
    at IncomingMessage.emit (events.js:412:35)
    at IncomingMessage.emit (domain.js:475:12)
    at endReadableNT (internal/streams/readable.js:1333:12)
    at processTicksAndRejections (internal/process/task_queues.js:82:21) {
  status: 403,
  displayName: 'AuthorizationException',
  path: '/_plugins/_security/tenantinfo',
  query: {},
  body: undefined,
  statusCode: 403,
  response: '',
  toString: [Function (anonymous)],
  toJSON: [Function (anonymous)]
}
  log   [12:16:20.542] [warning][environment] Detected an unhandled Promise rejection.
Authorization Exception :: {"path":"/_plugins/_security/tenantinfo","query":{},"statusCode":403,"response":""}
  log   [12:16:20.629] [info][listening] Server running at http://localhost:5601
  log   [12:16:20.799] [info][server][OpenSearchDashboards][http] http server running at http://localhost:5601

Then, when i login with the client1 account, i get this on the terminal :

 log   [12:18:24.688] [error][data][opensearch] [security_exception]: no permissions for [indices:data/read/get] and User [name=client1, backend_roles=[client1_role], requestedTenant=null]
  log   [12:18:24.708] [error][data][opensearch] [security_exception]: no permissions for [indices:data/read/get] and User [name=client1, backend_roles=[client1_role], requestedTenant=null]
  log   [12:18:24.784] [error][data][opensearch] [security_exception]: no permissions for [indices:data/read/get] and User [name=client1, backend_roles=[client1_role], requestedTenant=null]
  log   [12:18:24.789] [error][data][opensearch] [security_exception]: no permissions for [indices:data/read/get] and User [name=client1, backend_roles=[client1_role], requestedTenant=null]
  log   [12:18:26.099] [error][data][opensearch] [security_exception]: no permissions for [indices:data/read/search] and User [name=client1, backend_roles=[client1_role], requestedTenant=null]

Also in the OpenSearch instance’s terminal i get this as error :

[2023-05-22T14:20:06,888][WARN ][o.o.s.c.PrivilegesInterceptorImpl] [] Tenant global_tenant is not allowed for user client1
[2023-05-22T14:21:17,484][INFO ][o.o.s.p.PrivilegesEvaluator] [] No index-level perm match for User [name=client1, backend_roles=[client1_role], requestedTenant=null] Resolved [aliases=[], allIndices=[opensearch_dashboards_sample_data_ecommerce], types=[*], originalRequested=[opensearch_dashboards_sample_data_ecommerce], remoteIndices=[]] [Action [indices:admin/get]] [RolesChecked [client1_role, own_index]]
[2023-05-22T14:21:17,485][INFO ][o.o.s.p.PrivilegesEvaluator] [] No permissions for [indices:admin/get]

And the OpenSearch Dashboards UI looks like this :

As you can see i can’t add data because of the authorization exception

Also i can’t choose my tenant, unlike when i login with the admin account.

@zakaria You still have client1 assigned to the backend role.

[name=client1, backend_roles=[client1_role], requestedTenant=null]

@zakaria Please run the following command and share the output.

curl --insecure -u client1:<password> -XGET https://<OpenSearch_FQDN_or_IP>:9200/_plugins/_security/authinfo?pretty

@pablo i did like you said in the roles_mapping.yml file :

---
# In this file users, backendroles and hosts can be mapped to Security roles.
# Permissions for OpenSearch roles are configured in roles.yml

_meta:
  type: "rolesmapping"
  config_version: 2

# Define your roles mapping here


client1_role:
  hosts: []
  users:
  - "client1"
  reserved: false
  hidden: false
  backend_roles: []
  and_backend_roles: []

## Demo roles mapping

all_access:
  reserved: false
  backend_roles:
  - "admin"
  description: "Maps admin to all_access"

own_index:
  reserved: false
  users:
  - "*"
  description: "Allow full access to an index named like the username"

logstash:
  reserved: false
  backend_roles:
  - "logstash"

kibana_user:
  reserved: false
  backend_roles:
  - "kibanauser"
  description: "Maps kibanauser to kibana_user"

readall:
  reserved: false
  backend_roles:
  - "readall"

manage_snapshots:
  reserved: false
  backend_roles:
  - "snapshotrestore"

kibana_server:
  reserved: true
  users:
  - "kibanaserver"

and i saved it by running the securityadmin.sh (but i always have to switch plugins.security.ssl.http.enabled to true in order to run the securityadmin script and then i put it back to false otherwise the opensearch doesn’t run correctly), but then i check in the dashboard and i see that the modifications are saved thanks to the security admin.

@pablo Here’s the output :

> curl.exe -X GET http://localhost:9200/_plugins/_security/authinfo?pretty -u "client1:client1" --insecure
{
  "user" : "User [name=client1, backend_roles=[client1_role], requestedTenant=null]",
  "user_name" : "client1",
  "user_requested_tenant" : null,
  "remote_address" : "127.0.0.1:53947",
  "backend_roles" : [
    "client1_role"
  ],
  "custom_attribute_names" : [ ],
  "roles" : [
    "client1_role",
    "own_index"
  ],
  "tenants" : {
    "client1" : true
  },
  "principal" : null,
  "peer_certificates" : "0",
  "sso_logout_url" : null
}

@pablo do i need to modify this as well ?? in the internal_users.yml file :

# Define your internal users here

client1:
  hash: "$2y$12$GJi/gfAiGw4/KBI0vWnZFO/MQBCoPhwnqmzSpTpmLa3azK41JOBQS"
  reserved: false
  backend_roles:
    - "client1_role"
  description: "User for client1 with access to getSession logs"