diff --git a/Makefile b/Makefile index 3e5a7257..6fa313f5 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # To re-generate a bundle for another specific version without changing the standard setup, you can: # - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2) # - use environment variables to overwrite this value (e.g export VERSION=0.0.2) -VERSION ?= 1.1.0 +VERSION ?= 1.3.0 # CHANNELS define the bundle channels used in the bundle. # Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable") diff --git a/api/falcon/v1alpha1/falconadmission_types.go b/api/falcon/v1alpha1/falconadmission_types.go index cfa3ac3c..4f459e95 100644 --- a/api/falcon/v1alpha1/falconadmission_types.go +++ b/api/falcon/v1alpha1/falconadmission_types.go @@ -1,6 +1,8 @@ package v1alpha1 import ( + "strconv" + arv1 "k8s.io/api/admissionregistration/v1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -99,7 +101,29 @@ type FalconAdmissionConfigSpec struct { // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Ignore Namespace List",order=12 DisabledNamespaces FalconAdmissionNamespace `json:"disabledNamespaces,omitempty"` - // Currently ignored and internally set to 1. + // Determines if with falcon-watcher container is included in the Pod + // +kubebuilder:default:=true + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Deploy Watcher Container",order=13 + DeployWatcher *bool `json:"deployWatcher,omitempty"` + + // Determines if snapshots of Kubernetes resources are periodically taken for cluster visibility. + // +kubebuilder:default:=true + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Enable Resource Snapshots",order=15 + SnapshotsEnabled *bool `json:"snapshotsEnabled,omitempty"` + + // Time interval between two snapshots of Kubernetes resources in the cluster. + // +kubebuilder:default:="22h" + // +kubebuilder:validation:Type:=string + // +kubebuilder:validation:Format:=duration + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Time Interval Between Two Snapshots",order=16 + SnapshotsInterval *metav1.Duration `json:"snapshotsInterval,omitempty"` + + // Determines if Kubernetes resources are watched for cluster visibility. + // +kubebuilder:default:=true + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Enable Resource Watcher",order=17 + WatcherEnabled *bool `json:"watcherEnabled,omitempty"` + + // Currently ignored and internally set to 1 // +kubebuilder:default:=2 // +kubebuilder:validation:XIntOrString // +kubebuilder:validation:Minimum:=0 @@ -117,11 +141,15 @@ type FalconAdmissionConfigSpec struct { ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Falcon Admission Controller Client Resources",order=9,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:resourceRequirements"} - //+kubebuilder:default:={"limits":{"cpu":"750m","memory":"256Mi"},"requests":{"cpu":"500m","memory":"256Mi"}} + // +kubebuilder:default:={"limits":{"cpu":"750m","memory":"384Mi"},"requests":{"cpu":"500m","memory":"384Mi"}} ResourcesClient *corev1.ResourceRequirements `json:"resourcesClient,omitempty"` + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Falcon Admission Controller Watcher Resources",order=14,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:resourceRequirements"} + // +kubebuilder:default:={"limits":{"cpu":"750m","memory":"384Mi"},"requests":{"cpu":"500m","memory":"384Mi"}} + ResourcesWatcher *corev1.ResourceRequirements `json:"resourcesWatcher,omitempty"` + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Falcon Admission Controller Resources",order=10,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:resourceRequirements"} - //+kubebuilder:default:={"limits":{"cpu":"300m","memory":"512Mi"},"requests":{"cpu":"300m","memory":"512Mi"}} + //+kubebuilder:default:={"limits":{"cpu":"300m","memory":"256Mi"},"requests":{"cpu":"300m","memory":"256Mi"}} ResourcesAC *corev1.ResourceRequirements `json:"resources,omitempty"` // Type of Deployment update. Can be "RollingUpdate" or "OnDelete". Default is RollingUpdate. @@ -201,3 +229,35 @@ type FalconAdmissionList struct { func init() { SchemeBuilder.Register(&FalconAdmission{}, &FalconAdmissionList{}) } + +func (watcher FalconAdmissionConfigSpec) DeployWatcherContainer() bool { + if watcher.DeployWatcher == nil { + return false + } + + return *watcher.DeployWatcher +} + +func (watcher FalconAdmissionConfigSpec) GetSnapshotsEnabled() string { + if watcher.SnapshotsEnabled == nil { + return "true" + } + + return strconv.FormatBool(*watcher.SnapshotsEnabled) +} + +func (watcher FalconAdmissionConfigSpec) GetSnapshotsInterval() string { + if watcher.SnapshotsInterval == nil { + return "22h0m0s" + } + + return watcher.SnapshotsInterval.Duration.String() +} + +func (watcher FalconAdmissionConfigSpec) GetWatcherEnabled() string { + if watcher.WatcherEnabled == nil { + return "true" + } + + return strconv.FormatBool(*watcher.WatcherEnabled) +} diff --git a/api/falcon/v1alpha1/zz_generated.deepcopy.go b/api/falcon/v1alpha1/zz_generated.deepcopy.go index 386a09a4..89f39d3a 100644 --- a/api/falcon/v1alpha1/zz_generated.deepcopy.go +++ b/api/falcon/v1alpha1/zz_generated.deepcopy.go @@ -323,6 +323,26 @@ func (in *FalconAdmissionConfigSpec) DeepCopyInto(out *FalconAdmissionConfigSpec } in.TLS.DeepCopyInto(&out.TLS) in.DisabledNamespaces.DeepCopyInto(&out.DisabledNamespaces) + if in.DeployWatcher != nil { + in, out := &in.DeployWatcher, &out.DeployWatcher + *out = new(bool) + **out = **in + } + if in.SnapshotsEnabled != nil { + in, out := &in.SnapshotsEnabled, &out.SnapshotsEnabled + *out = new(bool) + **out = **in + } + if in.SnapshotsInterval != nil { + in, out := &in.SnapshotsInterval, &out.SnapshotsInterval + *out = new(v1.Duration) + **out = **in + } + if in.WatcherEnabled != nil { + in, out := &in.WatcherEnabled, &out.WatcherEnabled + *out = new(bool) + **out = **in + } if in.Replicas != nil { in, out := &in.Replicas, &out.Replicas *out = new(int32) @@ -338,6 +358,11 @@ func (in *FalconAdmissionConfigSpec) DeepCopyInto(out *FalconAdmissionConfigSpec *out = new(corev1.ResourceRequirements) (*in).DeepCopyInto(*out) } + if in.ResourcesWatcher != nil { + in, out := &in.ResourcesWatcher, &out.ResourcesWatcher + *out = new(corev1.ResourceRequirements) + (*in).DeepCopyInto(*out) + } if in.ResourcesAC != nil { in, out := &in.ResourcesAC, &out.ResourcesAC *out = new(corev1.ResourceRequirements) diff --git a/bundle/manifests/falcon-operator.clusterserviceversion.yaml b/bundle/manifests/falcon-operator.clusterserviceversion.yaml index 8d1fc3ad..2e49cc27 100644 --- a/bundle/manifests/falcon-operator.clusterserviceversion.yaml +++ b/bundle/manifests/falcon-operator.clusterserviceversion.yaml @@ -125,7 +125,7 @@ metadata: capabilities: Seamless Upgrades categories: Security,Monitoring containerImage: quay.io/crowdstrike/falcon-operator - createdAt: "2024-06-03T19:42:25Z" + createdAt: "2024-08-23T19:08:01Z" description: Falcon Operator installs CrowdStrike Falcon Sensors on the cluster features.operators.openshift.io/cnf: "false" features.operators.openshift.io/cni: "false" @@ -285,7 +285,7 @@ spec: - description: Additional configuration for Falcon Admission Controller deployment. displayName: Falcon Admission Controller Configuration path: admissionConfig - - description: Number of replicas for the Falcon Admission Controller deployment. + - description: Currently ignored and internally set to 1. displayName: Admission Controller Replica Count path: admissionConfig.replicas x-descriptors: @@ -346,6 +346,21 @@ spec: - description: Ignore admission control for a specific set of namespaces. displayName: Ignore Namespace List path: admissionConfig.disabledNamespaces + - displayName: Falcon Admission Controller Watcher Resources + path: admissionConfig.resourcesWatcher + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:resourceRequirements + - description: Determines if snapshots of Kubernetes resources are periodically + taken for cluster visibility. + displayName: Enable Resource Snapshots + path: admissionConfig.snapshotsEnabled + - description: Time interval between two snapshots of Kubernetes resources in + the cluster. + displayName: Time Interval Between Two Snapshots + path: admissionConfig.snapshotsInterval + - description: Determines if Kubernetes resources are watched for cluster visibility. + displayName: Enable Resource Watcher + path: admissionConfig.watcherEnabled version: v1alpha1 - description: FalconContainer is the Schema for the falconcontainers API displayName: Falcon Container @@ -1307,7 +1322,7 @@ spec: fieldPath: metadata.annotations['olm.targetNamespaces'] - name: OPERATOR_NAME value: falcon-operator - image: quay.io/crowdstrike/falcon-operator:1.0.0 + image: quay.io/crowdstrike/falcon-operator:1.2.0 livenessProbe: httpGet: path: /healthz diff --git a/bundle/manifests/falcon.crowdstrike.com_falconadmissions.yaml b/bundle/manifests/falcon.crowdstrike.com_falconadmissions.yaml index bc7c05c2..eef89a09 100644 --- a/bundle/manifests/falcon.crowdstrike.com_falconadmissions.yaml +++ b/bundle/manifests/falcon.crowdstrike.com_falconadmissions.yaml @@ -220,6 +220,63 @@ spec: Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' type: object type: object + resourcesWatcher: + default: + limits: + cpu: 750m + memory: 256Mi + requests: + cpu: 500m + memory: 256Mi + description: ResourceRequirements describes the compute resource + requirements. + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can only be + set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in + pod.spec.resourceClaims of the Pod where this field + is used. It makes that resource available inside a + container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. Requests cannot exceed + Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object serviceAccount: description: Define annotations that will be passed down to admision controller service account. This is useful for passing along @@ -242,6 +299,17 @@ spec: minimum: 0 type: integer x-kubernetes-int-or-string: true + snapshotsEnabled: + default: true + description: Determines if snapshots of Kubernetes resources are + periodically taken for cluster visibility. + type: boolean + snapshotsInterval: + default: 22h + description: Time interval between two snapshots of Kubernetes + resources in the cluster. + format: duration + type: string tls: description: Configure TLS setings for the Falcon Admission Controller properties: @@ -301,6 +369,11 @@ spec: x-kubernetes-int-or-string: true type: object type: object + watcherEnabled: + default: true + description: Determines if Kubernetes resources are watched for + cluster visibility. + type: boolean type: object falcon: description: CrowdStrike Falcon sensor configuration diff --git a/bundle/manifests/falcon.crowdstrike.com_falconnodesensors.yaml b/bundle/manifests/falcon.crowdstrike.com_falconnodesensors.yaml index a5654368..83a1b29a 100644 --- a/bundle/manifests/falcon.crowdstrike.com_falconnodesensors.yaml +++ b/bundle/manifests/falcon.crowdstrike.com_falconnodesensors.yaml @@ -139,7 +139,7 @@ spec: description: Various configuration for DaemonSet Deployment properties: backend: - default: kernel + default: bpf description: Sets the backend to be used by the DaemonSet Sensor. enum: - kernel diff --git a/config/crd/bases/falcon.crowdstrike.com_falconadmissions.yaml b/config/crd/bases/falcon.crowdstrike.com_falconadmissions.yaml index 89161a80..f54da098 100644 --- a/config/crd/bases/falcon.crowdstrike.com_falconadmissions.yaml +++ b/config/crd/bases/falcon.crowdstrike.com_falconadmissions.yaml @@ -56,6 +56,11 @@ spec: minimum: 0 type: integer x-kubernetes-int-or-string: true + deployWatcher: + default: true + description: Determines if with falcon-watcher container is included + in the Pod + type: boolean disabledNamespaces: description: Ignore admission control for a specific set of namespaces. properties: @@ -99,7 +104,7 @@ spec: type: array replicas: default: 2 - description: Currently ignored and internally set to 1. + description: Currently ignored and internally set to 1 format: int32 maximum: 65535 minimum: 0 @@ -109,10 +114,10 @@ spec: default: limits: cpu: 300m - memory: 512Mi + memory: 256Mi requests: cpu: 300m - memory: 512Mi + memory: 256Mi description: ResourceRequirements describes the compute resource requirements. properties: @@ -166,10 +171,67 @@ spec: default: limits: cpu: 750m - memory: 256Mi + memory: 384Mi requests: cpu: 500m - memory: 256Mi + memory: 384Mi + description: ResourceRequirements describes the compute resource + requirements. + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can only be + set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in + pod.spec.resourceClaims of the Pod where this field + is used. It makes that resource available inside a + container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. Requests cannot exceed + Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + resourcesWatcher: + default: + limits: + cpu: 750m + memory: 384Mi + requests: + cpu: 500m + memory: 384Mi description: ResourceRequirements describes the compute resource requirements. properties: @@ -241,6 +303,17 @@ spec: minimum: 0 type: integer x-kubernetes-int-or-string: true + snapshotsEnabled: + default: true + description: Determines if snapshots of Kubernetes resources are + periodically taken for cluster visibility. + type: boolean + snapshotsInterval: + default: 22h + description: Time interval between two snapshots of Kubernetes + resources in the cluster. + format: duration + type: string tls: description: Configure TLS setings for the Falcon Admission Controller properties: @@ -300,6 +373,11 @@ spec: x-kubernetes-int-or-string: true type: object type: object + watcherEnabled: + default: true + description: Determines if Kubernetes resources are watched for + cluster visibility. + type: boolean type: object falcon: description: CrowdStrike Falcon sensor configuration diff --git a/config/manifests/bases/falcon-operator.clusterserviceversion.yaml b/config/manifests/bases/falcon-operator.clusterserviceversion.yaml index 3eb92cf3..5fa8f882 100644 --- a/config/manifests/bases/falcon-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/falcon-operator.clusterserviceversion.yaml @@ -164,7 +164,7 @@ spec: - description: Additional configuration for Falcon Admission Controller deployment. displayName: Falcon Admission Controller Configuration path: admissionConfig - - description: Number of replicas for the Falcon Admission Controller deployment. + - description: Currently ignored and internally set to 1. displayName: Admission Controller Replica Count path: admissionConfig.replicas x-descriptors: @@ -225,6 +225,21 @@ spec: - description: Ignore admission control for a specific set of namespaces. displayName: Ignore Namespace List path: admissionConfig.disabledNamespaces + - displayName: Falcon Admission Controller Watcher Resources + path: admissionConfig.resourcesWatcher + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:resourceRequirements + - description: Determines if snapshots of Kubernetes resources are periodically + taken for cluster visibility. + displayName: Enable Resource Snapshots + path: admissionConfig.snapshotsEnabled + - description: Time interval between two snapshots of Kubernetes resources in + the cluster. + displayName: Time Interval Between Two Snapshots + path: admissionConfig.snapshotsInterval + - description: Determines if Kubernetes resources are watched for cluster visibility. + displayName: Enable Resource Watcher + path: admissionConfig.watcherEnabled version: v1alpha1 - description: FalconContainer is the Schema for the falconcontainers API displayName: Falcon Container diff --git a/deploy/falcon-operator.yaml b/deploy/falcon-operator.yaml index d4686d19..da6b3a14 100644 --- a/deploy/falcon-operator.yaml +++ b/deploy/falcon-operator.yaml @@ -70,6 +70,11 @@ spec: minimum: 0 type: integer x-kubernetes-int-or-string: true + deployWatcher: + default: true + description: Determines if with falcon-watcher container is included + in the Pod + type: boolean disabledNamespaces: description: Ignore admission control for a specific set of namespaces. properties: @@ -113,7 +118,7 @@ spec: type: array replicas: default: 2 - description: Currently ignored and internally set to 1. + description: Currently ignored and internally set to 1 format: int32 maximum: 65535 minimum: 0 @@ -123,10 +128,10 @@ spec: default: limits: cpu: 300m - memory: 512Mi + memory: 256Mi requests: cpu: 300m - memory: 512Mi + memory: 256Mi description: ResourceRequirements describes the compute resource requirements. properties: @@ -180,10 +185,67 @@ spec: default: limits: cpu: 750m - memory: 256Mi + memory: 384Mi requests: cpu: 500m - memory: 256Mi + memory: 384Mi + description: ResourceRequirements describes the compute resource + requirements. + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can only be + set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in + pod.spec.resourceClaims of the Pod where this field + is used. It makes that resource available inside a + container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. Requests cannot exceed + Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + resourcesWatcher: + default: + limits: + cpu: 750m + memory: 384Mi + requests: + cpu: 500m + memory: 384Mi description: ResourceRequirements describes the compute resource requirements. properties: @@ -255,6 +317,17 @@ spec: minimum: 0 type: integer x-kubernetes-int-or-string: true + snapshotsEnabled: + default: true + description: Determines if snapshots of Kubernetes resources are + periodically taken for cluster visibility. + type: boolean + snapshotsInterval: + default: 22h + description: Time interval between two snapshots of Kubernetes + resources in the cluster. + format: duration + type: string tls: description: Configure TLS setings for the Falcon Admission Controller properties: @@ -314,6 +387,11 @@ spec: x-kubernetes-int-or-string: true type: object type: object + watcherEnabled: + default: true + description: Determines if Kubernetes resources are watched for + cluster visibility. + type: boolean type: object falcon: description: CrowdStrike Falcon sensor configuration diff --git a/docs/deployment/openshift/resources/admission/README.md b/docs/deployment/openshift/resources/admission/README.md index 50562da0..21c4776a 100644 --- a/docs/deployment/openshift/resources/admission/README.md +++ b/docs/deployment/openshift/resources/admission/README.md @@ -59,10 +59,15 @@ 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.deployWatcher | (optional) Determines if falcon-watcher container is added to the Falcon Admission Controller Pod | +| admissionConfig.snapshotsEnabled | (optional) Determines if snapshots of Kubernetes resources are periodically taken for cluster visibility. | +| admissionConfig.snapshotsInterval | (optional) Time interval between two snapshots of Kubernetes resources in the cluster | +| admissionConfig.watcherEnabled | (optional) Determines if Kubernetes resources are watched for cluster visibility | | admissionConfig.replicas | (optional) Currently ignored and internally set to 1 | | 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 | | admissionConfig.resourcesClient | (optional) Configure the resources client of the Falcon Admission Controller | +| admissionConfig.resourcesWatcher | (optional) Configure the resources watcher of the Falcon Admission Controller | | admissionConfig.resources | (optional) Configure the resources of the Falcon Admission Controller | | admissionConfig.updateStrategy | (optional) Configure the deployment update strategy of the Falcon Admission Controller | diff --git a/docs/deployment/openshift/resources/container/README.md b/docs/deployment/openshift/resources/container/README.md index f6a9846e..e3418f46 100644 --- a/docs/deployment/openshift/resources/container/README.md +++ b/docs/deployment/openshift/resources/container/README.md @@ -95,7 +95,10 @@ See `docs/ADVANCED.md` for more details. | Spec | Default Value | Description | | :- | :- | :- | | advanced.autoUpdate | `off` | Automatically updates a deployed Falcon sensor as new versions are released. This has no effect if a specific image or version has been requested. Valid settings are: -| advanced.updatePolicy | _none_ | If set, applies the named Linux sensor update policy, configured in Falcon UI, to select which version of Falcon sensor to install. The policy must be enabled and must match the CPU architecture of the cluster (AMD64 or ARM64). | +| advanced.updatePolicy | _none_ | If set, applies the named Linux sensor update policy, configured in Falcon UI, to select which version of Falcon sensor to install. The policy must be enabled and must match the CPU architecture of the cluster (AMD64 or ARM64). | + +> [!NOTE] +> To use the `Default (Linux)` Sensor Update Policy, assign `advanced.updatePolicy` to `platform_default`. ##### Automatic Update Frequency The operator checks for new releases of Falcon sensor once every 24 hours by default. This can be adjusted by setting the `--sensor-auto-update-interval` command-line flag to any value acceptable by [Golang's ParseDuration](https://pkg.go.dev/time#ParseDuration) function. However, it is strongly recommended that this be left at the default, as each cycle involves queries to the Falcon API and too many could result in throttling. diff --git a/docs/resources/admission/README.md b/docs/resources/admission/README.md index 4c9b113e..629a6706 100644 --- a/docs/resources/admission/README.md +++ b/docs/resources/admission/README.md @@ -32,6 +32,12 @@ spec: ``` ### FalconAdmission Reference Manual +#### Falcon Operator Support for Falcon Admission Controller + +| Falcon Operator Version | Falcon Admission Controller Version | +|:-----------------------------|:------------------------------------------| +| `<= 1.2.x` | `< 7.20.x` | +| `>= 1.3.x` | `>= 7.20.x` | #### Falcon API Settings | Spec | Description | @@ -59,10 +65,15 @@ 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.deployWatcher | (optional) Determines if the falcon-watcher container is added to the Falcon Admission Controller Pod | +| admissionConfig.snapshotsEnabled | (optional) Determines if snapshots of Kubernetes resources are periodically taken for cluster visibility in. Requires falcon-watcher container. | +| admissionConfig.snapshotsInterval | (optional) Time interval between two snapshots of Kubernetes resources in the cluster. Requires falcon-watcher container. | +| admissionConfig.watcherEnabled | (optional) Determines if Kubernetes resources are watched for cluster visibility. Requires falcon-watcher container. | | admissionConfig.replicas | (optional) Currently ignored and internally set to 1 | | 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 | | admissionConfig.resourcesClient | (optional) Configure the resources client of the Falcon Admission Controller | +| admissionConfig.resourcesWatcher | (optional) Configure the resources watcher of the Falcon Admission Controller | | admissionConfig.resources | (optional) Configure the resources of the Falcon Admission Controller | | admissionConfig.updateStrategy | (optional) Configure the deployment update strategy of the Falcon Admission Controller | diff --git a/docs/src/resources/admission.md.tmpl b/docs/src/resources/admission.md.tmpl index 0b692a9d..a8452e10 100644 --- a/docs/src/resources/admission.md.tmpl +++ b/docs/src/resources/admission.md.tmpl @@ -53,17 +53,21 @@ spec: | registry.tls.caCertificateConfigMap | (optional) The name of a ConfigMap containing CA Certificate Authority Chains under keys ending in ".tls" for self-signed TLS Registry Certificates (ignored when registry.tls.caCertificate is set) | | registry.acr_name | (optional) Name of ACR for the Falcon Admission push. Only applicable to Azure cloud. (`registry.type="acr"`) | | resourcequota.pods | (optional) Configure the maximum number of pods that can be created in the falcon-kac namespace | -| admissionConfig.serviceAccount.annotations| (optional) Configure annotations for the falcon-kac service account (e.g. for IAM role association) | +| admissionConfig.serviceAccount.annotations| (optional) Configure annotations for the falcon-kac service account (e.g. for IAM role association) | | admissionConfig.servicePort | (optional) Configure the port the Falcon Admission Controller Service listens on | -| admissionConfig.containerPort | (optional) Configure the port the Falcon Admission Controller container listens on | -| 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.containerPort | (optional) Configure the port the Falcon Admission Controller container listens on | +| 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.snapshotsEnabled | (optional) Determines if snapshots of Kubernetes resources are periodically taken for cluster visibility. | +| admissionConfig.snapshotsInterval | (optional) Time interval between two snapshots of Kubernetes resources in the cluster | +| admissionConfig.watcherEnabled | (optional) Determines if Kubernetes resources are watched for cluster visibility | | admissionConfig.replicas | (optional) Currently ignored and internally set to 1 | | 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 | | admissionConfig.resourcesClient | (optional) Configure the resources client of the Falcon Admission Controller | -| admissionConfig.resources | (optional) Configure the resources of the Falcon Admission Controller | +| admissionConfig.resourcesWatcher | (optional) Configure the resources watcher of the Falcon Admission Controller | +| admissionConfig.resources | (optional) Configure the resources of the Falcon Admission Controller | | admissionConfig.updateStrategy | (optional) Configure the deployment update strategy of the Falcon Admission Controller | diff --git a/internal/controller/admission/falconadmission_controller.go b/internal/controller/admission/falconadmission_controller.go index 085c63cd..397ca437 100644 --- a/internal/controller/admission/falconadmission_controller.go +++ b/internal/controller/admission/falconadmission_controller.go @@ -556,20 +556,29 @@ func (r *FalconAdmissionReconciler) reconcileAdmissionDeployment(ctx context.Con updated = true } - for i, containers := range dep.Spec.Template.Spec.Containers { - if !reflect.DeepEqual(containers.Resources, existingDeployment.Spec.Template.Spec.Containers[i].Resources) { - existingDeployment.Spec.Template.Spec.Containers[i].Resources = containers.Resources - updated = true - } + if len(dep.Spec.Template.Spec.Containers) != len(existingDeployment.Spec.Template.Spec.Containers) { + existingDeployment.Spec.Template.Spec.Containers = dep.Spec.Template.Spec.Containers + updated = true + } else { + for i, containers := range dep.Spec.Template.Spec.Containers { + if !reflect.DeepEqual(containers.Resources, existingDeployment.Spec.Template.Spec.Containers[i].Resources) { + existingDeployment.Spec.Template.Spec.Containers[i].Resources = containers.Resources + updated = true + } - if !reflect.DeepEqual(containers.LivenessProbe.ProbeHandler.HTTPGet.Port, existingDeployment.Spec.Template.Spec.Containers[i].LivenessProbe.ProbeHandler.HTTPGet.Port) { - existingDeployment.Spec.Template.Spec.Containers[i].LivenessProbe.ProbeHandler.HTTPGet.Port = containers.LivenessProbe.ProbeHandler.HTTPGet.Port - updated = true - } + if !reflect.DeepEqual(containers.LivenessProbe.ProbeHandler.HTTPGet.Port, existingDeployment.Spec.Template.Spec.Containers[i].LivenessProbe.ProbeHandler.HTTPGet.Port) { + existingDeployment.Spec.Template.Spec.Containers[i].LivenessProbe.ProbeHandler.HTTPGet.Port = containers.LivenessProbe.ProbeHandler.HTTPGet.Port + updated = true + } - if !reflect.DeepEqual(containers.StartupProbe.ProbeHandler.HTTPGet.Port, existingDeployment.Spec.Template.Spec.Containers[i].StartupProbe.ProbeHandler.HTTPGet.Port) { - existingDeployment.Spec.Template.Spec.Containers[i].StartupProbe.ProbeHandler.HTTPGet.Port = containers.StartupProbe.ProbeHandler.HTTPGet.Port - updated = true + if !reflect.DeepEqual(containers.StartupProbe.ProbeHandler.HTTPGet.Port, existingDeployment.Spec.Template.Spec.Containers[i].StartupProbe.ProbeHandler.HTTPGet.Port) { + existingDeployment.Spec.Template.Spec.Containers[i].StartupProbe.ProbeHandler.HTTPGet.Port = containers.StartupProbe.ProbeHandler.HTTPGet.Port + updated = true + } + if !reflect.DeepEqual(containers.Env, existingDeployment.Spec.Template.Spec.Containers[i].Env) { + existingDeployment.Spec.Template.Spec.Containers[i].Env = containers.Env + updated = true + } } } diff --git a/internal/controller/assets/deployment.go b/internal/controller/assets/deployment.go index 11c3dbd0..73c4c049 100644 --- a/internal/controller/assets/deployment.go +++ b/internal/controller/assets/deployment.go @@ -11,6 +11,15 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" ) +type EAdmissionContainer int + +const ( + // These names are based on the container names used for AdmissionController deployment. + FalconKac EAdmissionContainer = iota + FalconClient + FalconWatcher +) + var enforcedSingleReplica = int32(1) // SideCarDeployment returns a Deployment object for the CrowdStrike Falcon sidecar @@ -404,17 +413,24 @@ func AdmissionDeployment(name string, namespace string, component string, imageU allowPrivilegeEscalation := false shareProcessNamespace := true resourcesClient := &corev1.ResourceRequirements{} + resourcesWatcher := &corev1.ResourceRequirements{} resourcesAC := &corev1.ResourceRequirements{} sizeLimitTmp := resource.MustParse("256Mi") sizeLimitPrivate := resource.MustParse("4Ki") + sizeLimitWatcher := resource.MustParse("64Mi") labels := common.CRLabels("deployment", name, component) registryCAConfigMapName := "" registryCABundleConfigMapName := name + "-registry-certs" + portWatcherHealthCheck := int32(4080) if falconAdmission.Spec.AdmissionConfig.ResourcesClient != nil { resourcesClient = falconAdmission.Spec.AdmissionConfig.ResourcesClient } + if falconAdmission.Spec.AdmissionConfig.ResourcesWatcher != nil { + resourcesWatcher = falconAdmission.Spec.AdmissionConfig.ResourcesWatcher + } + if falconAdmission.Spec.AdmissionConfig.ResourcesAC != nil { resourcesAC = falconAdmission.Spec.AdmissionConfig.ResourcesAC } @@ -444,6 +460,14 @@ func AdmissionDeployment(name string, namespace string, component string, imageU }, }, }, + { + Name: "crowdstrike-falcon-vol2", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{ + SizeLimit: &sizeLimitWatcher, + }, + }, + }, } if falconAdmission.Spec.Registry.TLS.CACertificateConfigMap != "" { @@ -471,6 +495,230 @@ func AdmissionDeployment(name string, namespace string, component string, imageU log.Info("ignoring Replicas setting as only one is currently supported") } + kacContainers := &[]corev1.Container{ + { + Name: "falcon-client", + Image: imageUri, + ImagePullPolicy: falconAdmission.Spec.AdmissionConfig.ImagePullPolicy, + Args: []string{"client"}, + SecurityContext: &corev1.SecurityContext{ + ReadOnlyRootFilesystem: &readOnlyRootFilesystem, + AllowPrivilegeEscalation: &allowPrivilegeEscalation, + RunAsNonRoot: &runNonRoot, + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{ + "ALL", + }, + }, + }, + Env: []corev1.EnvVar{ + { + Name: "__CS_POD_NAMESPACE", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "metadata.namespace", + }, + }, + }, + { + Name: "__CS_POD_NAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "metadata.name", + }, + }, + }, + { + Name: "__CS_POD_NODENAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "spec.nodeName", + }, + }, + }, + }, + EnvFrom: []corev1.EnvFromSource{ + { + ConfigMapRef: &corev1.ConfigMapEnvSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: name + "-config", + }, + }, + }, + }, + Ports: []corev1.ContainerPort{ + { + ContainerPort: *falconAdmission.Spec.AdmissionConfig.ContainerPort, + Name: common.FalconServiceHTTPSName, + Protocol: corev1.ProtocolTCP, + }, + }, + VolumeMounts: admissionDepVolumeMounts(name, registryCAConfigMapName, FalconClient), + StartupProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: common.FalconAdmissionClientStartupProbePath, + Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, + Scheme: corev1.URISchemeHTTPS, + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 1, + PeriodSeconds: 2, + SuccessThreshold: 1, + FailureThreshold: 30, + }, + LivenessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: common.FalconAdmissionClientLivenessProbePath, + Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, + Scheme: corev1.URISchemeHTTPS, + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + Resources: *resourcesClient, + }, + { + Name: "falcon-kac", + Image: imageUri, + ImagePullPolicy: falconAdmission.Spec.AdmissionConfig.ImagePullPolicy, + + SecurityContext: &corev1.SecurityContext{ + ReadOnlyRootFilesystem: &readOnlyRootFilesystem, + AllowPrivilegeEscalation: &allowPrivilegeEscalation, + RunAsNonRoot: &runNonRoot, + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{ + "ALL", + }, + }, + }, + EnvFrom: []corev1.EnvFromSource{ + { + ConfigMapRef: &corev1.ConfigMapEnvSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: name + "-config", + }, + }, + }, + }, + VolumeMounts: admissionDepVolumeMounts(name, registryCAConfigMapName, FalconKac), + StartupProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: common.FalconAdmissionStartupProbePath, + Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, + Scheme: corev1.URISchemeHTTPS, + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 1, + PeriodSeconds: 2, + SuccessThreshold: 1, + FailureThreshold: 30, + }, + LivenessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: common.FalconAdmissionLivenessProbePath, + Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, + Scheme: corev1.URISchemeHTTPS, + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + Resources: *resourcesAC, + }, + } + + if falconAdmission.Spec.AdmissionConfig.DeployWatcherContainer() { + *kacContainers = append(*kacContainers, corev1.Container{ + Name: "falcon-watcher", + Image: imageUri, + ImagePullPolicy: falconAdmission.Spec.AdmissionConfig.ImagePullPolicy, + Args: []string{ + "client", + "-app=watcher", + }, + SecurityContext: &corev1.SecurityContext{ + ReadOnlyRootFilesystem: &readOnlyRootFilesystem, + AllowPrivilegeEscalation: &allowPrivilegeEscalation, + RunAsNonRoot: &runNonRoot, + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{ + "ALL", + }, + }, + }, + Env: admissionDepWatcherEnvVars(falconAdmission), + EnvFrom: []corev1.EnvFromSource{ + { + ConfigMapRef: &corev1.ConfigMapEnvSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: name + "-config", + }, + }, + }, + }, + Ports: []corev1.ContainerPort{ + { + ContainerPort: portWatcherHealthCheck, + Name: common.FalconServiceHTTPSName, + Protocol: corev1.ProtocolTCP, + }, + }, + VolumeMounts: admissionDepVolumeMounts(name, registryCAConfigMapName, FalconWatcher), + StartupProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: common.FalconAdmissionClientStartupProbePath, + Port: intstr.IntOrString{ + Type: intstr.Int, + IntVal: portWatcherHealthCheck, + }, + Scheme: corev1.URISchemeHTTP, + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 1, + PeriodSeconds: 2, + SuccessThreshold: 1, + FailureThreshold: 30, + }, + LivenessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: common.FalconAdmissionClientLivenessProbePath, + Port: intstr.IntOrString{ + Type: intstr.Int, + IntVal: portWatcherHealthCheck, + }, + Scheme: corev1.URISchemeHTTP, + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + Resources: *resourcesWatcher, + }) + } + return &appsv1.Deployment{ TypeMeta: metav1.TypeMeta{ APIVersion: appsv1.SchemeGroupVersion.String(), @@ -537,162 +785,15 @@ func AdmissionDeployment(name string, namespace string, component string, imageU ServiceAccountName: common.AdmissionServiceAccountName, NodeSelector: common.NodeSelector, PriorityClassName: common.FalconPriorityClassName, - Containers: []corev1.Container{ - { - Name: "falcon-client", - Image: imageUri, - ImagePullPolicy: falconAdmission.Spec.AdmissionConfig.ImagePullPolicy, - Args: []string{"client"}, - SecurityContext: &corev1.SecurityContext{ - ReadOnlyRootFilesystem: &readOnlyRootFilesystem, - AllowPrivilegeEscalation: &allowPrivilegeEscalation, - RunAsNonRoot: &runNonRoot, - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", - }, - }, - }, - Env: []corev1.EnvVar{ - { - Name: "__CS_POD_NAMESPACE", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - APIVersion: "v1", - FieldPath: "metadata.namespace", - }, - }, - }, - { - Name: "__CS_POD_NAME", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - APIVersion: "v1", - FieldPath: "metadata.name", - }, - }, - }, - { - Name: "__CS_POD_NODENAME", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - APIVersion: "v1", - FieldPath: "spec.nodeName", - }, - }, - }, - }, - EnvFrom: []corev1.EnvFromSource{ - { - ConfigMapRef: &corev1.ConfigMapEnvSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: name + "-config", - }, - }, - }, - }, - Ports: []corev1.ContainerPort{ - { - ContainerPort: *falconAdmission.Spec.AdmissionConfig.ContainerPort, - Name: common.FalconServiceHTTPSName, - Protocol: corev1.ProtocolTCP, - }, - }, - VolumeMounts: admissionDepVolumeMounts(name, registryCAConfigMapName, true), - StartupProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: common.FalconAdmissionClientStartupProbePath, - Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, - Scheme: corev1.URISchemeHTTPS, - }, - }, - InitialDelaySeconds: 5, - TimeoutSeconds: 1, - PeriodSeconds: 2, - SuccessThreshold: 1, - FailureThreshold: 30, - }, - LivenessProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: common.FalconAdmissionClientLivenessProbePath, - Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, - Scheme: corev1.URISchemeHTTPS, - }, - }, - InitialDelaySeconds: 5, - TimeoutSeconds: 1, - PeriodSeconds: 10, - SuccessThreshold: 1, - FailureThreshold: 3, - }, - Resources: *resourcesClient, - }, - { - Name: "falcon-kac", - Image: imageUri, - ImagePullPolicy: falconAdmission.Spec.AdmissionConfig.ImagePullPolicy, - - SecurityContext: &corev1.SecurityContext{ - ReadOnlyRootFilesystem: &readOnlyRootFilesystem, - AllowPrivilegeEscalation: &allowPrivilegeEscalation, - RunAsNonRoot: &runNonRoot, - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", - }, - }, - }, - EnvFrom: []corev1.EnvFromSource{ - { - ConfigMapRef: &corev1.ConfigMapEnvSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: name + "-config", - }, - }, - }, - }, - VolumeMounts: admissionDepVolumeMounts(name, registryCAConfigMapName, false), - StartupProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: common.FalconAdmissionStartupProbePath, - Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, - Scheme: corev1.URISchemeHTTPS, - }, - }, - InitialDelaySeconds: 5, - TimeoutSeconds: 1, - PeriodSeconds: 2, - SuccessThreshold: 1, - FailureThreshold: 30, - }, - LivenessProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: common.FalconAdmissionLivenessProbePath, - Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, - Scheme: corev1.URISchemeHTTPS, - }, - }, - InitialDelaySeconds: 5, - TimeoutSeconds: 1, - PeriodSeconds: 10, - SuccessThreshold: 1, - FailureThreshold: 3, - }, - Resources: *resourcesAC, - }, - }, - Volumes: volumes, + Containers: *kacContainers, + Volumes: volumes, }, }, }, } } -func admissionDepVolumeMounts(name string, registryCAConfigMapName string, client bool) []corev1.VolumeMount { +func admissionDepVolumeMounts(name string, registryCAConfigMapName string, container EAdmissionContainer) []corev1.VolumeMount { certPath := "/etc/docker/certs.d/falcon-admission-certs" volumeMounts := []corev1.VolumeMount{ @@ -706,7 +807,7 @@ func admissionDepVolumeMounts(name string, registryCAConfigMapName string, clien }, } - if client { + if container == FalconClient { volumeMounts = append(volumeMounts, corev1.VolumeMount{ Name: name + "-tls-certs", MountPath: "/run/secrets/tls", @@ -714,6 +815,13 @@ func admissionDepVolumeMounts(name string, registryCAConfigMapName string, clien }) } + if container == FalconKac || container == FalconWatcher { + volumeMounts = append(volumeMounts, corev1.VolumeMount{ + Name: "crowdstrike-falcon-vol2", + MountPath: "/var/falcon-watcher", + }) + } + if registryCAConfigMapName != "" { volumeMounts = append(volumeMounts, corev1.VolumeMount{ Name: registryCAConfigMapName, @@ -741,3 +849,49 @@ func admissionDepUpdateStrategy(admission *falconv1alpha1.FalconAdmission) appsv RollingUpdate: &rollingUpdateSettings, } } + +func admissionDepWatcherEnvVars(admission *falconv1alpha1.FalconAdmission) []corev1.EnvVar { + envVars := []corev1.EnvVar{ + corev1.EnvVar{ + Name: "__CS_POD_NAMESPACE", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "metadata.namespace", + }, + }, + }, + corev1.EnvVar{ + Name: "__CS_POD_NAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "metadata.name", + }, + }, + }, + corev1.EnvVar{ + Name: "__CS_POD_NODENAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "spec.nodeName", + }, + }, + }, + corev1.EnvVar{ + Name: "__CS_SNAPSHOTS_ENABLED", + Value: admission.Spec.AdmissionConfig.GetSnapshotsEnabled(), + }, + corev1.EnvVar{ + Name: "__CS_SNAPSHOT_INTERVAL", + Value: admission.Spec.AdmissionConfig.GetSnapshotsInterval(), + }, + corev1.EnvVar{ + Name: "__CS_WATCH_EVENTS_ENABLED", + Value: admission.Spec.AdmissionConfig.GetWatcherEnabled(), + }, + } + + return envVars +} diff --git a/internal/controller/assets/deployment_test.go b/internal/controller/assets/deployment_test.go index 062c114e..0c657626 100644 --- a/internal/controller/assets/deployment_test.go +++ b/internal/controller/assets/deployment_test.go @@ -38,10 +38,15 @@ func TestAdmissionDeployment(t *testing.T) { falconAdmission := &falconv1alpha1.FalconAdmission{} falconAdmission.Spec.AdmissionConfig.ResourcesClient = &corev1.ResourceRequirements{} falconAdmission.Spec.AdmissionConfig.ResourcesAC = &corev1.ResourceRequirements{} + port := int32(1) falconAdmission.Spec.AdmissionConfig.Port = &port falconAdmission.Spec.AdmissionConfig.Replicas = &port falconAdmission.Spec.AdmissionConfig.ContainerPort = &port + + var deployWatcher *bool = new(bool) + *deployWatcher = false + falconAdmission.Spec.AdmissionConfig.DeployWatcher = deployWatcher want := testAdmissionDeployment("test", "test", "test", "test", falconAdmission) logger := log.FromContext(context.Background()) @@ -49,6 +54,15 @@ func TestAdmissionDeployment(t *testing.T) { if diff := cmp.Diff(want, got); diff != "" { t.Errorf("Deployment() mismatch (-want +got): %s", diff) } + + *deployWatcher = true + falconAdmission.Spec.AdmissionConfig.DeployWatcher = deployWatcher + + want = testAdmissionDeployment("test", "test", "test", "test", falconAdmission) + got = AdmissionDeployment("test", "test", "test", "test", falconAdmission, logger) + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("Deployment() mismatch (-want +got): %s", diff) + } } // TestAdmissionDepUpdateStrategy tests the Admission Controller Deployment Update Strategy function @@ -325,19 +339,330 @@ func testAdmissionDeployment(name string, namespace string, component string, im allowPrivilegeEscalation := false shareProcessNamespace := true resourcesClient := &corev1.ResourceRequirements{} + resourcesWatcher := &corev1.ResourceRequirements{} resourcesAC := &corev1.ResourceRequirements{} sizeLimitTmp := resource.MustParse("256Mi") sizeLimitPrivate := resource.MustParse("4Ki") + sizeLimitWatcher := resource.MustParse("64Mi") + portWatcherHealthCheck := int32(4080) labels := common.CRLabels("deployment", name, component) if falconAdmission.Spec.AdmissionConfig.ResourcesClient != nil { resourcesClient = falconAdmission.Spec.AdmissionConfig.ResourcesClient } + if falconAdmission.Spec.AdmissionConfig.ResourcesWatcher != nil { + resourcesWatcher = falconAdmission.Spec.AdmissionConfig.ResourcesWatcher + } + if falconAdmission.Spec.AdmissionConfig.ResourcesAC != nil { resourcesAC = falconAdmission.Spec.AdmissionConfig.ResourcesAC } + kacContainers := &[]corev1.Container{ + { + Name: "falcon-client", + Image: imageUri, + ImagePullPolicy: falconAdmission.Spec.AdmissionConfig.ImagePullPolicy, + Args: []string{"client"}, + SecurityContext: &corev1.SecurityContext{ + ReadOnlyRootFilesystem: &readOnlyRootFilesystem, + AllowPrivilegeEscalation: &allowPrivilegeEscalation, + RunAsNonRoot: &runNonRoot, + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{ + "ALL", + }, + }, + }, + Env: []corev1.EnvVar{ + { + Name: "__CS_POD_NAMESPACE", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "metadata.namespace", + }, + }, + }, + { + Name: "__CS_POD_NAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "metadata.name", + }, + }, + }, + { + Name: "__CS_POD_NODENAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "spec.nodeName", + }, + }, + }, + }, + EnvFrom: []corev1.EnvFromSource{ + { + ConfigMapRef: &corev1.ConfigMapEnvSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: name + "-config", + }, + }, + }, + }, + Ports: []corev1.ContainerPort{ + { + ContainerPort: *falconAdmission.Spec.AdmissionConfig.Port, + Name: common.FalconServiceHTTPSName, + Protocol: corev1.ProtocolTCP, + }, + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "crowdstrike-falcon-vol0", + MountPath: "/tmp", + }, + { + Name: "crowdstrike-falcon-vol1", + MountPath: "/var/private", + }, + { + Name: name + "-tls-certs", + MountPath: "/run/secrets/tls", + ReadOnly: true, + }, + }, + StartupProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: common.FalconAdmissionClientStartupProbePath, + Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, + Scheme: corev1.URISchemeHTTPS, + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 1, + PeriodSeconds: 2, + SuccessThreshold: 1, + FailureThreshold: 30, + }, + LivenessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: common.FalconAdmissionClientLivenessProbePath, + Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, + Scheme: corev1.URISchemeHTTPS, + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + Resources: *resourcesClient, + }, + { + Name: "falcon-kac", + Image: imageUri, + ImagePullPolicy: falconAdmission.Spec.AdmissionConfig.ImagePullPolicy, + + SecurityContext: &corev1.SecurityContext{ + ReadOnlyRootFilesystem: &readOnlyRootFilesystem, + AllowPrivilegeEscalation: &allowPrivilegeEscalation, + RunAsNonRoot: &runNonRoot, + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{ + "ALL", + }, + }, + }, + EnvFrom: []corev1.EnvFromSource{ + { + ConfigMapRef: &corev1.ConfigMapEnvSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: name + "-config", + }, + }, + }, + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "crowdstrike-falcon-vol0", + MountPath: "/tmp", + }, + { + Name: "crowdstrike-falcon-vol1", + MountPath: "/var/private", + }, + { + Name: "crowdstrike-falcon-vol2", + MountPath: "/var/falcon-watcher", + }, + }, + StartupProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: common.FalconAdmissionStartupProbePath, + Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, + Scheme: corev1.URISchemeHTTPS, + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 1, + PeriodSeconds: 2, + SuccessThreshold: 1, + FailureThreshold: 30, + }, + LivenessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: common.FalconAdmissionLivenessProbePath, + Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, + Scheme: corev1.URISchemeHTTPS, + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + Resources: *resourcesAC, + }, + } + + if *falconAdmission.Spec.AdmissionConfig.DeployWatcher { + *kacContainers = append(*kacContainers, corev1.Container{ + Name: "falcon-watcher", + Image: imageUri, + ImagePullPolicy: falconAdmission.Spec.AdmissionConfig.ImagePullPolicy, + Args: []string{ + "client", + "-app=watcher", + }, + SecurityContext: &corev1.SecurityContext{ + ReadOnlyRootFilesystem: &readOnlyRootFilesystem, + AllowPrivilegeEscalation: &allowPrivilegeEscalation, + RunAsNonRoot: &runNonRoot, + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{ + "ALL", + }, + }, + }, + Env: []corev1.EnvVar{ + corev1.EnvVar{ + Name: "__CS_POD_NAMESPACE", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "metadata.namespace", + }, + }, + }, + corev1.EnvVar{ + Name: "__CS_POD_NAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "metadata.name", + }, + }, + }, + corev1.EnvVar{ + Name: "__CS_POD_NODENAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "spec.nodeName", + }, + }, + }, + corev1.EnvVar{ + Name: "__CS_SNAPSHOTS_ENABLED", + Value: "true", + }, + corev1.EnvVar{ + Name: "__CS_SNAPSHOT_INTERVAL", + Value: "22h0m0s", + }, + corev1.EnvVar{ + Name: "__CS_WATCH_EVENTS_ENABLED", + Value: "true", + }, + }, + EnvFrom: []corev1.EnvFromSource{ + { + ConfigMapRef: &corev1.ConfigMapEnvSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: name + "-config", + }, + }, + }, + }, + Ports: []corev1.ContainerPort{ + { + ContainerPort: portWatcherHealthCheck, + Name: common.FalconServiceHTTPSName, + Protocol: corev1.ProtocolTCP, + }, + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "crowdstrike-falcon-vol0", + MountPath: "/tmp", + }, + { + Name: "crowdstrike-falcon-vol1", + MountPath: "/var/private", + }, + { + Name: "crowdstrike-falcon-vol2", + MountPath: "/var/falcon-watcher", + }, + }, + StartupProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: common.FalconAdmissionClientStartupProbePath, + Port: intstr.IntOrString{ + Type: intstr.Int, + IntVal: portWatcherHealthCheck, + }, + Scheme: corev1.URISchemeHTTP, + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 1, + PeriodSeconds: 2, + SuccessThreshold: 1, + FailureThreshold: 30, + }, + LivenessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: common.FalconAdmissionClientLivenessProbePath, + Port: intstr.IntOrString{ + Type: intstr.Int, + IntVal: portWatcherHealthCheck, + }, + Scheme: corev1.URISchemeHTTP, + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + }, + Resources: *resourcesWatcher, + }) + } + return &appsv1.Deployment{ TypeMeta: metav1.TypeMeta{ APIVersion: appsv1.SchemeGroupVersion.String(), @@ -403,177 +728,7 @@ func testAdmissionDeployment(name string, namespace string, component string, im ServiceAccountName: common.AdmissionServiceAccountName, NodeSelector: common.NodeSelector, PriorityClassName: common.FalconPriorityClassName, - Containers: []corev1.Container{ - { - Name: "falcon-client", - Image: imageUri, - ImagePullPolicy: falconAdmission.Spec.AdmissionConfig.ImagePullPolicy, - Args: []string{"client"}, - SecurityContext: &corev1.SecurityContext{ - ReadOnlyRootFilesystem: &readOnlyRootFilesystem, - AllowPrivilegeEscalation: &allowPrivilegeEscalation, - RunAsNonRoot: &runNonRoot, - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", - }, - }, - }, - Env: []corev1.EnvVar{ - { - Name: "__CS_POD_NAMESPACE", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - APIVersion: "v1", - FieldPath: "metadata.namespace", - }, - }, - }, - { - Name: "__CS_POD_NAME", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - APIVersion: "v1", - FieldPath: "metadata.name", - }, - }, - }, - { - Name: "__CS_POD_NODENAME", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - APIVersion: "v1", - FieldPath: "spec.nodeName", - }, - }, - }, - }, - EnvFrom: []corev1.EnvFromSource{ - { - ConfigMapRef: &corev1.ConfigMapEnvSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: name + "-config", - }, - }, - }, - }, - Ports: []corev1.ContainerPort{ - { - ContainerPort: *falconAdmission.Spec.AdmissionConfig.Port, - Name: common.FalconServiceHTTPSName, - Protocol: corev1.ProtocolTCP, - }, - }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "crowdstrike-falcon-vol0", - MountPath: "/tmp", - }, - { - Name: "crowdstrike-falcon-vol1", - MountPath: "/var/private", - }, - { - Name: name + "-tls-certs", - MountPath: "/run/secrets/tls", - ReadOnly: true, - }, - }, - StartupProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: common.FalconAdmissionClientStartupProbePath, - Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, - Scheme: corev1.URISchemeHTTPS, - }, - }, - InitialDelaySeconds: 5, - TimeoutSeconds: 1, - PeriodSeconds: 2, - SuccessThreshold: 1, - FailureThreshold: 30, - }, - LivenessProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: common.FalconAdmissionClientLivenessProbePath, - Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, - Scheme: corev1.URISchemeHTTPS, - }, - }, - InitialDelaySeconds: 5, - TimeoutSeconds: 1, - PeriodSeconds: 10, - SuccessThreshold: 1, - FailureThreshold: 3, - }, - Resources: *resourcesClient, - }, - { - Name: "falcon-kac", - Image: imageUri, - ImagePullPolicy: falconAdmission.Spec.AdmissionConfig.ImagePullPolicy, - - SecurityContext: &corev1.SecurityContext{ - ReadOnlyRootFilesystem: &readOnlyRootFilesystem, - AllowPrivilegeEscalation: &allowPrivilegeEscalation, - RunAsNonRoot: &runNonRoot, - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", - }, - }, - }, - EnvFrom: []corev1.EnvFromSource{ - { - ConfigMapRef: &corev1.ConfigMapEnvSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: name + "-config", - }, - }, - }, - }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "crowdstrike-falcon-vol0", - MountPath: "/tmp", - }, - { - Name: "crowdstrike-falcon-vol1", - MountPath: "/var/private", - }, - }, - StartupProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: common.FalconAdmissionStartupProbePath, - Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, - Scheme: corev1.URISchemeHTTPS, - }, - }, - InitialDelaySeconds: 5, - TimeoutSeconds: 1, - PeriodSeconds: 2, - SuccessThreshold: 1, - FailureThreshold: 30, - }, - LivenessProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: common.FalconAdmissionLivenessProbePath, - Port: intstr.IntOrString{IntVal: *falconAdmission.Spec.AdmissionConfig.ContainerPort}, - Scheme: corev1.URISchemeHTTPS, - }, - }, - InitialDelaySeconds: 5, - TimeoutSeconds: 1, - PeriodSeconds: 10, - SuccessThreshold: 1, - FailureThreshold: 3, - }, - Resources: *resourcesAC, - }, - }, + Containers: *kacContainers, Volumes: []corev1.Volume{ { Name: name + "-tls-certs", @@ -599,6 +754,14 @@ func testAdmissionDeployment(name string, namespace string, component string, im }, }, }, + { + Name: "crowdstrike-falcon-vol2", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{ + SizeLimit: &sizeLimitWatcher, + }, + }, + }, }, }, },