<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          自動(dòng)管理 Admission Webhook TLS 證書(shū)

          共 14089字,需瀏覽 29分鐘

           ·

          2021-01-27 17:43

          前面我們學(xué)習(xí)了如何開(kāi)發(fā)自己的準(zhǔn)入控制器 Webhook,這些準(zhǔn)入 Webhook 控制器調(diào)用自定義配置的 HTTP 回調(diào)服務(wù)來(lái)進(jìn)行其他檢查。但是,APIServer 僅通過(guò) HTTPS 與 Webhook 服務(wù)進(jìn)行通信,并且需要 TLS 證書(shū)的 CA 信息。所以對(duì)于如何處理該 Webhook 服務(wù)證書(shū)以及如何將 CA 信息自動(dòng)傳遞給 APIServer 帶來(lái)了一些麻煩。

          前面我們是通過(guò) openssl(cfssl)來(lái)手動(dòng)生成的相關(guān)證書(shū),然后手動(dòng)配置給 Webhook 服務(wù)的,除此之外,我們也可以使用 cert-manager 來(lái)處理這些 TLS 證書(shū)和 CA。但是,cert-manager 本身是一個(gè)比較大的應(yīng)用程序,由許多 CRD 組成來(lái)處理其操作。僅安裝 cert-manager 來(lái)處理準(zhǔn)入 webhook TLS 證書(shū)和 CA 不是一個(gè)很好的做法。

          另外一種做法就是我們可以使用自簽名證書(shū),然后通過(guò)使用 Init 容器來(lái)自行處理 CA,這就消除了對(duì)其他應(yīng)用程序(如 cert-manager)的依賴(lài)。接下來(lái)我們就來(lái)重點(diǎn)介紹下如何使用這種方式來(lái)管理相關(guān)證書(shū)。

          初始化容器

          這個(gè)初始化容器的主要功能是創(chuàng)建一個(gè)自簽名的 Webhook 服務(wù)證書(shū),并通過(guò) mutate/驗(yàn)證配置將 caBundle 提供給 APIServer。Webhook 服務(wù)如何使用該證書(shū)(通過(guò) Secret Volumes 或 emptyDir),取決于實(shí)際情況。這里我們這個(gè)初始化容器將運(yùn)行一個(gè)簡(jiǎn)單的 Go 二進(jìn)制文件來(lái)執(zhí)行這些功能。核心代碼如下所示:

          package?main

          import?(
          ?"bytes"
          ?cryptorand?"crypto/rand"
          ?"crypto/rsa"
          ?"crypto/x509"
          ?"crypto/x509/pkix"
          ?"encoding/pem"
          ?"fmt"
          ?log?"github.com/sirupsen/logrus"
          ?"math/big"
          ?"os"
          ?"time"
          )

          func?main()?{
          ?var?caPEM,?serverCertPEM,?serverPrivKeyPEM?*bytes.Buffer
          ?//?CA?config
          ?ca?:=?&x509.Certificate{
          ??SerialNumber:?big.NewInt(2021),
          ??Subject:?pkix.Name{
          ???Organization:?[]string{"ydzs.io"},
          ??},
          ??NotBefore:?????????????time.Now(),
          ??NotAfter:??????????????time.Now().AddDate(1,?0,?0),
          ??IsCA:??????????????????true,
          ??ExtKeyUsage:???????????[]x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth,?x509.ExtKeyUsageServerAuth},
          ??KeyUsage:??????????????x509.KeyUsageDigitalSignature?|?x509.KeyUsageCertSign,
          ??BasicConstraintsValid:?true,
          ?}

          ?//?CA?private?key
          ?caPrivKey,?err?:=?rsa.GenerateKey(cryptorand.Reader,?4096)
          ?if?err?!=?nil?{
          ??fmt.Println(err)
          ?}

          ?//?Self?signed?CA?certificate
          ?caBytes,?err?:=?x509.CreateCertificate(cryptorand.Reader,?ca,?ca,?&caPrivKey.PublicKey,?caPrivKey)
          ?if?err?!=?nil?{
          ??fmt.Println(err)
          ?}

          ?//?PEM?encode?CA?cert
          ?caPEM?=?new(bytes.Buffer)
          ?_?=?pem.Encode(caPEM,?&pem.Block{
          ??Type:??"CERTIFICATE",
          ??Bytes:?caBytes,
          ?})

          ?dnsNames?:=?[]string{"admission-registry",
          ??"admission-registry.default",?"admission-registry.default.svc"}
          ?commonName?:=?"admission-registry.default.svc"

          ?//?server?cert?config
          ?cert?:=?&x509.Certificate{
          ??DNSNames:?????dnsNames,
          ??SerialNumber:?big.NewInt(1658),
          ??Subject:?pkix.Name{
          ???CommonName:???commonName,
          ???Organization:?[]string{"ydzs.io"},
          ??},
          ??NotBefore:????time.Now(),
          ??NotAfter:?????time.Now().AddDate(1,?0,?0),
          ??SubjectKeyId:?[]byte{1,?2,?3,?4,?6},
          ??ExtKeyUsage:??[]x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth,?x509.ExtKeyUsageServerAuth},
          ??KeyUsage:?????x509.KeyUsageDigitalSignature,
          ?}

          ?//?server?private?key
          ?serverPrivKey,?err?:=?rsa.GenerateKey(cryptorand.Reader,?4096)
          ?if?err?!=?nil?{
          ??fmt.Println(err)
          ?}

          ?//?sign?the?server?cert
          ?serverCertBytes,?err?:=?x509.CreateCertificate(cryptorand.Reader,?cert,?ca,?&serverPrivKey.PublicKey,?caPrivKey)
          ?if?err?!=?nil?{
          ??fmt.Println(err)
          ?}

          ?//?PEM?encode?the?server?cert?and?key
          ?serverCertPEM?=?new(bytes.Buffer)
          ?_?=?pem.Encode(serverCertPEM,?&pem.Block{
          ??Type:??"CERTIFICATE",
          ??Bytes:?serverCertBytes,
          ?})

          ?serverPrivKeyPEM?=?new(bytes.Buffer)
          ?_?=?pem.Encode(serverPrivKeyPEM,?&pem.Block{
          ??Type:??"RSA?PRIVATE?KEY",
          ??Bytes:?x509.MarshalPKCS1PrivateKey(serverPrivKey),
          ?})

          ?err?=?os.MkdirAll("/etc/webhook/certs/",?0666)
          ?if?err?!=?nil?{
          ??log.Panic(err)
          ?}
          ?err?=?WriteFile("/etc/webhook/certs/tls.crt",?serverCertPEM)
          ?if?err?!=?nil?{
          ??log.Panic(err)
          ?}

          ?err?=?WriteFile("/etc/webhook/certs/tls.key",?serverPrivKeyPEM)
          ?if?err?!=?nil?{
          ??log.Panic(err)
          ?}

          }

          //?WriteFile?writes?data?in?the?file?at?the?given?path
          func?WriteFile(filepath?string,?sCert?*bytes.Buffer)?error?{
          ?f,?err?:=?os.Create(filepath)
          ?if?err?!=?nil?{
          ??return?err
          ?}
          ?defer?f.Close()

          ?_,?err?=?f.Write(sCert.Bytes())
          ?if?err?!=?nil?{
          ??return?err
          ?}
          ?return?nil
          }

          在上面的代碼中我們通過(guò)生成自簽名的 CA 并簽署 Webhook 服務(wù)證書(shū)來(lái)提供服務(wù):

          • 首先為 CA 創(chuàng)建一個(gè)配置 ca
          • 為該 CA 創(chuàng)建一個(gè) RSA 私鑰 caPrivKey
          • 生成一個(gè)自簽名的 CA、caByte 和 caPEM,在這里,caPEM 是 PEM 編碼的 caBytes,將是提供給 APIServer 的 CA_BUNDLE 數(shù)據(jù)
          • 創(chuàng)建 webhook 服務(wù)證書(shū)的配置,即上面代碼中的 cert。該配置中的重要屬性是 DNSNames 和 commonName,要注意的是該名稱(chēng)必須是到達(dá) Webhook 服務(wù)的完整地址名稱(chēng)
          • 然后為 Webhook 服務(wù)創(chuàng)建一個(gè) RS 私鑰 serverPrivKey
          • 使用上面代碼中的 ca 和 caPrivKey 創(chuàng)建服務(wù)端證書(shū) serverCertBytes
          • 然后用 PEM 對(duì) serverPrivKeyserverCertBytes 進(jìn)行編碼,這個(gè) serverPrivKeyPEMserverCertPEM 就是 TLS 證書(shū)和密鑰了,將由 Webhook 服務(wù)使用。

          到這里我們就可以生成所需的證書(shū),密鑰和 CA_BUNDLE 數(shù)據(jù)了。然后我們將與同一 Pod 中的實(shí)際 Webhook 服務(wù)容器共享該服務(wù)器證書(shū)和密鑰。

          • 一種方法是事先創(chuàng)建一個(gè)空的 Secret 資源,通過(guò)將該 Secret 作為環(huán)境變量傳遞來(lái)創(chuàng)建 Webhook 服務(wù),初始化容器將生成服務(wù)器證書(shū)和密鑰,并用證書(shū)和密鑰信息來(lái)填充該 Secret。此 Secret 將安裝到 Webhook 服務(wù)容器上,以使用 TLS 來(lái)啟動(dòng) HTTP 服務(wù)器。
          • 第二種方法(在上面的代碼中使用)是使用 Kubernete 的本地 Pod 特定的 emptyDir 卷。該數(shù)據(jù)卷將在兩個(gè)容器之間共享,在上面的代碼中,我們可以看到 init 容器將這些證書(shū)和密鑰信息寫(xiě)入特定路徑的文件中,該路徑就是其中的一個(gè) emptyDir 卷,并且 Webhook 服務(wù)容器將從該路徑讀取用于 TLS 配置的證書(shū)和密鑰,并啟動(dòng) HTTP Webhook 服務(wù)器。請(qǐng)參考下圖:

          Webhook 的 Pod 規(guī)范如下所示:

          spec:
          ??initContainers:
          ????-?image:??init-image?name>
          ??????imagePullPolicy:?IfNotPresent
          ??????name:?webhook-init
          ??????volumeMounts:
          ????????-?mountPath:?/etc/webhook/certs
          ??????????name:?webhook-certs
          ??containers:
          ????-?image:??server?image?name>
          ??????imagePullPolicy:?IfNotPresent
          ??????name:?webhook-server
          ??????volumeMounts:
          ????????-?mountPath:?/etc/webhook/certs
          ??????????name:?webhook-certs
          ??????????readOnly:?true
          ??volumes:
          ????-?name:?webhook-certs
          ??????emptyDir:?{}

          處理 CA Bundle

          然后剩下的就只有使用 mutate/驗(yàn)證配置將 ?CA_BUNDLE 信息提供給 APIServer,這可以通過(guò)兩種方式完成:

          • 使用 init 容器中的 ?client-go 在現(xiàn)有 MutatingWebhookConfigurationValidatingWebhookConfiguration 中來(lái)修補(bǔ) CA_BUNDLE 數(shù)據(jù)。
          • 另一種方式使用配置中的 CA_BUNDLE 數(shù)據(jù)在 init 容器本身中直接創(chuàng)建 MutatingWebhookConfigurationValidatingWebhookConfiguration 即可。

          在這里,我們將通過(guò) init 容器來(lái)創(chuàng)建配置,通過(guò)動(dòng)態(tài)獲取某些參數(shù),例如 mutate 配置名稱(chēng),Webhook 服務(wù)名稱(chēng)和 Webhook 命名空間,我們都可以直接從 init 容器的環(huán)境變量中來(lái)獲取這些值:

          initContainers:
          -?image:??init-image?name>
          ??imagePullPolicy:?IfNotPresent
          ??name:?webhook-init
          ??volumeMounts:
          ????-?mountPath:?/etc/webhook/certs
          ??????name:?webhook-certs
          ??env:
          ????-?name:?MUTATE_CONFIG
          ??????value:?admission-registry-mutate
          ????-?name:?VALIDATE_CONFIG
          ??????value:?admission-registry
          ????-?name:?WEBHOOK_SERVICE
          ??????value:?admission-registry
          ????-?name:?WEBHOOK_NAMESPACE
          ??????value:??default

          為了創(chuàng)建 MutatingWebhookConfiguration 或者 ValidatingWebhookConfiguration 資源對(duì)象,我們將以下代碼添加到上面的 init 容器代碼中。

          package?main

          import?(
          ?"bytes"
          ?"context"
          ?"os"

          ?admissionregistrationv1?"k8s.io/api/admissionregistration/v1"
          ?metav1?"k8s.io/apimachinery/pkg/apis/meta/v1"
          ?"k8s.io/client-go/kubernetes"
          ?"k8s.io/client-go/rest"
          )

          func?initKubeClient()?(*kubernetes.Clientset,?error)?{
          ?var?(
          ??err?error
          ??config?*rest.Config
          ?)
          ?if?config,?err?=?rest.InClusterConfig();?err?!=?nil?{
          ??return?nil,?err
          ?}

          ?//?創(chuàng)建?Clientset?對(duì)象
          ?clientset,?err?:=?kubernetes.NewForConfig(config)
          ?if?err?!=?nil?{
          ??return?nil,?err
          ?}
          ?return?clientset,?nil
          }

          func?CreateAdmissionConfig(caCert?*bytes.Buffer)?error?{
          ?var?(
          ??webhookNamespace,?_?=?os.LookupEnv("WEBHOOK_NAMESPACE")
          ??mutationCfgName,?_??=?os.LookupEnv("MUTATE_CONFIG")
          ??validateCfgName,?_?=?os.LookupEnv("VALIDATE_CONFIG")
          ??webhookService,?_?=?os.LookupEnv("WEBHOOK_SERVICE")
          ??validatePath,?_?=?os.LookupEnv("VALIDATE_PATH")
          ??mutationPath,?_?=?os.LookupEnv("MUTATE_PATH")
          ?)

          ?clientset,?err?:=?initKubeClient()
          ?if?err?!=?nil?{
          ??return?err
          ?}

          ?ctx?:=?context.Background()

          ?if?validateCfgName?!=?""?{
          ??validateConfig?:=?&admissionregistrationv1.ValidatingWebhookConfiguration{
          ???ObjectMeta:?metav1.ObjectMeta{
          ????Name:?validateCfgName,
          ???},
          ???Webhooks:?[]admissionregistrationv1.ValidatingWebhook{
          ????{
          ?????Name:?"io.ydzs.admission-registry",
          ?????ClientConfig:?admissionregistrationv1.WebhookClientConfig{
          ??????CABundle:?caCert.Bytes(),
          ??????Service:?&admissionregistrationv1.ServiceReference{
          ???????Name:?webhookService,
          ???????Namespace:?webhookNamespace,
          ???????Path:?&validatePath,
          ??????},
          ?????},
          ?????Rules:?[]admissionregistrationv1.RuleWithOperations{
          ??????{
          ???????Operations:?[]admissionregistrationv1.OperationType{admissionregistrationv1.Create},
          ???????Rule:?admissionregistrationv1.Rule{
          ????????APIGroups:???[]string{""},
          ????????APIVersions:?[]string{"v1"},
          ????????Resources:???[]string{"pods"},
          ???????},
          ??????},
          ?????},
          ?????FailurePolicy:?func()?*admissionregistrationv1.FailurePolicyType{
          ??????pt?:=?admissionregistrationv1.Fail
          ??????return?&pt
          ?????}(),
          ?????AdmissionReviewVersions:?[]string{"v1"},
          ?????SideEffects:?func()?*admissionregistrationv1.SideEffectClass?{
          ??????se?:=?admissionregistrationv1.SideEffectClassNone
          ??????return?&se
          ?????}(),
          ????},
          ???},
          ??}

          ??validateAdmissionClient?:=?clientset.AdmissionregistrationV1().ValidatingWebhookConfigurations()
          ??_,?err?:=?validateAdmissionClient.Get(ctx,?validateCfgName,?metav1.GetOptions{})
          ??if?err?!=?nil?{
          ???if?errors.IsNotFound(err)?{
          ????if?_,?err?=?validateAdmissionClient.Create(ctx,?validateConfig,?metav1.CreateOptions{});?err?!=?nil?{
          ?????return?err
          ????}
          ???}?else?{
          ????return?err
          ???}
          ??}?else?{
          ???if?_,?err?=?validateAdmissionClient.Update(ctx,?validateConfig,?metav1.UpdateOptions{});?err?!=?nil?{
          ????return?err
          ???}
          ??}

          ?}

          ?if?mutationCfgName?!=?""?{
          ??mutateConfig?:=?&admissionregistrationv1.MutatingWebhookConfiguration{
          ???ObjectMeta:?metav1.ObjectMeta{
          ????Name:?mutationCfgName,
          ???},
          ???Webhooks:?[]admissionregistrationv1.MutatingWebhook{{
          ????Name:?"io.ydzs.admission-registry-mutate",
          ????ClientConfig:?admissionregistrationv1.WebhookClientConfig{
          ?????CABundle:?caCert.Bytes(),?//?CA?bundle?created?earlier
          ?????Service:?&admissionregistrationv1.ServiceReference{
          ??????Name:??????webhookService,
          ??????Namespace:?webhookNamespace,
          ??????Path:??????&mutationPath,
          ?????},
          ????},
          ????Rules:?[]admissionregistrationv1.RuleWithOperations{{Operations:?[]admissionregistrationv1.OperationType{
          ?????admissionregistrationv1.Create},
          ?????Rule:?admissionregistrationv1.Rule{
          ??????APIGroups:???[]string{"apps",?""},
          ??????APIVersions:?[]string{"v1"},
          ??????Resources:???[]string{"deployments",?"services"},
          ?????},
          ????}},
          ????FailurePolicy:?func()?*admissionregistrationv1.FailurePolicyType{
          ?????pt?:=?admissionregistrationv1.Fail
          ?????return?&pt
          ????}(),
          ????AdmissionReviewVersions:?[]string{"v1"},
          ????SideEffects:?func()?*admissionregistrationv1.SideEffectClass?{
          ?????se?:=?admissionregistrationv1.SideEffectClassNone
          ?????return?&se
          ????}(),
          ???}},
          ??}

          ??mutateAdmissionClient?:=?clientset.AdmissionregistrationV1().MutatingWebhookConfigurations()
          ??_,?err?:=?mutateAdmissionClient.Get(ctx,?mutationCfgName,?metav1.GetOptions{})
          ??if?err?!=?nil?{
          ???if?errors.IsNotFound(err)?{
          ????if?_,?err?=?mutateAdmissionClient.Create(ctx,?mutateConfig,?metav1.CreateOptions{});?err?!=?nil?{
          ?????return?err
          ????}
          ???}?else?{
          ????return?err
          ???}
          ??}?else?{
          ???if?_,?err?=?mutateAdmissionClient.Update(ctx,?mutateConfig,?metav1.UpdateOptions{});?err?!=?nil?{
          ????return?err
          ???}
          ??}

          ?}

          ?return?nil
          }

          這里首先我們讀取環(huán)境變量,例如 webhookNamespace,接下來(lái),我們將使用 CA bundle 信息(先前創(chuàng)建)和其他必需信息來(lái)定義配置的資源對(duì)象結(jié)構(gòu)。最后,我們使用 client-go 來(lái)創(chuàng)建配置資源對(duì)象。對(duì)于 Pod 重新啟動(dòng)或刪除的情況,我們可以在 init 容器中添加額外的邏輯,例如首先刪除現(xiàn)有配置,然后再僅在創(chuàng)建或更新 CA bundle(如果配置已存在)之前刪除它們。

          對(duì)于證書(shū)輪換的情況,對(duì)于向服務(wù)器容器提供此證書(shū)所采用的每種方法,方法將有所不同:

          • 如果我們使用的是 emptyDir 卷,則方法將是僅重新啟動(dòng) Webhook Pod。由于 emptyDir 卷是臨時(shí)的,并且綁定到 Pod 的生命周期,因此在重新啟動(dòng)時(shí),將生成一個(gè)新證書(shū)并將其提供給服務(wù)器容器。如果已經(jīng)存在配置,則將在配置中添加新的 CA bundle。
          • 如果我們正在使用 Secret 卷,則在重新啟動(dòng) Webhook Pod 時(shí),可以檢查 Secret 中現(xiàn)有證書(shū)的有效期,以決定是將現(xiàn)有證書(shū)用于服務(wù)器還是創(chuàng)建新證書(shū)。

          在這兩種情況下,都需要重新啟動(dòng) Webhook Pod 才能觸發(fā)證書(shū)輪換/續(xù)訂過(guò)程。何時(shí)需要重新啟動(dòng) Webhook 容器以及如何重新啟動(dòng) Webhook 容器,將取決于實(shí)際情況??赡艿膸追N方法可以使用 Cronjob、controller 等來(lái)實(shí)現(xiàn)。

          到這里我們的自定義 Webhook 已注冊(cè),APIServer 可以通過(guò) config 讀取到 CA bundle 信息,并且 Webhook 服務(wù)已準(zhǔn)備好按照 configs 中定義的規(guī)則處理 mutate/驗(yàn)證請(qǐng)求。

          部署

          最后將上面的證書(shū)生成應(yīng)用打包成一個(gè) Docker 鏡像,將上節(jié)課部署的 Webhook 服務(wù)刪除,重新使用如下所示的資源對(duì)象進(jìn)行部署即可:

          apiVersion:?v1
          kind:?ServiceAccount
          metadata:
          ??name:?admission-registry-sa
          ---
          apiVersion:?rbac.authorization.k8s.io/v1
          kind:?ClusterRole
          metadata:
          ??name:?admission-registry-role
          rules:
          -?verbs:?["*"]
          ??resources:?["validatingwebhookconfigurations",?"mutatingwebhookconfigurations"]
          ??apiGroups:?["admissionregistration.k8s.io"]
          ---
          apiVersion:?rbac.authorization.k8s.io/v1
          kind:?ClusterRoleBinding
          metadata:
          ??name:?admission-registry-rolebinding
          roleRef:
          ??apiGroup:?rbac.authorization.k8s.io
          ??kind:?ClusterRole
          ??name:?admission-registry-role
          subjects:
          -?kind:?ServiceAccount
          ??name:?admission-registry-sa
          ??namespace:?default
          ---
          apiVersion:?apps/v1
          kind:?Deployment
          metadata:
          ??name:?admission-registry
          ??labels:
          ????app:?admission-registry
          spec:
          ??selector:
          ????matchLabels:
          ??????app:?admission-registry
          ??template:
          ????metadata:
          ??????labels:
          ????????app:?admission-registry
          ????spec:
          ??????serviceAccountName:?admission-registry-sa
          ??????initContainers:
          ??????-?image:?cnych/admission-registry-tls:v0.0.3
          ????????imagePullPolicy:?IfNotPresent
          ????????name:?webhook-init
          ????????env:
          ????????-?name:?WEBHOOK_NAMESPACE
          ??????????value:?default
          ????????-?name:?MUTATE_CONFIG
          ??????????value:?admission-registry-mutate
          ????????-?name:?VALIDATE_CONFIG
          ??????????value:?admission-registry
          ????????-?name:?WEBHOOK_SERVICE
          ??????????value:?admission-registry
          ????????-?name:?VALIDATE_PATH
          ??????????value:?/validate
          ????????-?name:?MUTATE_PATH
          ??????????value:?/mutate
          ????????volumeMounts:
          ??????????-?mountPath:?/etc/webhook/certs
          ????????????name:?webhook-certs
          ??????containers:
          ??????-?name:?webhook
          ????????image:?cnych/admission-registry:v0.1.4
          ????????imagePullPolicy:?IfNotPresent
          ????????env:
          ????????-?name:?WHITELIST_REGISTRIES
          ??????????value:?"docker.io,gcr.io"
          ????????ports:
          ????????-?containerPort:?443
          ????????volumeMounts:
          ????????-?name:?webhook-certs
          ??????????mountPath:?/etc/webhook/certs
          ??????????readOnly:?true
          ??????volumes:
          ????????-?name:?webhook-certs
          ??????????emptyDir:?{}
          ---
          apiVersion:?v1
          kind:?Service
          metadata:
          ??name:?admission-registry
          ??labels:
          ????app:?admission-registry
          spec:
          ??ports:
          ????-?port:?443
          ??????targetPort:?443
          ??selector:
          ????app:?admission-registry

          現(xiàn)在我們就不需要自己手動(dòng)去創(chuàng)建包含證書(shū)的 Secret 資源對(duì)象了,也不需要手動(dòng)去替換準(zhǔn)入控制器配置對(duì)象中的 CA bundle 信息了,這些都將通過(guò) Init 初始化容器來(lái)幫我們自動(dòng)完成。

          由于初始化容器需要訪問(wèn) MutatingWebhookConfigurationValidatingWebhookConfiguration 這兩個(gè)資源對(duì)象,所以我們需要聲明對(duì)應(yīng)的 RBAC 權(quán)限。創(chuàng)建完成后的資源對(duì)象如下所示:

          $?kubectl?get?pods?-l?app=admission-registry
          NAME??????????????????????????????????READY???STATUS????RESTARTS???AGE
          admission-registry-64f6b46cdc-vqbrl???1/1?????Running???0??????????96s
          $?kubectl?exec?-it?admission-registry-64f6b46cdc-vqbrl?--?ls?/etc/webhook/certs
          tls.crt??tls.key
          $?kubectl?get?validatingwebhookconfiguration???????
          NAME?????????????????????????????WEBHOOKS???AGE
          admission-registry???????????????1??????????20s
          ???admission-registry?git:(main)???kubectl?get?mutatingwebhookconfigurations????????
          NAME????????????????????????WEBHOOKS???AGE
          admission-registry-mutate???1??????????24s

          然后同樣再去測(cè)試一次即可,到這里我們就完成了使用初始化容器來(lái)管理 Admission Webhook 的 TLS 證書(shū)的功能,當(dāng)然上面的代碼擴(kuò)展性并不是很好,后續(xù)可以根據(jù)需要繼續(xù)優(yōu)化即可。


          CKA 認(rèn)證培訓(xùn)


          ?點(diǎn)擊屏末?|??|?即刻學(xué)習(xí)

          瀏覽 191
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操逼高清视频 | 成人免费黄色视屏 | a中文在线视频 | 欧美精品aa | 91在线观看欧美日韩 |