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

學習如何自動設定憑證預設值

上次驗證時間:2024 年 1 月 19 日

目標

我們將設定一個叢集,讓使用者在 Certificate 資源中盡可能少指定 YAML。這將透過使用 Kyverno 將自訂「預設」值應用到使用者未指定的 Certificate 欄位來實現。

設定預設值有一些好處

  • Certificate 的使用者可以盡量減少 YAML 資源。
  • Certificate 的使用者在需要時仍保有覆寫欄位的彈性。
  • 叢集操作員可以決定預設值應該是什麼,而不必依賴 cert-manager 的內建預設值。

使用案例

透過在我們的叢集中設定自訂預設值,我們讓平台團隊能夠解決以下的使用案例

  • 確保 CertificateRequest 資源被清除。

    使用 ClusterPolicyCertificate.Spec.RevisionHistoryLimit 欄位設定自訂預設值。

  • 協助使用者為他們的 Certificate 資源選擇安全的預設金鑰設定。

    使用 ClusterPolicyCertificate.Spec.PrivateKey 欄位設定自訂預設值。

  • 為叢集內的使用者預設 Issuer

    使用 ClusterPolicyCertificate.spec.issuerRef 欄位設定自訂預設值。

  • 為憑證將被填入的 Secret 命名設定預設模式。

    使用 ClusterPolicy 為必要的 spec.secretName 欄位設定自訂預設值。

  • 讓應用程式開發人員的生活更輕鬆,允許他們以最少的配置來建立安全的 X.509 TLS 憑證。

    使用 ClusterPolicy 設定所有其他必要的 Certificate.spec 欄位。只需要一個單一身份規範欄位,也就是以下其中一個

    • commonNameliteralSubject
    • dnsNames
    • uris
    • emailAddresses
    • ipAddresses
    • otherNames

流程

我們將為三種不同的情境設定預設值,每次都稍微進階一些

  1. 為選用的 Certificate 資源欄位設定預設值。
  2. 為必要的 Certificate 資源欄位設定預設值。
  3. 在使用 Ingress 註解請求憑證時,為 Certificate 資源欄位設定預設值。

設定

先決條件

💻 軟體

  1. kubectl:Kubernetes 的命令列工具,可讓您設定 Kubernetes 叢集。
  2. helm:Kubernetes 的套件管理器。
  3. kind (選用):用於建立在 Docker 或其他容器執行階段中執行的本機 Kubernetes 環境。

本機 Kubernetes 環境

⚠️ 如果您有其他 Kubernetes 環境,可以跳過此步驟。

  1. 使用 kind 為本教學建立叢集環境。

    kind create cluster --name defaults

    ⏲ 建立叢集所需的時間應少於一分鐘,具體時間取決於您的電腦效能。

    ⚠️ 此叢集僅適用於學習用途。不適用於生產環境。

軟體安裝

當您擁有叢集環境後,請使用 helm 安裝所需的 Kubernetes 套件。

  1. 為 helm 圖表版本設定一些環境變數

    export CERT_MANAGER_CHART_VERSION="v1.16.1" \
    KYVERNO_CHART_VERSION="3.1.4" \
    INGRESS_NGINX_CHART_VERSION="4.9.0"
  2. 安裝 cert-manager

    helm upgrade --install cert-manager cert-manager \
    --namespace cert-manager \
    --version $CERT_MANAGER_CHART_VERSION \
    --set crds.enabled=true \
    --set startupapicheck.enabled=false \
    --create-namespace \
    --repo https://charts.jetstack.io/
  3. 安裝 Kyverno

    helm upgrade --install kyverno kyverno \
    --namespace kyverno-system \
    --version $KYVERNO_CHART_VERSION \
    --create-namespace \
    --repo https://kyverno.github.io/kyverno/
  4. 安裝 ingress-nginx

    helm upgrade --install ingress-nginx ingress-nginx \
    --namespace ingress-nginx \
    --version $INGRESS_NGINX_CHART_VERSION \
    --create-namespace \
    --repo https://kubernetes.github.io/ingress-nginx

如需完整的安裝說明,請參閱下列連結

設定預設值

主要教學從這裡開始,先介紹一些背景知識,然後再處理三種情境。

必要與非必要

