在 Kubernetes 中實現 TLS termination 非常容易。Ingress 資源包含一 secretName
屬性,用於指定 Secret 資源名稱。在取得證照後,通過 kubectl create secret tls tls-secret --key tls.key --cert tls.crt
建立 Secret 儲存證照,便可以被 Ingress 使用了。
唯獨有些不方便的是,證照的申請以及建立 Secret 的過程需要手動執行。在證照即將過期前,還需要人工續期。在傳統 VM 部署的場景下,可以使用例如 certbot 或 acme.sh 等專案,配合 Let’s Encrypt 自動申請並定期續簽證照。而在 K8s 叢集中如何降低證照維護成本?來看看我們是怎麼做的。
認識 Cert-Manager
Cert-manager 顧名思義,是一款管理證照的工具。根據官網的描述:
cert-manager builds on top of Kubernetes, introducing certificate authorities and certificates as first-class resource types in the Kubernetes API. This makes it possible to provide ‘certificates as a service’ to developers working within your Kubernetes cluster.
簡單來說,cert-manager 利用 Kubernetes 的 CRD 特性提供了名為 Certificate 等資源,實現「證照即服務」。請看接下來的例子。
安裝 Cert-Manager
Cert-manager 的安裝方法有多種,可通過 kubectl
直接 apply 所有 manifest;也可以先安裝 CRD,再通過 Helm 安裝其它資源。
我個人傾向於後者。一鍵 apply 固然簡單,但沒有機會調整任何配置。使用 Helm 安裝 cert-manager 的 Chart 則可以根據需要調整部分選項。具體過程限於篇幅不再詳述,請查閱官方文件,僅展示我們使用的 helmfile.yaml
以供參考:
repositories:
- name: jetstack
url: https://charts.jetstack.io
releases:
- name: cert-manager
namespace: cert-manager
chart: jetstack/cert-manager
version: ^0.14.0
values:
- values/cert-manager/values.yaml
配置 Cert-Manager
建立 Issuer
Issuer 的作用主要是指定證照以何種方式簽發。目前 cert-manager 支援的 Issuer 型別有 ACME
、SelfSigned
等。其中,ACME 支援的驗證型別包括 HTTP01 和 DNS01。
使用 HTTP01 驗證 cert-manager 將會修改或建立新的 Ingress 資源用來處理 ACME 服務的驗證請求。而 DNS01 則只需配置 DNS 服務提供商的金鑰,cert-manager 負責維護對應的驗證記錄即可。我們使用的是 AWS 的 Route53 服務,正好也在 cert-manager 內建支援的 DNS provider 列表 內。因此我們選用了後者。
另外,cert-manager 提供了兩種 Issuer — Issuer
和 ClusterIssuer
,前者僅限於 Issuer 所在的名稱空間內使用,而 ClusterIssuer 可在叢集內的任意名稱空間通用。
我們建立了兩個 ClusterIssuer,名叫 letsencrypt-prd
和 letsencrypt-stg
,例如:
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: letsencrypt-prd
spec:
acme:
email: user@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prd # 用於儲存 ACME Account 私鑰的 Secret
solvers:
- selector: {}
dns01:
route53: # Route53 相關引數
region: us-east-2
accessKeyID: ... # AWS Access Key ID
secretAccessKeySecretRef:
name: route53-secret-access-key # 儲存 AWS Access Key Secret 的 Kubernetes Secret 名稱
key: secret_access_key # 儲存 AWS Access Key Secret 值的欄位名
修改 Chart Values
在上面的 helmfile.yaml
中,可以看到我們配置了 values 檔案 values/cert-manager/values.yaml
,內容如下:
ingressShim:
defaultIssuerKind: ClusterIssuer
defaultIssuerName: letsencrypt-prd # 剛剛建立的 ClusterIssuer 名稱
我們配置了針對 ingressShim
的預設 Issuer。這樣我們就可以不手動建立 Certificate,cert-manager 將會「監視」叢集內的 Ingress 資源,當有 Ingress 配置了 spec.tls
時,自動讀取 hosts
、建立證照並將證照儲存至 secretName
指定的 Secret 內,實現完全自動化。
建立並使用證照
由於開啟了 ingressShim
功能,因此我們只要按照通常思路使用 Ingress 即可。例如:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: api
namespace: staging
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: api
servicePort: http
path: /
tls:
- secretName: api-tls-certificate
把 spec.tls.secretName
設定為想要儲存證照的 Secret 名稱(例如例子中的 api-tls-certificate
),cert-manager 將讀取這個名稱並將申請好的證照儲存到該 Secert 內,以供 Ingress 使用。
小結
根據上文的介紹,似乎這是一套完美的解決方案?不盡然。
目前 cert-manager 專案還處於 beta 階段,每次釋出新的 release 都可能包含 breaking change。在我們使用的這段時間內,每隔幾個版本就需要手動升級一次,升級過程中有時會出現一些意料之外的小問題。例如最近的 0.13
-> 0.14
升級過程中,發現新版本的 CRD manifests 硬編碼要求相關資源必須安裝到 cert-manager
名稱空間。希望 cert-manager 官方能儘快推進正式版的釋出,減少手動升級的次數和成本。
本作品採用《CC 協議》,轉載必須註明作者和本文連結