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

Certificate resource (憑證資源)

apiVersion: cert-manager.io/v1
kind: Certificate

在 cert-manager 中,Certificate 資源代表憑證請求的可讀定義。cert-manager 使用此輸入來產生私鑰和 CertificateRequest 資源,以便從 IssuerClusterIssuer 取得已簽署的憑證。然後,已簽署的憑證和私鑰會儲存在指定的 Secret 資源中。cert-manager 將確保憑證在過期前自動續訂,並且在請求時重新頒發

為了頒發任何憑證,您需要先設定一個 IssuerClusterIssuer 資源。

建立憑證資源

Certificate 資源指定用於產生憑證簽署請求的欄位,然後由您所參考的簽發者類型來滿足這些請求。Certificates 指定它們想要從哪個簽發者取得憑證,透過指定 certificate.spec.issuerRef 欄位。

對於 example.comwww.example.com DNS 名稱、spiffe://cluster.local/ns/sandbox/sa/example URI 主體替代名稱、有效期為 90 天且在到期前 15 天續訂的 Certificate 資源範例如下。它包含 Certificate 資源可能擁有的所有選項的詳盡列表,但只有標示的欄位子集是必要的。

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com
namespace: sandbox
spec:
# Secret names are always required.
secretName: example-com-tls
# secretTemplate is optional. If set, these annotations and labels will be
# copied to the Secret named example-com-tls. These labels and annotations will
# be re-reconciled if the Certificate's secretTemplate changes. secretTemplate
# is also enforced, so relevant label and annotation changes on the Secret by a
# third party will be overwriten by cert-manager to match the secretTemplate.
secretTemplate:
annotations:
my-secret-annotation-1: "foo"
my-secret-annotation-2: "bar"
labels:
my-secret-label: foo
privateKey:
algorithm: RSA
encoding: PKCS1
size: 2048
# keystores allows adding additional output formats. This is an example for reference only.
keystores:
pkcs12:
create: true
passwordSecretRef:
name: example-com-tls-keystore
key: password
profile: Modern2023
duration: 2160h # 90d
renewBefore: 360h # 15d
isCA: false
usages:
- server auth
- client auth
subject:
organizations:
- cert-manager
# Avoid using commonName for DNS names in end-entity (leaf) certificates. Unless you have a specific
# need for it in your environment, use dnsNames exclusively to avoid issues with commonName.
# Usually, commonName is used to give human-readable names to CA certificates and can be avoided for
# other certificates.
commonName: example.com
# The literalSubject field is exclusive with subject and commonName. It allows
# specifying the subject directly as a string. This is useful for when the order
# of the subject fields is important or when the subject contains special types
# which can be specified by their OID.
#
# literalSubject: "O=jetstack, CN=example.com, 2.5.4.42=John, 2.5.4.4=Doe"
# At least one of commonName (possibly through literalSubject), dnsNames, uris, emailAddresses, ipAddresses or otherNames is required.
dnsNames:
- example.com
- www.example.com
uris:
- spiffe://cluster.local/ns/sandbox/sa/example
emailAddresses:
- john.doe@cert-manager.io
ipAddresses:
- 192.168.0.5
# Needs cert-manager 1.14+ and "OtherNames" feature flag
otherNames:
# Should only supply oid of ut8 valued types
- oid: 1.3.6.1.4.1.311.20.2.3 # User Principal Name "OID"
utf8Value: upn@example.local
# Issuer references are always required.
issuerRef:
name: ca-issuer
# We can reference ClusterIssuers by changing the kind here.
# The default value is Issuer (i.e. a locally namespaced Issuer)
kind: Issuer
# This is optional since cert-manager will default to this value however
# if you are using an external issuer, change this to that issuer group.
group: cert-manager.io

簽署的憑證將儲存在名為 example-com-tlsSecret 資源中,該資源與 Certificate 位於相同的命名空間中,一旦簽發者成功頒發請求的憑證。

如果存在 secretTemplate,則在此屬性中設定的註釋和標籤將複製到 example-com-tls 密鑰。這兩個屬性都是可選的。

