
簡(jiǎn)介
Cert-Manager[1]是一款用于 Kubernetes 集群中自動(dòng)化管理 TLS 證書(shū)的開(kāi)源工具,它使用了 Kubernetes 的自定義資源定義(CRD)機(jī)制,讓證書(shū)的創(chuàng)建、更新和刪除變得非常容易。
設(shè)計(jì)理念
Cert-Manager 是將 TLS 證書(shū)視為一種資源,就像 Pod、Service 和 Deployment 一樣,可以使用 Kubernetes API 進(jìn)行管理。它使用了自定義資源定義(CRD)機(jī)制,通過(guò)擴(kuò)展 Kubernetes API,為證書(shū)的生命周期提供了標(biāo)準(zhǔn)化的管理方式。
架構(gòu)設(shè)計(jì)
Cert-Manager 的架構(gòu)分為兩層:控制層和數(shù)據(jù)層。
控制層: 負(fù)責(zé)證書(shū)的管理,包括證書(shū)的創(chuàng)建、更新和刪除等。
數(shù)據(jù)層: 負(fù)責(zé)存儲(chǔ)證書(shū)相關(guān)的數(shù)據(jù),包括證書(shū)的私鑰、證書(shū)請(qǐng)求、證書(shū)頒發(fā)機(jī)構(gòu)等。
Cert-Manager 支持多種證書(shū)頒發(fā)機(jī)構(gòu),包括**自簽名證書(shū)selfSigned**、Let's Encrypt、HashiCorp Vault、Venafi 等。它還支持多種驗(yàn)證方式,包括 HTTP 驗(yàn)證、DNS 驗(yàn)證和 TLS-SNI 驗(yàn)證等。這些驗(yàn)證方式可以幫助確保證書(shū)的頒發(fā)機(jī)構(gòu)是可信的,并且確保證書(shū)的私鑰不會(huì)泄露。
使用場(chǎng)景
Cert-Manager 的使用場(chǎng)景非常廣泛,包括以下幾個(gè)方面:
- HTTPS 訪問(wèn):通過(guò) Cert-Manager 可以方便地為 Kubernetes 集群中的 Service 和 Ingress 創(chuàng)建 TLS 證書(shū),以便實(shí)現(xiàn) HTTPS 訪問(wèn)。
- 部署安全:Cert-Manager 可以為 Kubernetes 集群中的 Pod 創(chuàng)建 TLS 證書(shū),以確保 Pod 之間的通信是加密的。
- 服務(wù)間認(rèn)證:Cert-Manager 可以為 Kubernetes 集群中的 Service 創(chuàng)建 TLS 證書(shū),以確保 Service 之間的通信是加密的。
- 其他應(yīng)用場(chǎng)景:Cert-Manager 還可以用于為其他應(yīng)用程序創(chuàng)建 TLS 證書(shū),以確保通信是加密的。
解決的實(shí)際問(wèn)題
- 自動(dòng)化管理證書(shū):Cert-Manager 可以自動(dòng)化地管理 TLS 證書(shū),無(wú)需人工干預(yù),自動(dòng)簽發(fā)證書(shū)以及過(guò)期前 renew 證書(shū)等問(wèn)題,避免了證書(shū)管理的復(fù)雜性和錯(cuò)誤。
- 安全性:Cert-Manager 可以幫助確保證書(shū)的頒發(fā)機(jī)構(gòu)是可信的,并確保證書(shū)的私鑰不會(huì)泄露,從而提高了通信的安全性。
- 管理成本:Cert-Manager 可以通過(guò)標(biāo)準(zhǔn)化證書(shū)的管理方式,簡(jiǎn)化證書(shū)管理的成本和流程。
cert-manager 創(chuàng)建證書(shū)的過(guò)程
在 Kubernetes 中,cert-manager 通過(guò)以下流程創(chuàng)建資源對(duì)象以簽發(fā)證書(shū):
- 創(chuàng)建一個(gè) CertificateRequest 對(duì)象,包含證書(shū)的相關(guān)信息,例如證書(shū)名稱、域名等。該對(duì)象指定了使用的 Issuer 或 ClusterIssuer,以及證書(shū)簽發(fā)完成后,需要存儲(chǔ)的 Secret 的名稱。
- Issuer 或 ClusterIssuer 會(huì)根據(jù)證書(shū)請(qǐng)求的相關(guān)信息,創(chuàng)建一個(gè) Order 對(duì)象,表示需要簽發(fā)一個(gè)證書(shū)。該對(duì)象包含了簽發(fā)證書(shū)所需的域名列表、證書(shū)簽發(fā)機(jī)構(gòu)的名稱等信息。
- 證書(shū)簽發(fā)機(jī)構(gòu)根據(jù) Order 對(duì)象中的信息創(chuàng)建一個(gè)或多個(gè) Challenge 對(duì)象,用于驗(yàn)證證書(shū)申請(qǐng)者對(duì)該域名的控制權(quán)。Challenge 對(duì)象包含一個(gè) DNS 記錄或 HTTP 服務(wù),證明域名的所有權(quán)。
- cert-manager 接收到 Challenge 對(duì)象的回應(yīng)ChallengeResponse后,會(huì)將其更新為已解決狀態(tài)。證書(shū)簽發(fā)機(jī)構(gòu)會(huì)檢查所有的 Challenge 對(duì)象,如果全部通過(guò)驗(yàn)證,則會(huì)簽發(fā)證書(shū)。
- 簽發(fā)證書(shū)完成后,證書(shū)簽發(fā)機(jī)構(gòu)會(huì)將證書(shū)信息寫(xiě)入 Secret 對(duì)象,同時(shí)將 Order 對(duì)象標(biāo)記為已完成。證書(shū)信息現(xiàn)在可以被其他部署對(duì)象使用。
cert-manager 在 k8s 中創(chuàng)建證書(shū)的整個(gè)過(guò)程可以通過(guò)以下流程圖來(lái)描述:
+-------------+
| |
| 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 |
| |
+------+------+
實(shí)際上在我們手動(dòng)實(shí)踐的時(shí)候,可以通過(guò)以下命令查看各個(gè)過(guò)程的信息:
kubectl get CertificateRequests,Orders,Challenges
到這里,在了解了 cert-manager 的設(shè)計(jì)理念、架構(gòu)設(shè)計(jì)、使用場(chǎng)景、實(shí)際解決的問(wèn)題之后,動(dòng)手操作利用 cert-manager 給實(shí)際項(xiàng)目創(chuàng)建證書(shū)。
安裝和配置
安裝 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 將自動(dòng)創(chuàng)建 CRD(Custom Resource Definitions)和相關(guān)的資源,如證書(shū)、密鑰。
檢查 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 的證書(shū)頒發(fā)實(shí)體對(duì)象
cert-manager 的 Issuer 和 ClusterIssuer 都是用來(lái)定義證書(shū)頒發(fā)的實(shí)體的資源對(duì)象。
- Issuer 是命名空間級(jí)別的資源,用于在命名空間內(nèi)頒發(fā)證書(shū)。例如,當(dāng)您需要使用自簽名證書(shū)來(lái)保護(hù)您的服務(wù),或者使用 Let's Encrypt 等公共證書(shū)頒發(fā)機(jī)構(gòu)來(lái)頒發(fā)證書(shū)時(shí),可以使用 Issuer。
- ClusterIssuer 是集群級(jí)別的資源,用于在整個(gè)集群內(nèi)頒發(fā)證書(shū)。例如,當(dāng)您需要使用公司的內(nèi)部 CA 來(lái)頒發(fā)證書(shū)時(shí),可以使用 ClusterIssuer。
知道兩者之間的區(qū)別之后,你就可以根據(jù)自己的使用情況來(lái)決定自己的 issuer 的類型。這里列出幾種常用的 issuer 使用模板:
- 創(chuàng)建 staging 環(huán)境的證書(shū)頒發(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 #此處填寫(xiě)你的郵箱地址
# 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ā)的證書(shū)無(wú)法正常在公網(wǎng)使用,需要本地添加受信任根證書(shū)。
- 創(chuàng)建 prod 環(huán)境的證書(shū)頒發(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)境的證書(shū)頒發(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)境的證書(shū)頒發(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
通過(guò)應(yīng)用實(shí)際測(cè)試一下
這里我們基本上就完成了 cert-manager 簽署證書(shū)的所有前置工作,下面通過(guò)一個(gè)簡(jiǎn)單實(shí)例測(cè)試證書(shū):這里我們部署一個(gè)開(kāi)源小項(xiàng)目文件傳遞柜
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ā)一個(gè)prod的證書(shū)
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)建之后,這里就可以檢驗(yàn)一下證書(shū)的有效期,查看是否生效。
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
這里我們也可以通過(guò) kubectl 查看簽發(fā)生成的證書(shū)來(lái)確定。
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
在上面了解完證書(shū)頒發(fā)到簽發(fā)的過(guò)程后,就可以通過(guò)以下命令查看整個(gè)過(guò)程大概的細(xì)節(jié)
kubectl get CertificateRequests,Orders,Challenges
寫(xiě)到這里,cert-manager 簽署證書(shū)請(qǐng)求的方式基本上了解了,有感興趣的話題,可以一起交流,下一篇準(zhǔn)備記錄一下 cert-manager 如何在內(nèi)部局域網(wǎng)如何通過(guò)創(chuàng)建自簽頒發(fā)者來(lái)頒發(fā)以及簽發(fā)我們需要的證書(shū)來(lái)在盡可能節(jié)省成本的基礎(chǔ)上模擬真實(shí)環(huán)境。