K8s OD cluster. LDAP users can not download reports

Hi,
I have OD 1.13.2 deployed in a kubernettes cluster. All configs are done with configmaps and mounted in the pods upon boot. eg: roles.yml, roles_mapping.yml, etc
Users connect via LDAP which works just fine. My problem is that only the admin can download reports. Not sure if it is because of tenants, or if I am just not understanding the flow correctly. Below are my config files. Any help would be much appreciated.
Regards

  config.yml: |-
    _meta:
      type: "config"
      config_version: 2

    config:
      dynamic:
        authc:
          basic_internal_auth_domain:
            http_enabled: true
            transport_enabled: false
            order: 2
            http_authenticator:
              type: basic
              challenge: true
            authentication_backend:
              type: internal
          ldap:
            description: "Authenticate via LDAP or Active Directory"
            http_enabled: true
            transport_enabled: true
            order: 1
            http_authenticator:
              type: basic
              challenge: true
            authentication_backend:
              type: ldap
              config:
                enable_ssl: true
                enable_start_tls: false
                enable_ssl_client_auth: false
                verify_hostnames: false
                hosts:
                  - ldap.redacted.com:636
                bind_dn: "CN=redacted_user,OU=Generic,OU=ServiceAccounts,OU=Users,OU=Anzo,DC=corp,DC=redacted,DC=com"
                password: "redacted"
                userbase: "OU=Users,OU=Anzo,DC=corp,DC=redacted,DC=com"
                usersearch: '(SAMACCOUNTNAME={0})'
                username_attribute: "SAMACCOUNTNAME"
        authz:
          roles_from_myldap:
            http_enabled: true
            transport_enabled: true
            authorization_backend:
              type: ldap
              config:
                enable_ssl: true
                enable_start_tls: false
                enable_ssl_client_auth: false
                verify_hostnames: false
                hosts:
                  - ldap.redacted.com:636
                bind_dn: "CN=redacted_user,OU=Generic,OU=ServiceAccounts,OU=Users,OU=Anzo,DC=corp,DC=redacted,DC=com"
                password: "redacted"
                userbase: "OU=Users,OU=Anzo,DC=corp,DC=redacted,DC=com"
                usersearch: '(uid={0})'
                username_attribute: null
                rolebase: 'OU=Kibana,OU=Applications,OU=Groups,OU=Anzo,DC=corp,DC=redacted,DC=com'
                rolesearch: '(member={0})'
                userrolename: 'memberOf'
                resolve_nested_roles: true
                rolename: "cn"
                skip_users:
                  - "kibanaserver"
                  - "admin"
  roles_mapping.yml: |-
    # In this file users, backendroles and hosts can be mapped to Open Distro Security roles.
    # Permissions for Opendistro roles are configured in roles.yml
    _meta:
      type: "rolesmapping"
      config_version: 2

    # Define your roles mapping here
    all_access:
      reserved: false
      backend_roles:
      - "admin"
      - "sec.gg.kibana-admin"    #<-------- LDAP admin group
      description: "Maps admin to all_access"

    ldap_user:
      reserved: false
      backend_roles:
      - "sec.gg.kibana-ro"      #<-------- LDAP Read Only Group
      - "sec.gg.kibana-wl-noc-ro"      #<-------- LDAP Read Only Group
      users:
      - "*"
      description: "Maps ldap users to ldap_users"

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

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

  roles.yml: |-
    _meta:
      type: "roles"
      config_version: 2

    sec.gg.kibana-ro:   #<------- LDAP RO Group role
      reserved: false
      cluster_permissions:
        - 'cluster_all'
        - 'indices_all'
        - 'cluster:admin/opendistro/reports/definition/create'
        - 'cluster:admin/opendistro/reports/definition/update'
        - 'cluster:admin/opendistro/reports/definition/on_demand'
        - 'cluster:admin/opendistro/reports/definition/delete'
        - 'cluster:admin/opendistro/reports/definition/get'
        - 'cluster:admin/opendistro/reports/definition/list'
        - 'cluster:admin/opendistro/reports/instance/list'
        - 'cluster:admin/opendistro/reports/instance/get'
        - 'cluster:admin/opendistro/reports/menu/download'
      index_permissions:
        - index_patterns:
            - "*"
          allowed_actions:
            - '*'
      tenant_permissions:
        - tenant_patterns:
            - "*"
          allowed_actions:
            - "*"
      static: false

   sec.gg.kibana-wl-noc-ro:  #<------- LDAP RO Group role
      reserved: false
      cluster_permissions:
        - 'cluster_all'
        - 'indices_all'
        - 'cluster:admin/opendistro/reports/definition/create'
        - 'cluster:admin/opendistro/reports/definition/update'
        - 'cluster:admin/opendistro/reports/definition/on_demand'
        - 'cluster:admin/opendistro/reports/definition/delete'
        - 'cluster:admin/opendistro/reports/definition/get'
        - 'cluster:admin/opendistro/reports/definition/list'
        - 'cluster:admin/opendistro/reports/instance/list'
        - 'cluster:admin/opendistro/reports/instance/get'
        - 'cluster:admin/opendistro/reports/menu/download'
      index_permissions:
        - index_patterns:
            - "*"
          allowed_actions:
            - '*'
      tenant_permissions:
        - tenant_patterns:
            - "*"
          allowed_actions:
            - "*"
      static: false
