简体   繁体   English

无法使用 Kubernetes 上的 Node.Js 连接到 Elasticsearch(证书链中的自签名证书)

[英]Can't connect to Elasticsearch with Node.Js on Kubernetes (self signed certificate in certificate chain)

I have a NodeJs application running inside a Kubernetes cluster (I am using microk8s ).我有一个 NodeJs 应用程序在 Kubernetes 集群中运行(我使用的是microk8s )。 I've also followed the official steps to setup Elasticsearch on Kubernetes.我还按照官方步骤在 Kubernetes 上设置 Elasticsearch。

Issue问题

But I am unable to connect to the Elasticsearch cluster.但我无法连接到 Elasticsearch 集群。 I get this error:我收到此错误:

ConnectionError: self signed certificate in certificate chain

This is a code snippet of my connection:这是我的连接的代码片段

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

Minimal reproduction最小的繁殖

I've created a minimal reproduction of this issue here: https://github.com/flolu/elasticsearch-k8s-connection .我在这里创建了这个问题的最小复制: https://github.com/flolu/elasticsearch-k8s-connection (Setup instructions are in the README) (设置说明在自述文件中)

Basically, everything works fine when running Elasticsearch inside Docker compose, but I can't connect when running inside Kubernetes.基本上,在 Docker 组合中运行 Elasticsearch 时一切正常,但在 Kubernetes 中运行时我无法连接。

The reason for this is probably because I didn't setup TLS certificates correctly, but I haven't found any information about it.造成这种情况的原因可能是因为我没有正确设置 TLS 证书,但我没有找到任何有关它的信息。 Do I configure it inside my NodeJs application when creating the ES client or at a cluster level?创建 ES 客户端时,我是在我的 NodeJs 应用程序中配置它还是在集群级别配置它?

The solution is to configure SSL and the Elastic user when creating the Client解决方法是在创建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,
  },
});

The password and the certificate are provided by Elastic.密码和证书由 Elastic 提供。 They are stored inside Kubernetes secrets.它们存储在 Kubernetes 机密中。 So I've just passed the password and the certificate into my NodeJs service via environment variables like this:所以我刚刚通过这样的环境变量将密码和证书传递到我的 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

I'd like to build on top of @Florian Ludewig's answer on 2 points, since I struggled myself to have it work on my side.我想在@Florian Ludewig 的 2 点回答的基础上再接再厉,因为我一直在努力让它在我身边发挥作用。

1. Don't turn off rejectUnauthorized 1.不要关闭rejectUnauthorized

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

If you set rejectUnauthorized to false, the underlying nodejs https agent will bypass the certificate check.如果将rejectUnauthorized设置为false,则底层nodejs https 代理将绕过证书检查。 Of course if you are confident in the security of your cluster, you could disable it, but it renders the idea of providing the CA cert useless in the first place.当然,如果您对集群的安全性有信心,您可以禁用它,但这会使提供 CA 证书的想法一开始就毫无用处。

2. Make sure you provide a PEM CA cert - not the base64 encoded version 2. 确保您提供 PEM CA 证书 - 而不是 base64 编码版本

Perhaps you are providing the CA cert from your own config file without using Kubernetes' secret injection - possibly because the ES client application is in a different namespace and thus cannot access the CA secret.也许您在不使用 Kubernetes 的秘密注入的情况下从自己的配置文件中提供 CA 证书 - 可能是因为 ES 客户端应用程序位于不同的命名空间中,因此无法访问 CA 秘密。

In this case you may find it useful to store the CA cert as a base64 string, in a config file, but you should not forget to provide a decoded string to your client:在这种情况下,您可能会发现将 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
  },
});

In order to resolve your issue you will need to trust the CA, you should be able to do so using the following .为了解决您的问题,您需要信任 CA,您应该能够使用以下. Also found the following Question here .还在这里找到了以下问题

If you wish to import the CA as a env variable as discussed you might be able to do something like:如果您希望将 CA 导入为所讨论的 env 变量,您可以执行以下操作:

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

