新消息:在TwitterMastodon取得專案更新

ACME

ACME 簽發者類型代表在自動憑證管理環境 (ACME) 憑證授權伺服器上註冊的單一帳戶。當您建立新的 ACME Issuer 時,cert-manager 將會產生一個私鑰,用於在 ACME 伺服器上識別您的身分。

由公共 ACME 伺服器簽發的憑證通常預設受到客戶端電腦的信任。這表示,例如,瀏覽一個由為該 URL 簽發的 ACME 憑證所支援的網站,預設會被大多數客戶端的網頁瀏覽器信任。ACME 憑證通常是免費的。

解決挑戰

為了讓 ACME CA 伺服器驗證客戶端是否擁有網域,或正在請求憑證的網域,客戶端必須完成「挑戰」。這是為了確保客戶端無法為他們不擁有的網域請求憑證,並因此欺詐性地偽裝成其他人的網站。如 RFC8555 中詳述,cert-manager 提供兩種挑戰驗證方式 - HTTP01 和 DNS01 挑戰。

HTTP01 挑戰是透過呈現一個計算出的金鑰來完成的,該金鑰應該存在於 HTTP URL 端點,並且可以透過網際網路路由。此 URL 將使用為憑證請求的網域名稱。一旦 ACME 伺服器能夠從網際網路上的此 URL 取得此金鑰,ACME 伺服器就可以驗證您是此網域的所有者。當建立 HTTP01 挑戰時,cert-manager 將自動配置您的叢集入口 (ingress),以將此 URL 的流量路由到一個小的 Web 伺服器,該伺服器會呈現此金鑰。

DNS01 挑戰是透過提供一個計算出的金鑰來完成的,該金鑰存在於 DNS TXT 記錄中。一旦此 TXT 記錄已在網際網路上傳播,ACME 伺服器就可以透過 DNS 查詢成功檢索此金鑰,並且可以驗證客戶端擁有請求憑證的網域。憑藉正確的權限,cert-manager 將會自動為您指定的 DNS 提供者呈現此 TXT 記錄。

設定

建立基本的 ACME 簽發者

所有 ACME Issuers 都遵循類似的設定結構 - 客戶端的 emailserver URL、privateKeySecretRef 以及一個或多個 solvers。以下是一個簡單 ACME 簽發者的範例

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
# You must replace this email address with your own.
# Let's Encrypt will use this to contact you about expiring
# certificates, and issues related to your account.
email: user@example.com
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# Secret resource that will be used to store the account's private key.
name: example-issuer-account-key
# Add a single challenge solver, HTTP01 using nginx
solvers:
- http01:
ingress:
ingressClassName: nginx

解題器以 dns01http01 段落的形式出現。有關如何設定這些解題器類型的更多資訊,請參閱其各自的文件 - DNS01HTTP01

外部帳戶綁定

cert-manager 支援將外部帳戶綁定與您的 ACME 帳戶一起使用。外部帳戶綁定用於將您的 ACME 帳戶與外部帳戶(例如 CA 自訂資料庫)建立關聯。除非您明確知道需要它,否則大多數 cert-manager 使用者通常不需要此功能。

外部帳戶綁定在 ACME Issuer 上需要兩個欄位,代表您的 ACME 帳戶。這些欄位是

  • keyID - 您的外部帳戶綁定依外部帳戶管理員建立索引的金鑰 ID 或帳戶 ID
  • keySecretRef - 包含您的外部帳戶對稱 MAC 金鑰的 base 64 編碼 URL 字串的 Secret 名稱和金鑰

注意:在大多數情況下,MAC 金鑰必須以 base64URL 編碼。以下命令會對金鑰進行 base64 編碼並將其轉換為 base64URL

$ echo 'my-secret-key' | base64 -w0 | sed -e 's/+/-/g' -e 's/\//_/g' -e 's/=//g'

然後您可以使用以下程式碼建立 Secret 資源

