From 2759215a2b864a2128e2b7547afa59b8cbe723e4 Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Fri, 22 Dec 2023 15:26:49 +0100 Subject: [PATCH 01/19] new(falco): add k8s-metacollector chart as a dependency Signed-off-by: Aldo Lacuku --- charts/falco/Chart.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/charts/falco/Chart.yaml b/charts/falco/Chart.yaml index 109221ba6..6f128c77a 100644 --- a/charts/falco/Chart.yaml +++ b/charts/falco/Chart.yaml @@ -22,3 +22,7 @@ dependencies: version: "0.7.11" condition: falcosidekick.enabled repository: https://falcosecurity.github.io/charts + - name: k8s-metacollector + version: 0.1.* + repository: https://falcosecurity.github.io/charts + condition: collectors.kubernetes.enabled From f1d536e7417a55a164bd00dc43c6acdce623afc7 Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Fri, 22 Dec 2023 15:27:55 +0100 Subject: [PATCH 02/19] new(falco): integrate k8s-metacollector and k8smeta plugin The defualt mode to get kubernetes metadata is using the k8s-metacollector and the k8smeta plugin. This commit adds the required helpers and variables to enable the k8s-metacollector by default. Signed-off-by: Aldo Lacuku --- charts/falco/templates/_helpers.tpl | 52 +++++++++++++++++++ charts/falco/templates/configmap.yaml | 1 + .../falco/templates/falcoctl-configmap.yaml | 1 + charts/falco/templates/pod-template.tpl | 10 ---- charts/falco/values.yaml | 45 ++++++++-------- 5 files changed, 77 insertions(+), 32 deletions(-) diff --git a/charts/falco/templates/_helpers.tpl b/charts/falco/templates/_helpers.tpl index c64f3fe57..f47940c5d 100644 --- a/charts/falco/templates/_helpers.tpl +++ b/charts/falco/templates/_helpers.tpl @@ -318,4 +318,56 @@ be temporary and will stay here until we move this logic to the falcoctl tool. {{- if .Values.falcoctl.artifact.follow.env }} {{- include "falco.renderTemplate" ( dict "value" .Values.falcoctl.artifact.follow.env "context" $) | nindent 4 }} {{- end }} +{{- end -}} + + +{{/* + Build configuration for k8smeta plugin and update the relevant variables. + * The configuration that needs to be built up is the initconfig section: + init_config: + collectorPort: 0 + collectorHostname: "" + nodeName: "" + The falco chart exposes this configuriotino through two variable: + * collectors.kubenetetes.collectorHostname; + * collectors.kubernetes.collectorPort; + If those two variable are not set, then we take those values from the k8smetacollector subchart. + The hostname is built using the name of the service that exposes the collector endpoints and the + port is directly taken form the service's port that exposes the gRPC endpoint. + We reuse the helpers from the k8smetacollector subchart, by passing down the variables. There is a + hardcoded values that is the chart name for the k8s-metacollector chart. + + * The falcoctl configuration is updated to allow plugin artifacts to be installed. The refs in the install + section are updated by adding the reference for the k8s meta plugin that needs to be installed. + NOTE: It seems that the named templates run during the validation process. And then again during the + render fase. In our case we are setting global variable that persist during the various phases. + We need to make the helper idempotent. +*/}} +{{- define "k8smeta.configuration" -}} +{{- if and .Values.collectors.kubernetes.enabled .Values.driver.enabled -}} +{{- $hostname := "" -}} +{{- if .Values.collectors.kubernetes.collectorHostname -}} +{{- $hostname = .Values.collectors.kubernetes.collectorHostname -}} +{{- else -}} +{{- $collectorContext := (dict "Release" .Release "Values" (index .Values "k8s-metacollector") "Chart" (dict "Name" "k8s-metacollector")) -}} +{{- $hostname = printf "%s.%s.svc" (include "k8s-metacollector.fullname" $collectorContext) (include "k8s-metacollector.namespace" $collectorContext) -}} +{{- end -}} +{{- $hasConfig := false -}} +{{- range .Values.falco.plugins -}} +{{- if eq (get . "name") "k8smeta" -}} +{{ $hasConfig = true -}} +{{- end -}} +{{- end -}} +{{- if not $hasConfig -}} +{{- $listenPort := default (index .Values "k8s-metacollector" "service" "ports" "broker-grpc" "port") .Values.collectors.kubernetes.collectorPort -}} +{{- $listenPort = int $listenPort -}} +{{- $pluginConfig := dict "name" "k8smeta" "library_path" "libk8smeta.so" "init_config" (dict "collectorHostname" $hostname "collectorPort" $listenPort "nodeName" "${FALCO_K8S_NODE_NAME}") -}} +{{- $newConfig := append .Values.falco.plugins $pluginConfig -}} +{{- $_ := set .Values.falco "plugins" ($newConfig | uniq) -}} +{{- $loadedPlugins := append .Values.falco.load_plugins "k8smeta" -}} +{{- $_ = set .Values.falco "load_plugins" ($loadedPlugins | uniq) -}} +{{- end -}} +{{- $_ := set .Values.falcoctl.config.artifact.install "refs" ((append .Values.falcoctl.config.artifact.install.refs .Values.collectors.kubernetes.pluginRef) | uniq)}} +{{- $_ = set .Values.falcoctl.config.artifact "allowedTypes" ((append .Values.falcoctl.config.artifact.allowedTypes "plugin") | uniq)}} +{{- end -}} {{- end -}} \ No newline at end of file diff --git a/charts/falco/templates/configmap.yaml b/charts/falco/templates/configmap.yaml index 387dca145..f244e5435 100644 --- a/charts/falco/templates/configmap.yaml +++ b/charts/falco/templates/configmap.yaml @@ -8,4 +8,5 @@ metadata: data: falco.yaml: |- {{- include "falco.falcosidekickConfig" . }} + {{- include "k8smeta.configuration" . -}} {{- toYaml .Values.falco | nindent 4 }} diff --git a/charts/falco/templates/falcoctl-configmap.yaml b/charts/falco/templates/falcoctl-configmap.yaml index 302fa7b1a..7b769e870 100644 --- a/charts/falco/templates/falcoctl-configmap.yaml +++ b/charts/falco/templates/falcoctl-configmap.yaml @@ -8,5 +8,6 @@ metadata: {{- include "falco.labels" . | nindent 4 }} data: falcoctl.yaml: |- + {{- include "k8smeta.configuration" . -}} {{- toYaml .Values.falcoctl.config | nindent 4 }} {{- end }} diff --git a/charts/falco/templates/pod-template.tpl b/charts/falco/templates/pod-template.tpl index 2103adeeb..38b2d465f 100644 --- a/charts/falco/templates/pod-template.tpl +++ b/charts/falco/templates/pod-template.tpl @@ -80,16 +80,6 @@ spec: - --cri - /run/crio/crio.sock {{- end }} - {{- if .kubernetes.enabled }} - - -K - - {{ .kubernetes.apiAuth }} - - -k - - {{ .kubernetes.apiUrl }} - {{- if .kubernetes.enableNodeFilter }} - - --k8s-node - - "$(FALCO_K8S_NODE_NAME)" - {{- end }} - {{- end }} - -pk {{- end }} {{- end }} diff --git a/charts/falco/values.yaml b/charts/falco/values.yaml index b6467f422..2cc0a9076 100644 --- a/charts/falco/values.yaml +++ b/charts/falco/values.yaml @@ -215,7 +215,7 @@ driver: # -- The image repository to pull from. repository: falcosecurity/falco-driver-loader # -- Overrides the image tag whose default is the chart appVersion. - tag: "" + tag: "master" # -- Extra environment variables that will be pass onto Falco driver loader init container. env: [] # -- Arguments to pass to the Falco driver loader init container. @@ -262,30 +262,31 @@ collectors: # -- The path of the CRI-O socket. socket: /run/crio/crio.sock + # -- kubernetes holds the configuration for the kubernetes collector. Starting from version 0.37.0 of Falco, the legacy + # kubernetes client has been removed. A new standalone component named k8s-metacollector and a Falco plugin have been developed + # to solve the issues that were present in the old implementation. More info here: https://github.com/falcosecurity/falco/issues/2973 kubernetes: - # -- Enable Kubernetes meta data collection via a connection to the Kubernetes API server. - # When this option is disabled, Falco falls back to the container annotations to grap the meta data. + # -- enabled specifies whether the Kubernetes metadata should be collected using the k8smeta plugin and the k8s-metacollector component. + # It will deploy the k8s-metacollector external component that fetches Kubernetes metadata and pushes them to Falco instances. + # For more info see: + # https://github.com/falcosecurity/k8s-metacollector + # https://github.com/falcosecurity/charts/tree/master/charts/k8s-metacollector + # When this option is disabled, Falco falls back to the container annotations to grab the metadata. # In such a case, only the ID, name, namespace, labels of the pod will be available. enabled: true - # -- The apiAuth value is to provide the authentication method Falco should use to connect to the Kubernetes API. - # The argument's documentation from Falco is provided here for reference: - # - # | :[:], --k8s-api-cert | :[:] - # Use the provided files names to authenticate user and (optionally) verify the K8S API server identity. - # Each entry must specify full (absolute, or relative to the current directory) path to the respective file. - # Private key password is optional (needed only if key is password protected). - # CA certificate is optional. For all files, only PEM file format is supported. - # Specifying CA certificate only is obsoleted - when single entry is provided - # for this option, it will be interpreted as the name of a file containing bearer token. - # Note that the format of this command-line option prohibits use of files whose names contain - # ':' or '#' characters in the file name. - # -- Provide the authentication method Falco should use to connect to the Kubernetes API. - apiAuth: /var/run/secrets/kubernetes.io/serviceaccount/token - ## -- Provide the URL Falco should use to connect to the Kubernetes API. - apiUrl: "https://$(KUBERNETES_SERVICE_HOST)" - # -- If true, only the current node (on which Falco is running) will be considered when requesting metadata of pods - # to the API server. Disabling this option may have a performance penalty on large clusters. - enableNodeFilter: true + # --pluginRef is the OCI reference for the k8smeta plugin. It could be a full reference such as: + # "ghcr.io/falcosecurity/plugins/plugin/k8smeta:0.1.0". Or just name + tag: k8smeta:0.1.0. + pluginRef: "ghcr.io/falcosecurity/plugins/plugin/k8smeta:0.1.0" + # -- collectorHostname is the address of the k8s-metacollector. When not specified it will be set to match + # k8s-metacollector service. e.x: falco-k8smetacollecto.falco.svc. If for any reason you need to override + # it, make sure to set here the address of the k8s-metacollector. + # It is used by the k8smeta plugin to connect to the k8s-metacollector. + collectorHostname: "" + # -- collectorPort designates the port on which the k8s-metacollector gRPC service listens. If not specified + # the value of the port named `broker-grpc` in k8s-metacollector.service.ports is used. The default values is 45000. + # It is used by the k8smeta plugin to connect to the k8s-metacollector. + collectorPort: "" + ########################### # Extras and customization # From cf4096db04778de767278aa7329b47227f6e8844 Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Tue, 2 Jan 2024 11:33:13 +0100 Subject: [PATCH 03/19] update(falco): remove service account and related resources Signed-off-by: Aldo Lacuku --- charts/falco/templates/clusterrole.yaml | 43 ------------------- .../falco/templates/clusterrolebinding.yaml | 16 ------- charts/falco/templates/pod-template.tpl | 1 - charts/falco/templates/serviceaccount.yaml | 13 ------ charts/falco/values.yaml | 39 +---------------- 5 files changed, 1 insertion(+), 111 deletions(-) delete mode 100644 charts/falco/templates/clusterrole.yaml delete mode 100644 charts/falco/templates/clusterrolebinding.yaml delete mode 100644 charts/falco/templates/serviceaccount.yaml diff --git a/charts/falco/templates/clusterrole.yaml b/charts/falco/templates/clusterrole.yaml deleted file mode 100644 index 1e9e9eac3..000000000 --- a/charts/falco/templates/clusterrole.yaml +++ /dev/null @@ -1,43 +0,0 @@ -{{- if .Values.rbac.create }} -kind: ClusterRole -apiVersion: {{ include "rbac.apiVersion" . }} -metadata: - name: {{ include "falco.fullname" . }} - labels: - {{- include "falco.labels" . | nindent 4 }} -rules: - - apiGroups: - - extensions - - "" - resources: - - nodes - - namespaces - - pods - - replicationcontrollers - - replicasets - - services - - daemonsets - - deployments - - events - - configmaps - verbs: - - get - - list - - watch - - apiGroups: - - apps - resources: - - daemonsets - - deployments - - replicasets - - statefulsets - verbs: - - get - - list - - watch - - nonResourceURLs: - - /healthz - - /healthz/* - verbs: - - get -{{- end }} diff --git a/charts/falco/templates/clusterrolebinding.yaml b/charts/falco/templates/clusterrolebinding.yaml deleted file mode 100644 index 2a550634e..000000000 --- a/charts/falco/templates/clusterrolebinding.yaml +++ /dev/null @@ -1,16 +0,0 @@ -{{- if .Values.rbac.create }} -kind: ClusterRoleBinding -apiVersion: {{ include "rbac.apiVersion" . }} -metadata: - name: {{ include "falco.fullname" . }} - labels: - {{- include "falco.labels" . | nindent 4 }} -subjects: - - kind: ServiceAccount - name: {{ include "falco.serviceAccountName" . }} - namespace: {{ include "falco.namespace" . }} -roleRef: - kind: ClusterRole - name: {{ include "falco.fullname" . }} - apiGroup: rbac.authorization.k8s.io -{{- end }} diff --git a/charts/falco/templates/pod-template.tpl b/charts/falco/templates/pod-template.tpl index 38b2d465f..f493cae51 100644 --- a/charts/falco/templates/pod-template.tpl +++ b/charts/falco/templates/pod-template.tpl @@ -16,7 +16,6 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} spec: - serviceAccountName: {{ include "falco.serviceAccountName" . }} {{- with .Values.podSecurityContext }} securityContext: {{- toYaml . | nindent 4}} diff --git a/charts/falco/templates/serviceaccount.yaml b/charts/falco/templates/serviceaccount.yaml deleted file mode 100644 index 6f7e52f1c..000000000 --- a/charts/falco/templates/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "falco.serviceAccountName" . }} - namespace: {{ include "falco.namespace" . }} - labels: - {{- include "falco.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} \ No newline at end of file diff --git a/charts/falco/values.yaml b/charts/falco/values.yaml index 2cc0a9076..a4e829f03 100644 --- a/charts/falco/values.yaml +++ b/charts/falco/values.yaml @@ -23,19 +23,6 @@ fullnameOverride: "" # -- Override the deployment namespace namespaceOverride: "" -rbac: - # Create and use rbac resources when set to true. Needed to fetch k8s metadata from the api-server. - create: true - -serviceAccount: - # -- Specifies whether a service account should be created. - create: true - # -- Annotations to add to the service account. - annotations: {} - # -- The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - # -- Add additional pod annotations podAnnotations: {} @@ -215,7 +202,7 @@ driver: # -- The image repository to pull from. repository: falcosecurity/falco-driver-loader # -- Overrides the image tag whose default is the chart appVersion. - tag: "master" + tag: "" # -- Extra environment variables that will be pass onto Falco driver loader init container. env: [] # -- Arguments to pass to the Falco driver loader init container. @@ -1380,30 +1367,6 @@ falco: # Falco cloud orchestration systems integration # ################################################# - # [Stable] `metadata_download` - # - # -- When connected to an orchestrator like Kubernetes, Falco has the capability to - # collect metadata and enrich system call events with contextual data. The - # parameters mentioned here control the downloading process of this metadata. - # - # Please note that support for Mesos is deprecated, so these parameters - # currently apply only to Kubernetes. When using Falco with Kubernetes, you can - # enable this functionality by using the `-k` or `-K` command-line flag. - # - # However, it's worth mentioning that for important Kubernetes metadata fields - # such as namespace or pod name, these fields are automatically extracted from - # the container runtime, providing the necessary enrichment for common use cases - # of syscall-based threat detection. - # - # In summary, the `-k` flag is typically not required for most scenarios involving - # Kubernetes workload owner enrichment. The `-k` flag is primarily used when - # additional metadata is required beyond the standard fields, catering to more - # specific use cases, see https://falco.org/docs/reference/rules/supported-fields/#field-class-k8s. - metadata_download: - max_mb: 100 - chunk_wait_us: 1000 - watch_freq_sec: 1 - # [Stable] Guidance for Kubernetes container engine command-line args settings # # Modern cloud environments, particularly Kubernetes, heavily rely on From 55b2d60be09c901b980584969d044ede912ace1a Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Wed, 3 Jan 2024 12:32:42 +0100 Subject: [PATCH 04/19] new(falco/tests): add unit tests for k8s-metacollector integration Signed-off-by: Aldo Lacuku --- .github/workflows/test.yml | 7 +- .../unit/k8smetacollectorDependency_test.go | 517 ++++++++++++++++++ 2 files changed, 523 insertions(+), 1 deletion(-) create mode 100644 charts/falco/tests/unit/k8smetacollectorDependency_test.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ce424e8ee..485cbc5a4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,6 +14,8 @@ jobs: - name: Set up Helm uses: azure/setup-helm@5119fcb9089d432beecbf79bb2c7915207344b78 # v3.5 + with: + version: '3.10.3' - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 with: @@ -78,5 +80,8 @@ jobs: go-version: '1.21' check-latest: true - - name: k8s-metacollector unit tests + - name: K8s-metacollector unit tests run: go test ./charts/k8s-metacollector/tests/unit/... + + - name: Falco unit tests + run: go test ./charts/falco/tests/unit/... diff --git a/charts/falco/tests/unit/k8smetacollectorDependency_test.go b/charts/falco/tests/unit/k8smetacollectorDependency_test.go new file mode 100644 index 000000000..f43d59d36 --- /dev/null +++ b/charts/falco/tests/unit/k8smetacollectorDependency_test.go @@ -0,0 +1,517 @@ +package unit + +import ( + "encoding/json" + "fmt" + "path/filepath" + "regexp" + "slices" + "strings" + "testing" + + "github.com/gruntwork-io/terratest/modules/helm" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" +) + +const chartPath = "../../" + +// Using the default values we want to test that all the expected resources for the k8s-metacollector are rendered. +func TestRenderedResourcesWithDefaultValues(t *testing.T) { + t.Parallel() + + helmChartPath, err := filepath.Abs(chartPath) + require.NoError(t, err) + + releaseName := "rendered-resources" + + options := &helm.Options{} + // Template the chart using the default values.yaml file. + output, err := helm.RenderTemplateE(t, options, helmChartPath, releaseName, nil) + require.NoError(t, err) + + // Extract all rendered files from the output. + pattern := `# Source: falco/charts/k8s-metacollector/templates/([^\n]+)` + re := regexp.MustCompile(pattern) + matches := re.FindAllStringSubmatch(output, -1) + require.Len(t, matches, 0) + +} + +func TestRenderedResourcesWhenNotEnabled(t *testing.T) { + t.Parallel() + + helmChartPath, err := filepath.Abs(chartPath) + require.NoError(t, err) + + releaseName := "rendered-resources" + + // Template files that we expect to be rendered. + templateFiles := []string{ + "clusterrole.yaml", + "clusterrolebinding.yaml", + "deployment.yaml", + "service.yaml", + "serviceaccount.yaml", + } + + require.NoError(t, err) + + options := &helm.Options{SetValues: map[string]string{ + "collectors.kubernetes.enabled": "true", + }} + + // Template the chart using the default values.yaml file. + output, err := helm.RenderTemplateE(t, options, helmChartPath, releaseName, nil) + require.NoError(t, err) + + // Extract all rendered files from the output. + pattern := `# Source: falco/charts/k8s-metacollector/templates/([^\n]+)` + re := regexp.MustCompile(pattern) + matches := re.FindAllStringSubmatch(output, -1) + + var renderedTemplates []string + for _, match := range matches { + // Filter out test templates. + if !strings.Contains(match[1], "test-") { + renderedTemplates = append(renderedTemplates, match[1]) + } + } + + // Assert that the rendered resources are equal tho the expected ones. + require.Equal(t, len(renderedTemplates), len(templateFiles), "should be equal") + + for _, rendered := range renderedTemplates { + require.True(t, slices.Contains(templateFiles, rendered), "template files should contain all the rendered files") + } +} + +func TestPluginConfigurationInFalcoConfig(t *testing.T) { + t.Parallel() + + helmChartPath, err := filepath.Abs(chartPath) + require.NoError(t, err) + + releaseName := "rendered-resources" + + testCases := []struct { + name string + values map[string]string + expected func(t *testing.T, config any) + }{ + { + "defaultValues", + nil, + func(t *testing.T, config any) { + plugin := config.(map[string]interface{}) + // Get init config. + initConfig, ok := plugin["init_config"] + require.True(t, ok) + initConfigMap := initConfig.(map[string]interface{}) + // Check that the collector port is correctly set. + port := initConfigMap["collectorPort"] + require.Equal(t, float64(45000), port.(float64)) + // Check that the collector nodeName is correctly set. + nodeName := initConfigMap["nodeName"] + require.Equal(t, "${FALCO_K8S_NODE_NAME}", nodeName.(string)) + // Check that the collector hostname is correctly set. + hostName := initConfigMap["collectorHostname"] + require.Equal(t, fmt.Sprintf("%s-k8s-metacollector.default.svc", releaseName), hostName.(string)) + + // Check that the library path is set. + libPath := plugin["library_path"] + require.Equal(t, "libk8smeta.so", libPath) + }, + }, + { + "overrideK8s-metacollectorNamespace", + map[string]string{ + "k8s-metacollector.namespaceOverride": "test", + }, + func(t *testing.T, config any) { + plugin := config.(map[string]interface{}) + // Get init config. + initConfig, ok := plugin["init_config"] + require.True(t, ok) + initConfigMap := initConfig.(map[string]interface{}) + // Check that the collector port is correctly set. + port := initConfigMap["collectorPort"] + require.Equal(t, float64(45000), port.(float64)) + // Check that the collector nodeName is correctly set. + nodeName := initConfigMap["nodeName"] + require.Equal(t, "${FALCO_K8S_NODE_NAME}", nodeName.(string)) + // Check that the collector hostname is correctly set. + hostName := initConfigMap["collectorHostname"] + require.Equal(t, fmt.Sprintf("%s-k8s-metacollector.test.svc", releaseName), hostName.(string)) + + // Check that the library path is set. + libPath := plugin["library_path"] + require.Equal(t, "libk8smeta.so", libPath) + }, + }, + { + "overrideK8s-metacollectorName", + map[string]string{ + "k8s-metacollector.fullnameOverride": "collector", + }, + func(t *testing.T, config any) { + plugin := config.(map[string]interface{}) + // Get init config. + initConfig, ok := plugin["init_config"] + require.True(t, ok) + initConfigMap := initConfig.(map[string]interface{}) + // Check that the collector port is correctly set. + port := initConfigMap["collectorPort"] + require.Equal(t, float64(45000), port.(float64)) + // Check that the collector nodeName is correctly set. + nodeName := initConfigMap["nodeName"] + require.Equal(t, "${FALCO_K8S_NODE_NAME}", nodeName.(string)) + // Check that the collector hostname is correctly set. + hostName := initConfigMap["collectorHostname"] + require.Equal(t, "collector.default.svc", hostName.(string)) + + // Check that the library path is set. + libPath := plugin["library_path"] + require.Equal(t, "libk8smeta.so", libPath) + }, + }, + + { + "overrideK8s-metacollectorNamespaceAndName", + map[string]string{ + "k8s-metacollector.namespaceOverride": "test", + "k8s-metacollector.fullnameOverride": "collector", + }, + func(t *testing.T, config any) { + plugin := config.(map[string]interface{}) + // Get init config. + initConfig, ok := plugin["init_config"] + require.True(t, ok) + initConfigMap := initConfig.(map[string]interface{}) + // Check that the collector port is correctly set. + port := initConfigMap["collectorPort"] + require.Equal(t, float64(45000), port.(float64)) + // Check that the collector nodeName is correctly set. + nodeName := initConfigMap["nodeName"] + require.Equal(t, "${FALCO_K8S_NODE_NAME}", nodeName.(string)) + // Check that the collector hostname is correctly set. + hostName := initConfigMap["collectorHostname"] + require.Equal(t, "collector.test.svc", hostName.(string)) + + // Check that the library path is set. + libPath := plugin["library_path"] + require.Equal(t, "libk8smeta.so", libPath) + }, + }, + { + "set CollectorHostname", + map[string]string{ + "collectors.kubernetes.collectorHostname": "test", + }, + func(t *testing.T, config any) { + plugin := config.(map[string]interface{}) + // Get init config. + initConfig, ok := plugin["init_config"] + require.True(t, ok) + initConfigMap := initConfig.(map[string]interface{}) + // Check that the collector port is correctly set. + port := initConfigMap["collectorPort"] + require.Equal(t, float64(45000), port.(float64)) + // Check that the collector nodeName is correctly set. + nodeName := initConfigMap["nodeName"] + require.Equal(t, "${FALCO_K8S_NODE_NAME}", nodeName.(string)) + // Check that the collector hostname is correctly set. + hostName := initConfigMap["collectorHostname"] + require.Equal(t, "test", hostName.(string)) + + // Check that the library path is set. + libPath := plugin["library_path"] + require.Equal(t, "libk8smeta.so", libPath) + }, + }, + + { + "set CollectorHostname and namespace name", + map[string]string{ + "collectors.kubernetes.collectorHostname": "test-with-override", + "k8s-metacollector.namespaceOverride": "test", + "k8s-metacollector.fullnameOverride": "collector", + }, + func(t *testing.T, config any) { + plugin := config.(map[string]interface{}) + // Get init config. + initConfig, ok := plugin["init_config"] + require.True(t, ok) + initConfigMap := initConfig.(map[string]interface{}) + // Check that the collector port is correctly set. + port := initConfigMap["collectorPort"] + require.Equal(t, float64(45000), port.(float64)) + // Check that the collector nodeName is correctly set. + nodeName := initConfigMap["nodeName"] + require.Equal(t, "${FALCO_K8S_NODE_NAME}", nodeName.(string)) + // Check that the collector hostname is correctly set. + hostName := initConfigMap["collectorHostname"] + require.Equal(t, "test-with-override", hostName.(string)) + + // Check that the library path is set. + libPath := plugin["library_path"] + require.Equal(t, "libk8smeta.so", libPath) + }, + }, + + { + "set collectorPort", + map[string]string{ + "collectors.kubernetes.collectorPort": "8888", + }, + func(t *testing.T, config any) { + plugin := config.(map[string]interface{}) + // Get init config. + initConfig, ok := plugin["init_config"] + require.True(t, ok) + initConfigMap := initConfig.(map[string]interface{}) + // Check that the collector port is correctly set. + port := initConfigMap["collectorPort"] + require.Equal(t, float64(8888), port.(float64)) + // Check that the collector nodeName is correctly set. + nodeName := initConfigMap["nodeName"] + require.Equal(t, "${FALCO_K8S_NODE_NAME}", nodeName.(string)) + // Check that the collector hostname is correctly set. + hostName := initConfigMap["collectorHostname"] + require.Equal(t, fmt.Sprintf("%s-k8s-metacollector.default.svc", releaseName), hostName.(string)) + + // Check that the library path is set. + libPath := plugin["library_path"] + require.Equal(t, "libk8smeta.so", libPath) + }, + }, + { + "drive disabled", + map[string]string{ + "driver.enabled": "false", + }, + func(t *testing.T, config any) { + require.Nil(t, config) + }, + }, + } + + for _, testCase := range testCases { + testCase := testCase + + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + // Enable the collector. + if testCase.values != nil { + testCase.values["collectors.kubernetes.enabled"] = "true" + } else { + testCase.values = map[string]string{"collectors.kubernetes.enabled": "true"} + } + + options := &helm.Options{SetValues: testCase.values} + output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/configmap.yaml"}) + + var cm corev1.ConfigMap + helm.UnmarshalK8SYaml(t, output, &cm) + var config map[string]interface{} + + helm.UnmarshalK8SYaml(t, cm.Data["falco.yaml"], &config) + plugins := config["plugins"] + pluginsArray := plugins.([]interface{}) + found := false + // Find the k8smeta plugin configuration. + for _, plugin := range pluginsArray { + if name, ok := plugin.(map[string]interface{})["name"]; ok && name == "k8smeta" { + testCase.expected(t, plugin) + found = true + } + } + if found { + // Check that the plugin has been added to the ones that need to be loaded. + loadplugins := config["load_plugins"] + require.True(t, slices.Contains(loadplugins.([]interface{}), "k8smeta")) + } else { + testCase.expected(t, nil) + loadplugins := config["load_plugins"] + require.True(t, !slices.Contains(loadplugins.([]interface{}), "k8smeta")) + } + }) + } +} + +// Test that the helper does not overwrite user's configuration. +func TestPluginConfigurationUniqueEntries(t *testing.T) { + t.Parallel() + + pluginsJSON := `[ + { + "init_config": null, + "library_path": "libk8saudit.so", + "name": "k8saudit", + "open_params": "http://:9765/k8s-audit" + }, + { + "library_path": "libcloudtrail.so", + "name": "cloudtrail" + }, + { + "init_config": "", + "library_path": "libjson.so", + "name": "json" + }, + { + "init_config": { + "collectorHostname": "rendered-resources-k8s-metacollector.default.svc", + "collectorPort": 45000, + "nodeName": "${FALCO_K8S_NODE_NAME}" + }, + "library_path": "libk8smeta.so", + "name": "k8smeta" + } +]` + + loadPluginsJSON := `[ + "k8smeta", + "k8saudit" +]` + helmChartPath, err := filepath.Abs(chartPath) + require.NoError(t, err) + + releaseName := "rendered-resources" + + options := &helm.Options{SetJsonValues: map[string]string{ + "falco.plugins": pluginsJSON, + "falco.load_plugins": loadPluginsJSON, + }, SetValues: map[string]string{"collectors.kubernetes.enabled": "true"}} + output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/configmap.yaml"}) + + var cm corev1.ConfigMap + helm.UnmarshalK8SYaml(t, output, &cm) + var config map[string]interface{} + + helm.UnmarshalK8SYaml(t, cm.Data["falco.yaml"], &config) + plugins := config["plugins"] + + out, err := json.MarshalIndent(plugins, "", " ") + require.NoError(t, err) + require.Equal(t, pluginsJSON, string(out)) + pluginsArray := plugins.([]interface{}) + // Find the k8smeta plugin configuration. + numConfigK8smeta := 0 + for _, plugin := range pluginsArray { + if name, ok := plugin.(map[string]interface{})["name"]; ok && name == "k8smeta" { + numConfigK8smeta++ + } + } + + require.Equal(t, 1, numConfigK8smeta) + + // Check that the plugin has been added to the ones that need to be loaded. + loadplugins := config["load_plugins"] + require.Len(t, loadplugins.([]interface{}), 2) + require.True(t, slices.Contains(loadplugins.([]interface{}), "k8smeta")) +} + +// Test that the helper does not overwrite user's configuration. +func TestFalcoctlRefs(t *testing.T) { + t.Parallel() + + pluginsJSON := `[ + { + "init_config": null, + "library_path": "libk8saudit.so", + "name": "k8saudit", + "open_params": "http://:9765/k8s-audit" + }, + { + "library_path": "libcloudtrail.so", + "name": "cloudtrail" + }, + { + "init_config": "", + "library_path": "libjson.so", + "name": "json" + }, + { + "init_config": { + "collectorHostname": "rendered-resources-k8s-metacollector.default.svc", + "collectorPort": 45000, + "nodeName": "${FALCO_K8S_NODE_NAME}" + }, + "library_path": "libk8smeta.so", + "name": "k8smeta" + } + ]` + + testFunc := func(t *testing.T, config any) { + // Get artifact configuration map. + configMap := config.(map[string]interface{}) + artifactConfig := (configMap["artifact"]).(map[string]interface{}) + // Test allowed types. + allowedTypes := artifactConfig["allowedTypes"] + require.Len(t, allowedTypes, 2) + require.True(t, slices.Contains(allowedTypes.([]interface{}), "plugin")) + require.True(t, slices.Contains(allowedTypes.([]interface{}), "rulesfile")) + // Test plugin reference. + refs := artifactConfig["install"].(map[string]interface{})["refs"].([]interface{}) + require.Len(t, refs, 2) + require.True(t, slices.Contains(refs, "falco-rules:3")) + require.True(t, slices.Contains(refs, "ghcr.io/falcosecurity/plugins/plugin/k8smeta:0.1.0")) + } + + testCases := []struct { + name string + valuesJSON map[string]string + expected func(t *testing.T, config any) + }{ + { + "defaultValues", + nil, + testFunc, + }, + { + "setPluginConfiguration", + map[string]string{ + "falco.plugins": pluginsJSON, + }, + testFunc, + }, + { + "driver disabled", + map[string]string{ + "driver.enabled": "false", + }, + func(t *testing.T, config any) { + // Get artifact configuration map. + configMap := config.(map[string]interface{}) + artifactConfig := (configMap["artifact"]).(map[string]interface{}) + // Test plugin reference. + refs := artifactConfig["install"].(map[string]interface{})["refs"].([]interface{}) + require.True(t, !slices.Contains(refs, "ghcr.io/falcosecurity/plugins/plugin/k8smeta:0.1.0")) + }, + }, + } + + helmChartPath, err := filepath.Abs(chartPath) + require.NoError(t, err) + + releaseName := "rendered-resources" + + for _, testCase := range testCases { + testCase := testCase + + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + options := &helm.Options{SetJsonValues: testCase.valuesJSON, SetValues: map[string]string{"collectors.kubernetes.enabled": "true"}} + output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/falcoctl-configmap.yaml"}) + + var cm corev1.ConfigMap + helm.UnmarshalK8SYaml(t, output, &cm) + var config map[string]interface{} + helm.UnmarshalK8SYaml(t, cm.Data["falcoctl.yaml"], &config) + testCase.expected(t, config) + }) + } +} From 1f5ffcfe2caac748050adedf6009602a6e3c9d92 Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Tue, 9 Jan 2024 11:09:30 +0100 Subject: [PATCH 05/19] new(falco): enable falcoctl deps resolver Falco 0.37.0 will not ship with bundled plugins. Falcoctl with deps resolver enabled downloads the required plugins starting from the rulesfiles. Signed-off-by: Aldo Lacuku --- charts/falco/values-k8saudit.yaml | 10 ++++------ charts/falco/values-syscall-k8saudit.yaml | 11 ++++------- charts/falco/values.yaml | 5 +++-- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/charts/falco/values-k8saudit.yaml b/charts/falco/values-k8saudit.yaml index 2b5d1880b..e89c52517 100644 --- a/charts/falco/values-k8saudit.yaml +++ b/charts/falco/values-k8saudit.yaml @@ -18,22 +18,20 @@ controller: falcoctl: artifact: install: - # -- Enable the init container. We do not recommend installing (or following) plugins for security reasons since they are executable objects. + # -- Enable the init container. enabled: true follow: - # -- Enable the sidecar container. We do not support it yet for plugins. It is used only for rules feed such as k8saudit-rules rules. + # -- Enable the sidecar container. enabled: true config: artifact: install: - # -- Do not resolve the depenencies for artifacts. By default is true, but for our use case we disable it. - resolveDeps: false + # -- Resolve the dependencies for artifacts. + resolveDeps: true # -- List of artifacts to be installed by the falcoctl init container. - # Only rulesfiles, we do no recommend plugins for security reasonts since they are executable objects. refs: [k8saudit-rules:0.6] follow: # -- List of artifacts to be followed by the falcoctl sidecar container. - # Only rulesfiles, we do no recommend plugins for security reasonts since they are executable objects. refs: [k8saudit-rules:0.6] services: diff --git a/charts/falco/values-syscall-k8saudit.yaml b/charts/falco/values-syscall-k8saudit.yaml index 96023b0a2..33b1d45bf 100644 --- a/charts/falco/values-syscall-k8saudit.yaml +++ b/charts/falco/values-syscall-k8saudit.yaml @@ -21,23 +21,20 @@ controller: falcoctl: artifact: install: - # -- Enable the init container. We do not recommend installing plugins for security reasons since they are executable objects. - # We install only "rulesfiles". + # -- Enable the init container. enabled: true follow: - # -- Enable the sidecar container. We do not support it yet for plugins. It is used only for rules feed such as k8saudit-rules rules. + # -- Enable the sidecar container. enabled: true config: artifact: install: - # -- Do not resolve the depenencies for artifacts. By default is true, but for our use case we disable it. - resolveDeps: false + # -- Resolve the dependencies for artifacts. + resolveDeps: true # -- List of artifacts to be installed by the falcoctl init container. - # We do not recommend installing (or following) plugins for security reasons since they are executable objects. refs: [falco-rules:2, k8saudit-rules:0.6] follow: # -- List of artifacts to be followed by the falcoctl sidecar container. - # We do not recommend installing (or following) plugins for security reasons since they are executable objects. refs: [falco-rules:2, k8saudit-rules:0.6] services: diff --git a/charts/falco/values.yaml b/charts/falco/values.yaml index a4e829f03..07af3d6ee 100644 --- a/charts/falco/values.yaml +++ b/charts/falco/values.yaml @@ -394,9 +394,10 @@ falcoctl: # in the list it will refuse to downloade and install that artifact. allowedTypes: - rulesfile + - plugin install: - # -- Do not resolve the depenencies for artifacts. By default is true, but for our use case we disable it. - resolveDeps: false + # -- Resolve the dependencies for artifacts. + resolveDeps: true # -- List of artifacts to be installed by the falcoctl init container. refs: [falco-rules:2] # -- Directory where the rulesfiles are saved. The path is relative to the container, which in this case is an emptyDir From bcc958a320a63c961274b1c940855d0ca01ecfe8 Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Tue, 9 Jan 2024 14:10:29 +0100 Subject: [PATCH 06/19] update(falco/falcoctl): bump falcoctl version Signed-off-by: Aldo Lacuku --- charts/falco/values.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/falco/values.yaml b/charts/falco/values.yaml index 07af3d6ee..f4c52c32f 100644 --- a/charts/falco/values.yaml +++ b/charts/falco/values.yaml @@ -346,7 +346,7 @@ falcoctl: # -- The image repository to pull from. repository: falcosecurity/falcoctl # -- The image tag to pull. - tag: "0.6.2" + tag: "main" artifact: # -- Runs "falcoctl artifact install" command as an init container. It is used to install artfacts before # Falco starts. It provides them to Falco by using an emptyDir volume. @@ -355,7 +355,7 @@ falcoctl: # -- Extra environment variables that will be pass onto falcoctl-artifact-install init container. env: [] # -- Arguments to pass to the falcoctl-artifact-install init container. - args: ["--verbose"] + args: ["--log-format=json"] # -- Resources requests and limits for the falcoctl-artifact-install init container. resources: {} # -- Security context for the falcoctl init container. @@ -373,7 +373,7 @@ falcoctl: # -- Extra environment variables that will be pass onto falcoctl-artifact-follow sidecar container. env: [] # -- Arguments to pass to the falcoctl-artifact-follow sidecar container. - args: ["--verbose"] + args: ["--log-format=json"] # -- Resources requests and limits for the falcoctl-artifact-follow sidecar container. resources: {} # -- Security context for the falcoctl-artifact-follow sidecar container. From 80a690d6252449d1520ae4d1b45410b4bd99dc04 Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Thu, 11 Jan 2024 10:07:54 +0100 Subject: [PATCH 07/19] update(falco/driver)!: use the same names for drivers as falco Please see: https://github.com/falcosecurity/falco/pull/2413. Signed-off-by: Aldo Lacuku --- charts/falco/templates/NOTES.txt | 15 + charts/falco/templates/_helpers.tpl | 56 +++- charts/falco/templates/configmap.yaml | 1 + charts/falco/templates/pod-template.tpl | 56 ++-- charts/falco/tests/unit/consts.go | 22 ++ charts/falco/tests/unit/doc.go | 17 + charts/falco/tests/unit/driverConfig_test.go | 302 ++++++++++++++++++ charts/falco/tests/unit/driverLoader_test.go | 131 ++++++++ .../unit/k8smetacollectorDependency_test.go | 43 +-- charts/falco/values.yaml | 231 ++++---------- 10 files changed, 641 insertions(+), 233 deletions(-) create mode 100644 charts/falco/tests/unit/consts.go create mode 100644 charts/falco/tests/unit/doc.go create mode 100644 charts/falco/tests/unit/driverConfig_test.go create mode 100644 charts/falco/tests/unit/driverLoader_test.go diff --git a/charts/falco/templates/NOTES.txt b/charts/falco/templates/NOTES.txt index 94bf74c6e..cad1dc3d7 100644 --- a/charts/falco/templates/NOTES.txt +++ b/charts/falco/templates/NOTES.txt @@ -22,8 +22,23 @@ You can easily forward Falco events to Slack, Kafka, AWS Lambda and more with fa Full list of outputs: https://github.com/falcosecurity/charts/tree/master/falcosidekick. You can enable its deployment with `--set falcosidekick.enabled=true` or in your values.yaml. See: https://github.com/falcosecurity/charts/blob/master/falcosidekick/values.yaml for configuration values. + {{- end}} + +{{- if (has .Values.driver.kind (list "module" "modern-bpf")) -}} +{{- println }} +WARNING(drivers): +{{- printf "\nThe driver kind: \"%s\" is an alias and might be removed in the future.\n" .Values.driver.kind -}} +{{- $driver := "" -}} +{{- if eq .Values.driver.kind "module" -}} +{{- $driver = "kmod" -}} +{{- else if eq .Values.driver.kind "modern-bpf" -}} +{{- $driver = "modern_ebpf" -}} +{{- end -}} +{{- printf "Please use \"%s\" instead." $driver}} +{{- end -}} + {{- if and (not (empty .Values.falco.load_plugins)) (or .Values.falcoctl.artifact.follow.enabled .Values.falcoctl.artifact.install.enabled) }} WARNING: diff --git a/charts/falco/templates/_helpers.tpl b/charts/falco/templates/_helpers.tpl index f47940c5d..b24075db5 100644 --- a/charts/falco/templates/_helpers.tpl +++ b/charts/falco/templates/_helpers.tpl @@ -185,7 +185,7 @@ we just disable the sycall source. */}} {{- define "falco.configSyscallSource" -}} {{- $userspaceDisabled := true -}} -{{- $gvisorDisabled := (not .Values.gvisor.enabled) -}} +{{- $gvisorDisabled := (ne .Values.driver.kind "gvisor") -}} {{- $driverDisabled := (not .Values.driver.enabled) -}} {{- if or (has "-u" .Values.extra.args) (has "--userspace" .Values.extra.args) -}} {{- $userspaceDisabled = false -}} @@ -214,8 +214,8 @@ be temporary and will stay here until we move this logic to the falcoctl tool. set -o nounset set -o pipefail - root={{ .Values.gvisor.runsc.root }} - config={{ .Values.gvisor.runsc.config }} + root={{ .Values.driver.gvisor.runsc.root }} + config={{ .Values.driver.gvisor.runsc.config }} echo "* Configuring Falco+gVisor integration...". # Check if gVisor is configured on the node. @@ -240,12 +240,12 @@ be temporary and will stay here until we move this logic to the falcoctl tool. echo "* Falco+gVisor correctly configured." exit 0 volumeMounts: - - mountPath: /host{{ .Values.gvisor.runsc.path }} + - mountPath: /host{{ .Values.driver.gvisor.runsc.path }} name: runsc-path readOnly: true - - mountPath: /host{{ .Values.gvisor.runsc.root }} + - mountPath: /host{{ .Values.driver.gvisor.runsc.root }} name: runsc-root - - mountPath: /host{{ .Values.gvisor.runsc.config }} + - mountPath: /host{{ .Values.driver.gvisor.runsc.config }} name: runsc-config - mountPath: /gvisor-config name: falco-gvisor-config @@ -370,4 +370,48 @@ be temporary and will stay here until we move this logic to the falcoctl tool. {{- $_ := set .Values.falcoctl.config.artifact.install "refs" ((append .Values.falcoctl.config.artifact.install.refs .Values.collectors.kubernetes.pluginRef) | uniq)}} {{- $_ = set .Values.falcoctl.config.artifact "allowedTypes" ((append .Values.falcoctl.config.artifact.allowedTypes "plugin") | uniq)}} {{- end -}} +{{- end -}} + +{{/* +Based on the user input it populates the driver configuration in the falco config map. +*/}} +{{- define "falco.engineConfiguration" -}} +{{- if .Values.driver.enabled -}} +{{- $supportedDrivers := list "kmod" "ebpf" "modern_ebpf" "gvisor" -}} +{{- $aliasDrivers := list "module" "modern-bpf" -}} +{{- if and (not (has .Values.driver.kind $supportedDrivers)) (not (has .Values.driver.kind $aliasDrivers)) -}} +{{- fail (printf "unsupported driver kind: \"%s\". Supported drivers %s, alias %s" .Values.driver.kind $supportedDrivers $aliasDrivers) -}} +{{- end -}} +{{- if or (eq .Values.driver.kind "kmod") (eq .Values.driver.kind "module") -}} +{{- $kmodConfig := dict "kind" "kmod" "kmod" (dict "buf_size_preset" .Values.driver.kmod.bufSizePreset "drop_failed_exit" .Values.driver.kmod.dropFailedExit) -}} +{{- $_ := set .Values.falco "engine" $kmodConfig -}} +{{- else if eq .Values.driver.kind "ebpf" -}} +{{- $ebpfConfig := dict "kind" "ebpf" "ebpf" (dict "buf_size_preset" .Values.driver.ebpf.bufSizePreset "drop_failed_exit" .Values.driver.ebpf.dropFailedExit "probe" .Values.driver.ebpf.path) -}} +{{- $_ := set .Values.falco "engine" $ebpfConfig -}} +{{- else if or (eq .Values.driver.kind "modern_ebpf") (eq .Values.driver.kind "modern-bpf") -}} +{{- $ebpfConfig := dict "kind" "modern_ebpf" "modern_ebpf" (dict "buf_size_preset" .Values.driver.modernEbpf.bufSizePreset "drop_failed_exit" .Values.driver.modernEbpf.dropFailedExit "cpus_for_each_buffer" .Values.driver.modernEbpf.cpusForEachBuffer) -}} +{{- $_ := set .Values.falco "engine" $ebpfConfig -}} +{{- else if eq .Values.driver.kind "gvisor" -}} +{{- $root := printf "/host%s/k8s.io" .Values.driver.gvisor.runsc.root -}} +{{- $gvisorConfig := dict "kind" "gvisor" "gvisor" (dict "config" "/gvisor-config/pod-init.json" "root" $root) -}} +{{- $_ := set .Values.falco "engine" $gvisorConfig -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +It returns "true" if the driver loader has to be enabled, otherwise false. +*/}} +{{- define "driverLoader.enabled" -}} +{{- if or + (eq .Values.driver.kind "modern_ebpf") + (eq .Values.driver.kind "modern-bpf") + (eq .Values.driver.kind "gvisor") + (not .Values.driver.enabled) + (not .Values.driver.loader.enabled) +-}} +false +{{- else -}} +true +{{- end -}} {{- end -}} \ No newline at end of file diff --git a/charts/falco/templates/configmap.yaml b/charts/falco/templates/configmap.yaml index f244e5435..118c7f86b 100644 --- a/charts/falco/templates/configmap.yaml +++ b/charts/falco/templates/configmap.yaml @@ -9,4 +9,5 @@ data: falco.yaml: |- {{- include "falco.falcosidekickConfig" . }} {{- include "k8smeta.configuration" . -}} + {{- include "falco.engineConfiguration" . -}} {{- toYaml .Values.falco | nindent 4 }} diff --git a/charts/falco/templates/pod-template.tpl b/charts/falco/templates/pod-template.tpl index f493cae51..97e2dd8c3 100644 --- a/charts/falco/templates/pod-template.tpl +++ b/charts/falco/templates/pod-template.tpl @@ -45,7 +45,7 @@ spec: imagePullSecrets: {{- toYaml . | nindent 4 }} {{- end }} - {{- if .Values.gvisor.enabled }} + {{- if eq .Values.driver.kind "gvisor" }} hostNetwork: true hostPID: true {{- end }} @@ -59,15 +59,6 @@ spec: {{- include "falco.securityContext" . | nindent 8 }} args: - /usr/bin/falco - {{- if and .Values.driver.enabled (eq .Values.driver.kind "modern-bpf") }} - - --modern-bpf - {{- end }} - {{- if .Values.gvisor.enabled }} - - --gvisor-config - - /gvisor-config/pod-init.json - - --gvisor-root - - /host{{ .Values.gvisor.runsc.root }}/k8s.io - {{- end }} {{- include "falco.configSyscallSource" . | indent 8 }} {{- with .Values.collectors }} {{- if .enabled }} @@ -90,10 +81,6 @@ spec: valueFrom: fieldRef: fieldPath: spec.nodeName - {{- if and .Values.driver.enabled (eq .Values.driver.kind "ebpf") }} - - name: FALCO_BPF_PROBE - value: {{ .Values.driver.ebpf.path }} - {{- end }} {{- if .Values.extra.env }} {{- include "falco.renderTemplate" ( dict "value" .Values.extra.env "context" $) | nindent 8 }} {{- end }} @@ -151,7 +138,7 @@ spec: name: etc-fs readOnly: true {{- end }} - {{- if and .Values.driver.enabled (eq .Values.driver.kind "module") }} + {{- if and .Values.driver.enabled (eq .Values.driver.kind "kmod") }} - mountPath: /host/dev name: dev-fs readOnly: true @@ -199,13 +186,13 @@ spec: {{- with .Values.mounts.volumeMounts }} {{- toYaml . | nindent 8 }} {{- end }} - {{- if .Values.gvisor.enabled }} + {{- if eq .Values.driver.kind "gvisor" }} - mountPath: /usr/local/bin/runsc name: runsc-path readOnly: true - - mountPath: /host{{ .Values.gvisor.runsc.root }} + - mountPath: /host{{ .Values.driver.gvisor.runsc.root }} name: runsc-root - - mountPath: /host{{ .Values.gvisor.runsc.config }} + - mountPath: /host{{ .Values.driver.gvisor.runsc.config }} name: runsc-config - mountPath: /gvisor-config name: falco-gvisor-config @@ -217,14 +204,12 @@ spec: {{- with .Values.extra.initContainers }} {{- toYaml . | nindent 4 }} {{- end }} - {{- if and .Values.gvisor.enabled }} + {{- if eq .Values.driver.kind "gvisor" }} {{- include "falco.gvisor.initContainer" . | nindent 4 }} {{- end }} - {{- if and .Values.driver.enabled (ne .Values.driver.kind "modern-bpf") }} - {{- if.Values.driver.loader.enabled }} + {{- if eq (include "driverLoader.enabled" .) "true" }} {{- include "falco.driverLoader.initContainer" . | nindent 4 }} {{- end }} - {{- end }} {{- if .Values.falcoctl.artifact.install.enabled }} {{- include "falcoctl.initContainer" . | nindent 4 }} {{- end }} @@ -251,7 +236,7 @@ spec: hostPath: path: /etc {{- end }} - {{- if and .Values.driver.enabled (eq .Values.driver.kind "module") }} + {{- if and .Values.driver.enabled (eq .Values.driver.kind "kmod") }} - name: dev-fs hostPath: path: /dev @@ -288,17 +273,17 @@ spec: hostPath: path: /proc {{- end }} - {{- if .Values.gvisor.enabled }} + {{- if eq .Values.driver.kind "gvisor" }} - name: runsc-path hostPath: - path: {{ .Values.gvisor.runsc.path }}/runsc + path: {{ .Values.driver.gvisor.runsc.path }}/runsc type: File - name: runsc-root hostPath: - path: {{ .Values.gvisor.runsc.root }} + path: {{ .Values.driver.gvisor.runsc.root }} - name: runsc-config hostPath: - path: {{ .Values.gvisor.runsc.config }} + path: {{ .Values.driver.gvisor.runsc.config }} type: File - name: falco-gvisor-config emptyDir: {} @@ -348,10 +333,13 @@ spec: - name: {{ .Chart.Name }}-driver-loader image: {{ include "falco.driverLoader.image" . }} imagePullPolicy: {{ .Values.driver.loader.initContainer.image.pullPolicy }} - {{- with .Values.driver.loader.initContainer.args }} args: + {{- with .Values.driver.loader.initContainer.args }} {{- toYaml . | nindent 4 }} {{- end }} + {{- if eq .Values.driver.kind "ebpf" }} + - ebpf + {{- end }} {{- with .Values.driver.loader.initContainer.resources }} resources: {{- toYaml . | nindent 4 }} @@ -359,7 +347,7 @@ spec: securityContext: {{- if .Values.driver.loader.initContainer.securityContext }} {{- toYaml .Values.driver.loader.initContainer.securityContext | nindent 4 }} - {{- else if eq .Values.driver.kind "module" }} + {{- else if eq .Values.driver.kind "kmod" }} privileged: true {{- end }} volumeMounts: @@ -380,10 +368,6 @@ spec: name: etc-fs readOnly: true env: - {{- if eq .Values.driver.kind "ebpf" }} - - name: FALCO_BPF_PROBE - value: {{ .Values.driver.ebpf.path }} - {{- end }} {{- if .Values.driver.loader.initContainer.env }} {{- include "falco.renderTemplate" ( dict "value" .Values.driver.loader.initContainer.env "context" $) | nindent 4 }} {{- end }} @@ -392,7 +376,7 @@ spec: {{- define "falco.securityContext" -}} {{- $securityContext := dict -}} {{- if .Values.driver.enabled -}} - {{- if eq .Values.driver.kind "module" -}} + {{- if eq .Values.driver.kind "kmod" -}} {{- $securityContext := set $securityContext "privileged" true -}} {{- end -}} {{- if eq .Values.driver.kind "ebpf" -}} @@ -402,8 +386,8 @@ spec: {{- $securityContext := set $securityContext "privileged" true -}} {{- end -}} {{- end -}} - {{- if eq .Values.driver.kind "modern-bpf" -}} - {{- if .Values.driver.modern_bpf.leastPrivileged -}} + {{- if eq .Values.driver.kind "modern_ebpf" -}} + {{- if .Values.driver.modernEbpf.leastPrivileged -}} {{- $securityContext := set $securityContext "capabilities" (dict "add" (list "BPF" "SYS_RESOURCE" "PERFMON" "SYS_PTRACE")) -}} {{- else -}} {{- $securityContext := set $securityContext "privileged" true -}} diff --git a/charts/falco/tests/unit/consts.go b/charts/falco/tests/unit/consts.go new file mode 100644 index 000000000..54c4db5d5 --- /dev/null +++ b/charts/falco/tests/unit/consts.go @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package unit + +const ( + releaseName = "rendered-resources" + patternK8sMetacollectorFiles = `# Source: falco/charts/k8s-metacollector/templates/([^\n]+)` + k8sMetaPluginName = "k8smeta" +) diff --git a/charts/falco/tests/unit/doc.go b/charts/falco/tests/unit/doc.go new file mode 100644 index 000000000..244855831 --- /dev/null +++ b/charts/falco/tests/unit/doc.go @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package unit contains the unit tests for the Falco chart. +package unit diff --git a/charts/falco/tests/unit/driverConfig_test.go b/charts/falco/tests/unit/driverConfig_test.go new file mode 100644 index 000000000..91edf9e53 --- /dev/null +++ b/charts/falco/tests/unit/driverConfig_test.go @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package unit + +import ( + "fmt" + "path/filepath" + "strings" + "testing" + + "github.com/gruntwork-io/terratest/modules/helm" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" +) + +func TestDriverConfigInFalcoConfig(t *testing.T) { + t.Parallel() + + helmChartPath, err := filepath.Abs(chartPath) + require.NoError(t, err) + + testCases := []struct { + name string + values map[string]string + expected func(t *testing.T, config any) + }{ + { + "defaultValues", + nil, + func(t *testing.T, config any) { + require.Len(t, config, 2, "should have only two items") + kind, bufSizePreset, dropFailedExit, err := getKmodConfig(config) + require.NoError(t, err) + require.Equal(t, "kmod", kind) + require.Equal(t, float64(4), bufSizePreset) + require.False(t, dropFailedExit) + }, + }, + { + "kind=kmod", + map[string]string{ + "driver.kind": "kmod", + }, + func(t *testing.T, config any) { + require.Len(t, config, 2, "should have only two items") + kind, bufSizePreset, dropFailedExit, err := getKmodConfig(config) + require.NoError(t, err) + require.Equal(t, "kmod", kind) + require.Equal(t, float64(4), bufSizePreset) + require.False(t, dropFailedExit) + }, + }, + { + "kind=module(alias)", + map[string]string{ + "driver.kind": "module", + }, + func(t *testing.T, config any) { + require.Len(t, config, 2, "should have only two items") + kind, bufSizePreset, dropFailedExit, err := getKmodConfig(config) + require.NoError(t, err) + require.Equal(t, "kmod", kind) + require.Equal(t, float64(4), bufSizePreset) + require.False(t, dropFailedExit) + }, + }, + { + "kmod=onfig", + map[string]string{ + "driver.kmod.bufSizePreset": "6", + "driver.kmod.dropFailedExit": "true", + }, + func(t *testing.T, config any) { + require.Len(t, config, 2, "should have only two items") + kind, bufSizePreset, dropFailedExit, err := getKmodConfig(config) + require.NoError(t, err) + require.Equal(t, "kmod", kind) + require.Equal(t, float64(6), bufSizePreset) + require.True(t, dropFailedExit) + }, + }, + { + "kind=ebpf", + map[string]string{ + "driver.kind": "ebpf", + "driver.ebpf.bufSizePreset": "6", + "driver.ebpf.dropFailedExit": "true", + "driver.ebpf.path": "testing/Path/ebpf", + }, + func(t *testing.T, config any) { + require.Len(t, config, 2, "should have only two items") + kind, path, bufSizePreset, dropFailedExit, err := getEbpfConfig(config) + require.NoError(t, err) + require.Equal(t, "ebpf", kind) + require.Equal(t, "testing/Path/ebpf", path) + require.Equal(t, float64(6), bufSizePreset) + require.True(t, dropFailedExit) + }, + }, + { + "ebpf=config", + map[string]string{ + "driver.kind": "ebpf", + }, + func(t *testing.T, config any) { + require.Len(t, config, 2, "should have only two items") + kind, path, bufSizePreset, dropFailedExit, err := getEbpfConfig(config) + require.NoError(t, err) + require.Equal(t, "ebpf", kind) + require.Equal(t, "${HOME}/.falco/falco-bpf.o", path) + require.Equal(t, float64(4), bufSizePreset) + require.False(t, dropFailedExit) + }, + }, + { + "kind=modern_ebpf", + map[string]string{ + "driver.kind": "modern_ebpf", + }, + func(t *testing.T, config any) { + require.Len(t, config, 2, "should have only two items") + kind, bufSizePreset, cpusForEachBuffer, dropFailedExit, err := getModernEbpfConfig(config) + require.NoError(t, err) + require.Equal(t, "modern_ebpf", kind) + require.Equal(t, float64(4), bufSizePreset) + require.Equal(t, float64(2), cpusForEachBuffer) + require.False(t, dropFailedExit) + }, + }, + { + "kind=modern-bpf(alias)", + map[string]string{ + "driver.kind": "modern-bpf", + }, + func(t *testing.T, config any) { + require.Len(t, config, 2, "should have only two items") + kind, bufSizePreset, cpusForEachBuffer, dropFailedExit, err := getModernEbpfConfig(config) + require.NoError(t, err) + require.Equal(t, "modern_ebpf", kind) + require.Equal(t, float64(4), bufSizePreset) + require.Equal(t, float64(2), cpusForEachBuffer) + require.False(t, dropFailedExit) + }, + }, + { + "modernEbpf=config", + map[string]string{ + "driver.kind": "modern-bpf", + "driver.modernEbpf.bufSizePreset": "6", + "driver.modernEbpf.dropFailedExit": "true", + "driver.modernEbpf.cpusForEachBuffer": "8", + }, + func(t *testing.T, config any) { + require.Len(t, config, 2, "should have only two items") + kind, bufSizePreset, cpusForEachBuffer, dropFailedExit, err := getModernEbpfConfig(config) + require.NoError(t, err) + require.Equal(t, "modern_ebpf", kind) + require.Equal(t, float64(6), bufSizePreset) + require.Equal(t, float64(8), cpusForEachBuffer) + require.True(t, dropFailedExit) + }, + }, + { + "kind=gvisor", + map[string]string{ + "driver.kind": "gvisor", + }, + func(t *testing.T, config any) { + require.Len(t, config, 2, "should have only two items") + kind, config, root, err := getGvisorConfig(config) + require.NoError(t, err) + require.Equal(t, "gvisor", kind) + require.Equal(t, "/gvisor-config/pod-init.json", config) + require.Equal(t, "/host/run/containerd/runsc/k8s.io", root) + }, + }, + { + "gvisor=config", + map[string]string{ + "driver.kind": "gvisor", + "driver.gvisor.runsc.root": "/my/root/test", + }, + func(t *testing.T, config any) { + require.Len(t, config, 2, "should have only two items") + kind, config, root, err := getGvisorConfig(config) + require.NoError(t, err) + require.Equal(t, "gvisor", kind) + require.Equal(t, "/gvisor-config/pod-init.json", config) + require.Equal(t, "/host/my/root/test/k8s.io", root) + }, + }, + } + + for _, testCase := range testCases { + testCase := testCase + + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + options := &helm.Options{SetValues: testCase.values} + output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/configmap.yaml"}) + + var cm corev1.ConfigMap + helm.UnmarshalK8SYaml(t, output, &cm) + var config map[string]interface{} + + helm.UnmarshalK8SYaml(t, cm.Data["falco.yaml"], &config) + engine := config["engine"] + testCase.expected(t, engine) + }) + } +} + +func TestDriverConfigWithUnsupportedDriver(t *testing.T) { + t.Parallel() + + helmChartPath, err := filepath.Abs(chartPath) + require.NoError(t, err) + + values := map[string]string{ + "driver.kind": "notExisting", + } + options := &helm.Options{SetValues: values} + _, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/configmap.yaml"}) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "unsupported driver kind: \"notExisting\". Supported drivers [kmod ebpf modern_ebpf gvisor], alias [module modern-bpf]")) +} + +func getKmodConfig(config interface{}) (kind string, bufSizePreset float64, dropFailedExit bool, err error) { + configMap, ok := config.(map[string]interface{}) + if !ok { + err = fmt.Errorf("can't assert type of config") + return + } + + kind = configMap["kind"].(string) + kmod := configMap["kmod"].(map[string]interface{}) + bufSizePreset = kmod["buf_size_preset"].(float64) + dropFailedExit = kmod["drop_failed_exit"].(bool) + + return +} + +func getEbpfConfig(config interface{}) (kind, path string, bufSizePreset float64, dropFailedExit bool, err error) { + configMap, ok := config.(map[string]interface{}) + if !ok { + err = fmt.Errorf("can't assert type of config") + return + } + + kind = configMap["kind"].(string) + ebpf := configMap["ebpf"].(map[string]interface{}) + bufSizePreset = ebpf["buf_size_preset"].(float64) + dropFailedExit = ebpf["drop_failed_exit"].(bool) + path = ebpf["probe"].(string) + + return +} + +func getModernEbpfConfig(config interface{}) (kind string, bufSizePreset, cpusForEachBuffer float64, dropFailedExit bool, err error) { + configMap, ok := config.(map[string]interface{}) + if !ok { + err = fmt.Errorf("can't assert type of config") + return + } + + kind = configMap["kind"].(string) + modernEbpf := configMap["modern_ebpf"].(map[string]interface{}) + bufSizePreset = modernEbpf["buf_size_preset"].(float64) + dropFailedExit = modernEbpf["drop_failed_exit"].(bool) + cpusForEachBuffer = modernEbpf["cpus_for_each_buffer"].(float64) + + return +} + +func getGvisorConfig(cfg interface{}) (kind, config, root string, err error) { + configMap, ok := cfg.(map[string]interface{}) + if !ok { + err = fmt.Errorf("can't assert type of config") + return + } + + kind = configMap["kind"].(string) + gvisor := configMap["gvisor"].(map[string]interface{}) + config = gvisor["config"].(string) + root = gvisor["root"].(string) + + return +} diff --git a/charts/falco/tests/unit/driverLoader_test.go b/charts/falco/tests/unit/driverLoader_test.go new file mode 100644 index 000000000..ee7df6ee3 --- /dev/null +++ b/charts/falco/tests/unit/driverLoader_test.go @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package unit + +import ( + "path/filepath" + "testing" + + "github.com/gruntwork-io/terratest/modules/helm" + "github.com/stretchr/testify/require" + appsv1 "k8s.io/api/apps/v1" +) + +// TestDriverLoaderEnabled tests the helper that enables the driver loader based on the configuration. +func TestDriverLoaderEnabled(t *testing.T) { + t.Parallel() + + helmChartPath, err := filepath.Abs(chartPath) + require.NoError(t, err) + + testCases := []struct { + name string + values map[string]string + expected bool + }{ + { + "defaultValues", + nil, + true, + }, + { + "driver.kind=modern-bpf", + map[string]string{ + "driver.kind": "modern-bpf", + }, + false, + }, + { + "driver.kind=modern_ebpf", + map[string]string{ + "driver.kind": "modern_ebpf", + }, + false, + }, + { + "driver.kind=gvisor", + map[string]string{ + "driver.kind": "gvisor", + }, + false, + }, + { + "driver.disabled", + map[string]string{ + "driver.enabled": "false", + }, + false, + }, + { + "driver.loader.disabled", + map[string]string{ + "driver.loader.enabled": "false", + }, + false, + }, + { + "driver.kind=kmod", + map[string]string{ + "driver.kind": "kmod", + }, + true, + }, + { + "driver.kind=module", + map[string]string{ + "driver.kind": "module", + }, + true, + }, + { + "driver.kind=ebpf", + map[string]string{ + "driver.kind": "ebpf", + }, + true, + }, + { + "driver.kind=kmod&driver.loader.disabled", + map[string]string{ + "driver.kind": "kmod", + "driver.loader.enabled": "false", + }, + false, + }, + } + + for _, testCase := range testCases { + testCase := testCase + + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + options := &helm.Options{SetValues: testCase.values} + output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/daemonset.yaml"}) + + var ds appsv1.DaemonSet + helm.UnmarshalK8SYaml(t, output, &ds) + found := false + for i := range ds.Spec.Template.Spec.InitContainers { + if ds.Spec.Template.Spec.InitContainers[i].Name == "falco-driver-loader" { + found = true + } + } + + require.Equal(t, testCase.expected, found) + }) + } +} diff --git a/charts/falco/tests/unit/k8smetacollectorDependency_test.go b/charts/falco/tests/unit/k8smetacollectorDependency_test.go index f43d59d36..6e886a054 100644 --- a/charts/falco/tests/unit/k8smetacollectorDependency_test.go +++ b/charts/falco/tests/unit/k8smetacollectorDependency_test.go @@ -1,3 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package unit import ( @@ -5,13 +20,13 @@ import ( "fmt" "path/filepath" "regexp" - "slices" "strings" "testing" "github.com/gruntwork-io/terratest/modules/helm" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" + "slices" ) const chartPath = "../../" @@ -23,16 +38,13 @@ func TestRenderedResourcesWithDefaultValues(t *testing.T) { helmChartPath, err := filepath.Abs(chartPath) require.NoError(t, err) - releaseName := "rendered-resources" - options := &helm.Options{} // Template the chart using the default values.yaml file. output, err := helm.RenderTemplateE(t, options, helmChartPath, releaseName, nil) require.NoError(t, err) // Extract all rendered files from the output. - pattern := `# Source: falco/charts/k8s-metacollector/templates/([^\n]+)` - re := regexp.MustCompile(pattern) + re := regexp.MustCompile(patternK8sMetacollectorFiles) matches := re.FindAllStringSubmatch(output, -1) require.Len(t, matches, 0) @@ -44,8 +56,6 @@ func TestRenderedResourcesWhenNotEnabled(t *testing.T) { helmChartPath, err := filepath.Abs(chartPath) require.NoError(t, err) - releaseName := "rendered-resources" - // Template files that we expect to be rendered. templateFiles := []string{ "clusterrole.yaml", @@ -66,8 +76,7 @@ func TestRenderedResourcesWhenNotEnabled(t *testing.T) { require.NoError(t, err) // Extract all rendered files from the output. - pattern := `# Source: falco/charts/k8s-metacollector/templates/([^\n]+)` - re := regexp.MustCompile(pattern) + re := regexp.MustCompile(patternK8sMetacollectorFiles) matches := re.FindAllStringSubmatch(output, -1) var renderedTemplates []string @@ -92,8 +101,6 @@ func TestPluginConfigurationInFalcoConfig(t *testing.T) { helmChartPath, err := filepath.Abs(chartPath) require.NoError(t, err) - releaseName := "rendered-resources" - testCases := []struct { name string values map[string]string @@ -322,7 +329,7 @@ func TestPluginConfigurationInFalcoConfig(t *testing.T) { found := false // Find the k8smeta plugin configuration. for _, plugin := range pluginsArray { - if name, ok := plugin.(map[string]interface{})["name"]; ok && name == "k8smeta" { + if name, ok := plugin.(map[string]interface{})["name"]; ok && name == k8sMetaPluginName { testCase.expected(t, plugin) found = true } @@ -330,11 +337,11 @@ func TestPluginConfigurationInFalcoConfig(t *testing.T) { if found { // Check that the plugin has been added to the ones that need to be loaded. loadplugins := config["load_plugins"] - require.True(t, slices.Contains(loadplugins.([]interface{}), "k8smeta")) + require.True(t, slices.Contains(loadplugins.([]interface{}), k8sMetaPluginName)) } else { testCase.expected(t, nil) loadplugins := config["load_plugins"] - require.True(t, !slices.Contains(loadplugins.([]interface{}), "k8smeta")) + require.True(t, !slices.Contains(loadplugins.([]interface{}), k8sMetaPluginName)) } }) } @@ -378,8 +385,6 @@ func TestPluginConfigurationUniqueEntries(t *testing.T) { helmChartPath, err := filepath.Abs(chartPath) require.NoError(t, err) - releaseName := "rendered-resources" - options := &helm.Options{SetJsonValues: map[string]string{ "falco.plugins": pluginsJSON, "falco.load_plugins": loadPluginsJSON, @@ -400,7 +405,7 @@ func TestPluginConfigurationUniqueEntries(t *testing.T) { // Find the k8smeta plugin configuration. numConfigK8smeta := 0 for _, plugin := range pluginsArray { - if name, ok := plugin.(map[string]interface{})["name"]; ok && name == "k8smeta" { + if name, ok := plugin.(map[string]interface{})["name"]; ok && name == k8sMetaPluginName { numConfigK8smeta++ } } @@ -410,7 +415,7 @@ func TestPluginConfigurationUniqueEntries(t *testing.T) { // Check that the plugin has been added to the ones that need to be loaded. loadplugins := config["load_plugins"] require.Len(t, loadplugins.([]interface{}), 2) - require.True(t, slices.Contains(loadplugins.([]interface{}), "k8smeta")) + require.True(t, slices.Contains(loadplugins.([]interface{}), k8sMetaPluginName)) } // Test that the helper does not overwrite user's configuration. @@ -496,8 +501,6 @@ func TestFalcoctlRefs(t *testing.T) { helmChartPath, err := filepath.Abs(chartPath) require.NoError(t, err) - releaseName := "rendered-resources" - for _, testCase := range testCases { testCase := testCase diff --git a/charts/falco/values.yaml b/charts/falco/values.yaml index f4c52c32f..b628a3f53 100644 --- a/charts/falco/values.yaml +++ b/charts/falco/values.yaml @@ -165,13 +165,20 @@ driver: # -- Set it to false if you want to deploy Falco without the drivers. # Always set it to false when using Falco with plugins. enabled: true - # -- Tell Falco which driver to use. Available options: module (kernel driver), ebpf (eBPF probe), modern-bpf (modern eBPF probe). - kind: module + # -- kind tells Falco which driver to use. Available options: kmod (kernel driver), ebpf (eBPF probe), modern_ebpf (modern eBPF probe). + kind: kmod + # -- kmod holds the configuration for the kernel module. + kmod: + # -- bufSizePreset determines the size of the shared space between Falco and its drivers. + # This shared space serves as a temporary storage for syscall events. + bufSizePreset: 4 + # -- dropFailedExit if set true drops failed system call exit events before pushing them to userspace. + dropFailedExit: false # -- Configuration section for ebpf driver. ebpf: - # -- Path where the eBPF probe is located. It comes handy when the probe have been installed in the nodes using tools other than the init + # -- path where the eBPF probe is located. It comes handy when the probe have been installed in the nodes using tools other than the init # container deployed with the chart. - path: + path: "${HOME}/.falco/falco-bpf.o" # -- Needed to enable eBPF JIT at runtime for performance reasons. # Can be skipped if eBPF JIT is enabled from outside the container hostNetwork: false @@ -182,13 +189,37 @@ driver: # Usually 'kernel.perf_event_paranoid>2' means that you cannot use 'CAP_PERFMON' and you should fallback to 'CAP_SYS_ADMIN', but the behavior changes across different distros. # Read more on that here: https://falco.org/docs/event-sources/kernel/#least-privileged-mode-1 leastPrivileged: false - # -- Configuration section for modern bpf driver. - modern_bpf: + # -- bufSizePreset determines the size of the shared space between Falco and its drivers. + # This shared space serves as a temporary storage for syscall events. + bufSizePreset: 4 + # -- dropFailedExit if set true drops failed system call exit events before pushing them to userspace. + dropFailedExit: false + modernEbpf: # -- Constrain Falco with capabilities instead of running a privileged container. # Ensure the modern bpf driver is enabled (i.e., setting the `driver.kind` option to `modern-bpf`). # Capabilities used: {CAP_SYS_RESOURCE, CAP_BPF, CAP_PERFMON, CAP_SYS_PTRACE}. # Read more on that here: https://falco.org/docs/event-sources/kernel/#least-privileged-mode-2 leastPrivileged: false + # -- bufSizePreset determines the size of the shared space between Falco and its drivers. + # This shared space serves as a temporary storage for syscall events. + bufSizePreset: 4 + # -- dropFailedExit if set true drops failed system call exit events before pushing them to userspace. + dropFailedExit: false + # -- cpusForEachBuffer is the index that controls how many CPUs to assign to a single syscall buffer. + cpusForEachBuffer: 2 + + # -- Gvisor configuration. Based on your system you need to set the appropriate values. + # Please, remember to add pod tolerations and affinities in order to schedule the Falco pods in the gVisor enabled nodes. + gvisor: + # -- Runsc container runtime configuration. Falco needs to interact with it in order to intercept the activity of the sandboxed pods. + runsc: + # -- Absolute path of the `runsc` binary in the k8s nodes. + path: /home/containerd/usr/local/sbin + # -- Absolute path of the root directory of the `runsc` container runtime. It is of vital importance for Falco since `runsc` stores there the information of the workloads handled by it; + root: /run/containerd/runsc + # -- Absolute path of the `runsc` configuration file, used by Falco to set its configuration and make aware `gVisor` of its presence. + config: /run/containerd/runsc/config.toml + # -- Configuration for the Falco init container. loader: # -- Enable/disable the init container. @@ -212,20 +243,6 @@ driver: # -- Security context for the Falco driver loader init container. Overrides the default security context. If driver.kind == "module" you must at least set `privileged: true`. securityContext: {} -# -- Gvisor configuration. Based on your system you need to set the appropriate values. -# Please, rembember to add pod tolerations and affinities in order to schedule the Falco pods in the gVisor enabled nodes. -gvisor: - # -- Set it to true if you want to deploy Falco with gVisor support. - enabled: false - # -- Runsc container runtime configuration. Falco needs to interact with it in order to intercept the activity of the sandboxed pods. - runsc: - # -- Absolute path of the `runsc` binary in the k8s nodes. - path: /home/containerd/usr/local/sbin - # -- Absolute path of the root directory of the `runsc` container runtime. It is of vital importance for Falco since `runsc` stores there the information of the workloads handled by it; - root: /run/containerd/runsc - # -- Absolute path of the `runsc` configuration file, used by Falco to set its configuration and make aware `gVisor` of its presence. - config: /run/containerd/runsc/config.toml - # Collectors for data enrichment (scenario requirement) collectors: # -- Enable/disable all the metadata collectors. @@ -399,7 +416,7 @@ falcoctl: # -- Resolve the dependencies for artifacts. resolveDeps: true # -- List of artifacts to be installed by the falcoctl init container. - refs: [falco-rules:2] + refs: [falco-rules:3] # -- Directory where the rulesfiles are saved. The path is relative to the container, which in this case is an emptyDir # mounted also by the Falco pod. rulesfilesDir: /rulesfiles @@ -407,7 +424,7 @@ falcoctl: pluginsDir: /plugins follow: # -- List of artifacts to be followed by the falcoctl sidecar container. - refs: [falco-rules:2] + refs: [falco-rules:3] # -- How often the tool checks for new versions of the followed artifacts. every: 6h # -- HTTP endpoint that serves the api versions of the Falco instance. It is used to check if the new versions are compatible @@ -713,6 +730,10 @@ falco: client_key: "/etc/falco/certs/client/client.key" # -- Whether to echo server answers to stdout echo: false + # -- compress_uploads whether to compress data sent to http endpoint. + compress_uploads: false + # -- keep_alive whether to keep alive the connection. + keep_alive: false # [Stable] `program_output` # @@ -1061,13 +1082,22 @@ falco: # number of CPUs to determine overall usage. Memory metrics are provided in raw # units (`kb` for `RSS`, `PSS` and `VSZ` or `bytes` for `container_memory_used`) # and can be uniformly converted to megabytes (MB) using the - # `convert_memory_to_mb` functionality. In environments such as Kubernetes, it - # is crucial to track Falco's container memory usage. To customize the path of - # the memory metric file, you can create an environment variable named - # `FALCO_CGROUP_MEM_PATH` and set it to the desired file path. By default, Falco - # uses the file `/sys/fs/cgroup/memory/memory.usage_in_bytes` to monitor - # container memory usage, which aligns with Kubernetes' - # `container_memory_working_set_bytes` metric. + # `convert_memory_to_mb` functionality. In environments such as Kubernetes when + # deployed as daemonset, it is crucial to track Falco's container memory usage. + # To customize the path of the memory metric file, you can create an environment + # variable named `FALCO_CGROUP_MEM_PATH` and set it to the desired file path. By + # default, Falco uses the file `/sys/fs/cgroup/memory/memory.usage_in_bytes` to + # monitor container memory usage, which aligns with Kubernetes' + # `container_memory_working_set_bytes` metric. Finally, we emit the overall host + # CPU and memory usages, along with the total number of processes and open file + # descriptors (fds) on the host, obtained from the proc file system unrelated to + # Falco's monitoring. These metrics help assess Falco's usage in relation to the + # server's workload intensity. + # + # `state_counters_enabled`: Emit counters related to Falco's state engine, including + # added, removed threads or file descriptors (fds), and failed lookup, store, or + # retrieve actions in relation to Falco's underlying process cache table (threadtable). + # We also log the number of currently cached containers if applicable. # # `kernel_event_counters_enabled`: Emit kernel side event and drop counters, as # an alternative to `syscall_event_drops`, but with some differences. These @@ -1097,6 +1127,7 @@ falco: output_rule: true # output_file: /tmp/falco_stats.jsonl resource_utilization_enabled: true + state_counters_enabled: true kernel_event_counters_enabled: true libbpf_stats_enabled: true convert_memory_to_mb: true @@ -1107,68 +1138,6 @@ falco: # Falco performance tuning (advanced) # ####################################### - # [Stable] `syscall_buf_size_preset` - # - # --- [Description] - # - # -- The syscall buffer index determines the size of the shared space between Falco - # and its drivers. This shared space serves as a temporary storage for syscall - # events, allowing them to be transferred from the kernel to the userspace - # efficiently. The buffer size for each online CPU is determined by the buffer - # index, and each CPU has its own dedicated buffer. Adjusting this index allows - # you to control the overall size of the syscall buffers. - # - # --- [Usage] - # - # The index 0 is reserved, and each subsequent index corresponds to an - # increasing size in bytes. For example, index 1 corresponds to a size of 1 MB, - # index 2 corresponds to 2 MB, and so on: - # - # [(*), 1 MB, 2 MB, 4 MB, 8 MB, 16 MB, 32 MB, 64 MB, 128 MB, 256 MB, 512 MB] - # ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ - # | | | | | | | | | | | - # 0 1 2 3 4 5 6 7 8 9 10 - # - # - # The buffer dimensions in bytes are determined by the following requirements: - # (1) a power of 2. - # (2) a multiple of your system_page_dimension. - # (3) greater than `2 * (system_page_dimension). - # - # The buffer size constraints may limit the usability of certain indexes. Let's - # consider an example to illustrate this: - # - # If your system has a page size of 1 MB, the first available buffer size would - # be 4 MB because 2 MB is exactly equal to 2 * (system_page_size), which is not - # sufficient as we require more than 2 * (system_page_size). In this example, it - # is evident that if the page size is 1 MB, the first index that can be used is 3. - # - # However, in most cases, these constraints do not pose a limitation, and all - # indexes from 1 to 10 can be used. You can check your system's page size using - # the Falco `--page-size` command-line option. - # - # --- [Suggestions] - # - # The buffer size was previously fixed at 8 MB (index 4). You now have the - # option to adjust the size based on your needs. Increasing the size, such as to - # 16 MB (index 5), can reduce syscall drops in heavy production systems, but may - # impact performance. Decreasing the size can speed up the system but may - # increase syscall drops. It's important to note that the buffer size is mapped - # twice in the process' virtual memory, so a buffer of 8 MB will result in a 16 - # MB area in virtual memory. Use this parameter with caution and only modify it - # if the default size is not suitable for your use case. - syscall_buf_size_preset: 4 - - # [Experimental] `syscall_drop_failed_exit` - # - # -- Enabling this option in Falco allows it to drop failed system call exit events - # in the kernel driver before pushing them onto the ring buffer. This - # optimization can result in lower CPU usage and more efficient utilization of - # the ring buffer, potentially reducing the number of event losses. However, it - # is important to note that enabling this option also means sacrificing some - # visibility into the system. - syscall_drop_failed_exit: false - # [Experimental] `base_syscalls`, use with caution, read carefully # # --- [Description] @@ -1284,86 +1253,6 @@ falco: custom_set: [] repair: false - # [Experimental] `modern_bpf.cpus_for_each_syscall_buffer`, modern_bpf only - # - # --- [Description] - # - # -- The modern_bpf driver in Falco utilizes the new BPF ring buffer, which has a - # different memory footprint compared to the current BPF driver that uses the - # perf buffer. The Falco core maintainers have discussed the differences and - # their implications, particularly in Kubernetes environments where limits need - # to be carefully set to avoid interference with the Falco daemonset deployment - # from the OOM killer. Based on guidance received from the kernel mailing list, - # it is recommended to assign multiple CPUs to one buffer instead of allocating - # a buffer for each CPU individually. This helps optimize resource allocation - # and prevent potential issues related to memory usage. - # - # This is an index that controls how many CPUs you want to assign to a single - # syscall buffer (ring buffer). By default, for modern_bpf every syscall buffer - # is associated to 2 CPUs, so the mapping is 1:2. The modern BPF probe allows - # you to choose different mappings, for example, changing the value to `1` - # results in a 1:1 mapping and would mean one syscall buffer for each CPU (this - # is the default for the `bpf` driver). - # - # --- [Usage] - # - # You can choose an index from 0 to MAX_NUMBER_ONLINE_CPUs to set the dimension - # of the syscall buffers. The value 0 represents a single buffer shared among - # all online CPUs. It serves as a flexible option when the exact number of - # online CPUs is unknown. Here's an example to illustrate this: - # - # Consider a system with 7 online CPUs: - # - # CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU) - # - # - `1` means a syscall buffer for each CPU so 7 buffers - # - # CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU) - # | | | | | | | - # BUFFERs 0 1 2 3 4 5 6 - # - # - `2` (Default value) means a syscall buffer for each CPU pair, so 4 buffers - # - # CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU) - # | | | | | | | - # BUFFERs 0 0 1 1 2 2 3 - # - # Please note that in this example, there are 4 buffers in total. Three of the - # buffers are associated with pairs of CPUs, while the last buffer is mapped to - # a single CPU. This arrangement is necessary because we have an odd number of - # CPUs. - # - # - `0` or `MAX_NUMBER_ONLINE_CPUs` mean a syscall buffer shared between all - # CPUs, so 1 buffer - # - # CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU) - # | | | | | | | - # BUFFERs 0 0 0 0 0 0 0 - # - # Moreover, you have the option to combine this parameter with - # `syscall_buf_size_preset` index. For instance, you can create a large shared - # syscall buffer of 512 MB (using syscall_buf_size_preset=10) that is - # allocated among all the online CPUs. - # - # --- [Suggestions] - # - # The default choice of index 2 (one syscall buffer for each CPU pair) was made - # because the modern bpf probe utilizes a different memory allocation strategy - # compared to the other two drivers (bpf and kernel module). However, you have - # the flexibility to experiment and find the optimal configuration for your - # system. - # - # When considering a fixed syscall_buf_size_preset and a fixed buffer dimension: - # - Increasing this configs value results in lower number of buffers and you can - # speed up your system and reduce memory usage - # - However, using too few buffers may increase contention in the kernel, - # leading to a slowdown. - # - # If you have low event throughputs and minimal drops, reducing the number of - # buffers (higher `cpus_for_each_syscall_buffer`) can lower the memory footprint. - modern_bpf: - cpus_for_each_syscall_buffer: 2 - ################################################# # Falco cloud orchestration systems integration # ################################################# From 3b07b1a6ffae740a4a4663b1b0b5f066a35d4bd5 Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Thu, 11 Jan 2024 16:44:30 +0100 Subject: [PATCH 08/19] fix(falco): mount /etc in falco pods Signed-off-by: Aldo Lacuku --- charts/falco/templates/pod-template.tpl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/charts/falco/templates/pod-template.tpl b/charts/falco/templates/pod-template.tpl index 97e2dd8c3..7672e8980 100644 --- a/charts/falco/templates/pod-template.tpl +++ b/charts/falco/templates/pod-template.tpl @@ -134,10 +134,12 @@ spec: - mountPath: /host/usr name: usr-fs readOnly: true + {{- end }} + {{- if .Values.driver.enabled }} - mountPath: /host/etc name: etc-fs readOnly: true - {{- end }} + {{- end -}} {{- if and .Values.driver.enabled (eq .Values.driver.kind "kmod") }} - mountPath: /host/dev name: dev-fs From 33df745694ffd2477c23c7c9173605c4f7ea2829 Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Thu, 11 Jan 2024 16:45:56 +0100 Subject: [PATCH 09/19] update(falco/gvisor): update gvisor-gke prese values file Signed-off-by: Aldo Lacuku --- charts/falco/values-gvisor-gke.yaml | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/charts/falco/values-gvisor-gke.yaml b/charts/falco/values-gvisor-gke.yaml index 23c5b27d7..d38f7621c 100644 --- a/charts/falco/values-gvisor-gke.yaml +++ b/charts/falco/values-gvisor-gke.yaml @@ -22,17 +22,15 @@ tolerations: operator: Equal value: gvisor -# Disable the driver since it is not needed. +# Enable gVisor and set the appropriate paths. driver: - enabled: false - -# Enable gVisor and set the appropriate paths. -gvisor: enabled: true - runsc: - path: /home/containerd/usr/local/sbin - root: /run/containerd/runsc - config: /run/containerd/runsc/config.toml + kind: gvisor + gvisor: + runsc: + path: /home/containerd/usr/local/sbin + root: /run/containerd/runsc + config: /run/containerd/runsc/config.toml # Enable the containerd collector to enrich the syscall events with metadata. collectors: @@ -53,15 +51,13 @@ falcoctl: config: artifact: install: - # -- Do not resolve the depenencies for artifacts. By default is true, but for our use case we disable it. - resolveDeps: false # -- List of artifacts to be installed by the falcoctl init container. # We do not recommend installing (or following) plugins for security reasons since they are executable objects. - refs: [falco-rules:1] + refs: [falco-rules:3] follow: # -- List of artifacts to be followed by the falcoctl sidecar container. # We do not recommend installing (or following) plugins for security reasons since they are executable objects. - refs: [falco-rules:1] + refs: [falco-rules:3] # Set this to true to force Falco so output the logs as soon as they are emmitted. tty: false From fa24a2227214b27221df4402219a791eb0a9a85a Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Fri, 12 Jan 2024 11:28:20 +0100 Subject: [PATCH 10/19] update(falco/changelog): add changelog for chart 4.0.0 Signed-off-by: Aldo Lacuku --- charts/falco/CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/charts/falco/CHANGELOG.md b/charts/falco/CHANGELOG.md index a6e788e41..131e11b44 100644 --- a/charts/falco/CHANGELOG.md +++ b/charts/falco/CHANGELOG.md @@ -3,6 +3,17 @@ This file documents all notable changes to Falco Helm Chart. The release numbering uses [semantic versioning](http://semver.org). +## v4.0.0 +The new chart introduces some breaking changes. For folks upgrading Falco please see the BREAKING-CHANGES.md file. + +* Uniform driver names and configuration to the Falco one: https://github.com/falcosecurity/falco/pull/2413; +* Fix usernames and groupnames resolution by mounting the `/etc` filesystem; +* Drop old kubernetes collector related resources; +* Introduce the new k8s-metacollector and k8smeta plugin (experimental); +* Enable the dependency resolver for artifacts in falcoctl since the Falco image does not ship anymore the plugins; +* Bump Falco to 0.37.0; +* Bump falcoctl to 0.7.0. + ## v3.8.7 * Upgrade falcosidekick chart to `v0.7.11`. From 162094ba75657cf9b590b03ae00aa27e14ae4b38 Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Fri, 12 Jan 2024 11:29:14 +0100 Subject: [PATCH 11/19] new(falco): add breaking changes notice Signed-off-by: Aldo Lacuku --- charts/falco/BREAKING-CHANGES.md | 36 +++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/charts/falco/BREAKING-CHANGES.md b/charts/falco/BREAKING-CHANGES.md index 89e611eed..dfc953eff 100644 --- a/charts/falco/BREAKING-CHANGES.md +++ b/charts/falco/BREAKING-CHANGES.md @@ -1,11 +1,45 @@ # Helm chart Breaking Changes - + - [4.0.0](#400) + - [Drivers](#drivers) + - [K8s Collector](#k8s-collector) + - [Plugins](#plugins) - [3.0.0](#300) - [Falcoctl](#falcoctl-support) - [Rulesfiles](#rulesfiles) - [Falco Images](#drop-support-for-falcosecurityfalco-image) - [Driver Loader Init Container](#driver-loader-simplified-logic) +## 4.0.0 +### Drivers +The `driver` section has been reworked based on the following PR: https://github.com/falcosecurity/falco/pull/2413. +It is an attempt to uniform how a driver is configured in Falco. +It also groups the configuration based on the driver type. +Some of the drivers has been renamed: +* kernel modules has been renamed from `module` to `kmod`; +* the ebpf probe has not been changed. It's still `ebpf`; +* the modern ebpf probe has been renamed from `modern-bpf` to `modern_ebpf`. + +The `gvisor` configuration has been moved under the `driver` section since it is considered a driver on its own. + +### K8s Collector +The old Kubernetes client has been removed in Falco 0.37.0. For more info checkout this issue: https://github.com/falcosecurity/falco/issues/2973#issuecomment-1877803422. +The [k8s-metacollector](https://github.com/falcosecurity/k8s-metacollector) and [k8s-meta](https://github.com/falcosecurity/plugins/tree/master/plugins/k8smeta) substitute +the old implementation. + +The following resources needed by Falco to connect to the API server are no longer needed and has been removed from the chart: +* service account; +* cluster role; +* cluster role binding. + +When the `collectors.kubernetes` is enabled the chart deploys the [k8s-metacollector](https://github.com/falcosecurity/k8s-metacollector) and configures Falco to load the +[k8s-meta](https://github.com/falcosecurity/plugins/tree/master/plugins/k8smeta) plugin. + +By default, the `collectors.kubernetes.enabled` is off; for more info, see the following issue: https://github.com/falcosecurity/falco/issues/2995. + +### Plugins +The Falco docker image does not ship anymore the plugins: https://github.com/falcosecurity/falco/pull/2997. +For this reason, the `resolveDeps` is now enabled in relevant values files (ie. `values-k8saudit.yaml`). +When installing `rulesfile` artifacts `falcoctl` will try to resolve its dependencies and install the required plugins. ## 3.0.0 The new chart deploys new *k8s* resources and new configuration variables have been added to the `values.yaml` file. People upgrading the chart from `v2.x.y` have to port their configuration variables to the new `values.yaml` file used by the `v3.0.0` chart. From 2383b205222b9e33e6c33a85ada75654ff1ba0a4 Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Fri, 12 Jan 2024 11:44:14 +0100 Subject: [PATCH 12/19] update(falco/README.md): update README.md file Signed-off-by: Aldo Lacuku --- charts/falco/README.gotmpl | 87 +++++++++++++++----- charts/falco/README.md | 162 ++++++++++++++++++++++++------------- 2 files changed, 176 insertions(+), 73 deletions(-) diff --git a/charts/falco/README.gotmpl b/charts/falco/README.gotmpl index afa06568f..831d726bc 100644 --- a/charts/falco/README.gotmpl +++ b/charts/falco/README.gotmpl @@ -87,12 +87,13 @@ Note that **the driver is not required when using plugins**. gVisor is an application kernel, written in Go, that implements a substantial portion of the Linux system call interface. It provides an additional layer of isolation between running applications and the host operating system. For more information please consult the [official docs](https://gvisor.dev/docs/). In version `0.32.1`, Falco first introduced support for gVisor by leveraging the stream of system call information coming from gVisor. Falco requires the version of [runsc](https://gvisor.dev/docs/user_guide/install/) to be equal to or above `20220704.0`. The following snippet shows the gVisor configuration variables found in `values.yaml`: ```yaml -gvisor: - enabled: true - runsc: - path: /home/containerd/usr/local/sbin - root: /run/containerd/runsc - config: /run/containerd/runsc/config.toml +driver: + gvisor: + enabled: true + runsc: + path: /home/containerd/usr/local/sbin + root: /run/containerd/runsc + config: /run/containerd/runsc/config.toml ``` Falco uses the [runsc](https://gvisor.dev/docs/user_guide/install/) binary to interact with sandboxed containers. The following variables need to be set: * `runsc.path`: absolute path of the `runsc` binary in the k8s nodes; @@ -142,20 +143,21 @@ When using the [drivers](#about-the-driver), Falco is deployed as `daemonset`. B To run Falco with the [kernel module](https://falco.org/docs/event-sources/drivers/#kernel-module) you can use the default values of the helm chart: -```yaml -driver: - enabled: true - kind: module +```bash +helm install falco falcosecurity/falco \ + --create-namespace \ + --namespace falco ``` **eBPF probe** To run Falco with the [eBPF probe](https://falco.org/docs/event-sources/drivers/#ebpf-probe) you just need to set `driver.kind=ebpf` as shown in the following snippet: -```yaml -driver: - enabled: true - kind: ebpf +```bash +helm install falco falcosecurity/falco \ + --create-namespace \ + --namespace falco \ + --set driver.kind=ebpf ``` There are other configurations related to the eBPF probe, for more info please check the `values.yaml` file. After you have made your changes to the configuration file you just need to run: @@ -168,10 +170,11 @@ helm install falco falcosecurity/falco --namespace "your-custom-name-space" --cr To run Falco with the [modern eBPF probe](https://falco.org/docs/event-sources/drivers/#modern-ebpf-probe-experimental) you just need to set `driver.kind=modern-bpf` as shown in the following snippet: -```yaml -driver: - enabled: true - kind: modern-bpf +```bash +helm install falco falcosecurity/falco \ + --create-namespace \ + --namespace falco \ + --set driver.kind=modern_ebpf ``` #### Deployment @@ -211,6 +214,54 @@ A scenario when we need the `-p (--previous)` flag is when we have a restart of ### Enabling real time logs By default in Falco the output is buffered. When live streaming logs we will notice delays between the logs output (rules triggering) and the event happening. In order to enable the logs to be emitted without delays you need to set `.Values.tty=true` in `values.yaml` file. + +## K8s-metacollector +Starting from Falco `0.37` the old [k8s-client](https://github.com/falcosecurity/falco/issues/2973) has been removed. +A new component named [k8s-metacollector](https://github.com/falcosecurity/k8s-metacollector) replaces it. +The *k8s-metacollector* is a self-contained module that can be deployed within a Kubernetes cluster to perform the task of gathering metadata +from various Kubernetes resources and subsequently transmitting this collected metadata to designated subscribers. + +Kubernetes' resources for which metadata will be collected and sent to Falco: +* pods; +* namespaces; +* deployments; +* replicationcontrollers; +* replicasets; +* services; + +### Plugin +Since the *k8s-metacollector* is standalone, deployed in the cluster as a deployment, Falco instances need to connect to the component +in order to retrieve the `metadata`. Here it comes the [k8smeta](https://github.com/falcosecurity/plugins/tree/master/plugins/k8smeta) plugin. +The plugin gathers details about Kubernetes resources from the *k8s-metacollector*. It then stores this information +in tables and provides access to Falco upon request. The plugin specifically acquires data for the node where the +associated Falco instance is deployed, resulting in node-level granularity. + +### Exported Fields: Old and New +The old [k8s-client](https://github.com/falcosecurity/falco/issues/2973) used to populate the +[k8s](https://falco.org/docs/reference/rules/supported-fields/#field-class-k8s) fields. The **k8s** field class is still +available in Falco, for compatibility reasons, but most of the fields will return `N/A`. The following fields are still +usable and will return meaningful data when the `container runtime collectors` are enabled: +* k8s.pod.name; +* k8s.pod.id; +* k8s.pod.label; +* k8s.pod.labels; +* k8s.pod.ip; +* k8s.pod.cni.json; +* k8s.pod.namespace.name; + +The [k8smeta](https://github.com/falcosecurity/plugins/tree/master/plugins/k8smeta) plugin exports a whole new +[field class]https://github.com/falcosecurity/plugins/tree/master/plugins/k8smeta#supported-fields. Note that the new +`k8smeta.*` fields are usable only when the **k8smeta** plugin is loaded in Falco. + +### Enabling the k8s-metacollector +The following command will deploy Falco + k8s-metacollector + k8smeta: +```bash +helm install falco falcosecurity/falco \ + --namespace falco \ + --create-namespace \ + --set collectors.kubernetes.enabled=true +``` + ## Loading custom rules Falco ships with a nice default ruleset. It is a good starting point but sooner or later, we are going to need to add custom rules which fit our needs. diff --git a/charts/falco/README.md b/charts/falco/README.md index 671e17150..21d0d2ca0 100644 --- a/charts/falco/README.md +++ b/charts/falco/README.md @@ -87,12 +87,13 @@ Note that **the driver is not required when using plugins**. gVisor is an application kernel, written in Go, that implements a substantial portion of the Linux system call interface. It provides an additional layer of isolation between running applications and the host operating system. For more information please consult the [official docs](https://gvisor.dev/docs/). In version `0.32.1`, Falco first introduced support for gVisor by leveraging the stream of system call information coming from gVisor. Falco requires the version of [runsc](https://gvisor.dev/docs/user_guide/install/) to be equal to or above `20220704.0`. The following snippet shows the gVisor configuration variables found in `values.yaml`: ```yaml -gvisor: - enabled: true - runsc: - path: /home/containerd/usr/local/sbin - root: /run/containerd/runsc - config: /run/containerd/runsc/config.toml +driver: + gvisor: + enabled: true + runsc: + path: /home/containerd/usr/local/sbin + root: /run/containerd/runsc + config: /run/containerd/runsc/config.toml ``` Falco uses the [runsc](https://gvisor.dev/docs/user_guide/install/) binary to interact with sandboxed containers. The following variables need to be set: * `runsc.path`: absolute path of the `runsc` binary in the k8s nodes; @@ -142,20 +143,21 @@ When using the [drivers](#about-the-driver), Falco is deployed as `daemonset`. B To run Falco with the [kernel module](https://falco.org/docs/event-sources/drivers/#kernel-module) you can use the default values of the helm chart: -```yaml -driver: - enabled: true - kind: module +```bash +helm install falco falcosecurity/falco \ + --create-namespace \ + --namespace falco ``` **eBPF probe** To run Falco with the [eBPF probe](https://falco.org/docs/event-sources/drivers/#ebpf-probe) you just need to set `driver.kind=ebpf` as shown in the following snippet: -```yaml -driver: - enabled: true - kind: ebpf +```bash +helm install falco falcosecurity/falco \ + --create-namespace \ + --namespace falco \ + --set driver.kind=ebpf ``` There are other configurations related to the eBPF probe, for more info please check the `values.yaml` file. After you have made your changes to the configuration file you just need to run: @@ -168,10 +170,11 @@ helm install falco falcosecurity/falco --namespace "your-custom-name-space" --cr To run Falco with the [modern eBPF probe](https://falco.org/docs/event-sources/drivers/#modern-ebpf-probe-experimental) you just need to set `driver.kind=modern-bpf` as shown in the following snippet: -```yaml -driver: - enabled: true - kind: modern-bpf +```bash +helm install falco falcosecurity/falco \ + --create-namespace \ + --namespace falco \ + --set driver.kind=modern_ebpf ``` #### Deployment @@ -210,6 +213,54 @@ A scenario when we need the `-p (--previous)` flag is when we have a restart of ### Enabling real time logs By default in Falco the output is buffered. When live streaming logs we will notice delays between the logs output (rules triggering) and the event happening. In order to enable the logs to be emitted without delays you need to set `.Values.tty=true` in `values.yaml` file. + +## K8s-metacollector +Starting from Falco `0.37` the old [k8s-client](https://github.com/falcosecurity/falco/issues/2973) has been removed. +A new component named [k8s-metacollector](https://github.com/falcosecurity/k8s-metacollector) replaces it. +The *k8s-metacollector* is a self-contained module that can be deployed within a Kubernetes cluster to perform the task of gathering metadata +from various Kubernetes resources and subsequently transmitting this collected metadata to designated subscribers. + +Kubernetes' resources for which metadata will be collected and sent to Falco: +* pods; +* namespaces; +* deployments; +* replicationcontrollers; +* replicasets; +* services; + +### Plugin +Since the *k8s-metacollector* is standalone, deployed in the cluster as a deployment, Falco instances need to connect to the component +in order to retrieve the `metadata`. Here it comes the [k8smeta](https://github.com/falcosecurity/plugins/tree/master/plugins/k8smeta) plugin. +The plugin gathers details about Kubernetes resources from the *k8s-metacollector*. It then stores this information +in tables and provides access to Falco upon request. The plugin specifically acquires data for the node where the +associated Falco instance is deployed, resulting in node-level granularity. + +### Exported Fields: Old and New +The old [k8s-client](https://github.com/falcosecurity/falco/issues/2973) used to populate the +[k8s](https://falco.org/docs/reference/rules/supported-fields/#field-class-k8s) fields. The **k8s** field class is still +available in Falco, for compatibility reasons, but most of the fields will return `N/A`. The following fields are still +usable and will return meaningful data when the `container runtime collectors` are enabled: +* k8s.pod.name; +* k8s.pod.id; +* k8s.pod.label; +* k8s.pod.labels; +* k8s.pod.ip; +* k8s.pod.cni.json; +* k8s.pod.namespace.name; + +The [k8smeta](https://github.com/falcosecurity/plugins/tree/master/plugins/k8smeta) plugin exports a whole new +[field class]https://github.com/falcosecurity/plugins/tree/master/plugins/k8smeta#supported-fields. Note that the new +`k8smeta.*` fields are usable only when the **k8smeta** plugin is loaded in Falco. + +### Enabling the k8s-metacollector +The following command will deploy Falco + k8s-metacollector + k8smeta: +```bash +helm install falco falcosecurity/falco \ + --namespace falco \ + --create-namespace \ + --set collectors.kubernetes.enabled=true +``` + ## Loading custom rules Falco ships with a nice default ruleset. It is a good starting point but sooner or later, we are going to need to add custom rules which fit our needs. @@ -512,7 +563,7 @@ If you use a Proxy in your cluster, the requests between `Falco` and `Falcosidek ## Configuration -The following table lists the main configurable parameters of the falco chart v3.8.5 and their default values. See `values.yaml` for full list. +The following table lists the main configurable parameters of the falco chart v4.0.0 and their default values. See `values.yaml` for full list. ## Values @@ -533,22 +584,33 @@ The following table lists the main configurable parameters of the falco chart v3 | collectors.docker.enabled | bool | `true` | Enable Docker support. | | collectors.docker.socket | string | `"/var/run/docker.sock"` | The path of the Docker daemon socket. | | collectors.enabled | bool | `true` | Enable/disable all the metadata collectors. | -| collectors.kubernetes.apiAuth | string | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | Provide the authentication method Falco should use to connect to the Kubernetes API. | -| collectors.kubernetes.apiUrl | string | `"https://$(KUBERNETES_SERVICE_HOST)"` | | -| collectors.kubernetes.enableNodeFilter | bool | `true` | If true, only the current node (on which Falco is running) will be considered when requesting metadata of pods to the API server. Disabling this option may have a performance penalty on large clusters. | -| collectors.kubernetes.enabled | bool | `true` | Enable Kubernetes meta data collection via a connection to the Kubernetes API server. When this option is disabled, Falco falls back to the container annotations to grap the meta data. In such a case, only the ID, name, namespace, labels of the pod will be available. | +| collectors.kubernetes | object | `{"collectorHostname":"","collectorPort":"","enabled":false,"pluginRef":"ghcr.io/falcosecurity/plugins/plugin/k8smeta:0.1.0"}` | kubernetes holds the configuration for the kubernetes collector. Starting from version 0.37.0 of Falco, the legacy kubernetes client has been removed. A new standalone component named k8s-metacollector and a Falco plugin have been developed to solve the issues that were present in the old implementation. More info here: https://github.com/falcosecurity/falco/issues/2973 | +| collectors.kubernetes.collectorHostname | string | `""` | collectorHostname is the address of the k8s-metacollector. When not specified it will be set to match k8s-metacollector service. e.x: falco-k8smetacollecto.falco.svc. If for any reason you need to override it, make sure to set here the address of the k8s-metacollector. It is used by the k8smeta plugin to connect to the k8s-metacollector. | +| collectors.kubernetes.collectorPort | string | `""` | collectorPort designates the port on which the k8s-metacollector gRPC service listens. If not specified the value of the port named `broker-grpc` in k8s-metacollector.service.ports is used. The default values is 45000. It is used by the k8smeta plugin to connect to the k8s-metacollector. | +| collectors.kubernetes.enabled | bool | `false` | enabled specifies whether the Kubernetes metadata should be collected using the k8smeta plugin and the k8s-metacollector component. It will deploy the k8s-metacollector external component that fetches Kubernetes metadata and pushes them to Falco instances. For more info see: https://github.com/falcosecurity/k8s-metacollector https://github.com/falcosecurity/charts/tree/master/charts/k8s-metacollector When this option is disabled, Falco falls back to the container annotations to grab the metadata. In such a case, only the ID, name, namespace, labels of the pod will be available. | +| collectors.kubernetes.pluginRef | string | `"ghcr.io/falcosecurity/plugins/plugin/k8smeta:0.1.0"` | pluginRef is the OCI reference for the k8smeta plugin. It could be a full reference such as: "ghcr.io/falcosecurity/plugins/plugin/k8smeta:0.1.0". Or just name + tag: k8smeta:0.1.0. | | containerSecurityContext | object | `{}` | Set securityContext for the Falco container.For more info see the "falco.securityContext" helper in "pod-template.tpl" | | controller.annotations | object | `{}` | | | controller.daemonset.updateStrategy.type | string | `"RollingUpdate"` | Perform rolling updates by default in the DaemonSet agent ref: https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/ | | controller.deployment.replicas | int | `1` | Number of replicas when installing Falco using a deployment. Change it if you really know what you are doing. For more info check the section on Plugins in the README.md file. | | controller.kind | string | `"daemonset"` | | | customRules | object | `{}` | Third party rules enabled for Falco. More info on the dedicated section in README.md file. | -| driver.ebpf | object | `{"hostNetwork":false,"leastPrivileged":false,"path":null}` | Configuration section for ebpf driver. | +| driver.ebpf | object | `{"bufSizePreset":4,"dropFailedExit":false,"hostNetwork":false,"leastPrivileged":false,"path":"${HOME}/.falco/falco-bpf.o"}` | Configuration section for ebpf driver. | +| driver.ebpf.bufSizePreset | int | `4` | bufSizePreset determines the size of the shared space between Falco and its drivers. This shared space serves as a temporary storage for syscall events. | +| driver.ebpf.dropFailedExit | bool | `false` | dropFailedExit if set true drops failed system call exit events before pushing them to userspace. | | driver.ebpf.hostNetwork | bool | `false` | Needed to enable eBPF JIT at runtime for performance reasons. Can be skipped if eBPF JIT is enabled from outside the container | | driver.ebpf.leastPrivileged | bool | `false` | Constrain Falco with capabilities instead of running a privileged container. Ensure the eBPF driver is enabled (i.e., setting the `driver.kind` option to `ebpf`). Capabilities used: {CAP_SYS_RESOURCE, CAP_SYS_ADMIN, CAP_SYS_PTRACE}. On kernel versions >= 5.8 'CAP_PERFMON' and 'CAP_BPF' could replace 'CAP_SYS_ADMIN' but please pay attention to the 'kernel.perf_event_paranoid' value on your system. Usually 'kernel.perf_event_paranoid>2' means that you cannot use 'CAP_PERFMON' and you should fallback to 'CAP_SYS_ADMIN', but the behavior changes across different distros. Read more on that here: https://falco.org/docs/event-sources/kernel/#least-privileged-mode-1 | -| driver.ebpf.path | string | `nil` | Path where the eBPF probe is located. It comes handy when the probe have been installed in the nodes using tools other than the init container deployed with the chart. | +| driver.ebpf.path | string | `"${HOME}/.falco/falco-bpf.o"` | path where the eBPF probe is located. It comes handy when the probe have been installed in the nodes using tools other than the init container deployed with the chart. | | driver.enabled | bool | `true` | Set it to false if you want to deploy Falco without the drivers. Always set it to false when using Falco with plugins. | -| driver.kind | string | `"module"` | Tell Falco which driver to use. Available options: module (kernel driver), ebpf (eBPF probe), modern-bpf (modern eBPF probe). | +| driver.gvisor | object | `{"runsc":{"config":"/run/containerd/runsc/config.toml","path":"/home/containerd/usr/local/sbin","root":"/run/containerd/runsc"}}` | Gvisor configuration. Based on your system you need to set the appropriate values. Please, remember to add pod tolerations and affinities in order to schedule the Falco pods in the gVisor enabled nodes. | +| driver.gvisor.runsc | object | `{"config":"/run/containerd/runsc/config.toml","path":"/home/containerd/usr/local/sbin","root":"/run/containerd/runsc"}` | Runsc container runtime configuration. Falco needs to interact with it in order to intercept the activity of the sandboxed pods. | +| driver.gvisor.runsc.config | string | `"/run/containerd/runsc/config.toml"` | Absolute path of the `runsc` configuration file, used by Falco to set its configuration and make aware `gVisor` of its presence. | +| driver.gvisor.runsc.path | string | `"/home/containerd/usr/local/sbin"` | Absolute path of the `runsc` binary in the k8s nodes. | +| driver.gvisor.runsc.root | string | `"/run/containerd/runsc"` | Absolute path of the root directory of the `runsc` container runtime. It is of vital importance for Falco since `runsc` stores there the information of the workloads handled by it; | +| driver.kind | string | `"kmod"` | kind tells Falco which driver to use. Available options: kmod (kernel driver), ebpf (eBPF probe), modern_ebpf (modern eBPF probe). | +| driver.kmod | object | `{"bufSizePreset":4,"dropFailedExit":false}` | kmod holds the configuration for the kernel module. | +| driver.kmod.bufSizePreset | int | `4` | bufSizePreset determines the size of the shared space between Falco and its drivers. This shared space serves as a temporary storage for syscall events. | +| driver.kmod.dropFailedExit | bool | `false` | dropFailedExit if set true drops failed system call exit events before pushing them to userspace. | | driver.loader | object | `{"enabled":true,"initContainer":{"args":[],"env":[],"image":{"pullPolicy":"IfNotPresent","registry":"docker.io","repository":"falcosecurity/falco-driver-loader","tag":""},"resources":{},"securityContext":{}}}` | Configuration for the Falco init container. | | driver.loader.enabled | bool | `true` | Enable/disable the init container. | | driver.loader.initContainer.args | list | `[]` | Arguments to pass to the Falco driver loader init container. | @@ -558,8 +620,10 @@ The following table lists the main configurable parameters of the falco chart v3 | driver.loader.initContainer.image.repository | string | `"falcosecurity/falco-driver-loader"` | The image repository to pull from. | | driver.loader.initContainer.resources | object | `{}` | Resources requests and limits for the Falco driver loader init container. | | driver.loader.initContainer.securityContext | object | `{}` | Security context for the Falco driver loader init container. Overrides the default security context. If driver.kind == "module" you must at least set `privileged: true`. | -| driver.modern_bpf | object | `{"leastPrivileged":false}` | Configuration section for modern bpf driver. | -| driver.modern_bpf.leastPrivileged | bool | `false` | Constrain Falco with capabilities instead of running a privileged container. Ensure the modern bpf driver is enabled (i.e., setting the `driver.kind` option to `modern-bpf`). Capabilities used: {CAP_SYS_RESOURCE, CAP_BPF, CAP_PERFMON, CAP_SYS_PTRACE}. Read more on that here: https://falco.org/docs/event-sources/kernel/#least-privileged-mode-2 | +| driver.modernEbpf.bufSizePreset | int | `4` | bufSizePreset determines the size of the shared space between Falco and its drivers. This shared space serves as a temporary storage for syscall events. | +| driver.modernEbpf.cpusForEachBuffer | int | `2` | cpusForEachBuffer is the index that controls how many CPUs to assign to a single syscall buffer. | +| driver.modernEbpf.dropFailedExit | bool | `false` | dropFailedExit if set true drops failed system call exit events before pushing them to userspace. | +| driver.modernEbpf.leastPrivileged | bool | `false` | Constrain Falco with capabilities instead of running a privileged container. Ensure the modern bpf driver is enabled (i.e., setting the `driver.kind` option to `modern-bpf`). Capabilities used: {CAP_SYS_RESOURCE, CAP_BPF, CAP_PERFMON, CAP_SYS_PTRACE}. Read more on that here: https://falco.org/docs/event-sources/kernel/#least-privileged-mode-2 | | extra.args | list | `[]` | Extra command-line arguments. | | extra.env | list | `[]` | Extra environment variables that will be pass onto Falco containers. | | extra.initContainers | list | `[]` | Additional initContainers for Falco pods. | @@ -569,14 +633,16 @@ The following table lists the main configurable parameters of the falco chart v3 | falco.grpc | object | `{"bind_address":"unix:///run/falco/falco.sock","enabled":false,"threadiness":0}` | gRPC server using a local unix socket | | falco.grpc.threadiness | int | `0` | When the `threadiness` value is set to 0, Falco will automatically determine the appropriate number of threads based on the number of online cores in the system. | | falco.grpc_output | object | `{"enabled":false}` | Use gRPC as an output service. gRPC is a modern and high-performance framework for remote procedure calls (RPC). It utilizes protocol buffers for efficient data serialization. The gRPC output in Falco provides a modern and efficient way to integrate with other systems. By default the setting is turned off. Enabling this option stores output events in memory until they are consumed by a gRPC client. Ensure that you have a consumer for the output events or leave it disabled. | -| falco.http_output | object | `{"ca_bundle":"","ca_cert":"","ca_path":"/etc/falco/certs/","client_cert":"/etc/falco/certs/client/client.crt","client_key":"/etc/falco/certs/client/client.key","echo":false,"enabled":false,"insecure":false,"mtls":false,"url":"","user_agent":"falcosecurity/falco"}` | Send logs to an HTTP endpoint or webhook. | +| falco.http_output | object | `{"ca_bundle":"","ca_cert":"","ca_path":"/etc/falco/certs/","client_cert":"/etc/falco/certs/client/client.crt","client_key":"/etc/falco/certs/client/client.key","compress_uploads":false,"echo":false,"enabled":false,"insecure":false,"keep_alive":false,"mtls":false,"url":"","user_agent":"falcosecurity/falco"}` | Send logs to an HTTP endpoint or webhook. | | falco.http_output.ca_bundle | string | `""` | Path to a specific file that will be used as the CA certificate store. | | falco.http_output.ca_cert | string | `""` | Path to the CA certificate that can verify the remote server. | | falco.http_output.ca_path | string | `"/etc/falco/certs/"` | Path to a folder that will be used as the CA certificate store. CA certificate need to be stored as indivitual PEM files in this directory. | | falco.http_output.client_cert | string | `"/etc/falco/certs/client/client.crt"` | Path to the client cert. | | falco.http_output.client_key | string | `"/etc/falco/certs/client/client.key"` | Path to the client key. | +| falco.http_output.compress_uploads | bool | `false` | compress_uploads whether to compress data sent to http endpoint. | | falco.http_output.echo | bool | `false` | Whether to echo server answers to stdout | | falco.http_output.insecure | bool | `false` | Tell Falco to not verify the remote server. | +| falco.http_output.keep_alive | bool | `false` | keep_alive whether to keep alive the connection. | | falco.http_output.mtls | bool | `false` | Tell Falco to use mTLS | | falco.json_include_output_property | bool | `true` | When using JSON output in Falco, you have the option to include the "output" property itself in the generated JSON output. The "output" property provides additional information about the purpose of the rule. To reduce the logging volume, it is recommended to turn it off if it's not necessary for your use case. | | falco.json_include_tags_property | bool | `true` | When using JSON output in Falco, you have the option to include the "tags" field of the rules in the generated JSON output. The "tags" field provides additional metadata associated with the rule. To reduce the logging volume, if the tags associated with the rule are not needed for your use case or can be added at a later stage, it is recommended to turn it off. | @@ -586,9 +652,7 @@ The following table lists the main configurable parameters of the falco chart v3 | falco.log_level | string | `"info"` | The `log_level` setting determines the minimum log level to include in Falco's logs related to the functioning of the software. This setting is separate from the `priority` field of rules and specifically controls the log level of Falco's operational logging. By specifying a log level, you can control the verbosity of Falco's operational logs. Only logs of a certain severity level or higher will be emitted. Supported levels: "emergency", "alert", "critical", "error", "warning", "notice", "info", "debug". | | falco.log_stderr | bool | `true` | Send information logs to stderr. Note these are *not* security notification logs! These are just Falco lifecycle (and possibly error) logs. | | falco.log_syslog | bool | `true` | Send information logs to syslog. Note these are *not* security notification logs! These are just Falco lifecycle (and possibly error) logs. | -| falco.metadata_download | object | `{"chunk_wait_us":1000,"max_mb":100,"watch_freq_sec":1}` | When connected to an orchestrator like Kubernetes, Falco has the capability to collect metadata and enrich system call events with contextual data. The parameters mentioned here control the downloading process of this metadata. Please note that support for Mesos is deprecated, so these parameters currently apply only to Kubernetes. When using Falco with Kubernetes, you can enable this functionality by using the `-k` or `-K` command-line flag. However, it's worth mentioning that for important Kubernetes metadata fields such as namespace or pod name, these fields are automatically extracted from the container runtime, providing the necessary enrichment for common use cases of syscall-based threat detection. In summary, the `-k` flag is typically not required for most scenarios involving Kubernetes workload owner enrichment. The `-k` flag is primarily used when additional metadata is required beyond the standard fields, catering to more specific use cases, see https://falco.org/docs/reference/rules/supported-fields/#field-class-k8s. | -| falco.metrics | object | `{"convert_memory_to_mb":true,"enabled":false,"include_empty_values":false,"interval":"1h","kernel_event_counters_enabled":true,"libbpf_stats_enabled":true,"output_rule":true,"resource_utilization_enabled":true}` | - [Usage] `enabled`: Disabled by default. `interval`: The stats interval in Falco follows the time duration definitions used by Prometheus. https://prometheus.io/docs/prometheus/latest/querying/basics/#time-durations Time durations are specified as a number, followed immediately by one of the following units: ms - millisecond s - second m - minute h - hour d - day - assuming a day has always 24h w - week - assuming a week has always 7d y - year - assuming a year has always 365d Example of a valid time duration: 1h30m20s10ms A minimum interval of 100ms is enforced for metric collection. However, for production environments, we recommend selecting one of the following intervals for optimal monitoring: 15m 30m 1h 4h 6h `output_rule`: To enable seamless metrics and performance monitoring, we recommend emitting metrics as the rule "Falco internal: metrics snapshot". This option is particularly useful when Falco logs are preserved in a data lake. Please note that to use this option, the Falco rules config `priority` must be set to `info` at a minimum. `output_file`: Append stats to a `jsonl` file. Use with caution in production as Falco does not automatically rotate the file. `resource_utilization_enabled`: Emit CPU and memory usage metrics. CPU usage is reported as a percentage of one CPU and can be normalized to the total number of CPUs to determine overall usage. Memory metrics are provided in raw units (`kb` for `RSS`, `PSS` and `VSZ` or `bytes` for `container_memory_used`) and can be uniformly converted to megabytes (MB) using the `convert_memory_to_mb` functionality. In environments such as Kubernetes, it is crucial to track Falco's container memory usage. To customize the path of the memory metric file, you can create an environment variable named `FALCO_CGROUP_MEM_PATH` and set it to the desired file path. By default, Falco uses the file `/sys/fs/cgroup/memory/memory.usage_in_bytes` to monitor container memory usage, which aligns with Kubernetes' `container_memory_working_set_bytes` metric. `kernel_event_counters_enabled`: Emit kernel side event and drop counters, as an alternative to `syscall_event_drops`, but with some differences. These counters reflect monotonic values since Falco's start and are exported at a constant stats interval. `libbpf_stats_enabled`: Exposes statistics similar to `bpftool prog show`, providing information such as the number of invocations of each BPF program attached by Falco and the time spent in each program measured in nanoseconds. To enable this feature, the kernel must be >= 5.1, and the kernel configuration `/proc/sys/kernel/bpf_stats_enabled` must be set. This option, or an equivalent statistics feature, is not available for non `*bpf*` drivers. Additionally, please be aware that the current implementation of `libbpf` does not support granularity of statistics at the bpf tail call level. `include_empty_values`: When the option is set to true, fields with an empty numeric value will be included in the output. However, this rule does not apply to high-level fields such as `n_evts` or `n_drops`; they will always be included in the output even if their value is empty. This option can be beneficial for exploring the data schema and ensuring that fields with empty values are included in the output. todo: prometheus export option todo: syscall_counters_enabled option | -| falco.modern_bpf | object | `{"cpus_for_each_syscall_buffer":2}` | - [Suggestions] The default choice of index 2 (one syscall buffer for each CPU pair) was made because the modern bpf probe utilizes a different memory allocation strategy compared to the other two drivers (bpf and kernel module). However, you have the flexibility to experiment and find the optimal configuration for your system. When considering a fixed syscall_buf_size_preset and a fixed buffer dimension: - Increasing this configs value results in lower number of buffers and you can speed up your system and reduce memory usage - However, using too few buffers may increase contention in the kernel, leading to a slowdown. If you have low event throughputs and minimal drops, reducing the number of buffers (higher `cpus_for_each_syscall_buffer`) can lower the memory footprint. | +| falco.metrics | object | `{"convert_memory_to_mb":true,"enabled":false,"include_empty_values":false,"interval":"1h","kernel_event_counters_enabled":true,"libbpf_stats_enabled":true,"output_rule":true,"resource_utilization_enabled":true,"state_counters_enabled":true}` | - [Usage] `enabled`: Disabled by default. `interval`: The stats interval in Falco follows the time duration definitions used by Prometheus. https://prometheus.io/docs/prometheus/latest/querying/basics/#time-durations Time durations are specified as a number, followed immediately by one of the following units: ms - millisecond s - second m - minute h - hour d - day - assuming a day has always 24h w - week - assuming a week has always 7d y - year - assuming a year has always 365d Example of a valid time duration: 1h30m20s10ms A minimum interval of 100ms is enforced for metric collection. However, for production environments, we recommend selecting one of the following intervals for optimal monitoring: 15m 30m 1h 4h 6h `output_rule`: To enable seamless metrics and performance monitoring, we recommend emitting metrics as the rule "Falco internal: metrics snapshot". This option is particularly useful when Falco logs are preserved in a data lake. Please note that to use this option, the Falco rules config `priority` must be set to `info` at a minimum. `output_file`: Append stats to a `jsonl` file. Use with caution in production as Falco does not automatically rotate the file. `resource_utilization_enabled`: Emit CPU and memory usage metrics. CPU usage is reported as a percentage of one CPU and can be normalized to the total number of CPUs to determine overall usage. Memory metrics are provided in raw units (`kb` for `RSS`, `PSS` and `VSZ` or `bytes` for `container_memory_used`) and can be uniformly converted to megabytes (MB) using the `convert_memory_to_mb` functionality. In environments such as Kubernetes when deployed as daemonset, it is crucial to track Falco's container memory usage. To customize the path of the memory metric file, you can create an environment variable named `FALCO_CGROUP_MEM_PATH` and set it to the desired file path. By default, Falco uses the file `/sys/fs/cgroup/memory/memory.usage_in_bytes` to monitor container memory usage, which aligns with Kubernetes' `container_memory_working_set_bytes` metric. Finally, we emit the overall host CPU and memory usages, along with the total number of processes and open file descriptors (fds) on the host, obtained from the proc file system unrelated to Falco's monitoring. These metrics help assess Falco's usage in relation to the server's workload intensity. `state_counters_enabled`: Emit counters related to Falco's state engine, including added, removed threads or file descriptors (fds), and failed lookup, store, or retrieve actions in relation to Falco's underlying process cache table (threadtable). We also log the number of currently cached containers if applicable. `kernel_event_counters_enabled`: Emit kernel side event and drop counters, as an alternative to `syscall_event_drops`, but with some differences. These counters reflect monotonic values since Falco's start and are exported at a constant stats interval. `libbpf_stats_enabled`: Exposes statistics similar to `bpftool prog show`, providing information such as the number of invocations of each BPF program attached by Falco and the time spent in each program measured in nanoseconds. To enable this feature, the kernel must be >= 5.1, and the kernel configuration `/proc/sys/kernel/bpf_stats_enabled` must be set. This option, or an equivalent statistics feature, is not available for non `*bpf*` drivers. Additionally, please be aware that the current implementation of `libbpf` does not support granularity of statistics at the bpf tail call level. `include_empty_values`: When the option is set to true, fields with an empty numeric value will be included in the output. However, this rule does not apply to high-level fields such as `n_evts` or `n_drops`; they will always be included in the output even if their value is empty. This option can be beneficial for exploring the data schema and ensuring that fields with empty values are included in the output. todo: prometheus export option todo: syscall_counters_enabled option | | falco.output_timeout | int | `2000` | The `output_timeout` parameter specifies the duration, in milliseconds, to wait before considering the deadline exceeded. By default, the timeout is set to 2000ms (2 seconds), meaning that the consumer of Falco outputs can block the Falco output channel for up to 2 seconds without triggering a timeout error. Falco actively monitors the performance of output channels. With this setting the timeout error can be logged, but please note that this requires setting Falco's operational logs `log_level` to a minimum of `notice`. It's important to note that Falco outputs will not be discarded from the output queue. This means that if an output channel becomes blocked indefinitely, it indicates a potential issue that needs to be addressed by the user. | | falco.outputs | object | `{"max_burst":1000,"rate":0}` | A throttling mechanism, implemented as a token bucket, can be used to control the rate of Falco outputs. Each event source has its own rate limiter, ensuring that alerts from one source do not affect the throttling of others. The following options control the mechanism: - rate: the number of tokens (i.e. right to send a notification) gained per second. When 0, the throttling mechanism is disabled. Defaults to 0. - max_burst: the maximum number of tokens outstanding. Defaults to 1000. For example, setting the rate to 1 allows Falco to send up to 1000 notifications initially, followed by 1 notification per second. The burst capacity is fully restored after 1000 seconds of no activity. Throttling can be useful in various scenarios, such as preventing notification floods, managing system load, controlling event processing, or complying with rate limits imposed by external systems or APIs. It allows for better resource utilization, avoids overwhelming downstream systems, and helps maintain a balanced and controlled flow of notifications. With the default settings, the throttling mechanism is disabled. | | falco.outputs_queue | object | `{"capacity":0}` | Falco utilizes tbb::concurrent_bounded_queue for handling outputs, and this parameter allows you to customize the queue capacity. Please refer to the official documentation: https://oneapi-src.github.io/oneTBB/main/tbb_userguide/Concurrent_Queue_Classes.html. On a healthy system with optimized Falco rules, the queue should not fill up. If it does, it is most likely happening due to the entire event flow being too slow, indicating that the server is under heavy load. `capacity`: the maximum number of items allowed in the queue is determined by this value. Setting the value to 0 (which is the default) is equivalent to keeping the queue unbounded. In other words, when this configuration is set to 0, the number of allowed items is effectively set to the largest possible long value, disabling this setting. In the case of an unbounded queue, if the available memory on the system is consumed, the Falco process would be OOM killed. When using this option and setting the capacity, the current event would be dropped, and the event loop would continue. This behavior mirrors kernel-side event drops when the buffer between kernel space and user space is full. | @@ -598,8 +662,6 @@ The following table lists the main configurable parameters of the falco chart v3 | falco.rule_matching | string | `"first"` | | | falco.rules_file | list | `["/etc/falco/falco_rules.yaml","/etc/falco/falco_rules.local.yaml","/etc/falco/rules.d"]` | The location of the rules files that will be consumed by Falco. | | falco.stdout_output | object | `{"enabled":true}` | Redirect logs to standard output. | -| falco.syscall_buf_size_preset | int | `4` | - [Suggestions] The buffer size was previously fixed at 8 MB (index 4). You now have the option to adjust the size based on your needs. Increasing the size, such as to 16 MB (index 5), can reduce syscall drops in heavy production systems, but may impact performance. Decreasing the size can speed up the system but may increase syscall drops. It's important to note that the buffer size is mapped twice in the process' virtual memory, so a buffer of 8 MB will result in a 16 MB area in virtual memory. Use this parameter with caution and only modify it if the default size is not suitable for your use case. | -| falco.syscall_drop_failed_exit | bool | `false` | Enabling this option in Falco allows it to drop failed system call exit events in the kernel driver before pushing them onto the ring buffer. This optimization can result in lower CPU usage and more efficient utilization of the ring buffer, potentially reducing the number of event losses. However, it is important to note that enabling this option also means sacrificing some visibility into the system. | | falco.syscall_event_drops | object | `{"actions":["log","alert"],"max_burst":1,"rate":0.03333,"simulate_drops":false,"threshold":0.1}` | For debugging/testing it is possible to simulate the drops using the `simulate_drops: true`. In this case the threshold does not apply. | | falco.syscall_event_drops.actions | list | `["log","alert"]` | Actions to be taken when system calls were dropped from the circular buffer. | | falco.syscall_event_drops.max_burst | int | `1` | Max burst of messages emitted. | @@ -611,46 +673,40 @@ The following table lists the main configurable parameters of the falco chart v3 | falco.time_format_iso_8601 | bool | `false` | When enabled, Falco will display log and output messages with times in the ISO 8601 format. By default, times are shown in the local time zone determined by the /etc/localtime configuration. | | falco.watch_config_files | bool | `true` | Watch config file and rules files for modification. When a file is modified, Falco will propagate new config, by reloading itself. | | falco.webserver | object | `{"enabled":true,"k8s_healthz_endpoint":"/healthz","listen_port":8765,"ssl_certificate":"/etc/falco/falco.pem","ssl_enabled":false,"threadiness":0}` | Falco supports an embedded webserver that runs within the Falco process, providing a lightweight and efficient way to expose web-based functionalities without the need for an external web server. The following endpoints are exposed: - /healthz: designed to be used for checking the health and availability of the Falco application (the name of the endpoint is configurable). - /versions: responds with a JSON object containing the version numbers of the internal Falco components (similar output as `falco --version -o json_output=true`). Please note that the /versions endpoint is particularly useful for other Falco services, such as `falcoctl`, to retrieve information about a running Falco instance. If you plan to use `falcoctl` locally or with Kubernetes, make sure the Falco webserver is enabled. The behavior of the webserver can be controlled with the following options, which are enabled by default: The `ssl_certificate` option specifies a combined SSL certificate and corresponding key that are contained in a single file. You can generate a key/cert as follows: $ openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem $ cat certificate.pem key.pem > falco.pem $ sudo cp falco.pem /etc/falco/falco.pem | -| falcoctl.artifact.follow | object | `{"args":["--verbose"],"enabled":true,"env":[],"mounts":{"volumeMounts":[]},"resources":{},"securityContext":{}}` | Runs "falcoctl artifact follow" command as a sidecar container. It is used to automatically check for updates given a list of artifacts. If an update is found it downloads and installs it in a shared folder (emptyDir) that is accessible by Falco. Rulesfiles are automatically detected and loaded by Falco once they are installed in the correct folder by falcoctl. To prevent new versions of artifacts from breaking Falco, the tool checks if it is compatible with the running version of Falco before installing it. | -| falcoctl.artifact.follow.args | list | `["--verbose"]` | Arguments to pass to the falcoctl-artifact-follow sidecar container. | +| falcoctl.artifact.follow | object | `{"args":["--log-format=json"],"enabled":true,"env":[],"mounts":{"volumeMounts":[]},"resources":{},"securityContext":{}}` | Runs "falcoctl artifact follow" command as a sidecar container. It is used to automatically check for updates given a list of artifacts. If an update is found it downloads and installs it in a shared folder (emptyDir) that is accessible by Falco. Rulesfiles are automatically detected and loaded by Falco once they are installed in the correct folder by falcoctl. To prevent new versions of artifacts from breaking Falco, the tool checks if it is compatible with the running version of Falco before installing it. | +| falcoctl.artifact.follow.args | list | `["--log-format=json"]` | Arguments to pass to the falcoctl-artifact-follow sidecar container. | | falcoctl.artifact.follow.env | list | `[]` | Extra environment variables that will be pass onto falcoctl-artifact-follow sidecar container. | | falcoctl.artifact.follow.mounts | object | `{"volumeMounts":[]}` | A list of volume mounts you want to add to the falcoctl-artifact-follow sidecar container. | | falcoctl.artifact.follow.resources | object | `{}` | Resources requests and limits for the falcoctl-artifact-follow sidecar container. | | falcoctl.artifact.follow.securityContext | object | `{}` | Security context for the falcoctl-artifact-follow sidecar container. | -| falcoctl.artifact.install | object | `{"args":["--verbose"],"enabled":true,"env":[],"mounts":{"volumeMounts":[]},"resources":{},"securityContext":{}}` | Runs "falcoctl artifact install" command as an init container. It is used to install artfacts before Falco starts. It provides them to Falco by using an emptyDir volume. | -| falcoctl.artifact.install.args | list | `["--verbose"]` | Arguments to pass to the falcoctl-artifact-install init container. | +| falcoctl.artifact.install | object | `{"args":["--log-format=json"],"enabled":true,"env":[],"mounts":{"volumeMounts":[]},"resources":{},"securityContext":{}}` | Runs "falcoctl artifact install" command as an init container. It is used to install artfacts before Falco starts. It provides them to Falco by using an emptyDir volume. | +| falcoctl.artifact.install.args | list | `["--log-format=json"]` | Arguments to pass to the falcoctl-artifact-install init container. | | falcoctl.artifact.install.env | list | `[]` | Extra environment variables that will be pass onto falcoctl-artifact-install init container. | | falcoctl.artifact.install.mounts | object | `{"volumeMounts":[]}` | A list of volume mounts you want to add to the falcoctl-artifact-install init container. | | falcoctl.artifact.install.resources | object | `{}` | Resources requests and limits for the falcoctl-artifact-install init container. | | falcoctl.artifact.install.securityContext | object | `{}` | Security context for the falcoctl init container. | -| falcoctl.config | object | `{"artifact":{"allowedTypes":["rulesfile"],"follow":{"every":"6h","falcoversions":"http://localhost:8765/versions","pluginsDir":"/plugins","refs":["falco-rules:2"],"rulesfilesDir":"/rulesfiles"},"install":{"pluginsDir":"/plugins","refs":["falco-rules:2"],"resolveDeps":false,"rulesfilesDir":"/rulesfiles"}},"indexes":[{"name":"falcosecurity","url":"https://falcosecurity.github.io/falcoctl/index.yaml"}]}` | Configuration file of the falcoctl tool. It is saved in a configmap and mounted on the falcotl containers. | -| falcoctl.config.artifact | object | `{"allowedTypes":["rulesfile"],"follow":{"every":"6h","falcoversions":"http://localhost:8765/versions","pluginsDir":"/plugins","refs":["falco-rules:2"],"rulesfilesDir":"/rulesfiles"},"install":{"pluginsDir":"/plugins","refs":["falco-rules:2"],"resolveDeps":false,"rulesfilesDir":"/rulesfiles"}}` | Configuration used by the artifact commands. | -| falcoctl.config.artifact.allowedTypes | list | `["rulesfile"]` | List of artifact types that falcoctl will handle. If the configured refs resolves to an artifact whose type is not contained in the list it will refuse to downloade and install that artifact. | +| falcoctl.config | object | `{"artifact":{"allowedTypes":["rulesfile","plugin"],"follow":{"every":"6h","falcoversions":"http://localhost:8765/versions","pluginsDir":"/plugins","refs":["falco-rules:3"],"rulesfilesDir":"/rulesfiles"},"install":{"pluginsDir":"/plugins","refs":["falco-rules:3"],"resolveDeps":true,"rulesfilesDir":"/rulesfiles"}},"indexes":[{"name":"falcosecurity","url":"https://falcosecurity.github.io/falcoctl/index.yaml"}]}` | Configuration file of the falcoctl tool. It is saved in a configmap and mounted on the falcotl containers. | +| falcoctl.config.artifact | object | `{"allowedTypes":["rulesfile","plugin"],"follow":{"every":"6h","falcoversions":"http://localhost:8765/versions","pluginsDir":"/plugins","refs":["falco-rules:3"],"rulesfilesDir":"/rulesfiles"},"install":{"pluginsDir":"/plugins","refs":["falco-rules:3"],"resolveDeps":true,"rulesfilesDir":"/rulesfiles"}}` | Configuration used by the artifact commands. | +| falcoctl.config.artifact.allowedTypes | list | `["rulesfile","plugin"]` | List of artifact types that falcoctl will handle. If the configured refs resolves to an artifact whose type is not contained in the list it will refuse to downloade and install that artifact. | | falcoctl.config.artifact.follow.every | string | `"6h"` | How often the tool checks for new versions of the followed artifacts. | | falcoctl.config.artifact.follow.falcoversions | string | `"http://localhost:8765/versions"` | HTTP endpoint that serves the api versions of the Falco instance. It is used to check if the new versions are compatible with the running Falco instance. | | falcoctl.config.artifact.follow.pluginsDir | string | `"/plugins"` | See the fields of the artifact.install section. | -| falcoctl.config.artifact.follow.refs | list | `["falco-rules:2"]` | List of artifacts to be followed by the falcoctl sidecar container. | +| falcoctl.config.artifact.follow.refs | list | `["falco-rules:3"]` | List of artifacts to be followed by the falcoctl sidecar container. | | falcoctl.config.artifact.follow.rulesfilesDir | string | `"/rulesfiles"` | See the fields of the artifact.install section. | | falcoctl.config.artifact.install.pluginsDir | string | `"/plugins"` | Same as the one above but for the artifacts. | -| falcoctl.config.artifact.install.refs | list | `["falco-rules:2"]` | List of artifacts to be installed by the falcoctl init container. | -| falcoctl.config.artifact.install.resolveDeps | bool | `false` | Do not resolve the depenencies for artifacts. By default is true, but for our use case we disable it. | +| falcoctl.config.artifact.install.refs | list | `["falco-rules:3"]` | List of artifacts to be installed by the falcoctl init container. | +| falcoctl.config.artifact.install.resolveDeps | bool | `true` | Resolve the dependencies for artifacts. | | falcoctl.config.artifact.install.rulesfilesDir | string | `"/rulesfiles"` | Directory where the rulesfiles are saved. The path is relative to the container, which in this case is an emptyDir mounted also by the Falco pod. | | falcoctl.config.indexes | list | `[{"name":"falcosecurity","url":"https://falcosecurity.github.io/falcoctl/index.yaml"}]` | List of indexes that falcoctl downloads and uses to locate and download artiafcts. For more info see: https://github.com/falcosecurity/falcoctl/blob/main/proposals/20220916-rules-and-plugin-distribution.md#index-file-overview | | falcoctl.image.pullPolicy | string | `"IfNotPresent"` | The image pull policy. | | falcoctl.image.registry | string | `"docker.io"` | The image registry to pull from. | | falcoctl.image.repository | string | `"falcosecurity/falcoctl"` | The image repository to pull from. | -| falcoctl.image.tag | string | `"0.6.2"` | The image tag to pull. | +| falcoctl.image.tag | string | `"0.7.1"` | The image tag to pull. | | falcosidekick | object | `{"enabled":false,"fullfqdn":false,"listenPort":""}` | For configuration values, see https://github.com/falcosecurity/charts/blob/master/falcosidekick/values.yaml | | falcosidekick.enabled | bool | `false` | Enable falcosidekick deployment. | | falcosidekick.fullfqdn | bool | `false` | Enable usage of full FQDN of falcosidekick service (useful when a Proxy is used). | | falcosidekick.listenPort | string | `""` | Listen port. Default value: 2801 | | fullnameOverride | string | `""` | Same as nameOverride but for the fullname. | -| gvisor | object | `{"enabled":false,"runsc":{"config":"/run/containerd/runsc/config.toml","path":"/home/containerd/usr/local/sbin","root":"/run/containerd/runsc"}}` | Gvisor configuration. Based on your system you need to set the appropriate values. Please, rembember to add pod tolerations and affinities in order to schedule the Falco pods in the gVisor enabled nodes. | -| gvisor.enabled | bool | `false` | Set it to true if you want to deploy Falco with gVisor support. | -| gvisor.runsc | object | `{"config":"/run/containerd/runsc/config.toml","path":"/home/containerd/usr/local/sbin","root":"/run/containerd/runsc"}` | Runsc container runtime configuration. Falco needs to interact with it in order to intercept the activity of the sandboxed pods. | -| gvisor.runsc.config | string | `"/run/containerd/runsc/config.toml"` | Absolute path of the `runsc` configuration file, used by Falco to set its configuration and make aware `gVisor` of its presence. | -| gvisor.runsc.path | string | `"/home/containerd/usr/local/sbin"` | Absolute path of the `runsc` binary in the k8s nodes. | -| gvisor.runsc.root | string | `"/run/containerd/runsc"` | Absolute path of the root directory of the `runsc` container runtime. It is of vital importance for Falco since `runsc` stores there the information of the workloads handled by it; | | healthChecks | object | `{"livenessProbe":{"initialDelaySeconds":60,"periodSeconds":15,"timeoutSeconds":5},"readinessProbe":{"initialDelaySeconds":30,"periodSeconds":15,"timeoutSeconds":5}}` | Parameters used | | healthChecks.livenessProbe.initialDelaySeconds | int | `60` | Tells the kubelet that it should wait X seconds before performing the first probe. | | healthChecks.livenessProbe.periodSeconds | int | `15` | Specifies that the kubelet should perform the check every x seconds. | @@ -673,13 +729,9 @@ The following table lists the main configurable parameters of the falco chart v3 | podLabels | object | `{}` | Add additional pod labels | | podPriorityClassName | string | `nil` | Set pod priorityClassName | | podSecurityContext | object | `{}` | Set securityContext for the pods These security settings are overriden by the ones specified for the specific containers when there is overlap. | -| rbac.create | bool | `true` | | | resources.limits | object | `{"cpu":"1000m","memory":"1024Mi"}` | Maximum amount of resources that Falco container could get. If you are enabling more than one source in falco, than consider to increase the cpu limits. | | resources.requests | object | `{"cpu":"100m","memory":"512Mi"}` | Although resources needed are subjective on the actual workload we provide a sane defaults ones. If you have more questions or concerns, please refer to #falco slack channel for more info about it. | | scc.create | bool | `true` | Create OpenShift's Security Context Constraint. | -| serviceAccount.annotations | object | `{}` | Annotations to add to the service account. | -| serviceAccount.create | bool | `true` | Specifies whether a service account should be created. | -| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | | services | string | `nil` | Network services configuration (scenario requirement) Add here your services to be deployed together with Falco. | | tolerations | list | `[{"effect":"NoSchedule","key":"node-role.kubernetes.io/master"},{"effect":"NoSchedule","key":"node-role.kubernetes.io/control-plane"}]` | Tolerations to allow Falco to run on Kubernetes masters. | | tty | bool | `false` | Attach the Falco process to a tty inside the container. Needed to flush Falco logs as soon as they are emitted. Set it to "true" when you need the Falco logs to be immediately displayed. | From 1fc23ac133daea274445e4715de951ae63d61520 Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Fri, 12 Jan 2024 11:47:23 +0100 Subject: [PATCH 13/19] update(falco): bump chart and app versions Signed-off-by: Aldo Lacuku --- charts/falco/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/falco/Chart.yaml b/charts/falco/Chart.yaml index 6f128c77a..47968fd19 100644 --- a/charts/falco/Chart.yaml +++ b/charts/falco/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: falco -version: 3.8.7 -appVersion: "0.36.2" +version: 4.0.0 +appVersion: "0.37.0" description: Falco keywords: - monitoring From 6e1f38a4e92147b1b09f37018e78a399642a33db Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Fri, 12 Jan 2024 11:48:22 +0100 Subject: [PATCH 14/19] update(falco): bump falcoctl version to 0.7.1 Signed-off-by: Aldo Lacuku --- charts/falco/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/falco/values.yaml b/charts/falco/values.yaml index b628a3f53..b2590d4ca 100644 --- a/charts/falco/values.yaml +++ b/charts/falco/values.yaml @@ -363,7 +363,7 @@ falcoctl: # -- The image repository to pull from. repository: falcosecurity/falcoctl # -- The image tag to pull. - tag: "main" + tag: "0.7.1" artifact: # -- Runs "falcoctl artifact install" command as an init container. It is used to install artfacts before # Falco starts. It provides them to Falco by using an emptyDir volume. From 69c6e68c56f67511f5126002e77a4d0162d665ba Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Fri, 12 Jan 2024 12:44:28 +0100 Subject: [PATCH 15/19] update(falco): disable k8s-metacollector by default Signed-off-by: Aldo Lacuku --- charts/falco/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/falco/values.yaml b/charts/falco/values.yaml index b2590d4ca..ef2c41900 100644 --- a/charts/falco/values.yaml +++ b/charts/falco/values.yaml @@ -277,7 +277,7 @@ collectors: # https://github.com/falcosecurity/charts/tree/master/charts/k8s-metacollector # When this option is disabled, Falco falls back to the container annotations to grab the metadata. # In such a case, only the ID, name, namespace, labels of the pod will be available. - enabled: true + enabled: false # --pluginRef is the OCI reference for the k8smeta plugin. It could be a full reference such as: # "ghcr.io/falcosecurity/plugins/plugin/k8smeta:0.1.0". Or just name + tag: k8smeta:0.1.0. pluginRef: "ghcr.io/falcosecurity/plugins/plugin/k8smeta:0.1.0" From 4e6787f4c6ade7af473b698531c8ee783fcbecc8 Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Fri, 12 Jan 2024 12:49:56 +0100 Subject: [PATCH 16/19] update(falco/tests): use falco with k8saudit plugin for testing Signed-off-by: Aldo Lacuku --- tests/falco-test-ci.yaml | 63 +++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/tests/falco-test-ci.yaml b/tests/falco-test-ci.yaml index db2c7ad80..dfc9e48aa 100644 --- a/tests/falco-test-ci.yaml +++ b/tests/falco-test-ci.yaml @@ -1,19 +1,56 @@ # CI values for Falco. # To deploy Falco on CI we need to set an argument to bypass the installation # of the kernel module, so we bypass that. -extra: - args: - - --userspace - -falco: - grpc: - enabled: true - grpc_output: - enabled: true - +# -- Disable the drivers since we want to deploy only the k8saudit plugin. driver: enabled: false -# enforce /proc mounting since Falco still tries to scan it -mounts: - enforceProcMount: true +# -- Disable the collectors, no syscall events to enrich with metadata. +collectors: + enabled: false + +falcoctl: + artifact: + install: + # -- Enable the init container. + enabled: true + follow: + # -- Enable the sidecar container. + enabled: true + config: + artifact: + install: + # -- Resolve the dependencies for artifacts. + resolveDeps: true + # -- List of artifacts to be installed by the falcoctl init container. + refs: [k8saudit-rules:0.6] + follow: + # -- List of artifacts to be followed by the falcoctl sidecar container. + refs: [k8saudit-rules:0.6] + +services: + - name: k8saudit-webhook + type: NodePort + ports: + - port: 9765 # See plugin open_params + nodePort: 30007 + protocol: TCP + +falco: + rules_file: + - /etc/falco/k8s_audit_rules.yaml + - /etc/falco/rules.d + plugins: + - name: k8saudit + library_path: libk8saudit.so + init_config: + "" + # maxEventBytes: 1048576 + # sslCertificate: /etc/falco/falco.pem + open_params: "http://:9765/k8s-audit" + - name: json + library_path: libjson.so + init_config: "" + # Plugins that Falco will load. Note: the same plugins are installed by the falcoctl-artifact-install init container. + load_plugins: [k8saudit, json] + From 83410dc9a1cf6885eef7575c062e82ca3af514ab Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Tue, 23 Jan 2024 11:43:47 +0100 Subject: [PATCH 17/19] update(falco/k8saudit): bump k8saudit plugin and rulesfile to v0.7.0 Signed-off-by: Aldo Lacuku --- charts/falco/values-k8saudit.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/charts/falco/values-k8saudit.yaml b/charts/falco/values-k8saudit.yaml index e89c52517..21d93236d 100644 --- a/charts/falco/values-k8saudit.yaml +++ b/charts/falco/values-k8saudit.yaml @@ -26,13 +26,11 @@ falcoctl: config: artifact: install: - # -- Resolve the dependencies for artifacts. - resolveDeps: true # -- List of artifacts to be installed by the falcoctl init container. - refs: [k8saudit-rules:0.6] + refs: [k8saudit-rules:0.7] follow: # -- List of artifacts to be followed by the falcoctl sidecar container. - refs: [k8saudit-rules:0.6] + refs: [k8saudit-rules:0.7] services: - name: k8saudit-webhook From ff481166afa16b36d8e39d384efcf20a3090ad14 Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Wed, 24 Jan 2024 16:48:48 +0100 Subject: [PATCH 18/19] fix(falco): use alias for kmod and modern_ebpf drivers Signed-off-by: Aldo Lacuku --- charts/falco/templates/pod-template.tpl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/charts/falco/templates/pod-template.tpl b/charts/falco/templates/pod-template.tpl index 7672e8980..8a5b1a8f9 100644 --- a/charts/falco/templates/pod-template.tpl +++ b/charts/falco/templates/pod-template.tpl @@ -140,7 +140,7 @@ spec: name: etc-fs readOnly: true {{- end -}} - {{- if and .Values.driver.enabled (eq .Values.driver.kind "kmod") }} + {{- if and .Values.driver.enabled (or (eq .Values.driver.kind "kmod") (eq .Values.driver.kind "module")) }} - mountPath: /host/dev name: dev-fs readOnly: true @@ -238,7 +238,7 @@ spec: hostPath: path: /etc {{- end }} - {{- if and .Values.driver.enabled (eq .Values.driver.kind "kmod") }} + {{- if and .Values.driver.enabled (or (eq .Values.driver.kind "kmod") (eq .Values.driver.kind "module")) }} - name: dev-fs hostPath: path: /dev @@ -349,7 +349,7 @@ spec: securityContext: {{- if .Values.driver.loader.initContainer.securityContext }} {{- toYaml .Values.driver.loader.initContainer.securityContext | nindent 4 }} - {{- else if eq .Values.driver.kind "kmod" }} + {{- else if (or (eq .Values.driver.kind "kmod") (eq .Values.driver.kind "module")) }} privileged: true {{- end }} volumeMounts: @@ -378,7 +378,7 @@ spec: {{- define "falco.securityContext" -}} {{- $securityContext := dict -}} {{- if .Values.driver.enabled -}} - {{- if eq .Values.driver.kind "kmod" -}} + {{- if (or (eq .Values.driver.kind "kmod") (eq .Values.driver.kind "module")) -}} {{- $securityContext := set $securityContext "privileged" true -}} {{- end -}} {{- if eq .Values.driver.kind "ebpf" -}} @@ -388,7 +388,7 @@ spec: {{- $securityContext := set $securityContext "privileged" true -}} {{- end -}} {{- end -}} - {{- if eq .Values.driver.kind "modern_ebpf" -}} + {{- if (or (eq .Values.driver.kind "modern_ebpf") (eq .Values.driver.kind "modern-bpf")) -}} {{- if .Values.driver.modernEbpf.leastPrivileged -}} {{- $securityContext := set $securityContext "capabilities" (dict "add" (list "BPF" "SYS_RESOURCE" "PERFMON" "SYS_PTRACE")) -}} {{- else -}} From ec98464910a08883fc1ceb12d65b25f6aeccb366 Mon Sep 17 00:00:00 2001 From: Aldo Lacuku Date: Mon, 29 Jan 2024 09:39:05 +0100 Subject: [PATCH 19/19] update(falco): bump rules in preset values file Signed-off-by: Aldo Lacuku --- charts/falco/values-syscall-k8saudit.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/charts/falco/values-syscall-k8saudit.yaml b/charts/falco/values-syscall-k8saudit.yaml index 33b1d45bf..91dcdbd19 100644 --- a/charts/falco/values-syscall-k8saudit.yaml +++ b/charts/falco/values-syscall-k8saudit.yaml @@ -29,13 +29,11 @@ falcoctl: config: artifact: install: - # -- Resolve the dependencies for artifacts. - resolveDeps: true # -- List of artifacts to be installed by the falcoctl init container. - refs: [falco-rules:2, k8saudit-rules:0.6] + refs: [falco-rules:3, k8saudit-rules:0.7] follow: # -- List of artifacts to be followed by the falcoctl sidecar container. - refs: [falco-rules:2, k8saudit-rules:0.6] + refs: [falco-rules:3, k8saudit-rules:0.7] services: - name: k8saudit-webhook