K8S部署单节点Elasticsearch 并开启X-Pack安全认证
myluzh 发布于 阅读:1405 Kubernetes
0x00 说明
本文记录在 Kubernetes 中部署 Elasticsearch 7.17.24,并开启 X-Pack 安全认证。
这里默认采用的方式是:
- 9200 HTTP 接口开启用户名密码认证,访问方式仍然是
http:// - 9300 transport 节点通信开启 TLS 证书
- 单节点使用 StatefulSet 部署
- 数据目录挂载 PVC,避免 Pod 重建后数据和账号密码丢失
注意:如果你想让 9200 也走 HTTPS,需要额外开启 xpack.security.http.ssl.enabled: true,文章后面有单独说明。
0x01 生成百年证书
1、生成 p12 证书
使用 Elasticsearch 官方镜像生成证书,这样不用在本机安装 Elasticsearch。
# 创建临时容器
docker run -it --name es-temp elasticsearch:7.17.24 bash
进入容器后执行:
# 生成百年 CA 证书
bin/elasticsearch-certutil ca \
--days 36500 \
--out config/elastic-stack-ca.p12 \
--pass ''
# 使用 CA 证书签发 ES 节点通信证书
bin/elasticsearch-certutil cert \
--days 36500 \
--ca config/elastic-stack-ca.p12 \
--ca-pass '' \
--out config/elastic-certificates.p12 \
--pass ''
把证书从临时容器复制到本地:
docker cp es-temp:/usr/share/elasticsearch/config/elastic-certificates.p12 ./elastic-certificates.p12
docker rm -f es-temp
可以查看一下证书过期时间:
openssl pkcs12 -in elastic-certificates.p12 -nokeys -out elastic-certificates.crt
openssl x509 -enddate -noout -in elastic-certificates.crt
如果看到类似 notAfter=... 2124 GMT,说明百年证书生成正常。
0x02 证书放入 Kubernetes
证书有两种放法:
- 推荐方式:使用 Kubernetes Secret 挂载证书
- 简单方式:把证书打进 Elasticsearch 镜像
如果是生产环境,建议使用 Secret,不建议把带私钥的 p12 证书直接打进镜像。因为镜像只要被别人拉走,证书私钥也会一起泄露。
1、推荐:使用 Secret
kubectl create secret generic es-cert \
--from-file=elastic-certificates.p12=./elastic-certificates.p12 \
-n default
后面的 YAML 会演示如何把这个 Secret 挂载到 Pod。
2、可选:制作带证书的镜像
如果只是内网测试,也可以把证书直接塞到镜像里。
Dockerfile:
FROM elasticsearch:7.17.24
LABEL maintainer="myluzh <myluzh@qq.com>"
COPY --chown=1000:0 elastic-certificates.p12 /usr/share/elasticsearch/config/
EXPOSE 9200 9300
构建镜像:
docker build -t elasticsearch:7.17.24-p12 .
上传到 Harbor 私有仓:
docker tag elasticsearch:7.17.24-p12 172.30.82.223:5443/base/elasticsearch:7.17.24-p12
docker push 172.30.82.223:5443/base/elasticsearch:7.17.24-p12
0x03 部署 Elasticsearch 单节点
下面示例使用 Secret 挂载证书。如果你使用的是上面自定义镜像,可以删除 cert-volume 相关配置,并把镜像改成:
172.30.82.223:5443/base/elasticsearch:7.17.24-p12
1、部署 elasticsearch_single_node.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: elasticsearch-config
namespace: default
data:
elasticsearch.yml: |
cluster.name: elasticsearch
discovery.type: single-node
network.host: 0.0.0.0
# 开启 X-Pack 安全认证
xpack.security.enabled: true
# 开启 9300 transport 节点通信 TLS
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/elastic-certificates.p12
# 默认不建议直接放开 CORS,确实需要浏览器跨域访问 ES 时再打开
# http.cors.enabled: true
# http.cors.allow-origin: "*"
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
namespace: default
spec:
serviceName: elasticsearch
replicas: 1
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
spec:
securityContext:
fsGroup: 1000
containers:
- name: elasticsearch
image: elasticsearch:7.17.24
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9200
name: http
- containerPort: 9300
name: transport
env:
- name: ES_JAVA_OPTS
value: "-Xms2g -Xmx2g"
resources:
requests:
cpu: "500m"
memory: "3Gi"
limits:
memory: "3Gi"
volumeMounts:
- name: config-volume
mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
subPath: elasticsearch.yml
- name: cert-volume
mountPath: /usr/share/elasticsearch/config/elastic-certificates.p12
subPath: elastic-certificates.p12
readOnly: true
- name: es-data
mountPath: /usr/share/elasticsearch/data
volumes:
- name: config-volume
configMap:
name: elasticsearch-config
- name: cert-volume
secret:
secretName: es-cert
defaultMode: 0440
volumeClaimTemplates:
- metadata:
name: es-data
spec:
accessModes:
- ReadWriteOnce
# 按实际环境修改 StorageClass
storageClassName: managed-nfs-storage
resources:
requests:
storage: 20Gi
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: default
spec:
ports:
- name: http
port: 9200
targetPort: 9200
- name: transport
port: 9300
targetPort: 9300
selector:
app: elasticsearch
部署:
kubectl apply -f elasticsearch_single_node.yaml
查看 Pod 状态:
kubectl get pod -l app=elasticsearch -n default
kubectl logs -f elasticsearch-0 -n default
2、宿主机参数
Elasticsearch 需要 vm.max_map_count 至少为 262144。如果节点没配置,Pod 可能启动失败。
在 Kubernetes 节点上执行:
sysctl -w vm.max_map_count=262144
持久化配置:
echo "vm.max_map_count=262144" >> /etc/sysctl.conf
sysctl -p
0x04 初始化账号密码
Pod 启动正常后,进入容器设置内置用户密码。
kubectl exec -it elasticsearch-0 -n default -- bash
手动设置密码:
./bin/elasticsearch-setup-passwords interactive
也可以自动生成密码:
./bin/elasticsearch-setup-passwords auto
示例输出:
Please confirm that you would like to continue [y/N]y
...
Changed password for user elastic
PASSWORD elastic = xxxxxxxxxxxxxxxx
注意:
elasticsearch-setup-passwords主要用于首次初始化密码- 密码设置完成后要保存好,后面不能反复用这个命令重新初始化
- 生产环境不要在文章、脚本、Git 仓库里写真实密码
0x05 测试访问
在集群内创建一个临时 curl 容器测试:
kubectl run curl-test \
--rm -it \
--image=curlimages/curl \
--restart=Never \
-- sh
访问 Elasticsearch:
curl -u elastic:你的密码 \
http://elasticsearch.default.svc.cluster.local:9200/_cluster/health?pretty
正常会返回类似下面内容:
{
"cluster_name" : "elasticsearch",
"status" : "green",
"number_of_nodes" : 1
}
如果没有加账号密码,会返回 missing authentication credentials,说明 X-Pack 登录认证已经生效。
0x06 如果需要开启 9200 HTTPS
上面的配置只给 9300 transport 通信开启 TLS,9200 仍然是 HTTP,只是需要用户名密码。
如果需要让 9200 也走 HTTPS,在 elasticsearch.yml 中增加:
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/elastic-certificates.p12
xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/elastic-certificates.p12
开启后,测试命令要改成 https://:
curl -k -u elastic:你的密码 \
https://elasticsearch.default.svc.cluster.local:9200/_cluster/health?pretty
这里使用 -k 是因为证书不是公网 CA 签发的证书,curl 默认不会信任。
0x07 常见问题
1、为什么开启 transport.ssl 后还用 http 访问 9200?
因为 transport.ssl 加密的是 Elasticsearch 节点之间的 9300 通信,不是客户端访问的 9200 HTTP 接口。
9200 是否 HTTPS,由下面这个配置决定:
xpack.security.http.ssl.enabled: true
如果没有开启它,9200 就仍然是 HTTP。
2、为什么要挂载 data 目录?
Elasticsearch 的索引数据、用户密码、安全索引都会写到数据目录。
如果不挂载 /usr/share/elasticsearch/data,Pod 重建后数据可能丢失,之前初始化的账号密码也可能一起丢失。
3、为什么不建议把证书打进镜像?
elastic-certificates.p12 里面包含私钥。打进镜像后,只要镜像被拉取,证书私钥也会被拿走。
内网测试可以这么做,生产环境建议用 Kubernetes Secret 挂载。
4、集群模式怎么部署?
不建议直接手写 StatefulSet 部署 Elasticsearch 集群,维护成本比较高,滚动升级、证书、节点发现、扩缩容都比较麻烦。
Kubernetes 里部署 Elasticsearch 集群,推荐使用 Elasticsearch Operator,也就是 ECK。
参考我这篇文章:使用 Elasticsearch Operator(ECK)部署 Elasticsearch 集群
参考链接
- Elasticsearch 7.17 Security settings:https://www.elastic.co/guide/en/elasticsearch/reference/7.17/security-settings.html
- elasticsearch-certutil:https://www.elastic.co/guide/en/elasticsearch/reference/7.17/certutil.html
- Elasticsearch Docker 生产环境参数:https://www.elastic.co/guide/en/elasticsearch/reference/7.17/docker.html
k8s 部署 k8s部署 apply elasticsearch elasticsearch7 es 单节点