Certificate 資源有一個 spec 區段,其中包含一些「必要」欄位。這表示當您建立 Certificate 資源時,必須存在這些欄位。還有許多其他欄位不需在每個 Certificate 資源上明確定義。這基本上表示其中一個欄位的值不是必要的,或者在其他地方定義了預設值。其他地方可能在 cert-manager 的程式碼庫中,或者實際上是由建立和傳回 X.509 憑證的簽發者定義。讓我們探索如何操作這些值以自訂,並讓 Certificate 使用者的生活更輕鬆。

在本教學中,我們將設定一些 ClusterPolicy 資源和 Certificate 資源。我們將參考 Certificate 規格中不存在的 ClusterIssuer,但對於本教學來說,由於我們實際上不會請求憑證,因此不需要 ClusterIssuer。這表示即使沒有自己的網域,任何人都可以遵循本教學。

⚠️ 為了讓入門更容易,我們使用叢集範圍的 ClusterPolicy 資源。您未來可以使用 Policy 資源將預設值範圍設定為命名空間級別,但本教學不會涵蓋這部分。

1 - 設定選填欄位的預設值

在本節中,我們將建立規則,自動為所有 Certificate 資源設定三個欄位。這三個欄位都不是必填欄位,但可能需要根據平台和簽發者偏好進行設定。這些規則將會

ℹ️ 請注意這些規則如何處理我們 使用案例 中的前兩個。

  1. 首先看看 ClusterPolicy

    apiVersion: kyverno.io/v1
    kind: ClusterPolicy
    metadata:
    name: mutate-certificates
    spec:
    failurePolicy: Fail
    rules:
    # Set a sane default for the history field if not already present
    - name: set-revisionHistoryLimit
    match:
    any:
    - resources:
    kinds:
    - Certificate
    mutate:
    patchStrategicMerge:
    spec:
    # +(...) This is the clever syntax for if not already set
    +(revisionHistoryLimit): 2
    # Set rotation to always if not already set
    - name: set-privateKey-rotationPolicy
    match:
    any:
    - resources:
    kinds:
    - Certificate
    mutate:
    patchStrategicMerge:
    spec:
    privateKey:
    +(rotationPolicy): Always
    # Set private key details for algorithm and size
    - name: set-privateKey-details
    match:
    any:
    - resources:
    kinds:
    - Certificate
    mutate:
    patchStrategicMerge:
    spec:
    privateKey:
    +(algorithm): ECDSA
    +(size): 521
    +(encoding): PKCS1

    🔗 cpol-mutate-certificates-0.yaml

  2. 將原則套用至叢集,並檢查是否就緒

    kubectl apply -f cpol-mutate-certificates-0.yaml
    kubectl get cpol

    ClusterPolicy 就緒時,輸出應如下所示

    NAME ADMISSION BACKGROUND VALIDATE ACTION READY AGE MESSAGE
    mutate-certificates true true Audit True 0s Ready
  3. 現在檢查「test-revision」Certificate

    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
    name: test-revision
    namespace: default
    spec:
    dnsNames:
    - example.com
    issuerRef:
    group: cert-manager.io
    kind: ClusterIssuer
    name: not-my-corp-issuer
    secretName: test-revision-cert

    🔗 cert-test-revision.yaml

    您可以看到我們已設定目前最精簡的配置,僅指定憑證的 DNS 名稱、儲存位置 (secretName) 以及用於請求憑證的簽發者 (issuerRef)。

  4. 使用以下命令試執行套用憑證,然後將其與原始資源進行 diff,以查看如何套用 ClusterPolicy 中的預設值

    kubectl apply -f cert-test-revision.yaml --dry-run=server -o yaml | diff -uZ cert-test-revision.yaml -

    此命令應傳回類似於此範例的一些輸出

    --- cert-test-revision.yaml 2024-01-08 12:14:59.225074232 +0000
    +++ - 2024-01-12 17:37:51.076593214 +0000
    @@ -1,8 +1,14 @@
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
    + annotations:
    + kubectl.kubernetes.io/last-applied-configuration: |
    + {"apiVersion":"cert-manager.io/v1","kind":"Certificate","metadata":{"annotations":{},"name":"test-revision","namespace":"default"},"spec":{"dnsNames":["example.com"],"issuerRef":{"group":"cert-manager.io","kind":"ClusterIssuer","name":"not-my-corp-issuer"},"secretName":"test-revision-cert"}}
    + creationTimestamp: "2024-01-12T17:37:51Z"
    + generation: 1
    name: test-revision
    namespace: default
    + uid: 9f9a4f0a-4aa7-427d-ae4b-c1716fed8246
    spec:
    dnsNames:
    - example.com
    @@ -10,4 +16,10 @@
    group: cert-manager.io
    kind: ClusterIssuer
    name: not-my-corp-issuer
    + privateKey:
    + algorithm: ECDSA
    + encoding: PKCS1
    + rotationPolicy: Always
    + size: 521
    + revisionHistoryLimit: 2
    secretName: test-revision-cert

    我們已成功預設 privateKeyrevisionHistoryLimit 欄位!

  5. 讓我們覆寫所有這些預設欄位,以驗證我們仍然可以設定我們想要的最終使用者設定。若要測試此功能,讓我們使用「test-revision-override」Certificate

    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
    name: test-revision-override
    namespace: default
    spec:
    dnsNames:
    - example.com
    issuerRef:
    group: cert-manager.io
    kind: ClusterIssuer
    name: not-my-corp-issuer
    privateKey:
    algorithm: RSA
    encoding: PKCS8
    rotationPolicy: Never
    size: 4096
    revisionHistoryLimit: 44
    secretName: test-revision-override-cert

    🔗 cert-test-revision-override.yaml

    和之前一樣,試執行套用並使用輸入檔案 diff 輸出

    kubectl apply -f cert-test-revision-override.yaml --dry-run=server -o yaml | diff -uZ cert-test-revision-override.yaml -

    您可以在輸出中看到 Certificate 本身沒有任何規格變更。Certificate 已定義我們 ClusterPolicy 規則會影響的所有欄位。

    --- cert-test-revision-override.yaml 2024-01-05 14:45:14.972562067 +0000
    +++ - 2024-01-12 17:39:57.217028745 +0000
    @@ -1,8 +1,14 @@
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
    + annotations:
    + kubectl.kubernetes.io/last-applied-configuration: |
    + {"apiVersion":"cert-manager.io/v1","kind":"Certificate","metadata":{"annotations":{},"name":"test-revision-override","namespace":"default"},"spec":{"dnsNames":["example.com"],"issuerRef":{"group":"cert-manager.io","kind":"ClusterIssuer","name":"not-my-corp-issuer"},"privateKey":{"algorithm":"RSA","encoding":"PKCS8","rotationPolicy":"Never","size":4096},"revisionHistoryLimit":44,"secretName":"test-revision-override-cert"}}
    + creationTimestamp: "2024-01-12T17:39:57Z"
    + generation: 1
    name: test-revision-override
    namespace: default
    + uid: 83a6ddbc-6903-479e-802d-e11149985338
    spec:
    dnsNames:
    - example.com

