在上一篇博客中我介绍了 Istio 中是如何管理证书的,这篇文章将指导你如何使用外置 CA,通过集成 SPIRE 和 cert-manager 实现细粒度的证书管理和自动证书轮换。
如果你还不了解什么是 SPIRE 以及为什么我们要使用 SPIRE,推荐你阅读以下内容:
下图展示了本文中使用的基于 cert-manager 和 SPIRE 的证书信任链:
从图中你可以看出:
下图展示了在 Istio 中集成 SPIRE 和 cert-manger 后的证书颁发和更新流程。
在了解了大致流程后,下面我们将依次安装各个组件。各个组件版本如下:
运行下面的命令安装 cert-manager,我们将使用它来实现自动证书轮换:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.1/cert-manager.yaml
根 CA 是用自签名证书,运行下面的命令配置根 CA:
cat << EOF | kubectl apply -f -
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned
namespace: cert-manager
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: selfsigned-ca
namespace: cert-manager
spec:
isCA: true
duration: 21600h
secretName: selfsigned-ca
commonName: certmanager-ca
subject:
organizations:
- cert-manager
issuerRef:
name: selfsigned
kind: Issuer
group: cert-manager.io
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned-ca
spec:
ca:
secretName: selfsigned-ca
EOF
然后为 istiod 配置证书:
kubectl create namespace istio-system
cat << EOF | kubectl apply -f -
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: cacerts
namespace: istio-system
spec:
secretName: cacerts
duration: 1440h
renewBefore: 360h
commonName: istiod.istio-system.svc
isCA: true
usages:
- digital signature
- key encipherment
- cert sign
dnsNames:
- istiod.istio-system.svc
issuerRef:
name: selfsigned-ca
kind: ClusterIssuer
group: cert-manager.io
EOF
现在我们已经安装好了 cert-manager,并创建了名为 selfsigned-ca
的 clusterIssuer
,接下来,我们来安装 SPIRE 并将 cert-manager 作为 SPIRE 的 UpstreamAuthority
。
运行下面的命令快速安装 SPIRE:
kubectl apply -f https://jimmysong.io/blog/cert-manager-spire-istio/manifests/spire-with-cert-manager-upstream-authority-quick-start.yaml
该 YAML 文件比起 Istio 安装包中的 samples/security/spire/spire-quickstart.yaml
文件增加了对 cert-manager 的适配,如:
spire-server-cluster-role
ClusterRole 增加了对 cert-manager.io
API 组的权限;UpstreamAuthority "cert-manager"
配置;trust_domain
应与安装 Istio 时指定的 TRUST_DOMAIN
环境变量的值保持一致。
该命令中会安装 SPIRE Controller Manager,自动注册 Kubernetes 中的工作负载。所有工作负载将根据其服务账户注册 SPIFFE 标准的服务身份格式 spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>
。
如果你想调整 SPIRE CA 和 SVID 证书的 TTL,可以在 SPIRE Server 的配置中修改 ca_ttl
(默认 24h)和 default_svid_ttl
(默认 1h),详见 SPIRE Server 配置。
Pod 中的 Envoy 代理将共享本地 SPIRE Agent 的 Unix Domain Socket,通过 Workload API 与 SPIRE Server 通信获取证书,如下图所示。
运行下面的命令安装 Istio 并启用 CA 证书自动轮换:
istioctl install --skip-confirmation -f - <<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
namespace: istio-system
spec:
profile: default
meshConfig:
# 信任域应与 SPIRE Server 中配置的信任域相同
trustDomain: example.org
values:
global:
# 自定义 sidecar 模板
sidecarInjectorWebhook:
templates:
spire: |
spec:
containers:
- name: istio-proxy
volumeMounts:
- name: workload-socket
mountPath: /run/secrets/workload-spiffe-uds
readOnly: true
volumes:
- name: workload-socket
csi:
driver: "csi.spiffe.io"
readOnly: true
components:
pilot:
k8s:
env:
# 如果启用,如果用户引入新的中间插件 CA,用户不需要重新启动 istiod 来获取证书。Istiod 会获取新添加的中间插件 CA 的证书并更新它。不支持插入新的 Root-CA。
- name: AUTO_RELOAD_PLUGIN_CERTS
value: "true"
ingressGateways:
- name: istio-ingressgateway
enabled: true
label:
istio: ingressgateway
k8s:
overlays:
- apiVersion: apps/v1
kind: Deployment
name: istio-ingressgateway
patches:
- path: spec.template.spec.volumes.[name:workload-socket]
value:
name: workload-socket
csi:
driver: "csi.spiffe.io"
readOnly: true
- path: spec.template.spec.containers.[name:istio-proxy].volumeMounts.[name:workload-socket]
value:
name: workload-socket
mountPath: "/run/secrets/workload-spiffe-uds"
readOnly: true
EOF
因为我们要使用 Istio Operator 中声明的 spire
模板来部署工作负载,因此我们运行下面的命令部署 Bookinfo 应用:
istioctl kube-inject -f bookinfo-with-spire-template.yaml | kubectl apply -n default -f -
注意:上面命令中使用的 bookinfo-with-spire-template.yaml
文件可以在这里找到,与 Istio 安装包中的 samples/bookinfo/platform/kube/bookinfo.yaml
文件唯一的区别就是每个 Deployment 的 template 中都增加了以下注解:
annotations:
inject.istio.io/templates: "sidecar,spire"
我们将通过检查 productpage 服务的身份和证书配置来验证 SPIRE 是否生效。
使用下面的命令可以检查 SPIRE 是否给工作负载颁发了身份证明:
kubectl exec -i -t spire-server-0 -n spire -c spire-server -- /bin/sh -c "bin/spire-server entry show -socketPath /run/spire/sockets/server.sock -spiffeID spiffe://example.org/ns/default/sa/bookinfo-productpage"
你可以在输出结果中看到 protuctpage 服务的身份信息:
Found 1 entry
Entry ID : 69fbf896-a296-4c3c-8179-44bf4e49e474
SPIFFE ID : spiffe://example.org/ns/default/sa/bookinfo-productpage
Parent ID : spiffe://example.org/k8s-workload-registrar/demo-cluster/node/gke-cluster-1-default-pool-18d66649-z1lm
Revision : 1
TTL : default
Selector : k8s:node-name:gke-cluster-1-default-pool-18d66649-z1lm
Selector : k8s:ns:default
Selector : k8s:pod-uid:73347537-a3e5-4e43-b8c5-bd315c7385b7
DNS name : productpage-v1-7f444fc4dd-rq47m
DNS name : productpage.default.svc
查看 productpage
pod 的证书信任链:
istioctl -n default proxy-config secret deployment/productpage-v1 -o json | jq -r \
'.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' | base64 --decode > chain.pem
查看根证书:
istioctl -n default proxy-config secret deployment/productpage-v1 -o json | jq -r \
'.dynamicActiveSecrets[1].secret.validationContext.trustedCa.inlineBytes' | base64 --decode > root.pem
chain.pem
文件是证书信任链,其中包含两个证书,将它们保存到两个文件中:
split -p "-----BEGIN CERTIFICATE-----" chain.pem cert-
后使用 OpenSSL 查看所有证书:
openssl x509 -noout -text -in cert-aa
openssl x509 -noout -text -in cert-ab
openssl x509 -noout -text -in root.pem
你将看到如下的证书信任链 root.pem
-> cert-aa
-> cert-ab
,如下图所示:
查看 Istiod 的证书:
istioctl -n istio-system proxy-config secret deployment/istiod -o json | jq -r \
'.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' | base64 --decode > chain.pem
从证书信任链中我们可以看到:
如果你要修改 istiod 证书的轮换周期,从 60 天(1440 小时)缩短到 30 天(720 小时),运行下面的命令:
cat << EOF | kubectl apply -f -
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: cacerts
namespace: istio-system
spec:
secretName: cacerts
duration: 720h
renewBefore: 360h
commonName: istiod.istio-system.svc
isCA: true
usages:
- digital signature
- key encipherment
- cert sign
dnsNames:
- istiod.istio-system.svc
issuerRef:
name: selfsigned-ca
kind: ClusterIssuer
group: cert-manager.io
EOF
运行下面的命令查看 istiod 的日志:
kubectl logs -l app=istiod -n istio-system -f
过两分钟后,你将看到类似如下的证书更改记录:
2022-12-23T03:48:42.697360Z info Update Istiod cacerts
2022-12-23T03:48:42.697503Z info Using kubernetes.io/tls secret type for signing ca files
2022-12-23T03:48:42.778241Z info Istiod has detected the newly added intermediate CA and updated its key and certs accordingly
2022-12-23T03:48:42.779459Z info x509 cert - Issuer: "CN=istiod.istio-system.svc", Subject: "", SN: d7acac2301045f741e5e30cff380deaf, NotBefore: "2022-12-23T03:46:42Z", NotAfter: "2032-12-20T03:48:42Z"
2022-12-23T03:48:42.779561Z info x509 cert - Issuer: "CN=certmanager-ca,O=cert-manager", Subject: "CN=istiod.istio-system.svc", SN: 164bf045670a1716ed3f0f1c89b56122, NotBefore: "2022-12-23T03:48:14Z", NotAfter: "2023-01-22T03:48:14Z"
2022-12-23T03:48:42.779642Z info x509 cert - Issuer: "CN=certmanager-ca,O=cert-manager", Subject: "CN=certmanager-ca,O=cert-manager", SN: 8533dbfe0b84ed1fc4e3c76be7ef612f, NotBefore: "2022-12-20T07:50:12Z", NotAfter: "2025-06-07T07:50:12Z"
2022-12-23T03:48:42.779657Z info Istiod certificates are reloaded
要修改工作负载证书的自动轮换周期,你可以设置 pilot-agent
命令的环境变量 SECRET_TTL
,默认值为 24h0m0s
。
在本文中,我们使用了 cert-manager 作为 PKI,将 SPIRE 集成到我们的证书信任链中,并为 Istio 网格中的工作负载创建身份和证书。通过使用 cert-manager,你不用担心 istiod 证书过期的问题,还可以根据需要更新证书。你还可以根据需要将 cert-manager 集成到其他证书供应商,如 Let’s Encrypt、HashiCorp Vault、Venafi 等。你也可以使用 istio-csr 直接让 cert-manager 来管理 Istio 中的证书,或使用 Vault 来存储证书。
最后更新于 2024/12/11