使用 Kubernetes CSR 自定义 CA 集成

该特性正在积极研发中,目前尚处于 experimental 阶段。

这个特性需要 Kubernetes 版本 >= 1.18。

此任务显示如何提供工作负载证书的自定义证书颁发机构Kubernetes CSR API。这个特性利用了Chiron,一个轻量级组件与Istiod链接,使用 Kubernetes CSR API 签署证书。

这项任务分为两部分。第一部分演示了如何使用 Kubernetes CA 本身来签署工作负载证书。第二部分演示了如何使用与 Kubernetes CSR API 集成的自定义 CA 来为证书签名。

第一部分: 使用 Kubernetes CA

注意,这个示例只用于基本计算。不建议在生产环境中使用 kubernetes.io/legacy-unknown

使用 Kubernetes CA 部署 Istio

  1. 使用 istioctl 在集群上部署 Istio,配置如下。

    1. $ cat <<EOF > ./istio.yaml
    2. apiVersion: install.istio.io/v1alpha1
    3. kind: IstioOperator
    4. spec:
    5. pilot:
    6. k8s:
    7. env:
    8. # Indicate to Istiod that we use a Custom Certificate Authority
    9. - name: EXTERNAL_CA
    10. value: ISTIOD_RA_KUBERNETES_API
    11. # Tells Istiod to use the Kubernetes legacy CA Signer
    12. - name: K8S_SIGNER
    13. value: kubernetes.io/legacy-unknown
    14. EOF
    15. $ istioctl install --set profile=demo -f ./istio.yaml
  2. 在 bookinfo 命名空间中部署 bookinfo 示例应用程序。确保在 Istio 根目录下执行以下命令。

    1. $ kubectl create ns bookinfo
    2. $ kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo.yaml) -n bookinfo

验证安装的证书是否正确

在部署工作负载时,它们会向 Istiod 发送 CSR 请求,Istiod 将它们转发到 Kubernetes CA 进行签名。如果一切顺利,签名的证书将被发送回安装它们的工作负载。要验证它们是否已由 Kubernetes CA 签名,您需要先提取已签名的证书。

  1. 获取在命名空间中运行的所有 pod。

    1. $ kubectl get pods -n bookinfo

    为下一步选择任何一个正在运行的 Pod。

  2. 获取 Istio 代理用于 mTLS 的证书链和 CA 根证书。

    1. $ istioctl pc secret <pod-name> -o json > proxy_secret

    proxy_secret json 文件在 trustedCA 字段中包含 mTLS 的 CA 根证书。请注意,此证书是 base64 编码的。

  3. Kubernetes CA 使用的证书(特别是 kubernetes.io/legacy-unknown)被加载到与 bookinfo 命名空间中的每个服务帐号关联的密钥上。

    1. $ kubectl get secrets -n bookinfo

    选择与任何服务帐号关联的 secrets 名称。它们的名称中有一个 “token”。

    1. $ kubectl get secrets -n bookinfo <secret-name> -o json

    输出中的 ca.crt 字段包含 base64 编码的 Kubernetes CA 证书。

  4. 将上一步获得的 ca.cert 与上一步中 TrustedCA 字段的内容进行比较。这两个应该是一样的。

  5. (可选)按照bookinfo 示例中的其余步骤确保服务之间的通信按预期进行。

Cleanup Part 1

  • 删除 istio-systembookinfo 命名空间:

    1. $ kubectl delete ns istio-system
    2. $ kubectl delete ns bookinfo

第二部分: 使用自定义 CA

假设自定义 CA 实现了一个控制器,该控制器具有读取和签署 Kubernetes CSR 请求的必要权限。 更多细节请参考Kubernetes CSR 文档。请注意,以下步骤取决于外部源并且可能会发生变化。

在 Kubernetes 集群中部署自定义 CA 控制器

  1. 对于此示例,我们使用开源证书颁发机构实现。此代码构建了一个控制器,该控制器读取 Kubernetes 集群上的 CSR 资源并使用本地密钥创建证书。按照页面上的说明进行操作:

    1. 构建 Certificate-Controller docker 镜像
    2. 将镜像上传到 Docker Registry
    3. 生成 Kubernetes manifest 以进行部署
  2. 将在上一步中生成的 Kubernetes 清单部署到 signer-ca-system 命名空间中的本地集群上。

    1. $ kubectl apply -f local-ca.yaml

    确认所有的服务都在运行。

    1. $ kubectl get services -n signer-ca-system
    2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    3. signer-ca-controller-manager-metrics-service ClusterIP 10.8.9.25 none 8443/TCP 72s
  3. 获取 CA 的公钥。这是在 signer-ca-system 命名空间中的 “signer-ca-*” secrets 中编码的。

    1. $ kubectl get secrets signer-ca-5hff5h74hm -o json

    tls.crt 字段包含 base64 编码的公钥文件。记录下来以备将来使用。