2 - 設定必填欄位的預設值

⚠️ 本節需要 cert-manager v1.14.x 或更新版本才能順利運作。如需詳細資訊,請參閱附錄章節。

現在,我們可以設定 Kyverno ClusterPolicy,將預設值套用至任何 Certificate 欄位。這包括必填欄位。在我們的 ClusterPolicy 範例中,我們將執行兩項操作

  • 設定相關的 issuerRef 欄位,使其預設為使用「our-corp-issuer」ClusterIssuer
  • 套用預設的 secretName,該名稱是 Certificate 物件的名稱,並附加「-cert」字尾。

ℹ️ 請注意這些規則如何處理第三和第四個 使用案例

  1. 以下是 ClusterPolicy 資源,可使用預設值設定兩個欄位

    apiVersion: kyverno.io/v1
    kind: ClusterPolicy
    metadata:
    name: mutate-certificates
    spec:
    failurePolicy: Fail
    rules:
    # Set a sane default for the history field if not already present
    - name: set-revisionHistoryLimit
    match:
    any:
    - resources:
    kinds:
    - Certificate
    mutate:
    patchStrategicMerge:
    spec:
    # +(...) This is the clever syntax for if not already set
    +(revisionHistoryLimit): 2
    # Set rotation to always if not already set
    - name: set-privateKey-rotationPolicy
    match:
    any:
    - resources:
    kinds:
    - Certificate
    mutate:
    patchStrategicMerge:
    spec:
    privateKey:
    +(rotationPolicy): Always
    # Set private key details for algorithm and size
    - name: set-privateKey-details
    match:
    any:
    - resources:
    kinds:
    - Certificate
    mutate:
    patchStrategicMerge:
    spec:
    privateKey:
    +(algorithm): ECDSA
    +(size): 521
    +(encoding): PKCS1
    # Set a secretName when one is not provided
    - name: set-default-secret-name
    match:
    any:
    - resources:
    kinds:
    - Certificate
    mutate:
    patchStrategicMerge:
    spec:
    # You can read more about this syntax in the Kyverno documentation:
    # https://kyverno.io/docs/writing-policies/variables/#variables-from-admission-review-requests
    +(secretName): "{{request.object.metadata.name}}-cert"
    # Set a default for issuerRef fields
    - name: set-default-issuer-ref
    match:
    any:
    - resources:
    kinds:
    - Certificate
    mutate:
    patchStrategicMerge:
    spec:
    +(issuerRef):
    name: our-corp-issuer
    kind: ClusterIssuer
    group: cert-manager.io

    🔗 cpol-mutate-certificates-1.yaml

    這個 ClusterPolicy 是我們先前套用的原則的擴充功能。

  2. 套用此原則

    kubectl apply -f cpol-mutate-certificates-1.yaml

    您應該會看到我們現有的 ClusterPolicy 已變更

    clusterpolicy.kyverno.io/mutate-certificates configured

    取得 ClusterPolicy 以驗證其是否「就緒」

    kubectl get cpol

    此命令應傳回類似於此範例的一些輸出

    NAME ADMISSION BACKGROUND VALIDATE ACTION READY AGE MESSAGE
    mutate-certificates true true Audit True 6m21s Ready
  3. 查看「test-minimal」Certificate,旨在驗證原則中的所有規則是否都可運作

    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
    name: test-minimal
    namespace: default
    spec:
    dnsNames:
    - example.com

    🔗 cert-test-minimal.yaml

  4. 試執行套用並使用 diff 來驗證我們所有的預設值是否已套用至這個最精簡的 Certificate

    kubectl apply -f cert-test-minimal.yaml --dry-run=server -o yaml | diff -uZ cert-test-minimal.yaml -

    此命令應傳回類似於此範例的一些輸出

    --- cert-test-minimal.yaml 2024-01-05 14:45:07.140668401 +0000
    +++ - 2024-01-12 17:44:08.110290752 +0000
    @@ -1,8 +1,25 @@
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
    + annotations:
    + kubectl.kubernetes.io/last-applied-configuration: |
    + {"apiVersion":"cert-manager.io/v1","kind":"Certificate","metadata":{"annotations":{},"name":"test-minimal","namespace":"default"},"spec":{"dnsNames":["example.com"]}}
    + creationTimestamp: "2024-01-12T17:44:08Z"
    + generation: 1
    name: test-minimal
    namespace: default
    + uid: 792d29c7-8cf3-4f3a-9f12-4fba396e0d6e
    spec:
    dnsNames:
    - example.com
    + issuerRef:
    + group: cert-manager.io
    + kind: ClusterIssuer
    + name: our-corp-issuer
    + privateKey:
    + algorithm: ECDSA
    + encoding: PKCS1
    + rotationPolicy: Always
    + size: 521
    + revisionHistoryLimit: 2
    + secretName: test-minimal-cert

    請注意我們如何自動填入 spec.issuerRefspec.secretName 欄位值。這表示 Kyverno ClusterPolicy 已套用至提供的 Certificate 資源。

  5. 為了確保我們沒有強制執行任何設定,讓我們明確設定我們有預設規則的 Certificate 的每個屬性。我們將使用「test-revision-override」Certificate

    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
    name: test-revision-override
    namespace: default
    spec:
    dnsNames:
    - example.com
    issuerRef:
    group: cert-manager.io
    kind: ClusterIssuer
    name: not-my-corp-issuer
    privateKey:
    algorithm: RSA
    encoding: PKCS8
    rotationPolicy: Never
    size: 4096
    revisionHistoryLimit: 44
    secretName: test-revision-override-cert

    🔗 cert-test-revision-override.yaml

  6. 試執行套用並使用 diff 這個檔案

    kubectl apply -f cert-test-revision-override.yaml --dry-run=server -o yaml | diff -uZ cert-test-revision-override.yaml -

    此命令應傳回類似於此範例的一些輸出

    --- cert-test-revision-override.yaml 2024-01-05 14:45:14.972562067 +0000
    +++ - 2024-01-12 17:45:48.261997150 +0000
    @@ -1,8 +1,14 @@
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
    + annotations:
    + kubectl.kubernetes.io/last-applied-configuration: |
    + {"apiVersion":"cert-manager.io/v1","kind":"Certificate","metadata":{"annotations":{},"name":"test-revision-override","namespace":"default"},"spec":{"dnsNames":["example.com"],"issuerRef":{"group":"cert-manager.io","kind":"ClusterIssuer","name":"not-my-corp-issuer"},"privateKey":{"algorithm":"RSA","encoding":"PKCS8","rotationPolicy":"Never","size":4096},"revisionHistoryLimit":44,"secretName":"test-revision-override-cert"}}
    + creationTimestamp: "2024-01-12T17:45:48Z"
    + generation: 1
    name: test-revision-override
    namespace: default
    + uid: d0ad7abe-c703-45f7-acf9-634b3a263cfa
    spec:
    dnsNames:
    - example.com

    從此命令中,您可以看到 Certificate 規格欄位都沒有變更。只有 metadata 區段已變更,這告訴我們已套用原則,但由於已提供值,因此未設定任何預設值。這表示您在需要時可以保留覆寫叢集預設值的彈性。

