From 33b7970081e5e562d33f6cc014c6fd5ca329fe8f Mon Sep 17 00:00:00 2001 From: Stanislav Laznicka Date: Thu, 3 Aug 2023 14:34:33 +0200 Subject: [PATCH] ps syncer: add a controller for run-level 0 namespaces --- pkg/cmd/controller/config.go | 23 +++--- pkg/cmd/controller/psalabelsyncer.go | 17 +++++ .../privileged_namespaces_controller.go | 72 +++++++++++++++++++ 3 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 pkg/psalabelsyncer/privileged_namespaces_controller.go diff --git a/pkg/cmd/controller/config.go b/pkg/cmd/controller/config.go index a66594577..ef1717527 100644 --- a/pkg/cmd/controller/config.go +++ b/pkg/cmd/controller/config.go @@ -1,17 +1,20 @@ package controller var ControllerInitializers = map[string]InitFunc{ - "openshift.io/namespace-security-allocation": RunNamespaceSecurityAllocationController, - "openshift.io/resourcequota": RunResourceQuotaManager, - "openshift.io/cluster-quota-reconciliation": RunClusterQuotaReconciliationController, - "openshift.io/cluster-csr-approver": RunCSRApproverController, - "openshift.io/podsecurity-admission-label-syncer": runPodSecurityAdmissionLabelSynchronizationController, + "openshift.io/namespace-security-allocation": RunNamespaceSecurityAllocationController, + "openshift.io/resourcequota": RunResourceQuotaManager, + "openshift.io/cluster-quota-reconciliation": RunClusterQuotaReconciliationController, + "openshift.io/cluster-csr-approver": RunCSRApproverController, + "openshift.io/podsecurity-admission-label-syncer": runPodSecurityAdmissionLabelSynchronizationController, + "openshift.io/privileged-namespaces-psa-label-syncer": runPrivilegedNamespacesPSALabelSyncer, } const ( - infraClusterQuotaReconciliationControllerServiceAccountName = "cluster-quota-reconciliation-controller" - infraClusterCSRApproverControllerServiceAccountName = "cluster-csr-approver-controller" - infraNamespaceSecurityAllocationControllerServiceAccountName = "namespace-security-allocation-controller" - podSecurityAdmissionLabelSyncerControllerServiceAccountName = "podsecurity-admission-label-syncer-controller" - defaultOpenShiftInfraNamespace = "openshift-infra" + infraClusterQuotaReconciliationControllerServiceAccountName = "cluster-quota-reconciliation-controller" + infraClusterCSRApproverControllerServiceAccountName = "cluster-csr-approver-controller" + infraNamespaceSecurityAllocationControllerServiceAccountName = "namespace-security-allocation-controller" + podSecurityAdmissionLabelSyncerControllerServiceAccountName = "podsecurity-admission-label-syncer-controller" + privilegedNamespacesPodSecurityAdmissionLabelSyncerServiceAccountName = "privileged-namespaces-psa-label-syncer" + + defaultOpenShiftInfraNamespace = "openshift-infra" ) diff --git a/pkg/cmd/controller/psalabelsyncer.go b/pkg/cmd/controller/psalabelsyncer.go index 6896b4810..554f19b61 100644 --- a/pkg/cmd/controller/psalabelsyncer.go +++ b/pkg/cmd/controller/psalabelsyncer.go @@ -51,3 +51,20 @@ func runPodSecurityAdmissionLabelSynchronizationController(ctx context.Context, return true, nil } + +func runPrivilegedNamespacesPSALabelSyncer(ctx context.Context, controllerCtx *EnhancedControllerContext) (bool, error) { + kubeClient, err := controllerCtx.ClientBuilder.Client(privilegedNamespacesPodSecurityAdmissionLabelSyncerServiceAccountName) + if err != nil { + return true, err + } + + controller := psalabelsyncer.NewPrivilegedNamespacesPSALabelSyncer( + kubeClient.CoreV1().Namespaces(), + controllerCtx.KubernetesInformers.Core().V1().Namespaces(), + controllerCtx.EventRecorder.ForComponent("privileged-namespaces-psa-label-syncer"), + ) + + go controller.Run(ctx, 1) + + return true, nil +} diff --git a/pkg/psalabelsyncer/privileged_namespaces_controller.go b/pkg/psalabelsyncer/privileged_namespaces_controller.go new file mode 100644 index 000000000..366312f96 --- /dev/null +++ b/pkg/psalabelsyncer/privileged_namespaces_controller.go @@ -0,0 +1,72 @@ +package psalabelsyncer + +import ( + "context" + "fmt" + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + corev1apply "k8s.io/client-go/applyconfigurations/core/v1" + corev1informers "k8s.io/client-go/informers/core/v1" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + corev1listers "k8s.io/client-go/listers/core/v1" + psapi "k8s.io/pod-security-admission/api" + + "github.com/openshift/library-go/pkg/controller/factory" + "github.com/openshift/library-go/pkg/operator/events" +) + +const privilegedControllerName = "privileged-namespaces-psa-label-syncer" + +type privilegedNamespacesPSALabelSyncer struct { + nsClient corev1client.NamespaceInterface + nsLister corev1listers.NamespaceLister +} + +func NewPrivilegedNamespacesPSALabelSyncer( + namespaceClient corev1client.NamespaceInterface, + namespaceInformer corev1informers.NamespaceInformer, + eventRecorder events.Recorder, +) factory.Controller { + c := &privilegedNamespacesPSALabelSyncer{ + nsClient: namespaceClient, + nsLister: namespaceInformer.Lister(), + } + + return factory.New(). + WithSync(c.sync). + WithFilteredEventsInformersQueueKeyFunc( + factory.ObjectNameToKey, + factory.NamesFilter("default", "kube-system", "kube-public"), + namespaceInformer.Informer(), + ). + ResyncEvery(1*time.Hour). + ToController( + privilegedControllerName, + eventRecorder.WithComponentSuffix(privilegedControllerName), + ) +} + +func (c *privilegedNamespacesPSALabelSyncer) sync(ctx context.Context, controllerCtx factory.SyncContext) error { + qKey := controllerCtx.QueueKey() + ns, err := c.nsLister.Get(qKey) + if err != nil { + return fmt.Errorf("failed to retrieve ns %q: %w", qKey, err) + } + + if ns.Labels[psapi.EnforceLevelLabel] == "privileged" && + ns.Labels[psapi.WarnLevelLabel] == "privileged" && + ns.Labels[psapi.AuditLevelLabel] == "privileged" { + return nil + } + + nsApplyConfig := corev1apply.Namespace(ns.Name).WithLabels(map[string]string{ + psapi.EnforceLevelLabel: "privileged", + psapi.WarnLevelLabel: "privileged", + psapi.AuditLevelLabel: "privileged", + }) + + _, err = c.nsClient.Apply(ctx, nsApplyConfig, v1.ApplyOptions{FieldManager: privilegedControllerName, Force: true}) + + return err +}