Certificate 將使用在 sandbox 命名空間(與 Certificate 資源相同的命名空間)中名為 ca-issuer 的簽發者來頒發。

注意:如果您想要建立一個可以被所有命名空間中的 Certificate 資源引用的 Issuer,您應該建立一個 ClusterIssuer 資源,並將 certificate.spec.issuerRef.kind 欄位設定為 ClusterIssuer

注意:renewBeforeduration 欄位必須使用 Go time.Duration 字串格式指定,此格式不允許使用 d (天) 後綴。您必須改用 smh 後綴來指定這些值。如果沒有安裝 webhook 組件,則未能這樣做可能會阻止 cert-manager 正確運作 #1269

注意:請謹慎將 renewBefore 欄位設定為非常接近 duration 的值,因為這可能會導致續訂迴圈,其中 Certificate 始終處於續訂期間。某些 Issuers 會在頒發時間之前,在其頒發的 X.509 憑證上設定 notBefore 欄位,以解決時鐘偏差問題,導致憑證的有效期限少於憑證的完整期限。例如,Let's Encrypt 將其設定為頒發時間前一小時,因此憑證的實際有效期限為 89 天 23 小時(完整期限仍然是 90 天)。

可以在 API 參考文件中找到憑證資源上支援的欄位的完整列表。

目標密鑰

當憑證由中繼 CA 頒發,且 Issuer 可以提供頒發的憑證鏈時,tls.crt 的內容將是請求的憑證,後接憑證鏈。

此外,如果已知憑證授權單位,則對應的 CA 憑證將儲存在密鑰中,且密鑰為 ca.crt。例如,對於 ACME 簽發者,CA 是未知的,並且 ca.crt 將不存在於密鑰中。頒發時的 ca.crt 值可以複製到使用憑證的應用程式的信任儲存區中。但是,請勿直接將 ca.crt 值掛載到應用程式的信任儲存區中,因為憑證續訂時會更新此值(如需更多詳細資訊,請參閱信任憑證)。

cert-manager 有意避免將根憑證新增至 tls.crt,因為在安全地進行 TLS 的情況下,它們毫無用處。如需更多資訊,請參閱 RFC 5246 第 7.4.2 節,其中包含以下說明

因為憑證驗證要求獨立散發根金鑰,所以指定根憑證授權單位本身的自我簽署憑證可以從鏈中省略,假設遠端端點必須已擁有它,以便在任何情況下都進行驗證。

X.509 金鑰用法和擴展金鑰用法

cert-manager 支援請求具有多種自訂金鑰用法延伸金鑰用法的憑證。雖然 cert-manager 會嘗試遵守此請求,但某些發行者會移除、新增預設值或完全忽略該請求。CASelfSigned Issuer 一律會傳回符合您所請求用法的憑證。

除非已設定任何數量的用法,否則 cert-manager 將會設定預設請求用法為 數位簽章金鑰加密伺服器驗證。如果目前的憑證與目前設定的金鑰用法不符,cert-manager 將不會嘗試請求新的憑證。

支援的金鑰用法完整清單,請參閱API 參考文件

其他憑證輸出格式

additionalOutputFormats 是憑證 spec 中的一個欄位,允許指定已發行憑證及其私密金鑰的其他補充格式。目前支援兩種額外的輸出格式:CombinedPEMDER。這兩種輸出格式都可以在同一個憑證上指定。

apiVersion: cert-manager.io/v1
kind: Certificate
spec:
...
secretName: my-cert-tls
additionalOutputFormats:
- type: CombinedPEM
- type: DER
# Results in:
apiVersion: v1
kind: Secret
metadata:
name: my-cert-tls
type: kubernetes.io/tls
data:
ca.crt: <PEM CA certificate>
tls.key: <PEM private key>
tls.crt: <PEM signed certificate chain>
tls-combined.pem: <PEM private key + "\n" + PEM signed certificate chain>
key.der: <DER binary format of private key>

CombinedPEM