3 - 透過 Ingress 註釋設定預設值

許多 cert-manager 使用者不會直接建立 Certificate 資源,而是使用 ingress-shim 功能。cert-manager 會根據支援的註釋Ingress 規格建立 Certificate 資源。讓我們看看我們如何在此使用案例中仍然使用 ClusterPolicy 套用預設值。

  1. 這個 Ingress 資源具有 cert-manager.io/cluster-issuer 註釋,指示 cert-manager 建立 Certificate,並使用指向名為 our-corp-issuerClusterIssuerissuerRef 欄位

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    annotations:
    cert-manager.io/cluster-issuer: "our-corp-issuer"
    name: defaults-example
    namespace: default
    spec:
    ingressClassName: nginx
    rules:
    - host: app.example.com
    http:
    paths:
    - backend:
    service:
    name: app
    port:
    number: 80
    path: /
    pathType: ImplementationSpecific
    tls:
    - hosts:
    - app.example.com
    secretName: defaults-example-certificate-tls

    🔗 ingress.yaml

  2. 此註釋和相關的 ingress.spec.tls 配置是我們需要的所有項目,因此請套用資源

    kubectl apply -f ingress.yaml
  3. 現在驗證是否已自動產生 Certificate 資源

    kubectl get cert defaults-example-certificate-tls -o yaml

    此命令應傳回類似於此範例的一些輸出

    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
    creationTimestamp: "2024-01-12T17:47:04Z"
    generation: 1
    name: defaults-example-certificate-tls
    namespace: default
    ownerReferences:
    - apiVersion: networking.k8s.io/v1
    blockOwnerDeletion: true
    controller: true
    kind: Ingress
    name: defaults-example
    uid: bea33a55-a9ed-4664-a56a-a679eb8272c3
    resourceVersion: "584260"
    uid: 43ced989-723b-4eac-bad0-f8bead6976df
    spec:
    dnsNames:
    - app.example.com
    issuerRef:
    group: cert-manager.io
    kind: ClusterIssuer
    name: our-corp-issuer
    privateKey:
    algorithm: ECDSA
    encoding: PKCS1
    rotationPolicy: Always
    size: 521
    revisionHistoryLimit: 2
    secretName: defaults-example-certificate-tls
    usages:
    - digital signature
    - key encipherment
    status:
    conditions:
    - lastTransitionTime: "2024-01-12T17:47:04Z"
    message: Issuing certificate as Secret does not exist
    observedGeneration: 1
    reason: DoesNotExist
    status: "True"
    type: Issuing
    - lastTransitionTime: "2024-01-12T17:47:04Z"
    message: Issuing certificate as Secret does not exist
    observedGeneration: 1
    reason: DoesNotExist
    status: "False"
    type: Ready
    nextPrivateKeySecretName: defaults-example-certificate-tls-nbjws
  4. 您可以選擇查看 Kyverno 准入控制器容器的日誌,來驗證「mutate-certificates」ClusterPolicy 是否已套用。

    kubectl logs -n kyverno-system $(kubectl get pod -n kyverno-system -l app.kubernetes.io/component=admission-controller -o jsonpath='{.items[0].metadata.name}') -c kyverno --tail 3

    此命令應傳回類似於此範例的一些輸出

    I0112 17:47:04.425863 1 mutation.go:113] webhooks/resource/mutate "msg"="mutation rules from policy applied successfully" "clusterroles"=["cert-manager-controller-approve:cert-manager-io","cert-manager-controller-certificates","cert-manager-controller-certificatesigningrequests","cert-manager-controller-challenges","cert-manager-controller-clusterissuers","cert-manager-controller-ingress-shim","cert-manager-controller-issuers","cert-manager-controller-orders","system:basic-user","system:discovery","system:public-info-viewer","system:service-account-issuer-discovery"] "gvk"={"group":"cert-manager.io","version":"v1","kind":"Certificate"} "gvr"={"group":"cert-manager.io","version":"v1","resource":"certificates"} "kind"="Certificate" "name"="defaults-example-certificate-tls" "namespace"="default" "operation"="UPDATE" "policy"="mutate-certificates" "resource.gvk"={"Group":"cert-manager.io","Version":"v1","Kind":"Certificate"} "roles"=["kube-system:cert-manager:leaderelection"] "rules"=["set-revisionHistoryLimit","set-privateKey-rotationPolicy","set-privateKey-details"] "uid"="6f93bd8d-29ca-4eab-8e96-065ea82a1bf2" "user"={"username":"system:serviceaccount:cert-manager:cert-manager","uid":"21cbad67-9d2e-44ee-bb02-7fef9aa2e502","groups":["system:serviceaccounts","system:serviceaccounts:cert-manager","system:authenticated"],"extra":{"authentication.kubernetes.io/pod-name":["cert-manager-648cd49b44-z6g8s"],"authentication.kubernetes.io/pod-uid":["4bd741fa-a8ec-48a1-82d5-26c5b7acce5e"]}}
    I0112 17:47:04.458402 1 mutation.go:113] webhooks/resource/mutate "msg"="mutation rules from policy applied successfully" "clusterroles"=["cert-manager-controller-approve:cert-manager-io","cert-manager-controller-certificates","cert-manager-controller-certificatesigningrequests","cert-manager-controller-challenges","cert-manager-controller-clusterissuers","cert-manager-controller-ingress-shim","cert-manager-controller-issuers","cert-manager-controller-orders","system:basic-user","system:discovery","system:public-info-viewer","system:service-account-issuer-discovery"] "gvk"={"group":"cert-manager.io","version":"v1","kind":"Certificate"} "gvr"={"group":"cert-manager.io","version":"v1","resource":"certificates"} "kind"="Certificate" "name"="defaults-example-certificate-tls" "namespace"="default" "operation"="UPDATE" "policy"="mutate-certificates" "resource.gvk"={"Group":"cert-manager.io","Version":"v1","Kind":"Certificate"} "roles"=["kube-system:cert-manager:leaderelection"] "rules"=["set-revisionHistoryLimit","set-privateKey-rotationPolicy","set-privateKey-details"] "uid"="ec61a3c9-df0a-4daf-8bc3-227dc80348a9" "user"={"username":"system:serviceaccount:cert-manager:cert-manager","uid":"21cbad67-9d2e-44ee-bb02-7fef9aa2e502","groups":["system:serviceaccounts","system:serviceaccounts:cert-manager","system:authenticated"],"extra":{"authentication.kubernetes.io/pod-name":["cert-manager-648cd49b44-z6g8s"],"authentication.kubernetes.io/pod-uid":["4bd741fa-a8ec-48a1-82d5-26c5b7acce5e"]}}
    I0112 17:47:09.477776 1 mutation.go:113] webhooks/resource/mutate "msg"="mutation rules from policy applied successfully" "clusterroles"=["cert-manager-controller-approve:cert-manager-io","cert-manager-controller-certificates","cert-manager-controller-certificatesigningrequests","cert-manager-controller-challenges","cert-manager-controller-clusterissuers","cert-manager-controller-ingress-shim","cert-manager-controller-issuers","cert-manager-controller-orders","system:basic-user","system:discovery","system:public-info-viewer","system:service-account-issuer-discovery"] "gvk"={"group":"cert-manager.io","version":"v1","kind":"Certificate"} "gvr"={"group":"cert-manager.io","version":"v1","resource":"certificates"} "kind"="Certificate" "name"="defaults-example-certificate-tls" "namespace"="default" "operation"="UPDATE" "policy"="mutate-certificates" "resource.gvk"={"Group":"cert-manager.io","Version":"v1","Kind":"Certificate"} "roles"=["kube-system:cert-manager:leaderelection"] "rules"=["set-revisionHistoryLimit","set-privateKey-rotationPolicy","set-privateKey-details"] "uid"="c4384662-cb2a-49a0-8e83-e590942ec48d" "user"={"username":"system:serviceaccount:cert-manager:cert-manager","uid":"21cbad67-9d2e-44ee-bb02-7fef9aa2e502","groups":["system:serviceaccounts","system:serviceaccounts:cert-manager","system:authenticated"],"extra":{"authentication.kubernetes.io/pod-name":["cert-manager-648cd49b44-z6g8s"],"authentication.kubernetes.io/pod-uid":["4bd741fa-a8ec-48a1-82d5-26c5b7acce5e"]}}

    以最後一行作為範例,您可以提取出:

    "kind"="Certificate" "name"="defaults-example-certificate-tls" "namespace"="default" "operation"="UPDATE" "policy"="mutate-certificates" "resource.gvk"={"Group":"cert-manager.io","Version":"v1","Kind":"Certificate"} "roles"=["kube-system:cert-manager:leaderelection"] "rules"=["set-revisionHistoryLimit","set-privateKey-rotationPolicy","set-privateKey-details"]

    請注意,policy 鍵表示我們的策略已套用。在 rules 區段中,您可以識別出我們的五個規則中有三個已套用至產生的「defaults-example-certificate-tls」Certificate 資源。