...
...

  elasticsearch.yml: |-
    _meta:
      type: "config"
      config_version: 2

    cluster.name: "elasticsearch"
    network.host: 0.0.0.0

    # # minimum_master_nodes need to be explicitly set when bound on a public IP
    # # set to 1 to allow single node clusters
    # # Details: https://github.com/elastic/elasticsearch/pull/17288
    # discovery.zen.minimum_master_nodes: 1

    # # Breaking change in 7.0
    # # https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#breaking_70_discovery_changes
    # cluster.initial_master_nodes:
    #    - elasticsearch1
    #    - docker-test-node-1
    # xpack.security.enabled: false
    # xpack.monitoring.enabled: false
    ######## Start OpenDistro for Elasticsearch Security Demo Configuration ########
    # WARNING: revise all the lines below before you go into production
    opendistro_security.ssl.transport.pemcert_filepath: esnode.pem
    opendistro_security.ssl.transport.pemkey_filepath: esnode-key.pem
    opendistro_security.ssl.transport.pemtrustedcas_filepath: root-ca.pem
    opendistro_security.ssl.transport.enforce_hostname_verification: false
    opendistro_security.ssl.http.enabled: true
    opendistro_security.ssl.http.pemcert_filepath: esnode.pem
    opendistro_security.ssl.http.pemkey_filepath: esnode-key.pem
    opendistro_security.ssl.http.pemtrustedcas_filepath: root-ca.pem
    opendistro_security.allow_unsafe_democertificates: true
    opendistro_security.allow_default_init_securityindex: true
    opendistro_security.authcz.admin_dn:
      - CN=kirk,OU=client,O=client,L=test, C=de

    opendistro_security.multitenancy.enabled: true
    opendistro_security.multitenancy.enable_filter: true
    opendistro_security.multitenancy.tenants.preferred: ["Global"]   #<---- Only use one tenant for all
    opendistro_security.multitenancy.tenants.enable_private: false  #<--- Do not use private tenenat
    # server.defaultRoute: /?security_tenant=global

    opendistro_security.roles_mapping_resolution: BOTH
    opendistro_security.audit.type: internal_elasticsearch
    opendistro_security.enable_snapshot_restore_privilege: true
    opendistro_security.check_snapshot_restore_write_privileges: true
    opendistro_security.restapi.roles_enabled: ["all_access", "security_rest_api_access"]
    opendistro_security.system_indices.enabled: true
    opendistro_security.system_indices.indices: [".opendistro-alerting-config", ".opendistro-alerting-alert*", ".opendistro-anomaly-results*", ".opendistro-anomaly-detector*", ".opendistro-anomaly-checkpoints", ".opendistro-anomaly-detection-state", ".opendistro-notifications-*", ".opendistro-reports-*"]
    cluster.routing.allocation.disk.threshold_enabled: false
    node.max_local_storage_nodes: 1
    ######## End OpenDistro for Elasticsearch Security Demo Configuration ########
  kibana.yml: |-
    server.name: kibana
    server.host: "0"
    elasticsearch.hosts: https://localhost:9200
    elasticsearch.ssl.verificationMode: none
    elasticsearch.username: kibanaserver
    elasticsearch.password: kibanaserver
    elasticsearch.requestHeadersWhitelist: ["securitytenant","Authorization"]
    opendistro_security.basicauth.login.brandimage: "https://redacted.com/wp-content/uploads/2020/02/logo-04-1.png"
    opendistro_security.basicauth.login.title: "Welcome to...redacted"
    opendistro_security.basicauth.login.subtitle: To log in use your LDAP account and password

    opendistro_security.multitenancy.enabled: true
    opendistro_security.multitenancy.enable_filter: true
    opendistro_security.multitenancy.tenants.preferred: ["Global"]
    opendistro_security.multitenancy.tenants.enable_private: false

    opendistro_security.readonly_mode.roles: ["kibana_read_only"]

    # Use this setting if you are running kibana without https
    opendistro_security.cookie.secure: false

    newsfeed.enabled: false
    telemetry.optIn: false
    telemetry.enabled: false
    security.showInsecu^eClusterWarning: false