CombinedPEM 類型將在產生的憑證 Secret 中建立一個新的金鑰項目 tls-combined.pem。此項目將包含 PEM 編碼的私密金鑰,後跟至少一個換行字元,接著是 PEM 編碼的已簽署憑證鏈。

<private key> + "\n" + <signed certificate chain>
apiVersion: v1
kind: Secret
metadata:
name: my-cert-tls
type: kubernetes.io/tls
data:
tls-combined.pem: <PEM private key + "\n" + PEM signed certificate chain>
...

DER

DER 類型將在產生的憑證 Secret 中建立一個新的金鑰項目 key.der。此項目將包含私密金鑰的 DER 二進位格式。

apiVersion: v1
kind: Secret
metadata:
name: my-cert-tls
type: kubernetes.io/tls
data:
key.der: <DER binary format of private key>
...

建立具有名稱限制的憑證

根憑證或中繼 CA 憑證可以具有名稱限制。名稱限制表示一個名稱空間,憑證路徑中所有後續憑證的主體名稱都必須位於該空間內。請查看 https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 以取得更多詳細資訊。

⛔️ 只有在 cert-manager 控制器和 webhook 元件上新增到 --feature-gates 標記後,才能啟用此功能

--feature-gates=NameConstraints=true

若要建立具有名稱限制的 CA 憑證,請使用以下設定

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: ca-cert-example
spec:
secretName: example-ca-key-pair
isCA: true
issuerRef:
name: selfsigned
kind: ClusterIssuer
commonName: "example1.com"
dnsNames:
- example1.com
nameConstraints:
critical: true
permitted:
dnsDomains: ["example1.com", "example2.com"]
ipRanges: ["10.10.0.0/16"]
emailAddress: ["example@example.org"]
excluded:
ipRanges: ["10.10.0.0/24"]

請注意,當與 cert-manager 內建的 CA 和 SelfSigned 發行者一起使用時,SAN(DNS 名稱、IP 位址、URI 和電子郵件地址)不會與憑證本身的名稱限制進行檢查,也不會與憑證所屬憑證鏈中包含的任何名稱限制進行檢查。

憑證可能會成功發行,但在 TLS 交握期間被用戶端拒絕。

發行觸發

由到期觸發的重新發行(續約)

cert-manager 將自動續約 Certificate。它將根據已發行的 X.509 憑證的持續時間和一個「renewBefore」值來計算何時續約 Certificate,該值指定憑證應在到期前多久之前續約。

spec.durationspec.renewBefore/ spec.renewBeforePercentage Certificate 上的欄位可用於指定 X.509 憑證的持續時間和「renewBefore」值。spec.duration 的預設值為 90 天。某些發行者可能會設定為僅發行具有設定持續時間的憑證,因此實際持續時間可能會有所不同。spec.renewBefore 指定絕對持續時間,而 spec.renewBeforePercentage 使用已發行憑證的實際持續時間來計算有效的「renewBefore」。建議使用 spec.renewBeforePercentage,以防止在實際持續時間少於預期時出現續約迴圈。spec.duration 的最小值為 1 小時,有效 spec.renewBefore 的最小值為 5 分鐘。也必須 spec.duration > spec.renewBefore

一旦發行 X.509 憑證,cert-manager 將計算 Certificate 的續約時間。預設情況下,這將是 X.509 憑證持續時間的 2/3。如果已設定 spec.renewBeforespec.renewBeforePercentage,它將是到期前有效的 spec.renewBefore 時間量。cert-manager 將 Certificatestatus.RenewalTime 設定為將嘗試續約的時間。

由使用者操作觸發的重新發行

在下列情況下,憑證物件會重新發行

  • 當憑證的 spec 中的下列其中一個欄位發生變更時:commonNamednsNamesipAddressesurisemailAddressessubjectisCAusagesdurationissuerRef;更詳細的說明可在常見問題頁面上找到。
  • 當使用下列方式手動觸發重新發行時
    cmctl renew cert-1
    請注意,上述命令需要 cmctl

