ELK Elasticsearch Kibana 登录 LDAP 不起作用:bind_dn secure_bind_password k8s pod postStart - elasticsearch-keystore 有 bind_dn 用户的密码

问题描述 投票:0回答:1

ELK版本:7.17.10

  1. 在K8s集群中部署elasticsearch和Kibana。
  2. ES 和 Kibana 都已上线。
Charts
NAME            NAMESPACE   REVISION    UPDATED                                 STATUS      CHART                           APP VERSION
elasticsearch   logging     1           2023-10-09 22:36:22.805826199 +0000 UTC deployed    elasticsearch-7.17.10-spacex.6.3    7.17.10    
kibana          logging     1           2023-10-09 22:43:26.513922363 +0000 UTC deployed    kibana-7.17.10-spacex.6.1           7.17.10    


Pods
NAME                             READY   STATUS    RESTARTS   AGE
elk-master-0                     3/3     Running   0          45h
elk-master-1                     3/3     Running   0          45h
elk-master-2                     3/3     Running   0          45h
kibana-kibana-c479b8d7f-ddhzs    3/3     Running   0          46h

  1. 使用本机用户名/密码(本地用户),我可以登录 Kibana UI。 A。弹性用户登录也有效。
  2. LDAP 服务器:ldaps://ldap(即 636,因为它是安全的)。
  3. 我尝试在 Kibana UI 中输入的用户是:nklbobbyb 及其密码。
  4. 使用 ldapsearch 或 ldapwhoami,当我使用 CLI 验证 LDAP 用户是否存在时,使用其密码验证,它有效!!,我没有收到任何
    ldapsearch
    ldapwhoami
    CLI
  5. 的错误
  6. 我的目标是使用 xpack > bind_dn 设置基于 LDAP 的 Kibana 登录访问(使用 Elasticsearch .yml 配置),并且“secure_bind_password”已成功注入正确路径的 ES 密钥库,即 xpack.security.authc.realms .ldap.ldap1.secure_bind_password

-- 即运行elasticsearch-keystore show 显示bind_dn 用户(elk-bind)的密码

-- 参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/security-settings.html

  1. 我可以卷曲到 ES url :9200,它显示集群运行状况良好等。这同样适用于 /_cluster/settings/_cluster/health
$ curl http://127.0.0.1:9200 -u elastic:${p} -v

