[英]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。
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
});
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 点回答的基础上再接再厉,因为我一直在努力让它在我身边发挥作用。
rejectUnauthorized
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 证书的想法一开始就毫无用处。
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
kubectl port-forward service/<CUSTOM_NAME>-es-http 9200:9200
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 文件。
/etc/hosts
on your local machine. /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.