将 CA 根证书加载到 istiod 可以访问的 secret

  1. 将 secret 加载到 istiod 命名空间中。

    1. $ cat <<EOF > ./external-ca-secret.yaml
    2. apiVersion: v1
    3. kind: Secret
    4. metadata:
    5. name: external-ca-cert
    6. namespace: istio-system
    7. data:
    8. root-cert.pem: <tls.cert from the step above>
    9. EOF
    10. $ kubectl apply -f external-ca-secret.yaml

    Istio 需要此步骤来验证工作负载证书是否已由正确的证书颁发机构签名,并将根证书添加到信任包以使 mTLS 正常工作。

部署 Istio

  1. 使用 istioctl 在集群上部署 Istio,配置如下。

    1. $ cat <<EOF > ./istio.yaml
    2. apiVersion: install.istio.io/v1alpha1
    3. kind: IstioOperator
    4. spec:
    5. components:
    6. base:
    7. k8s:
    8. overlays:
    9. # Amend ClusterRole to add permission for istiod to approve certificate signing by custom signer
    10. - kind: ClusterRole
    11. name: istiod-istio-system
    12. patches:
    13. - path: rules[-1]
    14. value: |
    15. apiGroups:
    16. - certificates.k8s.io
    17. resourceNames:
    18. # Name of k8s external Signer in this example
    19. - example.com/foo
    20. resources:
    21. - signers
    22. verbs:
    23. - approve
    24. pilot:
    25. k8s:
    26. env:
    27. # Indicate to Istiod that we use an external signer
    28. - name: EXTERNAL_CA
    29. value: ISTIOD_RA_KUBERNETES_API
    30. # Indicate to Istiod the external k8s Signer Name
    31. - name: K8S_SIGNER
    32. value: example.com/foo
    33. overlays:
    34. - kind: Deployment
    35. name: istiod
    36. patches:
    37. - path: spec.template.spec.containers[0].volumeMounts[-1]
    38. value: |
    39. # Mount external CA certificate into Istiod
    40. name: external-ca-cert
    41. mountPath: /etc/external-ca-cert
    42. readOnly: true
    43. - path: spec.template.spec.volumes[-1]
    44. value: |
    45. name: external-ca-cert
    46. secret:
    47. secretName: external-ca-cert
    48. optional: true
    49. EOF
    50. $ istioctl install --set profile=demo -f ./istio.yaml
  2. 在 bookinfo 命名空间中部署 bookinfo 示例应用程序。

    1. $ kubectl create ns bookinfo
    2. $ kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo.yaml) -n bookinfo

验证安装的自定义 CA 证书是否正确

在部署工作负载时,它们会向 Istiod 发送 CSR 请求,Istiod 将它们转发到 Kubernetes CA 进行签名。如果一切顺利,签名的证书将被发送回安装它们的工作负载。要验证它们确实已由 Kubernetes CA 签名,您需要首先提取已签名的证书。

  1. 获取在命名空间中运行的所有 pod。

    1. $ kubectl get pods -n bookinfo

    为下一步选择任何正在运行的 Pod。

  2. 获取 Istio 代理用于 mTLS 的证书链和 CA 根证书。

    1. $ istioctl pc secret <pod-name> -o json > proxy_secret

    proxy_secret json 文件在 trustedCA 字段中包含 mTLS 的 CA 根证书。请注意,此证书是 base64 编码的。

  3. 将上述步骤中获得的 CA 根证书与 external-ca-cert 中的 ”root-cert.pem“ 值进行比较。这两个应该是一样的。

  4. (可选)按照bookinfo 示例中的其余步骤确保服务之间的通信按预期进行。

清理第 2 部分

  • 删除 istio-systembookinfo 命名空间:

    1. $ kubectl delete ns istio-system
    2. $ kubectl delete ns bookinfo

使用此功能的原因

  • 增加了安全性 - plugin-ca-cert 或默认的 self-signed 选项不同,启用此功能意味着 CA 私钥不需要存在于 Kubernetes 集群中。

  • 自定义 CA 集成 - 通过在 Kubernetes CSR 请求中指定签名者名称,此功能允许 Istio 使用 Kubernetes CSR API 接口与自定义证书颁发机构集成。这确实需要自定义 CA 来实现一个 Kubernetes 控制器来观察 CertificateSigningRequestCertificate 资源并对其采取行动。