插入 CA 证书

本任务介绍了系统管理员如何通过根证书、签名证书和密钥来配置 Istio 证书授权(CA)。

默认情况下,Istio CA 会生成一个自签名的根证书和密钥,并使用它们来签署工作负载证书。 为了保护根 CA 密钥,您应该使用在安全机器上离线运行的根 CA,并使用根 CA 向运行在每个集群上的 Istio CA 签发中间证书。Istio CA 可以使用管理员指定的证书和密钥来签署工作负载证书, 并将管理员指定的根证书作为信任根分配给工作负载。

下图展示了在包含两个集群的网格中推荐的 CA 层次结构。

CA Hierarchy

CA Hierarchy

本任务介绍如何生成和插入 Istio CA 的证书和密钥。这些步骤可以重复进行, 为每个集群中运行的 Istio CA 提供证书和密钥。

在集群中插入证书和密钥

以下内容仅用于演示。对于生产型集群的设置,强烈建议使用生产型 CA,如 Hashicorp Vault。 在具有强大安全保护功能的离线机器上管理根 CA 是一个很好的做法。

Go 1.18 默认禁用对 SHA-1 签名的支持。 如果您正在 macOS 上生成证书,请确保您使用的是 OpenSSL。详情请参阅 GitHub issue 38049

  1. 在 Istio 安装包的顶层目录下,创建一个目录来存放证书和密钥:

    1. $ mkdir -p certs
    2. $ pushd certs
  2. 生成根证书和密钥:

    1. $ make -f ../tools/certs/Makefile.selfsigned.mk root-ca

    将会生成以下文件:

    • root-cert.pem:生成的根证书
    • root-key.pem:生成的根密钥
    • root-ca.conf:生成根证书的 openssl 配置
    • root-cert.csr:为根证书生成的 CSR
  3. 对于每个集群,为 Istio CA 生成一个中间证书和密钥。 以下是集群 cluster1 的例子:

    1. $ make -f ../tools/certs/Makefile.selfsigned.mk cluster1-cacerts

    运行以上命令,将会在名为 cluster1 的目录下生成以下文件:

    • ca-cert.pem:生成的中间证书
    • ca-key.pem:生成的中间密钥
    • cert-chain.pem:istiod 使用的生成的证书链
    • root-cert.pem:根证书

    您可以使用一个您选择的字符串来替换 cluster1。例如,使用 cluster2-cacerts 参数, 您可以在一个名为 cluster2 的目录中创建证书和密钥。

    如果您正在离线机器上进行此操作,请将生成的目录复制到可以访问集群的机器上。

  4. 在每个集群中,创建一个私密 cacerts,包括所有输入文件 ca-cert.pemca-key.pemroot-cert.pemcert-chain.pem。例如,在 cluster1 集群上:

    1. $ kubectl create namespace istio-system
    2. $ kubectl create secret generic cacerts -n istio-system \
    3. --from-file=cluster1/ca-cert.pem \
    4. --from-file=cluster1/ca-key.pem \
    5. --from-file=cluster1/root-cert.pem \
    6. --from-file=cluster1/cert-chain.pem
  5. 返回 Istio 安装的顶层目录:

    1. $ popd

部署 Istio

  1. 使用 demo 配置文件部署 Istio。

    Istio 的 CA 将会从私密安装文件中读取证书和密钥。

    1. $ istioctl install --set profile=demo

部署实例服务

  1. 部署 httpbinsleep 示例服务。

    1. $ kubectl create ns foo
    2. $ kubectl apply -f <(istioctl kube-inject -f samples/httpbin/httpbin.yaml) -n foo
    3. $ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n foo
  2. foo 命名空间中的工作负载部署一个策略,使其只接受相互的 TLS 流量。

    1. $ kubectl apply -n foo -f - <<EOF
    2. apiVersion: security.istio.io/v1beta1
    3. kind: PeerAuthentication
    4. metadata:
    5. name: "default"
    6. spec:
    7. mtls:
    8. mode: STRICT
    9. EOF

验证证书

本节中,验证工作负载证书是否已通过插入到 CA 中的证书签署。验证的前提要求机器上安装有 openssl

  1. 在检索 httpbin 的证书链之前,请等待 20 秒使mTLS策略生效。由于本例中使用的 CA 证书是自签的, 所以可以预料 openssl 命令返回 verify error:num=19:self signed certificate in certificate chain

    1. $ sleep 20; kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c istio-proxy -n foo -- openssl s_client -showcerts -connect httpbin.foo:8000 > httpbin-proxy-cert.txt
  2. 解析证书链上的证书。

    1. $ sed -n '/-----BEGIN CERTIFICATE-----/{:start /-----END CERTIFICATE-----/!{N;b start};/.*/p}' httpbin-proxy-cert.txt > certs.pem
    2. $ awk 'BEGIN {counter=0;} /BEGIN CERT/{counter++} { print > "proxy-cert-" counter ".pem"}' < certs.pem
  3. 确认根证书与管理员指定的证书是否相同:

    1. $ openssl x509 -in certs/cluster1/root-cert.pem -text -noout > /tmp/root-cert.crt.txt
    2. $ openssl x509 -in ./proxy-cert-3.pem -text -noout > /tmp/pod-root-cert.crt.txt
    3. $ diff -s /tmp/root-cert.crt.txt /tmp/pod-root-cert.crt.txt
    4. Files /tmp/root-cert.crt.txt and /tmp/pod-root-cert.crt.txt are identical
  4. 验证 CA 证书与管理员指定的证书是否相同:

    1. $ openssl x509 -in certs/cluster1/ca-cert.pem -text -noout > /tmp/ca-cert.crt.txt
    2. $ openssl x509 -in ./proxy-cert-2.pem -text -noout > /tmp/pod-cert-chain-ca.crt.txt
    3. $ diff -s /tmp/ca-cert.crt.txt /tmp/pod-cert-chain-ca.crt.txt
    4. Files /tmp/ca-cert.crt.txt and /tmp/pod-cert-chain-ca.crt.txt are identical
  5. 验证从根证书到工作负载证书的证书链:

    1. $ openssl verify -CAfile <(cat certs/cluster1/ca-cert.pem certs/cluster1/root-cert.pem) ./proxy-cert-1.pem
    2. ./proxy-cert-1.pem: OK

清理

  • 从本地磁盘中删除证书、密钥和中间文件:

    1. $ rm -rf certs
  • 删除 Secret cacerts

    1. $ kubectl delete secret cacerts -n istio-system
  • foo 命名空间中删除身份验证策略:

    1. $ kubectl delete peerauthentication -n foo default
  • 删除示例应用 sleephttpbin

    1. $ kubectl delete -f samples/sleep/sleep.yaml -n foo
    2. $ kubectl delete -f samples/httpbin/httpbin.yaml -n foo
  • 从集群中卸载 Istio:

    1. $ istioctl uninstall --purge -y
  • 从集群中删除命名空间 fooistio-system

    1. $ kubectl delete ns foo istio-system