$ kubectl create secret generic eab-secret --from-literal \
secret={base64 encoded secret key}

以下是一個具有外部帳戶綁定的 ACME 簽發者範例。

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: my-acme-server-with-eab
spec:
acme:
email: user@example.com
server: https://my-acme-server-with-eab.com/directory
externalAccountBinding:
keyID: my-keyID-1
keySecretRef:
name: eab-secret
key: secret
privateKeySecretRef:
name: example-issuer-account-key
solvers:
- http01:
ingress:
ingressClassName: nginx

注意:cert-manager v1.3.0 之前的版本也要求使用者透過設定 Issuer.spec.acme.externalAccountBinding.keyAlgorithm 欄位來指定 EAB 的 MAC 演算法。此欄位現在已棄用,因為上游 Go x/crypto 函式庫將演算法硬式編碼為 HS256。(請參閱上游的相關討論 CL#41430)。

重複使用 ACME 帳戶

您可能希望在多個叢集中重複使用單一 ACME 帳戶。當使用 EAB 時,這可能特別有用。如果設定 disableAccountKeyGeneration 欄位,cert-manager 將不會建立新的 ACME 帳戶,並且會使用 privateKeySecretRef 中指定的現有金鑰。請注意,Issuer/ClusterIssuer 將不會就緒,並且會持續重試,直到提供 Secret

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: my-acme-server-with-existing-acme-account
spec:
acme:
email: user@example.com
disableAccountKeyGeneration: true
privateKeySecretRef:
name: example-issuer-account-key

新增多種解題器類型

您可能希望對不同的入口控制器使用不同類型的挑戰解題器設定,例如,如果您想使用 DNS01 發出萬用字元憑證,同時使用 HTTP01 驗證其他憑證。

solvers 段落有一個選用的 selector 欄位,可用於指定哪些 Certificates,進一步來說,這些 Certificates 上的哪些 DNS 名稱應該用於解決挑戰。

可以使用三種選取器類型來形成 Certificate 必須滿足的要求,才能被選取為解題器 - matchLabelsdnsNamesdnsZones。您可以在單一解題器上使用這三種選取器的任意數量。

符合標籤

matchLabel 選擇器要求所有的 Certificates 必須匹配該段落字串映射列表中定義的所有標籤。例如,以下的 Issuer 只會匹配具有標籤 "user-cloudflare-solver": "true""email": "user@example.com"Certificates

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
...
solvers:
- dns01:
cloudflare:
email: user@example.com
apiKeySecretRef:
name: cloudflare-apikey-secret
key: apikey
selector:
matchLabels:
"use-cloudflare-solver": "true"
"email": "user@example.com"

DNS 名稱

dnsNames 選擇器是一個應映射到解析器的確切 DNS 名稱列表。這表示將會選取包含任何這些 DNS 名稱的 Certificates。如果找到匹配項,則 dnsNames 選擇器將優先於 dnsZones 選擇器。如果有多個解析器與相同的 dnsNames 值匹配,則將選擇在 matchLabels 中具有最多匹配標籤的解析器。如果兩者都沒有更多匹配項,則將選擇列表中較早定義的解析器。

以下範例將為具有 DNS 名稱 example.com*.example.comCertificates 解決這些網域的挑戰。

注意:dnsNames 採用完全匹配,且不解析萬用字元,這表示以下的 Issuer *將不會* 為諸如 foo.example.com 等 DNS 名稱進行解析。請使用 dnsZones 選擇器類型來匹配區域內的所有子網域。

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
...
solvers:
- dns01:
cloudflare:
email: user@example.com
apiKeySecretRef:
name: cloudflare-apikey-secret
key: apikey
selector:
dnsNames:
- 'example.com'
- '*.example.com'

DNS 區域

dnsZones 段落定義了此解析器可以解決的 DNS 區域列表。如果 DNS 名稱是完全匹配,或是任何指定 dnsZones 的子網域,則將使用此解析器,除非配置了更明確的 dnsNames 匹配項。這表示對於網域 www.sys.example.com,將選取指定 sys.example.com 的解析器,而非指定 example.com 的解析器。如果有多個解析器與相同的 dnsZones 值匹配,則將選擇在 matchLabels 中具有最多匹配標籤的解析器。如果兩者都沒有更多匹配項,則將選擇列表中較早定義的解析器。

在以下範例中,此解析器將為網域 example.com 及其所有子網域 *.example.com 解決挑戰。

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
...
solvers:
- dns01:
cloudflare:
email: user@example.com
apiKeySecretRef:
name: cloudflare-apikey-secret
key: apikey
selector:
dnsZones:
- 'example.com'

全部一起

每個解析器都可以定義任何數量的三種選擇器類型。在以下範例中,將使用 CloudFlare 的 DNS01 解析器來為包含 DNS 名稱 a.example.comb.example.comCertificates 解決網域的挑戰。將使用 Google CloudDNS 的 DNS01 解析器來為 DNS 名稱與區域 test.example.com 及其所有子網域(例如 foo.test.example.com)匹配的 Certificates 解決挑戰。

對於所有其他挑戰,*只有*在 Certificate 也包含標籤 "use-http01-solver": "true" 的情況下,才會使用 HTTP01 解析器。

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
...
solvers:
- http01:
ingress:
ingressClassName: nginx
selector:
matchLabels:
"use-http01-solver": "true"
- dns01:
cloudflare:
email: user@example.com
apiKeySecretRef:
name: cloudflare-apikey-secret
key: apikey
selector:
dnsNames:
- 'a.example.com'
- 'b.example.com'
- dns01:
cloudDNS:
project: my-project-id
hostedZoneName: 'test-example.com'
serviceAccountSecretRef:
key: sa
name: gcp-sa-secret
selector:
dnsZones:
- 'test.example.com' # This should be the DNS name of the zone

每個單獨的選擇器區塊可以包含多個選擇器類型,例如

solvers:
- dns01:
cloudflare:
email: user@example.com
apiKeySecretRef:
name: cloudflare-apikey-secret
key: apikey
selector:
matchLabels:
'email': 'user@example.com'
'solver': 'cloudflare'
dnsZones:
- 'test.example.com'
- 'example.dev'

在這種情況下,只有當 Certificate 具有來自 matchLabels 的標籤*且* DNS 名稱與來自 dnsZones 的區域匹配時,才會使用 Cloudflare 的 DNS01 解析器來解決 DNS 名稱的挑戰。

私人 ACME 伺服器

只要符合 ACME 規範,cert-manager 也應與私有或自行託管的 ACME 伺服器搭配使用。

如果您的 ACME 伺服器不使用公開信任的憑證,您可以從 cert-manager 1.11 開始,傳遞一個受信任的 CA,以在建立簽發者時使用

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: my-acme-server-issuer
spec:
acme:
server: https://my-acme-server.example.com
caBundle: <base64 encoded CA Bundle in PEM format>
...

替代憑證鏈

從 ACME 伺服器取得憑證時,可以選擇替代憑證鏈。這讓簽發者可以在轉換期間順利地將使用者轉移到新的根憑證;最著名的例子是 Let's Encrypt 的 「ISRG Root」變更

此功能並非 Let's Encrypt 專屬;如果您的 ACME 伺服器支援由多個 CA 簽署,您可以使用 preferredChain 以及您想要在憑證的簽發者部分中使用的鏈的通用名稱值。如果通用名稱與不同的鏈匹配,則伺服器可以選擇使用並傳回該新鏈。

如果 preferredChain 未與憑證匹配,則伺服器將傳回其認為的預設憑證。

舉例來說,以下是使用者在(現在已完成)「ISRG Root」變更之前如何要求替代鏈,但請注意,由於此變更已發生,因此不再需要 Let's Encrypt 的此做法

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
preferredChain: "ISRG Root X1"