* About to connect() to 127.0.0.1 port 9200 (#0)
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 9200 (#0)
* Server auth using Basic with user 'elastic'
> GET / HTTP/1.1
> Authorization: Basic Kmxkc3RpYzpGoodLuckWithThat9OEotQ3e6
> User-Agent: curl/7.29.0
> Host: 127.0.0.1:9200
> Accept: */*
> 
< HTTP/1.1 200 OK
< X-elastic-product: Elasticsearch
< content-type: application/json; charset=UTF-8
< content-length: 544
< 
{
  "name" : "elk-master-0",
  "cluster_name" : "elk_cluster",
  "cluster_uuid" : "31tgxJzTSdGRbn9PbWDt7k",
  "version" : {
    "number" : "7.17.10",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "fecd68e3150eda0c307ab9a9d7557f5d5fd71349",
    "build_date" : "2023-04-23T05:33:18.138275597Z",
    "build_snapshot" : false,
    "lucene_version" : "8.11.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}
  1. 我在启动elasticsearch和kibana图表的helm图表时使用以下2个文件(yml)。 YML 文件用作覆盖或用于传递 key=values。 注意:两者都运行良好,我可以在 Rancher > 我的集群 > 工作负载 > Pod 中看到两者的 pod 都处于运行状态。

以下是我的xpack设置的elasticsearch yml文件:

clusterName: "elk_cluster"
masterService: "elk-master"
minimumMasterNodes: 1


podAnnotations:
  consul.hashicorp.com/connect-inject: true
  consul.hashicorp.com/connect-service: elasticsearch
  vault.hashicorp.com/agent-inject: true
  vault.hashicorp.com/agent-run-as-user: 22020
  vault.hashicorp.com/agent-run-as-group: 22020
  vault.hashicorp.com/role: elasticsearch
  vault.hashicorp.com/auth-path: auth/kubernetes-secure
  vault.hashicorp.com/tls-skip-verify: true
  vault.hashicorp.com/agent-inject-secret-elk-bind: "secret/data/passwords/ldap/elk-bind"
  vault.hashicorp.com/agent-inject-perms-elk-bind: "0644"
  vault.hashicorp.com/agent-inject-template-elk-bind: |
    {{- with secret "secret/data/passwords/ldap/elk-bind" -}}
    {{ .Data.data.value }}
    {{- end }}
  vault.hashicorp.com/agent-inject-secret-elastic: secret/data/passwords/elk/elastic
  vault.hashicorp.com/agent-inject-command-elastic: chmod 400 /vault/secrets/elastic
  vault.hashicorp.com/agent-inject-template-elastic: |
    {{- with secret "secret/data/passwords/elk/elastic" -}}
    {{ .Data.data.value }}
    {{- end }}
  vault.hashicorp.com/agent-inject-secret-kibana: secret/data/passwords/elk/kibana
  vault.hashicorp.com/agent-inject-command-kibana: chmod 400 /vault/secrets/kibana
  vault.hashicorp.com/agent-inject-template-kibana: |
    {{- with secret "secret/data/passwords/elk/kibana" -}}
    {{ .Data.data.value }}
    {{- end }}

extraEnvs:
  - name: ELASTIC_USERNAME
    value: elastic 
  - name: ELASTIC_PASSWORD_FILE
    value: /vault/secrets/elastic

extraInitContainers:
  - name: ulimit-1
    image: artifactory:8443/docker/elastic/elasticsearch:7.17.10
    command: ["/bin/sh", "-c", "ulimit -n 65536"]
    securityContext:
      privileged: true
  - name: ulimit-2
    image: artifactory:8443/docker/elastic/elasticsearch:7.17.10
    command: ["/bin/sh", "-c", "ulimit -u 4096"]
    securityContext:
      privileged: true
  - name: wait-for-consul
    image: artifactory:8443/docker/elastic/elasticsearch:7.17.10
    command:
    - "/bin/bash"
    - "-c"
    - |
      consul_url=https://$CONSUL_NAME:8501/v1/health/node/$NODE_NAME
      while [[ "$(curl -sk -o /dev/null -w '%{http_code}\n' $consul_url)" != "200" ]] && [[ "$(curl -sk $consul_url)" = "[]" ]]; \
      do echo waiting for consul; sleep 5; done
    env:
      - name: CONSUL_NAME
        value: consul-consul-server-0.consul-consul-server.consul.svc.cluster.local
      - name: NODE_NAME
        valueFrom:
          fieldRef:
            fieldPath: spec.nodeName

extraVolumes:
  - name: elasticsearch-tls-cert
    secret:
      secretName: elasticsearch-cert
  - name: cacerts
    persistentVolumeClaim:
      claimName: cacerts
  - name: elasticsearch-data
    persistentVolumeClaim:
      claimName: elasticsearch-data
  - name: elasticsearch-backup
    persistentVolumeClaim:
      claimName: elasticsearch-backup

extraVolumeMounts:
  - name: elasticsearch-tls-cert
    readOnly: true
    mountPath: /usr/share/elasticsearch/config/elasticsearch.crt
    subPath: tls.crt
  - name: elasticsearch-tls-cert
    readOnly: true
    mountPath: /usr/share/elasticsearch/config/elasticsearch.key
    subPath: tls.key
  - name: cacerts
    mountPath: /var/local/cacerts.d
  - name: cacerts
    mountPath: /usr/share/elasticsearch/config/CA_cert.crt
    subPath: CA_cert.crt
  - name: elasticsearch-data
    mountPath: /usr/share/elasticsearch/data
  - name: elasticsearch-backup
    mountPath: /usr/backup

esJavaOpts: "-Xmx25g -Xms25g"
breakerLimit: "80%"

resources:
  requests:
    cpu: "1000m" 
    memory: "4Gi"
  limits:
    cpu: "8000m"
    memory: "32Gi"

initResources:
  limits:
    cpu: "200m"
    memory: "128Mi"
  requests:
    cpu: "200m"
    memory: "128Mi"

rbac: 
  create: true
  serviceAccountName: "elasticsearch"

podSecurityPolicy:
  create: true

podSecurityContext:
  fsGroup: 22020
  runAsUser: 22020

securityContext:
  runAsUser: 22020

persistence:
  enabled: false

esConfig:
  elasticsearch.yml: |
    path.repo: [ "/usr/backup" ]
    node.max_local_storage_nodes: 3
    
    xpack.security.enabled: true
    xpack.monitoring.collection.enabled: true

    ingest.geoip.downloader.enabled: false

    #index.merge.scheduler.max_thread_count: 1
    cluster.name: elk_cluster
    network.host: "elk-master.logging"
    xpack.license.self_generated.type: trial
    xpack:
      security:
        authc:
          realms:
            ldap:
              ldap1:
                order: 0
                metadata: cn
                
                # secure port 636 of ldap connection, no need to define below, even if you define, no behavior changed.
                url: "ldaps://ldap"

                #bind_dn: "cn=elk-bind,ou=serviceaccounts,dc=infra.spacex"
                
                # !!NOTE!!: In my LDAP, elk-bind is setup using uid instead of cn. It's a service account and it'll be used to bind to LDAP first(using uid=elk-bind and secure_bind_password) i.e. es keystore's xpack.security.authc.realms.ldap.ldap1.secure_bind_password 
                # ----- THEN >> it'll search for the DN of the Kibana UI's "login user (nklbobbyb)", and using Kibana login user's password (entered  through Kibana UI) to authenticate with LDAP. 
                # ----- This process will search the user_search.filter option to find the DN of the Kibana's UI login user "nklbobbyb" (i.e. ldap user that I'm using in Kibana UI)
                bind_dn: "uid=elk-bind,ou=ServiceAccounts,dc=infra.spacex"
                
                # The following setting 'secure_bind_password' is already shoved to elasticsearch-keystore. elasticsearch-keystore add xpack.security.authc.realms.ldap.ldap1.secure_bind_password and elasticsearch-keystore show <same path> spits the value for secure_bind_password used for the bind_dn user i.e. uid=elk-bind.
                # -- I don't think ELK official docs for 7.x/8.x requires the following line or anything like that. Saw a blog with this, will try to see if it helps.
                #secure_bind_password: xpack.security.authc.realms.ldap.ldap1.secure_bind_password               
        
                ssl.verification_mode: none

                #ssl.verification_mode: certificate

                user_search.base_dn: "ou=People,dc=infra.spacex" 
                user_search.filter: "(uid={0})"
                #user_search.filter: "(cn={0})"
                group_search.base_dn: "ou=Groups,dc=infra.spacex" 
                
                # As role mapping file is a file on the filesystem, we don't need to explicitly call REST API (mapping api) to map Kibana roles with LDAP groups. This file IIRC is read every 5 seconds(default) by ELK for mapping purposes.
                files:
                  role_mapping: "/usr/share/elasticsearch/config/role_mapping.yml"
                unmapped_groups_as_roles: false
            native:
              native1:
                order: 1
    xpack.security.transport.ssl.enabled: true
    #xpack.security.transport.ssl.verification_mode: none
    xpack.security.transport.ssl.verification_mode: certificate
    xpack.security.transport.ssl.key: /usr/share/elasticsearch/config/elasticsearch.key
    xpack.security.transport.ssl.certificate: /usr/share/elasticsearch/config/elasticsearch.crt
    xpack.security.transport.ssl.certificate_authorities: [ "/usr/share/elasticsearch/config/CA_cert.crt" ]
    xpack.security.audit.enabled: true
    xpack.security.audit.logfile.events.ignore_filters.test.users: [ "any_logstash_user_writer", "kibana" ]
    
    # For testing purpose, I'm not much worried about the following settings (secure / encryption settings for now). later.
    # ----------------------------------------------------------------------
    #xpack.security.http.ssl.enabled: true
    #xpack.security.http.ssl.verification_mode: none
    ##xpack.security.http.ssl.verification_mode: certificate
    #xpack.security.http.ssl.key: /usr/share/elasticsearch/config/elasticsearch.key
    #xpack.security.http.ssl.certificate: /usr/share/elasticsearch/config/elasticsearch.crt
    #xpack.security.http.ssl.certificate_authorities: [ "/usr/share/elasticsearch/config/CA_cert.crt" ]
    #xpack.security.authc.token.enabled: true

    logger.org.elasticsearch: DEBUG
    logger.org.elasticsearch.http: DEBUG
    logger.org.elasticsearch.transport: DEBUG

  roles.yml: |
    ams:
      cluster: [ "manage_index_templates", "monitor" ]
      indices:
        - names: [ "metricbeat-*", "syslog-*" ]
          privileges: [ 'read' ]
    beat_reader:
      indices: 
        - names: [ "metricbeat-*" ]
          privileges: ["read", "view_index_metadata"]
    beat_writer:
      cluster: [ "manage_index_templates","monitor","manage_ilm" ]
      indices:
        - names: [ "metricbeat-*" ]
          privileges: ["read","write","delete","create_index","manage","manage_ilm"]

    # Kibana 7.16.3 missing manage permissions on indexes
    kibana_supp:
      cluster: [ "all" ]
      indices:
        - names: [ "*" ]
          privileges: ["manage"]
    sec_admin:
      cluster: [ "manage_index_templates", "monitor" ] 
      indices:
        - names: [ 'metricbeat-*', 'syslog-*' ]
          privileges: [ 'read' ]

  role_mapping.yml: |
    ams:
      - "cn=sys_integration,ou=Groups,dc=infra.spacex"
    kibana_admin:
      - "cn=system_admin,ou=Groups,dc=infra.spacex"
    kibana_system:
      - "cn=system_admin,ou=Groups,dc=infra.spacex"
    kibana_user:
      - "cn=ldap_admins,ou=Groups,dc=infra.spacex"
      - "cn=system_admin,ou=Groups,dc=infra.spacex"
    reporting_user:
      - "cn=sys_integration,ou=Groups,dc=infra.spacex"
    superuser:
      - "cn=system_admin,ou=Groups,dc=infra.spacex"
      - "uid=nklbobbyb,ou=people,dc=infra.spacex"

image: artifactory:8443/docker/elastic/elasticsearch

service:
  type: LoadBalancer
  annotations:
    metallb.universe.tf/address-pool: default
    metallb.universe.tf/allow-shared-ip: elasticsearch
  loadBalancerIP: 10.20.30.40

nodeSelector:
  com.company.host.hostType: deployhosts

ingress:
  enabled: true
  path: /
  hosts:
    - elasticsearch.domain.secure
    - elasticsearch
  tls:
    - secretName: elasticsearch-cert
      hosts:
        - elasticsearch.domain.secure
        - elasticsearch

# Do not need a high successThreshold because lifecycle won't work unless service is listening
readinessProbe:
  successThreshold: 1

# Must be yellow or green to be ready (yellow meaning not all shared are assigned/active)
clusterHealthCheckParams: "wait_for_status=yellow&timeout=1s"


## POST START HOOK is where I'm using shell code to add secure_bind_password to elasticsearch-keystore.
lifecycle:
  postStart:
    exec:
      command:
        - bash
        - -c
        - |
          #!/bin/bash
          # Update passwords based on what is in vault
          source /usr/share/elasticsearch/bin/elasticsearch-env-from-file
          CREDS="-u $ELASTIC_USERNAME:$ELASTIC_PASSWORD"

          ES_URL=http://localhost:9200
          while [[ "$(curl -s -o /dev/null -w '%{http_code}\n' $CREDS $ES_URL)" != "200" ]]; do sleep 2; done
          curl -k $CREDS -XPOST "${ES_URL}/_security/user/healthcheck" -H 'Content-Type: application/json' -d '{ "password":"'healthcheck'", "roles" : ["remote_monitoring_collector"] }'

          # Set bind_dn(ldap) password (for uid=elk-bind) as secure_bind_password in ElasticSearch Keystore using elk-bind secret
          # --------------------------
          # https://www.elastic.co/guide/en/elasticsearch/reference/current/ldap-realm.html#mapping-roles-ldap
          #
          if test -f "/vault/secrets/elk-bind"; then
            echo "Injecting bind_dn password as secure_bind_password (in ElasticSearch Keystore) using elk-bind secret (from Vault)"
            ELK_BIND_PASSWORD="$(cat /vault/secrets/elk-bind)"
            echo "${ELK_BIND_PASSWORD}" | elasticsearch-keystore add xpack.security.authc.realms.ldap.ldap1.secure_bind_password
          fi

          # Create a different kibana user because the default one in 7.16.3 is broken (permissions issues)
          # May be able to be removed at a newer version (replace all instances of kibana_mgmr)
          if test -f "/vault/secrets/kibana"; then
            echo "Setting kibana credentials"
            KIB_PASSWORD=$(cat /vault/secrets/kibana)
            curl -k $CREDS -XPOST "${ES_URL}/_security/user/kibana_mgmr" -H 'Content-Type: application/json' -d '{ "password":"'$KIB_PASSWORD'", "roles" : ["kibana_system", "kibana_supp"] }'
          fi

          # Sleeping for a period of time before gathering indices to let elasticsearch load index names from filesystem
          # Currently do not know of an endpoint that we can use to check for index loading.
          sleep 60

          
          
          # IGNORE ----- All code listed below.
          # some curl etc command below.

Kibana .yml中的主要/相关代码如下所示:

elasticsearchHosts: "http://elk-master:9200"
#... more stuff ...generic stuff

kibanaConfig:
  kibana.yml: |-
    server.name: kibana
    server.host: 0.0.0.0
    server.publicBaseUrl: https://kibana.domain.secure
    xpack.monitoring.ui.container.elasticsearch.enabled: true

    #elasticsearch.hosts: ["http://elk-master.logging:9200"]
    elasticsearch.hosts: ["http://elk-master:9200"]

    logging.root.level: debug
    elasticsearch.ssl.verificationMode: none

    #elasticsearch.ssl.verificationMode: certificate
    server.ssl.clientAuthentication: none


resources:
  requests:
    cpu: "1000m"
    memory: "2Gi"
  limits:
    cpu: "1000m"
    memory: "2Gi"

podSecurityContext:
  fsGroup: 22060

securityContext:
  runAsUser: 22060

serviceAccount: "kibana"

extraVolumes:
  - name: keystore
    emptyDir: {}

extraVolumeMounts:
  - name: keystore
    mountPath: /usr/share/kibana/config/kibana.keystore
    subPath: kibana.keystore

service:
  type: LoadBalancer
  loadBalancerIP: 10.20.30.40

ingress:
  enabled: true
  path: /
  hosts:
    - kibana.domain.secure
    - kibana
  tls:
    - secretName: kibana-cert
      hosts:
        - kibana.domain.secure
        - kibana

nodeSelector:
  com.company.host.hostType: deployhosts

当我使用 nklbobbyb(在 Kibana UI 中)登录时,我在 elk-master-0 pod 的日志中看到以下内容。即

$ kubectl logs -n logging elk-master-0 -c elasticsearch -f | egrep -i "ldap|nklbobbyb|auth"

错误信息列于下方:

{"type": "server", "timestamp": "2023-10-02T19:52:36,018Z", "level": "WARN", "component": "o.e.x.s.a.l.s.LdapUtils", "cluster.name": "elk_cluster", "node.name": "elk-master-0", "message": "Failed to obtain LDAP connection from pool - LDAPException(resultCode=89 (parameter error), diagnosticMessage='Simple bind operations are not allowed to contain a bind DN without a password.', ldapSDKVersion=4.0.8, revision=28812)", "cluster.uuid": "31tgxJzTSdGRbn9PbWDt7K", "node.id": "lOYvRY7zSNW7ZMwewL9Vzg"  }
{"type": "server", "timestamp": "2023-10-02T19:52:36,018Z", "level": "WARN", "component": "o.e.x.s.a.RealmsAuthenticator", "cluster.name": "elk_cluster", "node.name": "elk-master-0", "message": "Authentication to realm ldap1 failed - authenticate failed (Caused by LDAPException(resultCode=89 (parameter error), diagnosticMessage='Simple bind operations are not allowed to contain a bind DN without a password.', ldapSDKVersion=4.0.8, revision=28812))", "cluster.uuid": "31tgxJzTSdGRbn9PbWDt7K", "node.id": "lOYvRY7zSNW7ZMwewL9Vzg"  }

Kibana 日志 显示:

$ kubectl logs -n logging kibana-kibana-5645ccf7dd-kx7jh -c kibana -f  | egrep -i "ldap|asangal|auth"

---
{"type":"log","@timestamp":"2023-10-02T21:22:32+00:00","tags":["info","plugins","security","authentication"],"pid":8,"message":"Authentication attempt failed: {\"error\":{\"root_cause\":[{\"type\":\"security_exception\",\"reason\":\"unable to authenticate user [nklbobbyb] for REST request [/_security/_authenticate]\",\"header\":{\"WWW-Authenticate\":\"Basic realm=\\\"security\\\" charset=\\\"UTF-8\\\"\"}}],\"type\":\"security_exception\",\"reason\":\"unable to authenticate user [nklbobbyb] for REST request [/_security/_authenticate]\",\"header\":{\"WWW-Authenticate\":\"Basic realm=\\\"security\\\" charset=\\\"UTF-8\\\"\"}},\"status\":401}"}
===

为了让这个简单的 LDAP 正常工作,我可能会缺少什么?

非常奇怪,在 Kibana UI 中,当我以“elastic”(具有所有超级用户权限)身份登录时,“安全”部分下没有 LDAP 部分,即 因此用户可以在以下位置查看 LDAP 中的设置:网络浏览器..

elasticsearch kubernetes ldap kibana bind
1个回答
0
投票

我错过了一些东西。

我们可以使用 lifeCycle > postStart 或使用 extraInitContainers 方式,但我采用了后一种方法。

解决方案

  1. podAnnotations: 添加 agent-init-first: true,这将使 SECRETS(来自Vault)也可用于额外的 Init 级别容器。否则,这些秘密对于任何额外的 Init 级别容器都将不可见。

    注意:保留那些agent-inject-secret-elk-bind和行

  2. 在 extraInitContainer 中定义一个条目(在上面的 yml 中,在 wait-for-consul 部分之后)。见下文

  3. extraVolumeMounts: 添加 keystore 路径,见下文。

  4. extraVolumes 下: 添加 keystore 卷路径

  5. xpack

    部分下的 bind_dn 行将保持原样。就我而言,我还删除/注释掉了任何 user|group.filter

    vault.hashicorp.com/agent-init-first:true


  - name: elasticsearch-keystore
    image: artifactory:8443/docker/elastic/elasticsearch:7.17.10
    command:
    - bash
    - -c
    - |
      set -euo pipefail
      elasticsearch-keystore create

      echo "Adding bootstrap.password to keystore"
      cat $ELASTIC_PASSWORD_FILE | bin/elasticsearch-keystore add --stdin bootstrap.password

      echo "Adding bind_dn password as secure_bind_password to keystore"
      cat $ELASTIC_BIND_PASSWORD_FILE | bin/elasticsearch-keystore add --stdin xpack.security.authc.realms.ldap.ldap1.secure_bind_password

      cp -a /usr/share/elasticsearch/config/elasticsearch.keystore /tmp/keystore/
    env:
      - name: ELASTIC_BIND_PASSWORD_FILE
        value: /vault/somepath/secrets/elk-bind
      - name: ELASTIC_PASSWORD_FILE
        value: /vault/somepath/secrets/elastic
    securityContext:
      runAsUser: 23059
    volumeMounts:
      - name: keystore
        mountPath: /tmp/keystore

  - name: keystore
    mountPath: /usr/share/elasticsearch/config/elasticsearch.keystore
    subPath: elasticsearch.keystore

  - name: keystore
    emptyDir: {}
© www.soinside.com 2019 - 2024. All rights reserved.