當使用 Ingress 資源時,您始終需要指定從哪個 secretName 來載入憑證。在這種使用情況下,不需要預設值,因為這是 Ingress 規格的必要部分。

使用者需要在 Ingress 資源上指定的唯一額外 YAML 是註釋:

cert-manager.io/cluster-issuer: "our-corp-issuer"

此註釋既作為 cert-manager 對此 Ingress 採取行動的觸發器,也作為 Certificate.spec.issuerRef 欄位的組態值。這一行取代了使用者建立 Certificate 資源的需要。這減少了保護此 Ingress 後端應用程式所需的總 YAML 數量。

總結

這是一個相當簡單的範例,說明為您的叢集 Certificate 資源設定預設值有多麼容易。我們展示了 ClusterPolicy 不必「強制執行」設定,而是可以用來設定和擴展預設選項。Certificate 使用者可以減少他們的 YAML,同時保持在需要時覆蓋任何值的彈性。

我們展示了一個只有 5 個規則的簡單 ClusterPolicy 如何改變使用者建立 Certificate 資源的體驗,從:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: test-revision-override
namespace: default
spec:
dnsNames:
- example.com
issuerRef:
group: cert-manager.io
kind: ClusterIssuer
name: not-my-corp-issuer
privateKey:
algorithm: RSA
encoding: PKCS8
rotationPolicy: Never
size: 4096
revisionHistoryLimit: 44
secretName: test-revision-override-cert