Note: I've not tried the above, an alternative would be to mound the secret as a volume and import it that way:)注意:我没有尝试过上述方法,另一种方法是将秘密作为一个卷堆积并以这种方式导入:)

Please note that If you wish to disable TLS on your Elasticsearch deployment you can do so as follows:请注意,如果您希望在 Elasticsearch 部署上禁用 TLS,您可以执行以下操作:

spec:
  http:
    tls:
      selfSignedCertificate:
        disabled: true

Please note that disabling TLS isn't recommended.请注意,不建议禁用 TLS。

This is an SSL problem Please try to disable verifying SSL or apply for an SSL from CA.这是 SSL 问题 请尝试禁用验证 SSL 或从 CA 申请 SSL。 Cloudflare SSL is also a good choice. Cloudflare SSL 也是不错的选择。

Here's how to disable verifying SSL for NodeJs以下是如何为 NodeJs 禁用验证 SSL

process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

I ran into this error with Minikube using the elasticsearch JS client:我在使用 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}

The following solution doesn't require disabling TLS verification on the client side using a self signed cert.以下解决方案不需要使用自签名证书在客户端禁用 TLS 验证。

es-stack yaml: es堆栈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. Port forwarding to access the ES cluster:访问ES集群的端口转发:
kubectl port-forward service/<CUSTOM_NAME>-es-http 9200:9200

  1. Settings in ES JS client: 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,
        },
      };
    )

I use the ca.crt key in <CUSTOM_NAME>-es-http-certs-public for /tmp/ca.pem .我将<CUSTOM_NAME>-es-http-certs-public中的ca.crt密钥用于/tmp/ca.pem You can also get rid of this line if you set the system environment NODE_EXTRA_CA_CERTS to /tmp/ca.pem before you start node.js, like this:如果在启动/tmp/ca.pem之前将系统环境NODE_EXTRA_CA_CERTS设置为 /tmp/ca.pem 也可以去掉这一行,如下所示:

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

If you aren't sure what CA cert you need to refer to, just ssh into the ES container, and check the ca.crt file in config/http-certs/ .如果您不确定需要参考什么 CA 证书,只需将 ssh 放入 ES 容器中,然后检查config/http-certs/中的 ca.crt 文件。

  1. This is the most important step.这是最重要的一步。 Append this line to /etc/hosts on your local machine. Append 这一行到本地机器上的/etc/hosts
127.0.0.1   <CUSTOM_NAME>-es-default-0.<CUSTOM_NAME>-es-default.default.svc

You should be good to go.你应该对 go 好。 I came up with the idea after reading this tutorial about Ingress:在阅读了有关 Ingress 的本教程后,我想到了这个想法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 证书链中的自签名证书将node.js SDK用于Watson Assistant时出错 - Self signed certificate in certificate chain Error while using node.js SDK for watson assistant Node.js 依赖项安装提供“证书链中的自签名证书” - Node.js dependency installation giving "self signed certificate in certificate chain" ionic 3 / node.js - 证书链中的自签名证书(如何禁用strict-ssl?) - ionic 3 / node.js - Self signed certificate in certificate chain (how to disable strict-ssl?) 节点JS REST调用错误:证书链中的自签名证书 - Node JS REST call Error: self signed certificate in certificate chain 证书链中的自签名证书 - Self signed certificate in certificate chain 获取 Node.js 信任自签名证书 - Getting Node.js To Trust Self Signed Certificate 在Node.JS中带有自签名证书的HTTPS代理 - HTTPS proxy with a self-signed certificate in Node.JS 无法将Node.js中的IP用于自签名证书 - Cannot use IP in Node.js for self-signed certificate 自签名证书Windows模拟器-node.js应用程序 - Self Signed Certificate Windows Emulator - node.js application 错误:自签名证书,node.JS https 客户端证书认证请求 - Error: Self-signed certificate, node.JS https client certificate authentication with request
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM