pkg/controllers/webhookconfig_controller.go (111 lines of code) (raw):
// Copyright (c) 2021, 2023, Oracle and/or its affiliates.
//
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
package controllers
import (
"context"
"encoding/json"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch"
k8s "k8s.io/client-go/kubernetes"
typedadmissionregistrationv1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1"
klog "k8s.io/klog/v2"
)
// WebhookConfigController defines a webhookConfig control interface
type WebhookConfigController interface {
UpdateWebhookConfigCertificate(ctx context.Context, labelSelector string, cert []byte) bool
}
// validatingWebhookConfigController implements WebhookConfigController for ValidatingWebhookConfigs
type validatingWebhookConfigController struct {
vwcInterface typedadmissionregistrationv1.ValidatingWebhookConfigurationInterface
}
// NewValidatingWebhookConfigController creates and returns a new validatingWebhookConfigController
func NewValidatingWebhookConfigController(client k8s.Interface) WebhookConfigController {
return &validatingWebhookConfigController{
vwcInterface: client.AdmissionregistrationV1().ValidatingWebhookConfigurations(),
}
}
// mutatingWebhookConfigController implements WebhookConfigController for MutatingWebhookConfigs
type mutatingWebhookConfigController struct {
mwcInterface typedadmissionregistrationv1.MutatingWebhookConfigurationInterface
}
// NewMutatingWebhookConfigController creates and returns a new mutatingWebhookConfigController
func NewMutatingWebhookConfigController(client k8s.Interface) WebhookConfigController {
return &mutatingWebhookConfigController{
mwcInterface: client.AdmissionregistrationV1().MutatingWebhookConfigurations(),
}
}
// UpdateWebhookConfigCertificate updates the webhooks with the given TLS certificate data
func (c *validatingWebhookConfigController) UpdateWebhookConfigCertificate(
ctx context.Context, labelSelector string, cert []byte) bool {
// Get all validating configs with matching label
vwcList, err := c.vwcInterface.List(ctx, metav1.ListOptions{
LabelSelector: labelSelector,
})
if err != nil {
klog.Errorf("Failed to retrieve validating webhook config list : %s", err)
return false
}
// Update them one by one
for _, vwc := range vwcList.Items {
// Make a copy of the webhook config to update
newVwc := vwc.DeepCopy()
// Update all webhooks' CA bundle
for i := range newVwc.Webhooks {
newVwc.Webhooks[i].ClientConfig.CABundle = cert
}
// Prepare a patch to be applied
existingJSON, err := json.Marshal(vwc)
if err != nil {
klog.Error("Failed to encode existing validating webhook config : ", err)
return false
}
updatedJSON, err := json.Marshal(newVwc)
if err != nil {
klog.Error("Failed to encode updated validating webhook config : ", err)
return false
}
patch, err := strategicpatch.CreateTwoWayMergePatch(
existingJSON, updatedJSON, admissionregistrationv1.ValidatingWebhookConfiguration{})
if err != nil {
klog.Error("Failed to generate the patch to be applied : ", err)
return false
}
// Apply the patch
if newVwc, err = c.vwcInterface.Patch(
ctx, newVwc.Name, types.StrategicMergePatchType, patch, metav1.PatchOptions{}); err != nil {
klog.Errorf("Failed to patch validating webhook config %s : %s",
newVwc.Name, err)
return false
}
klog.Infof("Successfully updated the validatingWebhookConfig '%s' with the certificate", newVwc.Name)
}
return true
}
// UpdateWebhookConfigCertificate updates the webhooks with the given TLS certificate data
func (c *mutatingWebhookConfigController) UpdateWebhookConfigCertificate(
ctx context.Context, labelSelector string, cert []byte) bool {
// Get all validating configs with matching label
mwcList, err := c.mwcInterface.List(ctx, metav1.ListOptions{
LabelSelector: labelSelector,
})
if err != nil {
klog.Errorf("Failed to retrieve mutating webhook config list : %s", err)
return false
}
// Update them one by one
for _, mwc := range mwcList.Items {
// Make a copy of the webhook config to update
newMwc := mwc.DeepCopy()
// Update all webhooks' CA bundle
for i := range newMwc.Webhooks {
newMwc.Webhooks[i].ClientConfig.CABundle = cert
}
// Prepare a patch to be applied
existingJSON, err := json.Marshal(mwc)
if err != nil {
klog.Error("Failed to encode existing mutating webhook config : ", err)
return false
}
updatedJSON, err := json.Marshal(newMwc)
if err != nil {
klog.Error("Failed to encode updated mutating webhook config : ", err)
return false
}
patch, err := strategicpatch.CreateTwoWayMergePatch(
existingJSON, updatedJSON, admissionregistrationv1.MutatingWebhookConfiguration{})
if err != nil {
klog.Error("Failed to generate the patch to be applied : ", err)
return false
}
// Apply the patch
if newMwc, err = c.mwcInterface.Patch(
ctx, newMwc.Name, types.StrategicMergePatchType, patch, metav1.PatchOptions{}); err != nil {
klog.Errorf("Failed to patch mutating webhook config %s : %s",
newMwc.Name, err)
return false
}
klog.Infof("Successfully updated the mutatingWebhookConfig '%s' with the certificate", newMwc.Name)
}
return true
}