From e0d40fb46700a213a9f84737ab1965cd151b9db5 Mon Sep 17 00:00:00 2001 From: Gabe Alford Date: Wed, 1 May 2024 16:33:48 -0600 Subject: [PATCH] feat(admission): automate ocp & falcon ns exclusions --- api/falcon/v1alpha1/falconadmission_types.go | 4 --- cmd/main.go | 5 +-- ...lcon.crowdstrike.com_falconadmissions.yaml | 4 --- deploy/falcon-operator.yaml | 4 --- .../openshift/resources/admission/README.md | 1 - docs/resources/admission/README.md | 1 - docs/src/resources/admission.md.tmpl | 1 - .../admission/falconadmission_controller.go | 17 ++++++--- internal/controller/common/utils.go | 25 +++++++++++-- internal/controller/common/utils_test.go | 35 +++++++++++++++++-- 10 files changed, 71 insertions(+), 26 deletions(-) diff --git a/api/falcon/v1alpha1/falconadmission_types.go b/api/falcon/v1alpha1/falconadmission_types.go index 4fa2957e..96a30e00 100644 --- a/api/falcon/v1alpha1/falconadmission_types.go +++ b/api/falcon/v1alpha1/falconadmission_types.go @@ -154,10 +154,6 @@ type FalconAdmissionNamespace struct { // Configure a list of namespaces to ignore admission control. // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Ignore Namespace List",order=1 Namespaces []string `json:"namespaces,omitempty"` - - // For OpenShift clusters, ignore openshift-specific namespaces for admission control. - // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Ignore OpenShift Namespaces",order=2,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:booleanSwitch"} - IgnoreOpenShiftNamespaces bool `json:"ignoreOpenShiftNamespaces,omitempty"` } // FalconAdmissionStatus defines the observed state of FalconAdmission diff --git a/cmd/main.go b/cmd/main.go index cd0754f7..3b808768 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -198,8 +198,9 @@ func main() { os.Exit(1) } if err = (&admissioncontroller.FalconAdmissionReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + OpenShift: openShift, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "FalconAdmission") os.Exit(1) diff --git a/config/crd/bases/falcon.crowdstrike.com_falconadmissions.yaml b/config/crd/bases/falcon.crowdstrike.com_falconadmissions.yaml index c9a91832..d7e6b338 100644 --- a/config/crd/bases/falcon.crowdstrike.com_falconadmissions.yaml +++ b/config/crd/bases/falcon.crowdstrike.com_falconadmissions.yaml @@ -59,10 +59,6 @@ spec: disabledNamespaces: description: Ignore admission control for a specific set of namespaces. properties: - ignoreOpenShiftNamespaces: - description: For OpenShift clusters, ignore openshift-specific - namespaces for admission control. - type: boolean namespaces: description: Configure a list of namespaces to ignore admission control. diff --git a/deploy/falcon-operator.yaml b/deploy/falcon-operator.yaml index 2319b0bc..6d2fc009 100644 --- a/deploy/falcon-operator.yaml +++ b/deploy/falcon-operator.yaml @@ -73,10 +73,6 @@ spec: disabledNamespaces: description: Ignore admission control for a specific set of namespaces. properties: - ignoreOpenShiftNamespaces: - description: For OpenShift clusters, ignore openshift-specific - namespaces for admission control. - type: boolean namespaces: description: Configure a list of namespaces to ignore admission control. diff --git a/docs/deployment/openshift/resources/admission/README.md b/docs/deployment/openshift/resources/admission/README.md index 8e8f0a43..aa4a5ae6 100644 --- a/docs/deployment/openshift/resources/admission/README.md +++ b/docs/deployment/openshift/resources/admission/README.md @@ -59,7 +59,6 @@ spec: | admissionConfig.tls.validity | (optional) Configure the validity of the TLS certificate used by the Falcon Admission Controller | | admissionConfig.failurePolicy | (optional) Configure the failure policy of the Falcon Admission Controller | | admissionConfig.disabledNamespaces.namespaces | (optional) Configure the list of namespaces the Falcon Admission Controller validating webhook should ignore | -| admissionConfig.disabledNamespaces.ignoreOpenShiftNamespaces | (optional) Configure whether the Falcon Admission Controller validating webhook should ignore OpenShift-specific namespaces | | admissionConfig.replicas | (optional) Configure the number of replicas of the Falcon Admission Controller | | admissionConfig.imagePullPolicy | (optional) Configure the image pull policy of the Falcon Admission Controller | | admissionConfig.imagePullSecrets | (optional) Configure the image pull secrets of the Falcon Admission Controller | diff --git a/docs/resources/admission/README.md b/docs/resources/admission/README.md index 668abcc8..28f25fea 100644 --- a/docs/resources/admission/README.md +++ b/docs/resources/admission/README.md @@ -59,7 +59,6 @@ spec: | admissionConfig.tls.validity | (optional) Configure the validity of the TLS certificate used by the Falcon Admission Controller | | admissionConfig.failurePolicy | (optional) Configure the failure policy of the Falcon Admission Controller | | admissionConfig.disabledNamespaces.namespaces | (optional) Configure the list of namespaces the Falcon Admission Controller validating webhook should ignore | -| admissionConfig.disabledNamespaces.ignoreOpenShiftNamespaces | (optional) Configure whether the Falcon Admission Controller validating webhook should ignore OpenShift-specific namespaces | | admissionConfig.replicas | (optional) Configure the number of replicas of the Falcon Admission Controller | | admissionConfig.imagePullPolicy | (optional) Configure the image pull policy of the Falcon Admission Controller | | admissionConfig.imagePullSecrets | (optional) Configure the image pull secrets of the Falcon Admission Controller | diff --git a/docs/src/resources/admission.md.tmpl b/docs/src/resources/admission.md.tmpl index a64d339b..f533d677 100644 --- a/docs/src/resources/admission.md.tmpl +++ b/docs/src/resources/admission.md.tmpl @@ -59,7 +59,6 @@ spec: | admissionConfig.tls.validity | (optional) Configure the validity of the TLS certificate used by the Falcon Admission Controller | | admissionConfig.failurePolicy | (optional) Configure the failure policy of the Falcon Admission Controller | | admissionConfig.disabledNamespaces.namespaces | (optional) Configure the list of namespaces the Falcon Admission Controller validating webhook should ignore | -| admissionConfig.disabledNamespaces.ignoreOpenShiftNamespaces | (optional) Configure whether the Falcon Admission Controller validating webhook should ignore OpenShift-specific namespaces | | admissionConfig.replicas | (optional) Configure the number of replicas of the Falcon Admission Controller | | admissionConfig.imagePullPolicy | (optional) Configure the image pull policy of the Falcon Admission Controller | | admissionConfig.imagePullSecrets | (optional) Configure the image pull secrets of the Falcon Admission Controller | diff --git a/internal/controller/admission/falconadmission_controller.go b/internal/controller/admission/falconadmission_controller.go index d5011aea..366925a6 100644 --- a/internal/controller/admission/falconadmission_controller.go +++ b/internal/controller/admission/falconadmission_controller.go @@ -39,13 +39,15 @@ import ( // FalconAdmissionReconciler reconciles a FalconAdmission object type FalconAdmissionReconciler struct { client.Client - Scheme *runtime.Scheme + Scheme *runtime.Scheme + OpenShift bool } // SetupWithManager sets up the controller with the Manager. func (r *FalconAdmissionReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&falconv1alpha1.FalconAdmission{}). + Owns(&corev1.Namespace{}). Owns(&corev1.ConfigMap{}). Owns(&corev1.ResourceQuota{}). Owns(&corev1.Secret{}). @@ -412,14 +414,21 @@ func (r *FalconAdmissionReconciler) reconcileAdmissionValidatingWebHook(ctx cont failPolicy := arv1.Ignore port := int32(443) - if falconAdmission.Spec.AdmissionConfig.DisabledNamespaces.IgnoreOpenShiftNamespaces { - ocpNS, err := k8sutils.GetNamespaceNamesSort(ctx, r.Client) + if r.OpenShift { + ocpNS, err := k8sutils.GetOpenShiftNamespaceNamesSort(ctx, r.Client) if err != nil { return false, err } disabledNamespaces = append(disabledNamespaces, ocpNS...) } + falconNS, err := k8sutils.GetRunningFalconNS(r.Client, ctx) + if err != nil { + return false, err + } + + disabledNamespaces = append(disabledNamespaces, falconNS...) + if falconAdmission.Spec.AdmissionConfig.FailurePolicy != "" { failPolicy = falconAdmission.Spec.AdmissionConfig.FailurePolicy } @@ -431,7 +440,7 @@ func (r *FalconAdmissionReconciler) reconcileAdmissionValidatingWebHook(ctx cont webhook := assets.ValidatingWebhook(falconAdmission.Name, falconAdmission.Spec.InstallNamespace, webhookName, cabundle, port, failPolicy, disabledNamespaces) updated := false - err := r.Get(ctx, types.NamespacedName{Name: webhookName}, existingWebhook) + err = r.Get(ctx, types.NamespacedName{Name: webhookName}, existingWebhook) if err != nil && apierrors.IsNotFound(err) { err = k8sutils.Create(r.Client, r.Scheme, ctx, req, log, falconAdmission, &falconAdmission.Status, webhook) if err != nil { diff --git a/internal/controller/common/utils.go b/internal/controller/common/utils.go index ccf660a1..91f112e4 100644 --- a/internal/controller/common/utils.go +++ b/internal/controller/common/utils.go @@ -9,6 +9,7 @@ import ( "github.com/crowdstrike/falcon-operator/api/falcon/v1alpha1" falconv1alpha1 "github.com/crowdstrike/falcon-operator/api/falcon/v1alpha1" "github.com/go-logr/logr" + "golang.org/x/exp/slices" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" @@ -249,7 +250,27 @@ func GetDeployment(r client.Client, ctx context.Context, namespace string, match return &depList.Items[0], nil } -func GetNamespaceNamesSort(ctx context.Context, cli client.Client) ([]string, error) { +func GetRunningFalconNS(r client.Client, ctx context.Context) ([]string, error) { + podList := &corev1.PodList{} + falconNamespaces := []string{} + listOpts := []client.ListOption{ + client.MatchingLabels{"crowdstrike.com/provider": "crowdstrike"}, + } + + if err := r.List(ctx, podList, listOpts...); err != nil { + return []string{}, fmt.Errorf("unable to list pods: %v", err) + } + + for _, pod := range podList.Items { + if !slices.Contains(falconNamespaces, pod.GetNamespace()) { + falconNamespaces = append(falconNamespaces, pod.GetNamespace()) + } + } + + return falconNamespaces, nil +} + +func GetOpenShiftNamespaceNamesSort(ctx context.Context, cli client.Client) ([]string, error) { nsList := []string{} ns := &corev1.NamespaceList{} err := cli.List(ctx, ns) @@ -258,7 +279,7 @@ func GetNamespaceNamesSort(ctx context.Context, cli client.Client) ([]string, er } for _, i := range ns.Items { - if strings.Contains(i.Name, "openshift") || strings.Contains(i.Name, "falcon") { + if strings.Contains(i.Name, "openshift") && !slices.Contains(nsList, i.Name) { nsList = append(nsList, i.Name) } } diff --git a/internal/controller/common/utils_test.go b/internal/controller/common/utils_test.go index 5cf901ef..984d3d2c 100644 --- a/internal/controller/common/utils_test.go +++ b/internal/controller/common/utils_test.go @@ -138,7 +138,36 @@ func TestGetDeployment(t *testing.T) { } } -func TestGetNamespaceNamesSort(t *testing.T) { +func TestGetRunningFalconNS(t *testing.T) { + ctx := context.Background() + + fakeClient, err := getFakeClient() + if err != nil { + t.Errorf("TestGetRunningFalconNS getFakeClient() error = %v", err) + } + + err = fakeClient.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace"}}) + if err != nil { + t.Errorf("TestGetRunningFalconNS Create() error = %v", err) + } + + err = fakeClient.Create(ctx, &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "test-pod", Namespace: "test-namespace", Labels: map[string]string{"crowdstrike.com/provider": "crowdstrike"}}}) + if err != nil { + t.Errorf("TestGetRunningFalconNS Create() error = %v", err) + } + + want := []string{"test-namespace"} + got, err := GetRunningFalconNS(fakeClient, ctx) + if err != nil { + t.Errorf("GetRunningFalconNS() error = %v", err) + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("GetRunningFalconNS() mismatch (-want +got):\n%s", diff) + } +} + +func TestGetOpenShiftNamespaceNamesSort(t *testing.T) { ctx := context.Background() fakeClient, err := getFakeClient() @@ -153,8 +182,8 @@ func TestGetNamespaceNamesSort(t *testing.T) { } } - want := []string{"falcon-system", "openshift"} - got, err := GetNamespaceNamesSort(ctx, fakeClient) + want := []string{"openshift"} + got, err := GetOpenShiftNamespaceNamesSort(ctx, fakeClient) if err != nil { t.Errorf("GetNamespaceNamesSort() error = %v", err) }