
簡介
Cert-Manager[1]是一款用于 Kubernetes 集群中自動化管理 TLS 證書的開源工具,它使用了 Kubernetes 的自定義資源定義(CRD)機制,讓證書的創(chuàng)建、更新和刪除變得非常容易。
設(shè)計理念
Cert-Manager 是將 TLS 證書視為一種資源,就像 Pod、Service 和 Deployment 一樣,可以使用 Kubernetes API 進(jìn)行管理。它使用了自定義資源定義(CRD)機制,通過擴(kuò)展 Kubernetes API,為證書的生命周期提供了標(biāo)準(zhǔn)化的管理方式。
架構(gòu)設(shè)計
Cert-Manager 的架構(gòu)分為兩層:控制層和數(shù)據(jù)層。
控制層: 負(fù)責(zé)證書的管理,包括證書的創(chuàng)建、更新和刪除等。
數(shù)據(jù)層: 負(fù)責(zé)存儲證書相關(guān)的數(shù)據(jù),包括證書的私鑰、證書請求、證書頒發(fā)機構(gòu)等。
Cert-Manager 支持多種證書頒發(fā)機構(gòu),包括**自簽名證書selfSigned**、Let's Encrypt、HashiCorp Vault、Venafi 等。它還支持多種驗證方式,包括 HTTP 驗證、DNS 驗證和 TLS-SNI 驗證等。這些驗證方式可以幫助確保證書的頒發(fā)機構(gòu)是可信的,并且確保證書的私鑰不會泄露。
使用場景
Cert-Manager 的使用場景非常廣泛,包括以下幾個方面:
- HTTPS 訪問:通過 Cert-Manager 可以方便地為 Kubernetes 集群中的 Service 和 Ingress 創(chuàng)建 TLS 證書,以便實現(xiàn) HTTPS 訪問。
- 部署安全:Cert-Manager 可以為 Kubernetes 集群中的 Pod 創(chuàng)建 TLS 證書,以確保 Pod 之間的通信是加密的。
- 服務(wù)間認(rèn)證:Cert-Manager 可以為 Kubernetes 集群中的 Service 創(chuàng)建 TLS 證書,以確保 Service 之間的通信是加密的。
- 其他應(yīng)用場景:Cert-Manager 還可以用于為其他應(yīng)用程序創(chuàng)建 TLS 證書,以確保通信是加密的。
解決的實際問題
- 自動化管理證書:Cert-Manager 可以自動化地管理 TLS 證書,無需人工干預(yù),自動簽發(fā)證書以及過期前 renew 證書等問題,避免了證書管理的復(fù)雜性和錯誤。
- 安全性:Cert-Manager 可以幫助確保證書的頒發(fā)機構(gòu)是可信的,并確保證書的私鑰不會泄露,從而提高了通信的安全性。
- 管理成本:Cert-Manager 可以通過標(biāo)準(zhǔn)化證書的管理方式,簡化證書管理的成本和流程。
cert-manager 創(chuàng)建證書的過程
在 Kubernetes 中,cert-manager 通過以下流程創(chuàng)建資源對象以簽發(fā)證書:
- 創(chuàng)建一個 CertificateRequest 對象,包含證書的相關(guān)信息,例如證書名稱、域名等。該對象指定了使用的 Issuer 或 ClusterIssuer,以及證書簽發(fā)完成后,需要存儲的 Secret 的名稱。
- Issuer 或 ClusterIssuer 會根據(jù)證書請求的相關(guān)信息,創(chuàng)建一個 Order 對象,表示需要簽發(fā)一個證書。該對象包含了簽發(fā)證書所需的域名列表、證書簽發(fā)機構(gòu)的名稱等信息。
- 證書簽發(fā)機構(gòu)根據(jù) Order 對象中的信息創(chuàng)建一個或多個 Challenge 對象,用于驗證證書申請者對該域名的控制權(quán)。Challenge 對象包含一個 DNS 記錄或 HTTP 服務(wù),證明域名的所有權(quán)。
- cert-manager 接收到 Challenge 對象的回應(yīng)ChallengeResponse后,會將其更新為已解決狀態(tài)。證書簽發(fā)機構(gòu)會檢查所有的 Challenge 對象,如果全部通過驗證,則會簽發(fā)證書。
- 簽發(fā)證書完成后,證書簽發(fā)機構(gòu)會將證書信息寫入 Secret 對象,同時將 Order 對象標(biāo)記為已完成。證書信息現(xiàn)在可以被其他部署對象使用。
cert-manager 在 k8s 中創(chuàng)建證書的整個過程可以通過以下流程圖來描述:
+-------------+
| |
| Ingress/ |
| annotations |
| |
+------+------+
|
| watch ingress change
|
v
+-------------+
| |
| Issuer/ |
| ClusterIssuer |
| |
+------+------+
|
| Create CertificateRequest
|
v
+------+------+
| |
|CertificateRequest|
| |
+------+------+
|
| Create Order
|
v
+------+------+
| |
| Order |
| |
+------+------+
|
| Create Challenges
|
v
+------+------+
| |
| Challenge |
| |
+------+------+
|
| Respond to Challenge
|
v
+------+------+
| |
|ChallengeResponse|
| |
+------+------+
|
| Issue Certificate
|
v
+------+------+
| |
| Secret |
| |
+------+------+
實際上在我們手動實踐的時候,可以通過以下命令查看各個過程的信息:
kubectl get CertificateRequests,Orders,Challenges
到這里,在了解了 cert-manager 的設(shè)計理念、架構(gòu)設(shè)計、使用場景、實際解決的問題之后,動手操作利用 cert-manager 給實際項目創(chuàng)建證書。
安裝和配置
安裝 cert-manager。
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.yaml
NAME READY STATUS RESTARTS AGE
cert-manager-5d495db6fc-6rtxx 1/1 Running 0 9m56s
cert-manager-cainjector-5f9c9d977f-bxchd 1/1 Running 0 9m56s
cert-manager-webhook-57bd45f9c-89q87 1/1 Running 0 9m56s
使用 cmctl 命令行工具檢查 cert-manager 是否正常
brew install cmctl
cmctl check api
安裝完成后,Cert-manager 將自動創(chuàng)建 CRD(Custom Resource Definitions)和相關(guān)的資源,如證書、密鑰。
檢查 cert-manager 的webhook是否正常。
cat <<EOF > 02-test-resources.yaml
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager-test
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: test-selfsigned
namespace: cert-manager-test
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: selfsigned-cert
namespace: cert-manager-test
spec:
dnsNames:
- example.com
secretName: selfsigned-cert-tls
issuerRef:
name: test-selfsigned
EOF
kubectl apply -f 02-test-resources.yaml
kubectl delete -f 02-test-resources.yaml
創(chuàng)建 cert-manager 的證書頒發(fā)實體對象
cert-manager 的 Issuer 和 ClusterIssuer 都是用來定義證書頒發(fā)的實體的資源對象。
- Issuer 是命名空間級別的資源,用于在命名空間內(nèi)頒發(fā)證書。例如,當(dāng)您需要使用自簽名證書來保護(hù)您的服務(wù),或者使用 Let's Encrypt 等公共證書頒發(fā)機構(gòu)來頒發(fā)證書時,可以使用 Issuer。
- ClusterIssuer 是集群級別的資源,用于在整個集群內(nèi)頒發(fā)證書。例如,當(dāng)您需要使用公司的內(nèi)部 CA 來頒發(fā)證書時,可以使用 ClusterIssuer。
知道兩者之間的區(qū)別之后,你就可以根據(jù)自己的使用情況來決定自己的 issuer 的類型。這里列出幾種常用的 issuer 使用模板:
- 創(chuàng)建 staging 環(huán)境的證書頒發(fā)者 issuer。
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-staging
spec:
acme:
# The ACME server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: xxx@qq.com #此處填寫你的郵箱地址
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx
使用 staging 環(huán)境頒發(fā)的證書無法正常在公網(wǎng)使用,需要本地添加受信任根證書。
- 創(chuàng)建 prod 環(huán)境的證書頒發(fā)者 issuer。
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration 歡迎關(guān)注·云原生生態(tài)圈
email: xxx@qq.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx
- 創(chuàng)建 staging 環(huán)境的證書頒發(fā)者 ClusterIssuer。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
# The ACME server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration 歡迎關(guān)注·云原生生態(tài)圈
email: xxx@qq.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx
- 創(chuàng)建 Prod 環(huán)境的證書頒發(fā)者 ClusterIssuer。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration 歡迎關(guān)注·云原生生態(tài)圈
email: xxx@qq.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx
通過應(yīng)用實際測試一下
這里我們基本上就完成了 cert-manager 簽署證書的所有前置工作,下面通過一個簡單實例測試證書:這里我們部署一個開源小項目文件傳遞柜
apiVersion: v1
kind: PersistentVolume
metadata:
name: filecodebox-pv
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/data/filecodebox"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: filecodebox-pvc
namespace: blogs
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: filecodebox
namespace: blogs
labels:
app: filecodebox
spec:
replicas: 1
template:
metadata:
name: filecodebox
labels:
app: filecodebox
spec:
containers:
- name: filecodebox
image: lanol/filecodebox:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /app/data
name: filecodeboxdata
- mountPath: /etc/localtime
name: timezone
readOnly: true
restartPolicy: Always
volumes:
- name: filecodeboxdata
persistentVolumeClaim:
claimName: filecodebox-pvc
- name: timezone
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
selector:
matchLabels:
app: filecodebox
---
apiVersion: v1
kind: Service
metadata:
name: filecodebox-svc
namespace: blogs
spec:
selector:
app: filecodebox
ports:
- port: 12345
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: filecodebox-ingress
namespace: blogs
labels:
exposed_by: ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod" #此處我們是基于issuer頒發(fā)一個prod的證書
spec:
ingressClassName: nginx
tls:
- hosts:
- file.devopsman.cn
secretName: filecodebox-tls
rules:
- host: file.devopsman.cn
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: filecodebox-svc
port:
number: 12345
創(chuàng)建之后,這里就可以檢驗一下證書的有效期,查看是否生效。
root# echo | openssl s_client -servername file.devopsman.cn -connect file.devopsman.cn:443 2>/dev/null | openssl x509 -noout -dates
notBefore=Mar 1 04:02:01 2023 GMT
notAfter=May 30 04:02:00 2023 GMT
這里我們也可以通過 kubectl 查看簽發(fā)生成的證書來確定。
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
creationTimestamp: "2023-03-01T05:01:18Z"
generation: 1
labels:
exposed_by: ingress
name: filecodebox-tls
namespace: blogs
ownerReferences:
- apiVersion: networking.k8s.io/v1
blockOwnerDeletion: true
controller: true
kind: Ingress
name: filecodebox-ingress
uid: 3e2972a3-934b-431f-afee-4f649f5e1df3
resourceVersion: "26802670"
uid: 3d58d600-87aa-4119-bbdd-6566a8a0331b
spec:
dnsNames:
- file.devopsman.cn
issuerRef:
group: cert-manager.io
kind: ClusterIssuer
name: letsencrypt-prod
secretName: filecodebox-tls
usages:
- digital signature
- key encipherment
status:
conditions:
- lastTransitionTime: "2023-03-01T05:02:03Z"
message: Certificate is up to date and has not expired
observedGeneration: 1
reason: Ready
status: "True"
type: Ready
notAfter: "2023-05-30T04:02:00Z"
notBefore: "2023-03-01T04:02:01Z"
renewalTime: "2023-04-30T04:02:00Z"
revision: 1
在上面了解完證書頒發(fā)到簽發(fā)的過程后,就可以通過以下命令查看整個過程大概的細(xì)節(jié)
kubectl get CertificateRequests,Orders,Challenges
寫到這里,cert-manager 簽署證書請求的方式基本上了解了,有感興趣的話題,可以一起交流,下一篇準(zhǔn)備記錄一下 cert-manager 如何在內(nèi)部局域網(wǎng)如何通過創(chuàng)建自簽頒發(fā)者來頒發(fā)以及簽發(fā)我們需要的證書來在盡可能節(jié)省成本的基礎(chǔ)上模擬真實環(huán)境。