«

K8S部署单节点Elasticsearch 并开启X-Pack安全认证

myluzh 发布于 阅读:1406 Kubernetes


0x00 说明

本文记录在 Kubernetes 中部署 Elasticsearch 7.17.24,并开启 X-Pack 安全认证。

这里默认采用的方式是:

注意:如果你想让 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

证书有两种放法:

如果是生产环境,建议使用 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

注意:

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 集群

参考链接

k8s 部署 k8s部署 apply elasticsearch elasticsearch7 es 单节点


正文到此结束
版权声明:若无特殊注明,本文皆为 Myluzh Blog 原创,转载请保留文章出处。
文章内容:https://itho.cn/k8s/452.html
文章标题:《K8S部署单节点Elasticsearch 并开启X-Pack安全认证