🔗 cert-test-revision-override.yaml

到只需要指定對他們重要的組態,例如:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: test-minimal
namespace: default
spec:
dnsNames:
- example.com

🔗 cert-test-minimal.yaml

透過此策略,我們達成了目標,並使使用者能夠提交最小化的 Certifiate 資源。這完成了我們的第五個使用案例,規範中只包含一個欄位,即 dnsNames 項目。其他所有指定的欄位都使用 Kyverno 和 ClusterPolicy 自動預設,這通常由平台管理員設定。

清理

如果您為本教學建立了一個 kind 叢集,您可以簡單地執行:

kind delete cluster --name defaults

否則,要移除本教學中部署的所有資源:

# Assuming you are running from this directly or saved all the files to yamls/
kubectl delete -f ingress.yaml
kubectl delete -f cpol-mutate-certificates-1.yaml
helm uninstall kyverno -n kyverno-system
helm uninstall cert-manager -n cert-manager
helm uninstall ingress-nginx -n ingress-nginx

附錄

cert-manager 版本要求

從 v1.14.x 開始,cert-manager 的變更 webhook 行為已變更。如需更完整的說明和變更詳細資訊,請參閱PR #6311。手動修復的說明可以在 PR #6311 上的此評論中找到

預設值功能請求

如需更多關於設定「預設值」或「預設設定」的背景閱讀,您可以參考issue 2239。本教學來自對該問題的調查。

cert-manager 團隊認為,可以使用其他更通用的開放原始碼策略工具來實現所請求的解決方案。Kyverno 只是其中一個範例,也可以使用 Gatekeeper 作為替代工具來實現類似的功能。