【问题标题】:Can't connect to Elasticsearch with Node.Js on Kubernetes (self signed certificate in certificate chain)无法在 Kubernetes 上使用 Node.Js 连接到 Elasticsearch(证书链中的自签名证书)
【发布时间】:2020-10-28 17:27:21
【问题描述】:

我有一个在 Kubernetes 集群中运行的 NodeJs 应用程序(我使用的是microk8s)。我还关注official steps 在 Kubernetes 上设置 Elasticsearch。

问题

但我无法连接到 Elasticsearch 集群。我收到此错误:

ConnectionError: self signed certificate in certificate chain

这是我的联系人code snippet:

const client = new elasticsearch.Client({
  node: process.env.elasticsearch_node,
  // https://elasticsearch-es-http.default.svc.cluster.local:9200
});

最小复制

我在这里创建了此问题的最小复制:https://github.com/flolu/elasticsearch-k8s-connection。 (设置说明在 README 中)

基本上,在 Docker compose 中运行 Elasticsearch 时一切正常,但在 Kubernetes 中运行时无法连接。

这可能是因为我没有正确设置 TLS 证书,但我没有找到任何相关信息。 我是在创建 ES 客户端时在我的 NodeJs 应用程序中配置它还是在集群级别配置它?

【问题讨论】:

  • 在使用 9200 端口时将 elasticsearch url 协议从 https 更改为 http。
  • @VamshiSiddarth 哇哦,我没试过。不幸的是,我现在得到ConnectionError: socket hang up(请参阅更新的问题)
  • 您能否尝试将xpack.security.transport.ssl.enabled: 'false' 添加到您的配置中以进行elasticsearch、重新部署和检查。
  • 我仍然得到“socket hang up”
  • 可以尝试在你的 nodejs 代码中配置连接超时。看看它是否有帮助。除此之外,我不确定:)

标签: node.js typescript elasticsearch kubernetes microk8s


【解决方案1】:

我在使用 elasticsearch JS 客户端的 Minikube 中遇到了这个错误:

getaddrinfo ENOTFOUND <CUSTOM_NAME>-es-default-0.<CUSTOM_NAME>-es-default.default.svc {"name":"ConnectionError","meta":{"body":null,"statusCode":null,"headers":null,"meta":{"context":null,"request":{"params":{"method":"HEAD","path":"/xxx","body":null,"querystring":"","headers":{"user-agent":"elasticsearch-js/7.12.0 (linux 5.11.16-arch1-1-x64; Node.js v16.1.0)","x-elastic-client-meta":"es=7.12.0,js=16.1.0,t=7.12.0,hc=16.1.0"},"timeout":30000},"options":{},"id":2}

以下解决方案不需要使用自签名证书在客户端禁用 TLS 验证。

es-stack yaml:

apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: <CUSTOM_NAME>
  namespace: default
spec:
  version: 7.12.1
  auth:
    roles:
      - secretName: roles
    fileRealm:
      - secretName: filerealm
  http:
    tls:
      selfSignedCertificate:
        subjectAltNames:
          - ip: 127.0.0.1
  1. 访问 ES 集群的端口转发:
kubectl port-forward service/<CUSTOM_NAME>-es-http 9200:9200

  1. ES JS 客户端中的设置:
    const client = new Client(
     {
        node: `https://127.0.0.1:9200`,
        sniffOnStart: true,
        ConnectionPool: MyConnectionPool,
        auth: {
          username,
          password,
        },
        ssl: {
          ca: fs.readFileSync("/tmp/ca.pem"),
          rejectUnauthorized: true,
        },
      };
    )

我将&lt;CUSTOM_NAME&gt;-es-http-certs-public 中的ca.crt 键用于/tmp/ca.pem。如果在启动node.js之前将系统环境NODE_EXTRA_CA_CERTS设置为/tmp/ca.pem也可以去掉这行,像这样:

NODE_EXTRA_CA_CERTS=/tmp/ca.pem node index.js

如果您不确定需要参考什么 CA 证书,只需 ssh 进入 ES 容器,然后检查config/http-certs/ 中的 ca.crt 文件。

  1. 这是最重要的一步。将此行附加到本地计算机上的/etc/hosts。
127.0.0.1   <CUSTOM_NAME>-es-default-0.<CUSTOM_NAME>-es-default.default.svc

你应该很高兴。在阅读了有关 Ingress 的教程后,我想到了这个想法:

https://kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/

【讨论】:

    【解决方案2】:

    我想在 @Florian Ludewig 的 2 点回答的基础上再接再厉,因为我一直在努力让它在我身边发挥作用。

    1。不要关闭rejectUnauthorized

    const client = new elasticsearch.Client({
      node: 'node httpS url here',
      ssl: {
        ca: process.env.elasticsearch_certificate,
        rejectUnauthorized: true, // <-- this is important
      },
    });
    

    如果您将rejectUnauthorized 设置为false,则底层nodejs https 代理将绕过证书检查。当然,如果您对集群的安全性有信心,您可以禁用它,但这会使提供 CA 证书的想法一开始就毫无用处。

    2。确保您提供 PEM CA 证书 - 而不是 base64 编码版本

    也许您在不使用 Kubernetes 的秘密注入的情况下从自己的配置文件中提供 CA 证书 - 可能是因为 ES 客户端应用程序位于不同的命名空间中,因此无法访问 CA 秘密。

    在这种情况下,您可能会发现将 CA 证书作为 base64 字符串存储在配置文件中很有用,但您不应忘记向客户端提供解码后的字符串:

    const config = loadConfigFromFile('config.yml');
    const caCertificate = Buffer.from(config.base64CaCertificate, 'base64').toString();
    
    const client = new elasticsearch.Client({
      node: 'node httpS url here',
      ssl: {
        ca: caCertificate,
        rejectUnauthorized: true
      },
    });
    
    

    【讨论】:

      【解决方案3】:

      解决方法是在创建Client时配置SSL和Elastic用户

      const client = new elasticsearch.Client({
        node: process.env.elasticsearch_node,
        auth: {
          username: "elastic",
          password: process.env.elasticsearch_password || "changeme",
        },
        ssl: {
          ca: process.env.elasticsearch_certificate,
          rejectUnauthorized: false,
        },
      });
      

      密码和证书由 Elastic 提供。它们存储在 Kubernetes 机密中。 所以我刚刚通过这样的环境变量将密码和证书传递到我的 NodeJs 服务中:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: search-deployment
      spec:
        selector:
          matchLabels:
            app: search
        replicas: 1
        template:
          metadata:
            labels:
              app: search
          spec:
            containers:
              - name: search
                image: search:placeholder_name
                imagePullPolicy: Always
                env:
                  - name: elasticsearch_node
                    value: https://elasticsearch-es-http.default.svc.cluster.local:9200
                  - name: elasticsearch_certificate
                    valueFrom:
                      secretKeyRef:
                        name: elasticsearch-es-http-ca-internal
                        key: tls.crt
                  - name: elasticsearch_password
                    valueFrom:
                      secretKeyRef:
                        name: elasticsearch-es-elastic-user
                        key: elastic
      

      【讨论】:

        【解决方案4】:

        这是一个 SSL 问题 请尝试禁用验证 SSL 或向 CA 申请 SSL。 Cloudflare SSL 也是一个不错的选择。

        这里是如何禁用验证 NodeJs 的 SSL

        process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
        

        【讨论】:

        • 你可能是对的。似乎 Elastic 甚至以 Kubernetes 机密的形式提供证书。所以我可以使用它们。但我不知道如何以及在哪里“应用”它们。
        • 另外:禁用 TLS 似乎不起作用(Elasticsearch 抛出安全异常)
        【解决方案5】:

        为了解决您的问题,您需要信任 CA,您应该能够使用 following 来做到这一点。还发现了以下Question here。

        如果您希望将 CA 导入为所讨论的环境变量,您可以执行以下操作:

        - name: NODE_EXTRA_CA_CERTS
            valueFrom:
              secretKeyRef:
                name: elasticsearch-ca
                key: tls.crt
        

        注意:我没有尝试过上述方法,另一种方法是将秘密作为一个卷堆积并以这种方式导入:)

        请注意,如果您希望在您的 Elasticsearch 部署中禁用 TLS,您可以执行以下操作:

        spec:
          http:
            tls:
              selfSignedCertificate:
                disabled: true
        

        请注意,不建议禁用 TLS。

        【讨论】:

        • 我都试过了,在这两种情况下我都得到另一个错误:ResponseError: security_exception
        • 您是否将 tls 禁用添加到 elasticsearch 部署?
        猜你喜欢
        • 2018-05-11
        • 1970-01-01
        • 1970-01-01
        • 2014-11-20
        • 2015-05-23
        • 2019-12-11
        • 2020-05-22
        • 2023-03-02
        • 2010-11-05
        相关资源
        最近更新 更多