11

我有一个在 Kubernetes 集群中运行的 NodeJs 应用程序(我使用的是microk8s)。我还按照官方步骤在 Kubernetes 上设置 Elasticsearch。

问题

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

ConnectionError: self signed certificate in certificate chain

这是我的连接的代码片段:

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 。(设置说明在自述文件中)

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

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

4

5 回答 5

6

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

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
于 2020-07-14T07:24:00.123 回答
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
  },
});

于 2021-03-25T15:44:21.623 回答
1

为了解决您的问题,您需要信任 CA,您应该能够使用以下. 还在这里找到了以下问题

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

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

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

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

spec:
  http:
    tls:
      selfSignedCertificate:
        disabled: true

请注意,不建议禁用 TLS。

于 2020-07-08T12:42:10.087 回答
1

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

这是禁用 NodeJ 验证 SSL 的方法

process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
于 2020-07-14T05:33:09.483 回答
0

我在使用 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,
        },
      };
    )

我使用for中的ca.crt键。如果在启动 node.js 之前将系统环境设置为,也可以去掉这一行,如下所示:<CUSTOM_NAME>-es-http-certs-public/tmp/ca.pemNODE_EXTRA_CA_CERTS/tmp/ca.pem

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

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

  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/

于 2021-05-06T14:33:28.193 回答