刪除與憑證資源相關聯的 Secret 資源並非手動輪換私密金鑰的建議解決方案。手動輪換私密金鑰的建議方式是使用以下命令觸發憑證資源的重新發行(需要 cmctl

cmctl renew cert-1

發行行為:發行時的臨時憑證

當請求憑證使用 ingress-shim時,如果使用元件 ingress-gce,則在等待簽署憑證發行時,需要存在臨時憑證。為了方便起見,如果使用以下註解

cert-manager.io/issue-temporary-certificate: "true"

如果憑證上不存在已簽署的憑證,則在簽署憑證發出之前,Secret 上會存在一個自簽的臨時憑證,直到被覆寫為止。

在 Ingress 上加入以下註解將會自動在憑證上設定 "issue-temporary-certificate"

acme.cert-manager.io/http01-edit-in-place: "true"

發行行為:私鑰輪換

預設情況下,私鑰不會自動輪換。使用設定 rotationPolicy: Always,可以將與憑證物件相關聯的私鑰 Secret 設定為在憑證重新發行時立即輪換(請參閱發行觸發器)。

使用 rotationPolicy: Always,cert-manager 會等到憑證物件正確簽署後,才會覆寫 Secret 中的 tls.key 檔案。

有了此設定,如果您的應用程式可以偵測到掛載的 tls.crttls.key 的變更,並優雅地重新載入它們或自動重新啟動,您可以預期不會有停機時間

如果您的應用程式僅在啟動時載入私鑰和已簽署的憑證一次,則您的應用程式不會立即提供新的憑證,您需要使用 kubectl rollout restart 手動重新啟動您的 pod,或透過執行 wave 來自動執行此操作。Wave 是一個 Secret 控制器,可確保在掛載的 Secret 變更時重新啟動部署。

私鑰的重複使用

某些簽發者(例如內建的 Venafi 簽發者)可能不允許重複使用私鑰。如果是這種情況,您必須為每個憑證物件明確配置 rotationPolicy: Always 設定。

在以下範例中,憑證已設定為 rotationPolicy: Always

apiVersion: cert-manager.io/v1
kind: Certificate
spec:
secretName: my-cert-tls
privateKey:
rotationPolicy: Always # 🔰 Here.

rotationPolicy 設定

rotationPolicy 的可能值為

描述
Never (預設)cert-manager 在每次發行時重複使用現有的私鑰
Always (建議)cert-manager 在每次發行時重新產生新的私鑰

使用 rotationPolicy: Never 時,僅當目標 Secret 資源中尚不存在私鑰時(使用 tls.key 金鑰),才會產生私鑰。所有進一步的發行都將重複使用此私鑰。為了與先前的版本保持相容性,這是預設值。

使用 rotationPolicy: Always 時,每次有動作觸發重新發行憑證物件時,都會產生新的私鑰(請參閱上方觸發私鑰輪換的動作)。請注意,如果在建立憑證物件時私鑰 Secret 已經存在,則不會使用現有的私鑰,因為輪換機制也包括初始發行。

👉 我們建議您在憑證資源上配置 rotationPolicy: Always。同時輪換憑證和私鑰可防止使用外洩的私鑰簽發憑證的風險。定期更新私鑰的另一個好處是讓您確信在緊急情況下可以完成私鑰輪換。更一般來說,盡可能經常輪換金鑰是一種好習慣,可以降低與金鑰洩漏相關的風險。

刪除憑證時清理 Secret

預設情況下,當對應的 Certificate 資源被刪除時,cert-manager 不會刪除包含已簽署憑證的 Secret 資源。這表示刪除 Certificate 不會關閉任何目前依賴該憑證的服務,但該憑證將不再續約。如果不再需要該 Secret,則需要手動刪除。

如果您希望在刪除 Certificate 時自動刪除 Secret,您需要設定您的安裝,將 --enable-certificate-owner-ref 標誌傳遞給控制器。

開發人員的內部運作圖

[1] https://cert-manager.dev.org.tw/docs/usage/certificaterequest