Istio安全-證書管理
注:本章更新至1.8版本
插入現有CA證書
本節展示了管理員如何使用現有的根證書來授權istio證書,簽發證書和密鑰,不使用Istio自動生成的證書。
默認情況下,istio的CA會生成一個自簽的根證書和密鑰,並使用它們簽發負載證書。istio的CA也可以使用管理員指定的證書和密鑰,以及管理員指定的根證書來簽發負載證書。
根CA是網格中所有負載信任的根證書。每個Istio CA會使用一個中間CA來簽發密鑰和證書,該CA由根CA簽發。當一個網格中存在多個Istio CA時,會在CA之間建立起信任層級。
本節展示如何將這些證書和密鑰插入Istio的CA。
插入現有證書和密鑰
在istio的samples/certs目錄下有一套證書,可以比較好地解釋istio的證書交互原理。
root-cert.pem
: root CA certificate.ca-[cert|key].pem
: Citadel intermediate certificate and corresponding private key.cert-chain.pem
: certificate trust chain.workload-foo-[cert|key].pem
: workload certificate and key for URI SANspiffe://trust-domain-foo/ns/foo/sa/foo
signed byca-cert.key
.workload-bar-[cert|key].pem
: workload certificate and key for URI SANspiffe://trust-domain-bar/ns/bar/sa/bar
signed byca-cert.key
.假如希望使用現有的CA證書
ca-cert.pem
和ca-key.pem
(root-cert.pem
簽發了ca-cert.pem
,因此root-cert.pem
作為所有負載的根證書)。由於ca-cert.pem
不同於root-cert.pem
,因此無法直接通過根證書進行校驗,此時需要通過一個cert-chain.pem
來指定信任鏈,包含負載到根CA的所有中間CAs。在上述例子中,僅包含了istio的CA簽名證書,因此cert-chain.pem
與ca-cert.pem
相同。注意:如果ca-cert.pem
與root-cert.pem
是相同的,那么cert-chain.pem
文件應該是空的。上述證書例子中的證書鏈為:
root-cert.pem
-->cert-chain.pem
(含ca-cert.pem
)-->workload-foo-cert.pem
/workload-bar-cert.pem
,可以使用如下方式進行校驗:# openssl verify -CAfile <(cat ca-cert.pem root-cert.pem) workload-bar-cert.pem workload-bar-cert.pem: OK
對於生產環境,最好在一台離線機器上執行如下步驟,確保將根密鑰暴露給盡可能少的人
-
創建一個保存證書和密鑰的目錄
$ mkdir -p certs $ pushd certs
-
生成根證書和密鑰
$ make -f ../tools/certs/Makefile.selfsigned.mk root-ca
上述命令將生成如下文件:
root-cert.pem
: 根證書root-key.pem
: 根密鑰root-ca.conf
:openssl
使用該配置來生成根證書root-cert.csr
: 為根證書生成的CSR
-
生成中間證書和密鑰
$ make -f ../tools/certs/Makefile.selfsigned.mk cluster1-cacerts
執行如上命令會生成一個名為
cluster1
的目錄,包含如下文件,root-cert.pem
簽發了ca-cert.pem
ca-cert.pem
: 中間證書ca-key.pem
: 中間密鑰cert-chain.pem
: Istiod使用的證書鏈root-cert.pem
: 根證書intermediate.conf
:openssl
使用該配置來生成中間證書cluster-ca.csr
: 為中間證書生成的CSR
可以將
cluster1
替換為任何字符串。例如make mycluster-certs
將會生成名為mycluster的目錄為了配置其他Istio CA,可以重復執行上述步驟來生成不同名稱的證書目錄
-
創建一個
cacerts
secret,包含如下輸入文件ca-cert.pem
,ca-key.pem
,root-cert.pem
和cert-chain.pem
。需要注意的是創建出來的secret的名稱必須是cacerts
,這樣才能被istio正確掛載。$ kubectl create namespace istio-system $ kubectl create secret generic cacerts -n istio-system \ --from-file=cluster1/ca-cert.pem \ --from-file=cluster1/ca-key.pem \ --from-file=cluster1/root-cert.pem \ --from-file=cluster1/cert-chain.pem
-
返回Istio安裝的頂層目錄
$ popd
部署Istio
使用demo profile,Istio會從掛載的secret文件中讀取證書
$ istioctl install --set profile=demo
在下面的例子中,istio的CA證書(ca-cert.pem
)與根證書(root-cert.pem
)不同,因此負載無法通過根證書驗證工作負載證書,需要使用一個cert-chain.pem
來指定信任的證書鏈,該證書鏈包含負載和根CA之間的所有中間CA,在此例子中,它包含了istio的CA簽名證書,因此cert-chain.pem
和ca-cert.pem
是相同的。注意,如果ca-cert.pem
與root-cert.pem
相同,那么ca-chain.pem
文件應該是空的。
配置示例services
-
部署httpbin和sleep示例services
$ kubectl create ns foo $ kubectl apply -f <(istioctl kube-inject -f samples/httpbin/httpbin.yaml) -n foo $ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n foo
-
部署一個策略,使得foo命名空間的負載僅接受mutual TLS流量
$ kubectl apply -n foo -f - <<EOF apiVersion: "security.istio.io/v1beta1" kind: "PeerAuthentication" metadata: name: "default" spec: mtls: mode: STRICT EOF
校驗證書
本節中會校驗插入到CA中的證書是否簽發了負載證書。
-
sleep 20s,等待mTLS策略下
httpbin
的證書鏈生效。由於CA證書是自簽的,因此openssl命令會返回verify error:num=19:self signed certificate in certificate chain
錯誤。$ 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
-
解析證書鏈中的證書
$ sed -n '/-----BEGIN CERTIFICATE-----/{:start /-----END CERTIFICATE-----/!{N;b start};/.*/p}' httpbin-proxy-cert.txt > certs.pem $ awk 'BEGIN {counter=0;} /BEGIN CERT/{counter++} { print > "proxy-cert-" counter ".pem"}' < certs.pem
-
校驗根證書與管理員指定的證書相同
$ openssl x509 -in samples/certs/root-cert.pem -text -noout > /tmp/root-cert.crt.txt $ openssl x509 -in ./proxy-cert-3.pem -text -noout > /tmp/pod-root-cert.crt.txt $ diff -s /tmp/root-cert.crt.txt /tmp/pod-root-cert.crt.txt Files /tmp/root-cert.crt.txt and /tmp/pod-root-cert.crt.txt are identical
-
校驗CA證書與管理員指定的相同
$ openssl x509 -in samples/certs/ca-cert.pem -text -noout > /tmp/ca-cert.crt.txt $ openssl x509 -in ./proxy-cert-2.pem -text -noout > /tmp/pod-cert-chain-ca.crt.txt $ diff -s /tmp/ca-cert.crt.txt /tmp/pod-cert-chain-ca.crt.txt Files /tmp/ca-cert.crt.txt and /tmp/pod-cert-chain-ca.crt.txt are identical
-
校驗從根證書到負載證書的證書鏈。下面使用中間證書和根證書組成的證書鏈來校驗其簽發了負載證書
$ openssl verify -CAfile <(cat samples/certs/ca-cert.pem samples/certs/root-cert.pem) ./proxy-cert-1.pem ./proxy-cert-1.pem: OK
卸載
卸載證書cacert
和foo
以及istio-system
命名空間
$ kubectl delete secret cacerts -n istio-system
$ kubectl delete ns foo istio-system
Istio的DNS證書管理
本節展示如何使用 Chiron提供和管理DNS證書,Chiron是一個與istiod相連的輕量型組件,它使用kubernetes的CA API簽發證書,無需管理私鑰。有如下優勢:
- 與isitod不同,這種方式無需維護簽發的私鑰,增強了安全性
- 簡化了將根證書分發到TLS客戶端。客戶端不再需要等待istiod生成並分發其CA證書
首先使用istioctl
安裝istio,並配置DNS證書,當istiod啟動后會讀取該配置:
$ cat <<EOF > ./istio.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
certificates:
- secretName: dns.example1-service-account
dnsNames: [example1.istio-system.svc, example1.istio-system]
- secretName: dns.example2-service-account
dnsNames: [example2.istio-system.svc, example2.istio-system]
EOF
$ istioctl install -f ./istio.yaml
可以看到在istio-system下生成了兩個secret:
# kubectl get secret -n istio-system |grep dns
dns.example1-service-account istio.io/dns-key-and-cert 3 81s
dns.example2-service-account istio.io/dns-key-and-cert 3 81s
DNS證書的提供和管理
Istio根據用戶的配置為DNS證書提供了DNS名字和secret名稱。DNS證書由kubernetes CA簽發,並根據配置保存到secret中。istio也管理着DNS證書的生命周期,包括證書滾動和重新生成。
配置DNS證書
可以在 istioctl install
命令中使用IstioControlPlane
用戶資源對istio進行配置。dnsNames
字段用於設定證書中的DNS名稱,secretName
字段指定保存證書和密鑰的kubernetes secret的名稱。
檢查提供的DNS證書
在配置istio生成DNS證書並保存到secret后,需要校驗提供的證書是否能夠正確運行。
為了校驗istio前面例子中生成的dns.example1-service-account
的DNS證書,以及校驗該證書是否包含配置的DNS名稱,需要獲取kubernetes的secret,解析並對其解碼,查看其具體內容:
$ kubectl get secret dns.example1-service-account -n istio-system -o jsonpath="{.data['cert-chain\.pem']}" | base64 --decode | openssl x509 -in /dev/stdin -text -noout
輸出的文本包括:
X509v3 Subject Alternative Name:
DNS:example1.istio-system.svc, DNS:example1.istio-system
重新生成DNS證書
istio可以在DNS證書被錯刪的情況下重新生成證書。
-
刪除前面保存的DNS證書
$ kubectl delete secret dns.example1-service-account -n istio-system
-
校驗istio重新生成了刪除的DNS證書,且證書包含配置的DNS名稱。需要從kubernetes獲取secret,解析並對其解碼,獲取其內容:
$sleep 10; kubectl get secret dns.example1-service-account -n istio-system -o jsonpath="{.data['cert-chain\.pem']}" | base64 --decode | openssl x509 -in /dev/stdin -text -noout
輸出包括
X509v3 Subject Alternative Name:
DNS:example1.istio-system.svc, DNS:example1.istio-system
卸載
$ kubectl delete ns istio-system