I see in the logs:
… No index-level perm match for User … [Action [indices:data/read/search]] [RolesChecked [own_index, kibana_user]]…No permissions for [indices:data/read/search]

WHY is it only looking at “own_index” & “kibana_user”
How do I tell kibana to look at my new roles that were created?

This looks like a security issue rather than a reporting issue given it’s really about access to the report rather than the report itself. Should I move this to the security category?

Hi @searchymcsearchface
If you think that would be better, sure. Thank you for your reply.
Regards

Also, @reporting-team - if you have thoughts. Seems like a security/permissions issue to me though.

@Darrell It would seem the backend roles are not being matched, as a result you only get the own_index and kibana_user.

Can you verify role_mappings have been uploaded to the security index using below API:

GET _opendistro/_security/api/rolesmapping

Its possible the files have been uploaded to k8s, but not uploaded to the security config, therefore have no effect of the default config which maps all users to kibana_user and own_index roles

{
  "manage_snapshots" : {
    "hosts" : [ ],
    "users" : [ ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "snapshotrestore"
    ],
    "and_backend_roles" : [ ]
  },
  "logstash" : {
    "hosts" : [ ],
    "users" : [ ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "logstash"
    ],
    "and_backend_roles" : [ ]
  },
  "own_index" : {
    "hosts" : [ ],
    "users" : [
      "*"
    ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [ ],
    "and_backend_roles" : [ ],
    "description" : "Allow full access to an index named like the username"
  },
  "kibana_user" : {
    "hosts" : [ ],
    "users" : [
      "*"
    ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "reports_full_access",
      "roxor_all_role",
      "sec.gg.kibana-ro",
      "sec.gg.kibana-wl-noc-ro"
    ],
    "and_backend_roles" : [ ],
    "description" : "Maps kibanauser to kibana_user"
  },
  "all_access" : {
    "hosts" : [ ],
    "users" : [ ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "reports_full_access",
      "admin",
      "sec.gg.kibana-admin"
    ],
    "and_backend_roles" : [ ],
    "description" : "Maps admin to all_access"
  },
  "readall" : {
    "hosts" : [ ],
    "users" : [ ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "reports_full_access"
    ],
    "and_backend_roles" : [ ]
  },
  "kibana_server" : {
    "hosts" : [ ],
    "users" : [
      "kibanaserver"
    ],
    "reserved" : true,
    "hidden" : false,
    "backend_roles" : [ ],
    "and_backend_roles" : [ ]
  }
}

The volumes are mapped to the pods via configmaps and I can confirm that they are there. An example of this is as follows for the od-es-client:

        volumeMounts:
        - mountPath: /usr/share/elasticsearch/config/logging.yml
          name: config
          subPath: logging.yml
        - mountPath: /tmp/elasticsearch.yml
          name: elasticsearch
          subPath: elasticsearch.yml
        - mountPath: /tmp/create_truststore.sh
          name: create-truststore
          subPath: create_truststore.sh
        - mountPath: /usr/share/elasticsearch/plugins/opendistro_security/securityconfig/config.yml
          name: ldap-config
          subPath: config.yml
        - mountPath: /usr/share/elasticsearch/plugins/opendistro_security/securityconfig/internal_users.yml
          name: internal-users
          subPath: internal_users.yml
        - mountPath: /usr/share/elasticsearch/plugins/opendistro_security/securityconfig/roles.yml
          name: roles
          subPath: roles.yml
        - mountPath: /usr/share/elasticsearch/plugins/opendistro_security/securityconfig/roles_mapping.yml
          name: roles-mapping
          subPath: roles_mapping.yml
        lifecycle:
          postStart:
            exec:
              command: ["sh", "-c", "/tmp/create_truststore.sh"]

you will notice there is a “create_truststore.sh” script there that runs when the pod starts up. This script creates the truststore.jks for LDAP and then copies the elasticsearch.yml file and then updates the config with:

sh /usr/share/elasticsearch/plugins/opendistro_security/tools/securityadmin.sh -cd /usr/share/elasticsearch/plugins/opendistro_security/securityconfig/ -icl -nhnv -cacert /usr/share/elasticsearch/config/root-ca.pem -cert /usr/share/elasticsearch/config/kirk.pem -key /usr/share/elasticsearch/config/kirk-key.pem

The strange thing here is if I log in with an LDAP user that is part of the admin group I can access everything. This means to me that the config files are definitely there and applying. The non admin users that should be part of the kibana_user roles_mapping do not allow me to do a discover or reporting unless I add the ldap groups to the readall mapping.

I have noted this error when trying to do a discover

@Darrell notice that in your result for role_mappings there is no role ldap_user

therefore it would seem that the configuration that you are providing to k8s is not reflected in security index.

Or have you changed this since the original post?

Hi Anthony. I have been struggling with this for 3 days now and I have finally got it working. Admins have full access and normal LDAP users now can’t see the admin menus (like security) or accidentally go delete any indexes. Below are my new roles_mapping.yml and roles.yml. Thank you all for the support. Much appreciated.

apiVersion: v1
kind: ConfigMap
metadata:
  name: roles-mapping
  namespace: logging
  labels:
    app: opendistro-es
data:
  roles_mapping.yml: |-
    # In this file users, backendroles and hosts can be mapped to Open Distro Security roles.
    # Permissions for Opendistro roles are configured in roles.yml ## sec.gg.kibana-admin sec.gg.kibana-ro sec.gg.kibana-wl-noc-ro
    _meta:
      type: "rolesmapping"
      config_version: 2

    # Define your roles mapping here
    all_access:
      reserved: false
      backend_roles:
      - "sec.gg.kibana-admin"
      - "admin"
      description: "Maps admin to all_access"

    own_index:
      reserved: false
      users:
      - "*"
      backend_roles:
      - "sec.gg.kibana-ro"
      - "sec.gg.kibana-wl-noc-ro"
      - "roxor_all_role"
      - "reports_full_access"
      - "kibanauser"
      description: "Allow full access to an index named like the username"

    logstash:
      reserved: false
      backend_roles:
      - "logstash"

    kibana_user:
      hosts: []
      users: []
      reserved: false
      hidden: false
      backend_roles:
      - "sec.gg.kibana-ro"
      - "sec.gg.kibana-wl-noc-ro"
      - "roxor_all_role"
      - "reports_full_access"
      - "kibanauser"
      and_backend_roles: []
      description: "Maps our LDAP to kibana_user"

    roxor_all_role:
      hosts: []
      users: []
      reserved: false
      hidden: false
      backend_roles:
      - "*"
      and_backend_roles: []


    readall:
      reserved: false
      backend_roles:
      - "readall"

    manage_snapshots:
      reserved: false
      backend_roles:
      - "snapshotrestore"

    kibana_server:
      reserved: true
      users:
      - "kibanaserver"
apiVersion: v1
kind: ConfigMap
metadata:
  name: roles
  namespace: logging
  labels:
    app: opendistro-es
data:
  roles.yml: |-
    _meta:
      type: "roles"
      config_version: 2

    roxor_all_role:
      reserved: false
      hidden: false
      cluster_permissions:
      - "cluster_all"
      - "indices_all"
      - "kibana_all_write"
      - "kibana_all_read"
      - "index"
      index_permissions:
      - index_patterns:
        - "*"
        fls: []
        masked_fields: []
        allowed_actions:
        - "cluster_all"
        - "indices_all"
        - "kibana_all_write"
        - "kibana_all_read"
        - "index"
      tenant_permissions:
      - tenant_patterns:
        - "global_tenant"
        allowed_actions:
        - "kibana_all_write"
      static: false

    # Restrict users so they can only view visualization and dashboard on kibana
    kibana_read_only:
      reserved: true

    # The security REST API access role is used to assign specific users access to change the security settings through the REST API.
    security_rest_api_access:
      reserved: true

    # Allows users to view monitors, destinations and alerts
    alerting_read_access:
      reserved: true
      cluster_permissions:
        - 'cluster:admin/opendistro/alerting/alerts/get'
        - 'cluster:admin/opendistro/alerting/destination/get'
        - 'cluster:admin/opendistro/alerting/monitor/get'
        - 'cluster:admin/opendistro/alerting/monitor/search'

    # Allows users to view and acknowledge alerts
    alerting_ack_alerts:
      reserved: true
      cluster_permissions:
        - 'cluster:admin/opendistro/alerting/alerts/*'

    # Allows users to use all alerting functionality
    alerting_full_access:
      reserved: true
      cluster_permissions:
        - 'cluster_monitor'
        - 'cluster:admin/opendistro/alerting/*'
      index_permissions:
        - index_patterns:
            - '*'
          allowed_actions:
            - 'indices_monitor'
            - 'indices:admin/aliases/get'
            - 'indices:admin/mappings/get'

    # Allow users to read Anomaly Detection detectors and results
    anomaly_read_access:
      reserved: true
      cluster_permissions:
        - 'cluster:admin/opendistro/ad/detector/info'
        - 'cluster:admin/opendistro/ad/detector/search'
        - 'cluster:admin/opendistro/ad/detectors/get'
        - 'cluster:admin/opendistro/ad/result/search'

    # Allows users to use all Anomaly Detection functionality
    anomaly_full_access:
      reserved: true
      cluster_permissions:
        - 'cluster_monitor'
        - 'cluster:admin/opendistro/ad/*'
      index_permissions:
        - index_patterns:
            - '*'
          allowed_actions:
            - 'indices_monitor'
            - 'indices:admin/aliases/get'
            - 'indices:admin/mappings/get'

    # Allows users to read and download Reports
    reports_instances_read_access:
      reserved: true
      cluster_permissions:
        - 'cluster:admin/opendistro/reports/instance/list'
        - 'cluster:admin/opendistro/reports/instance/get'
        - 'cluster:admin/opendistro/reports/menu/download'

    # Allows users to read and download Reports and Report-definitions
    reports_read_access:
      reserved: true
      cluster_permissions:
        - 'cluster:admin/opendistro/reports/definition/get'
        - 'cluster:admin/opendistro/reports/definition/list'
        - 'cluster:admin/opendistro/reports/instance/list'
        - 'cluster:admin/opendistro/reports/instance/get'
        - 'cluster:admin/opendistro/reports/menu/download'

    # Allows users to all Reports functionality
    reports_full_access:
      reserved: true
      cluster_permissions:
        - 'cluster:admin/opendistro/reports/definition/create'
        - 'cluster:admin/opendistro/reports/definition/update'
        - 'cluster:admin/opendistro/reports/definition/on_demand'
        - 'cluster:admin/opendistro/reports/definition/delete'
        - 'cluster:admin/opendistro/reports/definition/get'
        - 'cluster:admin/opendistro/reports/definition/list'
        - 'cluster:admin/opendistro/reports/instance/list'
        - 'cluster:admin/opendistro/reports/instance/get'
        - 'cluster:admin/opendistro/reports/menu/download'
      index_permissions:
        - index_patterns:
            - '*'
          allowed_actions:
            - 'indices_monitor'
            - 'indices:admin/aliases/get'
            - 'indices:admin/mappings/get'

I hope this helps someone who is also struggling to get understand the flow and ldap integration