ssl Kubernetes将ca证书添加到pod的信任根

nkhmeac6  于 2023-01-21  发布在  Kubernetes
关注(0)|答案(3)|浏览(394)

在我的10台机器裸机Kubernetes集群中,一个服务需要调用另一个使用自签名证书的基于https的服务。但是,由于此自签名证书未添加到pod的受信任根ca中,调用失败,无法验证x.509证书。
所有的pod都是基于ubuntu docker镜像的,但是在ubuntu上添加ca证书到信任列表的方法(使用dpkg-reconfigure ca证书)在这个pod上不再起作用了,当然,即使我成功地在一个pod上添加了ca证书到信任根目录,当另一个pod被踢的时候,它也会消失。
我搜索了Kubernetes文档,惊讶地发现除了配置证书与API服务对话之外没有任何其他内容,这不是我要找的。如果Pod之间需要任何安全通道,这应该是很常见的场景。

jhiyze9q

jhiyze9q1#

如果你想在构建时把证书保存起来,编辑你的Docker文件,添加命令从构建上下文复制证书并更新信任。你甚至可以把它作为一个层添加到Docker hub等的东西中。

COPY my-cert.crt /usr/local/share/ca-certificates/
RUN update-ca-certificates

如果你试图在运行时更新信任,事情会变得更加复杂,我自己还没有这样做,但是你可以创建一个包含证书的configMap,将它安装到容器中的上述路径,然后使用一个入口点脚本在主进程之前运行update-ca-certificates

lmyy7pcs

lmyy7pcs2#

更新编辑读取选项3:

如果我在您的情况下,我可以想到3个选项来解决您的问题:

选项1。)(这是我能提供的唯一完整解决方案,不幸的是,我的其他解决方案都是半解决方案,归功于Paras Patidar/以下站点:)

https://medium.com/@paraspatidar/add-ssl-tls-certificate-or-pem-file-to-kubernetes-pod-s-trusted-root-ca-store-7bed5cd683d
1.)将证书添加到配置Map:假设你的pem文件是my-cert.pem
kubectl -n <namespace-for-config-map-optional> create configmap ca-pemstore — from-file=my-cert.pem
2.)将configmap作为卷装载到容器的现有CA根位置:例如,在目录/etc/ssl/certs/ as file中安装卷中,以一对一文件关系安装配置Map文件

apiVersion: v1 
kind: Pod
metadata:
  name: cacheconnectsample
spec:
      containers:
      - name: cacheconnectsample
        image: cacheconnectsample:v1
        volumeMounts:
        - name: ca-pemstore
          mountPath: /etc/ssl/certs/my-cert.pem
          subPath: my-cert.pem
          readOnly: false
        ports:
        - containerPort: 80
        command: [ "dotnet" ]
        args: [ "cacheconnectsample.dll" ]
      volumes:
      - name: ca-pemstore
        configMap:
          name: ca-pemstore

所以我相信这里的想法是/etc/ssl/certs/是pod信任的tls证书的位置,并且subPath方法允许您添加一个文件,而无需清除文件夹的内容,该文件夹将包含k8s秘密。
如果所有的pod共享这个mountPath,那么您可以向每个名称空间添加一个pod present和configmap,但这是alpha版本,只对静态名称空间有用。(但如果这是真的,那么您的所有pod都将信任该证书。

选项2。)(半个解决方案/想法+不能完全回答您的问题,但可以解决您的问题,我相当有信心在理论上可行,这需要您进行研究,但我认为您会发现这是最佳选项:)

理论上,您应该能够利用cert-manager + external-dns + Lets Encrypt Free +公共域名来用公共证书替换自签名证书。
(cert-manager的最终结果是在您的群集中自动生成由Lets Encrypt Free签名的k8s tls密钥,他们有一个dns 01挑战,可用于证明您拥有该证书,这意味着您应该能够利用该解决方案,即使没有入口/即使群集仅用于专用网络。)

编辑:选项3。)(在获得更多Kubernetes实践经验后)

我相信switchboard.op的答案可能是最好的/应该是公认的答案。这个“可以”在运行时完成,但我认为它永远不应该在运行时完成,在运行时完成它是超级黑客和充满边缘案例/没有一个通用的解决方案。
而且,我的选项1只对了一半。在pod上单独安装ca.crt是不够的。在pod上安装该文件后,您需要运行一个命令来信任它。这意味着您可能需要覆盖pod启动命令。例如,您无法执行连接到数据库之类的操作(默认的启动命令),然后更新受信任的CA证书的命令。你必须覆盖启动文件,使之成为一只手卡住,覆盖默认的启动脚本,更新受信任的CA证书,连接到数据库。而问题是Ubuntu,RHEL,Alpine,和其他主机具有不同的位置,您必须在这些位置装载CA证书,有时使用不同的命令来信任CA证书,因此,您可以在运行时将通用解决方案应用于群集中的所有Pod以更新其ca.cert,这并非不可能,但是将需要大量的if语句和变化的webhook/复杂性。(手工制作的每个吊舱解决方案是非常可能的,虽然如果你只需要能够动态更新它的一个吊舱。)
op的答案是如果我必须这么做的话我会这么做。构建一个新的自定义docker映像,并将您的自定义ca.cert信任地烘焙到映像中。这是一个通用的解决方案,并且极大地简化了YAML方面。而且在docker映像方面做起来相对容易。

zkure5ic

zkure5ic3#

出于好奇,这里有一个使用init容器方法的manifest示例。

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: demo
data:
  # in my case it is CloudFlare CA used to sign certificates for origin servers
  origin_ca_rsa_root.pem: |
    -----BEGIN CERTIFICATE-----
    ...
    -----END CERTIFICATE-----
---
apiVersion: v1
kind: Pod
metadata:
  name: demo
  labels:
    name: demo
spec:
  nodeSelector:
    kubernetes.io/os: linux
  initContainers:
  - name: init
    # image: ubuntu
    # command: ["/bin/sh", "-c"]
    # args: ["apt -qq update && apt -qq install -y ca-certificates && update-ca-certificates && cp -r /etc/ssl/certs/* /artifact/"]
    # # alternative image with preinstalled ca-certificates utilities
    image: grafana/alpine:3.15.4
    command: ["/bin/sh", "-c"]
    args: ["update-ca-certificates && cp -r /etc/ssl/certs/* /artifact/"]
    volumeMounts:
    - name: demo
      # note - we need change extension to crt here
      mountPath: /usr/local/share/ca-certificates/origin_ca_rsa_root.crt
      subPath: origin_ca_rsa_root.pem
      readOnly: false
    - name: tmp
      mountPath: /artifact
      readOnly: false
  containers:
  - name: demo
    # note - even so init container is alpine base, and this one is ubuntu based everything still works
    image: nginx
    ports:
      - containerPort: 80
    volumeMounts:
      - name: tmp
        mountPath: /etc/ssl/certs
        readOnly: false
  volumes:
    - name: demo
      configMap:
        name: demo
    # will be used to pass files between init container and actual container
    - name: tmp
      emptyDir: {}

其用途为:

kubectl apply -f demo.yml
kubectl exec demo -c demo -- curl --resolve foo.bar.com:443:10.0.14.14 https://foo.bar.com/swagger/v1/swagger.json
kubectl delete -f demp.yml

注:

  • 将www.example.com替换为您的域名foo.bar.com to your domain name
  • 将www.example.com替换为入口控制器群集IP10.0.14.14 to ingress controller cluster IP
  • 您可能需要添加-vv标志以查看更多详细信息

的确,它有点丑陋和可怕,但至少它确实有效,并且是概念验证。简单ConfigMap的解决方案不起作用,因为curl读取ca-certificates.crt,而在该方法中没有修改它。

相关问题