Linkerd 2.10(Step by Step)—3. 自動輪換控制平面 TLS &Webhook TLS 憑證
- 2021 年 6 月 15 日
- 筆記

Linkerd 2.10 系列
- 快速上手 Linkerd v2 Service Mesh(服務網格)
- 騰訊雲 K8S 集群實戰 Service Mesh—Linkerd2 & Traefik2 部署 emojivoto 應用
- 詳細了解 Linkerd 2.10 基礎功能,一起步入 Service Mesh 微服務架構時代
- Linkerd 2.10(Step by Step)—1. 將您的服務添加到 Linkerd
- Linkerd 2.10(Step by Step)—2. 自動化的金絲雀發布
Linkerd 2.10 中文手冊持續修正更新中:
自動輪換控制平面 TLS 憑證
Linkerd 的自動 mTLS 功能使用一組 TLS 憑據(TLS credentials)為代理生成 TLS 證書(TLS certificates):
信任錨(trust anchor)、頒發者證書(issuer certificate)和私鑰(private key)。
雖然 Linkerd 每 24 小時自動輪換數據平面代理的 TLS 證書,
但它不會輪換用於頒發這些證書的 TLS 憑據。
在本文檔中,我們將描述如何使用外部解決方案
自動輪換頒發者證書和私鑰。
(請注意,Linkerd 的信任錨仍然必須在 long-lived 集群上手動輪換)
Cert manager
Cert-manager
是一個流行的項目,用於使來自外部來源的 TLS 憑證(TLS credentials)可用於 Kubernetes 集群。
第一步,在您的集群上安裝
cert-manager。
如果您要安裝 cert-manager >= 1.0,
則需要 kubernetes >= 1.16。
cert-manager 中用於 kubernetes <= 1.15
的傳統自定義資源定義沒有 keyAlgorithm 選項,
因此證書將使用 RSA 生成並且與 linkerd 不兼容。
有關版本要求的更多詳細資訊,請參閱 v0.16 到 v1.0 升
級說明。
Cert manager 作為集群上的證書頒發機構(CA)
在這種情況下,我們不會從外部來源(external source)獲取憑據,
而是將其配置為集群上的
CA,
並讓它定期重新頒發 Linkerd 的頒發者證書(issuer certificate)和私鑰(private key)。
首先,創建 cert-manager 將用來存儲其 Linkerd 相關資源的命名空間。
為簡單起見,我們建議使用默認的 Linkerd 控制平面命名空間:
kubectl create namespace linkerd
將簽名密鑰對(signing key pair)保存為 Secret
接下來,使用 step 工具,
創建一個簽名密鑰對(signing key pair)並將其存儲在上面創建的
命名空間中的 Kubernetes Secret 中:
step certificate create root.linkerd.cluster.local ca.crt ca.key \
--profile root-ca --no-password --insecure &&
kubectl create secret tls \
linkerd-trust-anchor \
--cert=ca.crt \
--key=ca.key \
--namespace=linkerd
對於壽命更長(longer-lived)的信任錨證書,將 --not-after 參數傳遞
給具有所需值(desired value)的 step 命令(例如 --not-after=87600h)。
創建引用密鑰(referencing the secret)的頒發者(Issuer)
有了 Secret,我們可以創建一個引用它的 cert-manager "Issuer" 資源:
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: linkerd-trust-anchor
namespace: linkerd
spec:
ca:
secretName: linkerd-trust-anchor
EOF
頒發證書(Issuing certificates)並將它們寫入一個 secret
最後,我們可以創建一個 cert-manager "Certificate" 資源,
它使用這個 Issuer 來生成所需的證書:
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: linkerd-identity-issuer
namespace: linkerd
spec:
secretName: linkerd-identity-issuer
duration: 48h
renewBefore: 25h
issuerRef:
name: linkerd-trust-anchor
kind: Issuer
commonName: identity.linkerd.cluster.local
dnsNames:
- identity.linkerd.cluster.local
isCA: true
privateKey:
algorithm: ECDSA
usages:
- cert sign
- crl sign
- server auth
- client auth
EOF
(在上面的 YAML 清單中,duration key 指示 cert-manager 將
證書視為有效 48 小時,而 renewBefore key 指示
cert-manager 將嘗試在當前證書到期前 25 小時頒發新證書。
這些值可以根據您的喜好訂製。)
此時,cert-manager 現在可以使用此證書資源(Certificate resource)
獲取 TLS 憑據(TLS credentials),
該憑據將存儲在名為 linkerd-identity-issuer 的 secret 中。
要驗證您新頒發的證書,您可以運行:
kubectl get secret linkerd-identity-issuer -o yaml -n linkerd
現在我們只需要通知 Linkerd 使用這些憑據。
由於 cert-manager 中的
bug,
如果您將 cert-manager 版本 0.15 與實驗控制器(experimental controllers)一起使用,
則它頒發的證書與 Linkerd 版本 <= stable-2.8.1 不兼容。
您的 linkerd-identity pod 可能會因以下日誌輸出而崩潰:
"Failed to initialize identity service: failed to read CA from disk:
unsupported block type: 'PRIVATE KEY'"
解決此問題的一些可能方法是:
- 將 Linkerd 升級到包含修復程式的邊緣版本
>= edge-20.6.4。 - 將 cert-manager 升級到版本
>= 0.16。(如何升級) - 關閉 cert-manager 實驗控制器(experimental controllers)。(docs)
替代 CA 提供商
您可以將 Cert Manager 配置為依賴於許多其他解決方案,
例如 Vault,
而不是使用 Cert Manager 作為 CA。
可以在此處找到
有關如何設置現有證書管理器
以使用不同類型的頒發者的更多詳細資訊。
第三方證書管理解決方案
需要注意的是,Linkerd 提供的機制也可以在 cert-manager 之外使用。
Linkerd 將讀取 linkerd-identity-issuer Secret,
如果它是 kubernetes.io/tls 類型,將使用內容作為其 TLS 憑證(TLS credentials)。
這意味著任何能夠通過將 TLS 證書(certificates)寫入此密鑰
來輪換它們的解決方案都可用於提供動態 TLS 證書管理。
在 CLI 安裝中使用這些憑據
對於 CLI 安裝,Linkerd 控制平面應該
與 --identity-external-issuer 標誌一起安裝,
該標誌指示 Linkerd 從 linkerd-identity-issuer secret 讀取證書。
每當更新存儲在 secret 中的 certificate 和 key 時,
identity 服務將自動檢測此更改並重新載入新憑據。
瞧!我們已經設置了 Linkerd 控制平面 TLS 憑據的自動輪換。
如果你想監控更新過程,你可以檢查服務發出的 IssuerUpdated 事件:
kubectl get events --field-selector reason=IssuerUpdated -n linkerd
使用 Helm 安裝
對於 Helm 安裝,而不是運行 linkerd install,
將 identityTrustAnchorsPEM 設置為
linkerd-identity-issuer Secret 中 ca.crt 的值:
helm install linkerd2 \
--set-file identityTrustAnchorsPEM=ca.crt \
--set identity.issuer.scheme=kubernetes.io/tls \
--set installNamespace=false \
linkerd/linkerd2 \
-n linkerd
對於低於 v3 的 Helm 版本,必須專門傳遞 --name 標誌。
在 Helm v3 中,它已被棄用,並且是上面指定的第一個參數。
自動輪換 Webhook TLS 憑證
Linkerd 控制平面包含幾個組件,稱為 webhooks,
由 Kubernetes 本身直接調用。
從 Kubernetes 到 Linkerd webhooks 的流量使用 TLS 進行保護,
因此每個 webhooks 都需要一個包含 TLS 憑據的 secret。
這些證書與 Linkerd 代理用於保護 pod 到 pod 通訊並
使用完全獨立的信任鏈的證書不同。
默認情況下,當 Linkerd 與 Linkerd CLI 或 Linkerd Helm chart 一起安裝時,
會自動為所有 webhook 生成 TLS 憑據。
如果這些證書過期或因任何原因需要重新生成,
執行 Linkerd upgrade(使用 Linkerd CLI 或使用 Helm)將重新生成它們。
此工作流程適用於大多數用戶。
但是,如果您需要定期自動輪換這些 webhook 證書,
則可以使用 cert-manager 來自動管理它們。
安裝 Cert manager
第一步,在
您的集群上安裝 cert-manager
並創建 cert-manager 將用於存儲其 webhook 相關資源的命名空間。
為簡單起見,我們建議使用默認命名空間 linkerd 使用:
# control plane core
kubectl create namespace linkerd
# viz (ignore if not using the viz extension)
kubectl create namespace linkerd-viz
# viz (ignore if not using the jaeger extension)
kubectl create namespace linkerd-jaeger
將簽名密鑰對(signing key pair)保存為 Secret
接下來,我們將使用 step
工具創建一個簽名密鑰對(signing key pair),用於對每個 webhook 證書進行簽名:
step certificate create webhook.linkerd.cluster.local ca.crt ca.key \
--profile root-ca --no-password --insecure --san webhook.linkerd.cluster.local
kubectl create secret tls webhook-issuer-tls --cert=ca.crt --key=ca.key --namespace=linkerd
# ignore if not using the viz extension
kubectl create secret tls webhook-issuer-tls --cert=ca.crt --key=ca.key --namespace=linkerd-viz
# ignore if not using the jaeger extension
kubectl create secret tls webhook-issuer-tls --cert=ca.crt --key=ca.key --namespace=linkerd-jaeger
創建引用 secrets 的發行者(Issuers)
有了 Secrets,我們就可以創建引用它們的 cert-manager "Issuer" 資源:
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: webhook-issuer
namespace: linkerd
spec:
ca:
secretName: webhook-issuer-tls
---
# ignore if not using the viz extension
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: webhook-issuer
namespace: linkerd-viz
spec:
ca:
secretName: webhook-issuer-tls
---
# ignore if not using the jaeger extension
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: webhook-issuer
namespace: linkerd-jaeger
spec:
ca:
secretName: webhook-issuer-tls
EOF
頒發證書並將其寫入 secrets
最後,我們可以創建 cert-manager "Certificate" 資源,
它使用頒發者(Issuers)來生成所需的證書:
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: linkerd-proxy-injector
namespace: linkerd
spec:
secretName: linkerd-proxy-injector-k8s-tls
duration: 24h
renewBefore: 1h
issuerRef:
name: webhook-issuer
kind: Issuer
commonName: linkerd-proxy-injector.linkerd.svc
dnsNames:
- linkerd-proxy-injector.linkerd.svc
isCA: false
privateKey:
algorithm: ECDSA
usages:
- server auth
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: linkerd-sp-validator
namespace: linkerd
spec:
secretName: linkerd-sp-validator-k8s-tls
duration: 24h
renewBefore: 1h
issuerRef:
name: webhook-issuer
kind: Issuer
commonName: linkerd-sp-validator.linkerd.svc
dnsNames:
- linkerd-sp-validator.linkerd.svc
isCA: false
privateKey:
algorithm: ECDSA
usages:
- server auth
---
# ignore if not using the viz extension
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: tap
namespace: linkerd-viz
spec:
secretName: tap-k8s-tls
duration: 24h
renewBefore: 1h
issuerRef:
name: webhook-issuer
kind: Issuer
commonName: tap.linkerd-viz.svc
dnsNames:
- tap.linkerd-viz.svc
isCA: false
privateKey:
algorithm: ECDSA
usages:
- server auth
---
# ignore if not using the viz extension
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: linkerd-tap-injector
namespace: linkerd-viz
spec:
secretName: tap-injector-k8s-tls
duration: 24h
renewBefore: 1h
issuerRef:
name: webhook-issuer
kind: Issuer
commonName: tap-injector.linkerd-viz.svc
dnsNames:
- tap-injector.linkerd-viz.svc
isCA: false
privateKey:
algorithm: ECDSA
usages:
- server auth
---
# ignore if not using the jaeger extension
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: jaeger-injector
namespace: linkerd-jaeger
spec:
secretName: jaeger-injector-k8s-tls
duration: 24h
renewBefore: 1h
issuerRef:
name: webhook-issuer
kind: Issuer
commonName: jaeger-injector.linkerd.svc
dnsNames:
- jaeger-injector.linkerd.svc
isCA: false
privateKey:
algorithm: ECDSA
usages:
- server auth
EOF
此時 cert-manager 現在可以使用這些 Certificate resources 來獲取 TLS 憑證,
這些憑證分別存儲在 linkerd-proxy-injector-k8s-tls、linkerd-sp-validator-k8s-tls、tap- k8s-tls、tap-injector-k8s-tls 和 jaeger-injector-k8s-tls 這些 secrets 中。
現在我們只需要通知 Linkerd 使用這些憑據。
在 CLI 安裝中使用這些憑據
要將 Linkerd 配置為使用來自 cert-manager 的憑據而不是生成自己的憑據,
我們生成了一個補充配置文件:
CA=$(awk '{ print " " $0 }' ca.crt)
cat > config.yml <<EOF
proxyInjector:
externalSecret: true
caBundle: |
$CA
profileValidator:
externalSecret: true
caBundle: |
$CA
EOF
# ignore if not using the viz extension
cat > config-viz.yml <<EOF
tap:
externalSecret: true
caBundle: |
$CA
tapInjector:
externalSecret: true
caBundle: |
$CA
EOF
# ignore if not using the jaeger extension
cat > config-jaeger.yml <<EOF
webhook:
externalSecret: true
caBundle: |
$CA
EOF
現在我們可以使用這些配置文件安裝 Linkerd:
linkerd install --values=config.yml | kubectl apply -f -
# ignore if not using the viz extension
linkerd viz install --values=config-viz.yml | kubectl apply -f -
# ignore if not using the jaeger extension
linkerd jaeger install --values=config-jaeger.yml | kubectl apply -f -
使用 Helm 安裝
對於 Helm 安裝,我們可以直接配置 Helm 值:
helm install linkerd2 \
--set installNamespace=false \
--set proxyInjector.externalSecret=true \
--set-file proxyInjector.caBundle=ca.crt \
--set profileValidator.externalSecret=true \
--set-file profileValidator.caBundle=ca.crt \
linkerd/linkerd2 \
-n linkerd
# ignore if not using the viz extension
helm install linkerd-viz \
--set installNamespace=false \
--set tap.externalSecret=true \
--set-file tap.caBundle=ca.crt \
--set tapInjector.externalSecret=true \
--set-file tapInjector.caBundle=ca.crt \
linkerd/linkerd-viz \
-n linkerd-viz
# ignore if not using the jaeger extension
helm install linkerd-jaeger \
--set installNamespace=false \
--set webhook.externalSecret=true \
--set-file webhook.caBundle=ca.crt \
linkerd/linkerd-jaeger \
-n linkerd-jaeger
使用 Helm 安裝 Linkerd 時,
您還必須提供頒發者信任根(issuer trust root)和頒發者憑據(issuer credentials),
如使用 Helm 安裝 Linkerd 中所述。
對於低於 v3 的 Helm 版本,必須專門傳遞 --name 標誌。
在 Helm v3 中,它已被棄用,並且是上面指定的第一個參數。
我是為少
微信:uuhells123
公眾號:黑客下午茶
加我微信(互相學習交流),關注公眾號(獲取更多學習資料~)

