github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/caasadmission/admission.go (about) 1 // Copyright 2020 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package caasadmission 5 6 import ( 7 "bytes" 8 "fmt" 9 10 "github.com/juju/errors" 11 admission "k8s.io/api/admissionregistration/v1" 12 meta "k8s.io/apimachinery/pkg/apis/meta/v1" 13 14 k8sconstants "github.com/juju/juju/caas/kubernetes/provider/constants" 15 k8sutils "github.com/juju/juju/caas/kubernetes/provider/utils" 16 "github.com/juju/juju/pki" 17 ) 18 19 // AdmissionCreator represents a creator of mutating webhooks that is context aware of the 20 // current controller. 21 type AdmissionCreator interface { 22 EnsureMutatingWebhookConfiguration() (func(), error) 23 } 24 25 // AdmissionCreatorFunc is the func type of AdmissionCreator. 26 type AdmissionCreatorFunc func() (func(), error) 27 28 const ( 29 // Component describes a sub zone to use on the juju tld for unique resource 30 // ids. For example using this component "admission" with "juju.io" would 31 // yield admission.juju.io 32 Component = "admission" 33 34 // we still accept v1beta1 AdmissionReview only. 35 reviewVersionV1beta1 = "v1beta1" 36 ) 37 38 var ( 39 anyMatch = []string{"*"} 40 ) 41 42 // EnsureMutatingWebhookConfiguration implements AdmissionCreator interface for 43 // func type. 44 func (a AdmissionCreatorFunc) EnsureMutatingWebhookConfiguration() (func(), error) { 45 return a() 46 } 47 48 // NewAdmissionCreator instantiates a new AdmissionCreator for the supplied 49 // context arguments. 50 func NewAdmissionCreator( 51 authority pki.Authority, 52 namespace, modelName string, 53 legacyLabels bool, 54 ensureConfig func(*admission.MutatingWebhookConfiguration) (func(), error), 55 service *admission.ServiceReference) (AdmissionCreator, error) { 56 57 caPemBuffer := bytes.Buffer{} 58 if err := pki.CertificateToPemWriter(&caPemBuffer, map[string]string{}, 59 authority.Certificate()); err != nil { 60 return nil, errors.Trace(err) 61 } 62 63 // TODO change to fail 64 failurePolicy := admission.Ignore 65 matchPolicy := admission.Equivalent 66 ruleScope := admission.AllScopes 67 sideEffects := admission.SideEffectClassNone 68 69 // MutatingWebhook Obj 70 obj := admission.MutatingWebhookConfiguration{ 71 ObjectMeta: meta.ObjectMeta{ 72 Labels: k8sutils.LabelsForModel(modelName, legacyLabels), 73 Name: fmt.Sprintf("juju-model-admission-%s", namespace), 74 Namespace: namespace, 75 }, 76 Webhooks: []admission.MutatingWebhook{ 77 { 78 SideEffects: &sideEffects, 79 ClientConfig: admission.WebhookClientConfig{ 80 CABundle: caPemBuffer.Bytes(), 81 Service: service, 82 }, 83 AdmissionReviewVersions: []string{reviewVersionV1beta1}, 84 FailurePolicy: &failurePolicy, 85 MatchPolicy: &matchPolicy, 86 Name: k8sutils.MakeK8sDomain(Component), 87 NamespaceSelector: &meta.LabelSelector{ 88 MatchLabels: k8sutils.LabelsForModel(modelName, legacyLabels), 89 }, 90 ObjectSelector: &meta.LabelSelector{ 91 MatchExpressions: []meta.LabelSelectorRequirement{ 92 { 93 Key: k8sconstants.LabelJujuModelOperatorDisableWebhook, 94 Operator: meta.LabelSelectorOpDoesNotExist, 95 }, 96 }, 97 }, 98 Rules: []admission.RuleWithOperations{ 99 { 100 Operations: []admission.OperationType{ 101 admission.Create, 102 admission.Update, 103 }, 104 Rule: admission.Rule{ 105 APIGroups: anyMatch, 106 APIVersions: anyMatch, 107 Resources: anyMatch, 108 Scope: &ruleScope, 109 }, 110 }, 111 }, 112 }, 113 }, 114 } 115 116 return AdmissionCreatorFunc(func() (func(), error) { 117 leafGroup := fmt.Sprintf("k8sadmission-%s", modelName) 118 _, err := authority.LeafRequestForGroup(leafGroup). 119 AddDNSNames(fmt.Sprintf("%s.%s.svc", service.Name, service.Namespace)). 120 Commit() 121 if err != nil { 122 return nil, errors.Trace(err) 123 } 124 125 configCleanup, err := ensureConfig(&obj) 126 if err != nil { 127 return nil, errors.Trace(err) 128 } 129 130 return func() { 131 configCleanup() 132 }, nil 133 }), nil 134 }