@@ -7,20 +7,28 @@ import (
77 "time"
88
99 "github.com/spf13/cobra"
10+ admissionv1 "k8s.io/api/admissionregistration/v1"
1011 rbacv1 "k8s.io/api/rbac/v1"
1112 "k8s.io/apimachinery/pkg/runtime"
13+ "k8s.io/utils/ptr"
14+ "sigs.k8s.io/controller-runtime/pkg/client"
1215
1316 crdutil "github.com/openmcp-project/controller-utils/pkg/crds"
17+ "github.com/openmcp-project/controller-utils/pkg/resources"
1418
1519 clustersv1alpha1 "github.com/openmcp-project/openmcp-operator/api/clusters/v1alpha1"
1620 apiconst "github.com/openmcp-project/openmcp-operator/api/constants"
21+ corev2alpha1 "github.com/openmcp-project/openmcp-operator/api/core/v2alpha1"
1722 "github.com/openmcp-project/openmcp-operator/api/crds"
1823 "github.com/openmcp-project/openmcp-operator/api/install"
1924 "github.com/openmcp-project/openmcp-operator/cmd/openmcp-operator/app/options"
2025 "github.com/openmcp-project/openmcp-operator/internal/controllers/managedcontrolplane"
2126 "github.com/openmcp-project/openmcp-operator/lib/clusteraccess"
2227)
2328
29+ // currently hard-coded, can be made configurable in the future if needed
30+ const MCPPurposeOverrideValidationPolicyName = "mcp-purpose-override-validation"
31+
2432func NewInitCommand (po * options.PersistentOptions ) * cobra.Command {
2533 opts := & InitOptions {
2634 PersistentOptions : po ,
@@ -94,6 +102,11 @@ func (o *InitOptions) Run(ctx context.Context) error {
94102 Resources : []string {"customresourcedefinitions" },
95103 Verbs : []string {"*" },
96104 },
105+ {
106+ APIGroups : []string {"admissionregistration.k8s.io" },
107+ Resources : []string {"validatingadmissionpolicies" , "validatingadmissionpolicybindings" },
108+ Verbs : []string {"*" },
109+ },
97110 },
98111 },
99112 })
@@ -111,6 +124,115 @@ func (o *InitOptions) Run(ctx context.Context) error {
111124 if err := crdManager .CreateOrUpdateCRDs (ctx , & o .Log ); err != nil {
112125 return fmt .Errorf ("error creating/updating CRDs: %w" , err )
113126 }
127+
128+ // ensure ValidatingAdmissionPolicy to prevent removal or changes to the MCP purpose override label
129+ labelSelector := client.MatchingLabels {
130+ apiconst .ManagedByLabel : managedcontrolplane .ControllerName ,
131+ apiconst .ManagedPurposeLabel : corev2alpha1 .ManagedPurposeMCPPurposeOverride ,
132+ }
133+ evapbs := & admissionv1.ValidatingAdmissionPolicyBindingList {}
134+ if err := onboardingCluster .Client ().List (ctx , evapbs , labelSelector ); err != nil {
135+ return fmt .Errorf ("error listing ValidatingAdmissionPolicyBindings: %w" , err )
136+ }
137+ for _ , evapb := range evapbs .Items {
138+ if evapb .Name != MCPPurposeOverrideValidationPolicyName {
139+ setupLog .Info ("Deleting existing ValidatingAdmissionPolicyBinding with architecture immutability purpose" , "name" , evapb .Name )
140+ if err := onboardingCluster .Client ().Delete (ctx , & evapb ); client .IgnoreNotFound (err ) != nil {
141+ return fmt .Errorf ("error deleting ValidatingAdmissionPolicyBinding '%s': %w" , evapb .Name , err )
142+ }
143+ }
144+ }
145+ evaps := & admissionv1.ValidatingAdmissionPolicyList {}
146+ if err := onboardingCluster .Client ().List (ctx , evaps , labelSelector ); err != nil {
147+ return fmt .Errorf ("error listing ValidatingAdmissionPolicies: %w" , err )
148+ }
149+ for _ , evap := range evaps .Items {
150+ if evap .Name != MCPPurposeOverrideValidationPolicyName {
151+ setupLog .Info ("Deleting existing ValidatingAdmissionPolicy with architecture immutability purpose" , "name" , evap .Name )
152+ if err := onboardingCluster .Client ().Delete (ctx , & evap ); client .IgnoreNotFound (err ) != nil {
153+ return fmt .Errorf ("error deleting ValidatingAdmissionPolicy '%s': %w" , evap .Name , err )
154+ }
155+ }
156+ }
157+ setupLog .Info ("creating/updating ValidatingAdmissionPolicies to prevent undesired changes to the MCP purpose override label ..." )
158+ vapm := resources .NewValidatingAdmissionPolicyMutator (MCPPurposeOverrideValidationPolicyName , admissionv1.ValidatingAdmissionPolicySpec {
159+ FailurePolicy : ptr .To (admissionv1 .Fail ),
160+ MatchConstraints : & admissionv1.MatchResources {
161+ ResourceRules : []admissionv1.NamedRuleWithOperations {
162+ {
163+ RuleWithOperations : admissionv1.RuleWithOperations {
164+ Operations : []admissionv1.OperationType {
165+ admissionv1 .Create ,
166+ admissionv1 .Update ,
167+ },
168+ Rule : admissionv1.Rule { // match all resources, actual restriction happens in the binding
169+ APIGroups : []string {"*" },
170+ APIVersions : []string {"*" },
171+ Resources : []string {"*" },
172+ },
173+ },
174+ },
175+ },
176+ },
177+ Variables : []admissionv1.Variable {
178+ {
179+ Name : "purposeOverrideLabel" ,
180+ Expression : fmt .Sprintf (`(has(object.metadata.labels) && "%s" in object.metadata.labels) ? object.metadata.labels["%s"] : ""` , corev2alpha1 .MCPPurposeOverrideLabel , corev2alpha1 .MCPPurposeOverrideLabel ),
181+ },
182+ {
183+ Name : "oldPurposeOverrideLabel" ,
184+ Expression : fmt .Sprintf (`(oldObject != null && has(oldObject.metadata.labels) && "%s" in oldObject.metadata.labels) ? oldObject.metadata.labels["%s"] : ""` , corev2alpha1 .MCPPurposeOverrideLabel , corev2alpha1 .MCPPurposeOverrideLabel ),
185+ },
186+ },
187+ Validations : []admissionv1.Validation {
188+ {
189+ Expression : `request.operation == "CREATE" || (variables.oldPurposeOverrideLabel == variables.purposeOverrideLabel)` ,
190+ Message : fmt .Sprintf (`The label "%s" is immutable, it cannot be added after creation and is not allowed to be changed or removed once set.` , corev2alpha1 .MCPPurposeOverrideLabel ),
191+ },
192+ },
193+ })
194+ vapm .MetadataMutator ().WithLabels (map [string ]string {
195+ apiconst .ManagedByLabel : managedcontrolplane .ControllerName ,
196+ apiconst .ManagedPurposeLabel : corev2alpha1 .ManagedPurposeMCPPurposeOverride ,
197+ })
198+ if err := resources .CreateOrUpdateResource (ctx , onboardingCluster .Client (), vapm ); err != nil {
199+ return fmt .Errorf ("error creating/updating ValidatingAdmissionPolicy for mcp purpose override validation: %w" , err )
200+ }
201+
202+ vapbm := resources .NewValidatingAdmissionPolicyBindingMutator (MCPPurposeOverrideValidationPolicyName , admissionv1.ValidatingAdmissionPolicyBindingSpec {
203+ PolicyName : MCPPurposeOverrideValidationPolicyName ,
204+ ValidationActions : []admissionv1.ValidationAction {
205+ admissionv1 .Deny ,
206+ },
207+ MatchResources : & admissionv1.MatchResources {
208+ ResourceRules : []admissionv1.NamedRuleWithOperations {
209+ {
210+ RuleWithOperations : admissionv1.RuleWithOperations {
211+ Operations : []admissionv1.OperationType {
212+ admissionv1 .Create ,
213+ admissionv1 .Update ,
214+ },
215+ Rule : admissionv1.Rule {
216+ APIGroups : []string {corev2alpha1 .GroupVersion .Group },
217+ APIVersions : []string {corev2alpha1 .GroupVersion .Version },
218+ Resources : []string {
219+ "managedcontrolplanev2s" ,
220+ },
221+ },
222+ },
223+ },
224+ },
225+ },
226+ })
227+ vapbm .MetadataMutator ().WithLabels (map [string ]string {
228+ apiconst .ManagedByLabel : managedcontrolplane .ControllerName ,
229+ apiconst .ManagedPurposeLabel : corev2alpha1 .ManagedPurposeMCPPurposeOverride ,
230+ })
231+ if err := resources .CreateOrUpdateResource (ctx , onboardingCluster .Client (), vapbm ); err != nil {
232+ return fmt .Errorf ("error creating/updating ValidatingAdmissionPolicyBinding for mcp purpose override validation: %w" , err )
233+ }
234+ setupLog .Info ("ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding for mcp purpose override validation created/updated" )
235+
114236 log .Info ("Finished init command" )
115237 return nil
116238}
0 commit comments