diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index c516b031..b7a45299 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -39,6 +39,8 @@ Please remove the leading whitespace before the `/kind <>` you uncommented. > /area falcosidekick-chart +> /area falco-talon + > /area event-generator-chart > /area k8s-metacollector diff --git a/charts/falco-talon/CHANGELOG.md b/charts/falco-talon/CHANGELOG.md new file mode 100644 index 00000000..388a49c0 --- /dev/null +++ b/charts/falco-talon/CHANGELOG.md @@ -0,0 +1,13 @@ +# Change Log + +This file documents all notable changes to Falco Talon Helm Chart. The release +numbering uses [semantic versioning](http://semver.org). + +## 0.1.1 - 2024-10-01 + +- Use version `0.1.1` +- Fix wrong port for the `serviceMonitor` + +## 0.1.0 - 2024-09-05 + +- First release diff --git a/charts/falco-talon/Chart.yaml b/charts/falco-talon/Chart.yaml new file mode 100644 index 00000000..da061e5d --- /dev/null +++ b/charts/falco-talon/Chart.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +appVersion: 0.1.1 +description: React to the events from Falco +name: falco-talon +version: 0.1.1 +keywords: + - falco + - monitoring + - security + - response-engine +home: https://github.com/falco-talon/falco-talon +sources: + - https://github.com/falco-talon/falco-talon +maintainers: + - name: Issif + email: issif+github@gadz.org diff --git a/charts/falco-talon/README.gotmpl b/charts/falco-talon/README.gotmpl new file mode 100644 index 00000000..d2ef61ca --- /dev/null +++ b/charts/falco-talon/README.gotmpl @@ -0,0 +1,61 @@ +# Falco Talon + +![release](https://flat.badgen.net/github/release/falco-talon/falco-talon/latest?color=green) ![last commit](https://flat.badgen.net/github/last-commit/falco-talon/falco-talon) ![licence](https://flat.badgen.net/badge/license/MIT/blue) ![docker pulls](https://flat.badgen.net/docker/pulls/issif/falco-talon?icon=docker) + +## Description + +`Falco Talon` is a Response Engine for managing threats in your Kubernetes. It enhances the solutions proposed by the Falco community with a no-code tailor made solution. With easy rules, you can react to `events` from [`Falco`](https://falco.org) in milliseconds. + +## Architecture + +`Falco Talon` can receive the `events` from [`Falco`](https://falco.org) or [`Falcosidekick`](https://github.com/falco-talon/falcosidekick): + +## Documentation + +The full documentation is available on its own website: [https://docs.falco-talon.org/docs](https://docs.falco-talon.org/docs). + +## Helm + +The helm chart is available in the folder [`deployment/helm`](https://github.com/falco-talon/falco-talon/tree/main/deployment/helm). + +Two config files are provided: +* `values.yaml` allows you to configure `Falcon Talon` and the deployment +* `rules.yaml` contains rules to set + +### Install Falco Talon + +```shell +git clone https://github.com/falco-talon/falco-talon.git +cd deployment/helm/ +helm upgrade -i falco-talon . -n falco --create-namespace -f values.yaml +``` + +### Uninstall Falco Talon + +``` +helm delete falco-talon -n falco +```` + +### Configuration + +{{ template "chart.valuesSection" . }} + +## Configure Falcosidekick + +Once you have installed `Falco Talon` with Helm, you need to connect `Falcosidekick` by adding the flag `--set falcosidekick.config.webhook.address=http://falco-talon:2803` + +```shell +helm upgrade -i falco falco-talon/falco --namespace falco \ + --create-namespace \ + --set tty=true \ + --set falcosidekick.enabled=true \ + --set falcosidekick.config.talon.address=http://falco-talon:2803 +``` + +## License + +Falco Talon is licensed to you under the **Apache 2.0** open source license. + +## Author + +Thomas Labarussias (https://github.com/Issif) \ No newline at end of file diff --git a/charts/falco-talon/README.md b/charts/falco-talon/README.md new file mode 100644 index 00000000..354a8ea0 --- /dev/null +++ b/charts/falco-talon/README.md @@ -0,0 +1,160 @@ +# Falco Talon + +![release](https://flat.badgen.net/github/release/falco-talon/falco-talon/latest?color=green) ![last commit](https://flat.badgen.net/github/last-commit/falco-talon/falco-talon) ![licence](https://flat.badgen.net/badge/license/MIT/blue) ![docker pulls](https://flat.badgen.net/docker/pulls/issif/falco-talon?icon=docker) + +## Description + +`Falco Talon` is a Response Engine for managing threats in your Kubernetes. It enhances the solutions proposed by the Falco community with a no-code tailor made solution. With easy rules, you can react to `events` from [`Falco`](https://falco.org) in milliseconds. + +## Architecture + +`Falco Talon` can receive the `events` from [`Falco`](https://falco.org) or [`Falcosidekick`](https://github.com/falco-talon/falcosidekick): + +## Documentation + +The full documentation is available on its own website: [https://docs.falco-talon.org/docs](https://docs.falco-talon.org/docs). + +## Helm + +The helm chart is available in the folder [`deployment/helm`](https://github.com/falco-talon/falco-talon/tree/main/deployment/helm). + +Two config files are provided: +* `values.yaml` allows you to configure `Falcon Talon` and the deployment +* `rules.yaml` contains rules to set + +### Install Falco Talon + +```shell +git clone https://github.com/falco-talon/falco-talon.git +cd deployment/helm/ +helm upgrade -i falco-talon . -n falco --create-namespace -f values.yaml +``` + +### Uninstall Falco Talon + +``` +helm delete falco-talon -n falco +```` + +### Configuration + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | affinity | +| config | object | `{"aws":{"accesKey":"","externalId":"","region":"","roleArn":"","secretKey":""},"deduplication":{"leaderElection":true,"timeWindowSeconds":5},"defaultNotifiers":["k8sevents"],"listenAddress":"0.0.0.0","listenPort":2803,"minio":{"accessKey":"","endpoint":"","secretKey":"","useSsl":false},"notifiers":{"elasticsearch":{"createIndexTemplate":true,"numberOfReplicas":1,"numberOfShards":1,"url":""},"loki":{"apiKey":"","customHeaders":[],"hostPort":"","tenant":"","user":""},"slack":{"footer":"https://github.com/falco-talon/falco-talon","format":"long","icon":"https://upload.wikimedia.org/wikipedia/commons/2/26/Circaetus_gallicus_claw.jpg","username":"Falco Talon","webhookUrl":""},"smtp":{"format":"html","from":"","hostPort":"","password":"","tls":false,"to":"","user":""},"webhook":{"url":""}},"otel":{"collectorEndpoint":"","collectorPort":4317,"collectorUseInsecureGrpc":false,"metricsEnabled":false,"tracesEnabled":false},"printAllEvents":false,"rulesFiles":["rules.yaml","rules_override.yaml"],"watchRules":true}` | config of Falco Talon (See https://docs.falco-talon.org/docs/configuration/) | +| config.aws | object | `{"accesKey":"","externalId":"","region":"","roleArn":"","secretKey":""}` | aws | +| config.aws.accesKey | string | `""` | access key (if not specified, default access_key from provider credential chain will be used) | +| config.aws.externalId | string | `""` | external id | +| config.aws.region | string | `""` | region (if not specified, default region from provider credential chain will be used) | +| config.aws.roleArn | string | `""` | role arn | +| config.aws.secretKey | string | `""` | secret key (if not specified, default secret_key from provider credential chain will be used) | +| config.deduplication | object | `{"leaderElection":true,"timeWindowSeconds":5}` | deduplication of the Falco events | +| config.deduplication.leaderElection | bool | `true` | enable the leader election for cluster mode | +| config.deduplication.timeWindowSeconds | int | `5` | duration in seconds for the deduplication time window | +| config.defaultNotifiers | list | `["k8sevents"]` | default notifiers for all rules | +| config.listenAddress | string | `"0.0.0.0"` | listen address | +| config.listenPort | int | `2803` | listen port | +| config.minio | object | `{"accessKey":"","endpoint":"","secretKey":"","useSsl":false}` | minio | +| config.minio.accessKey | string | `""` | access key | +| config.minio.endpoint | string | `""` | endpoint | +| config.minio.secretKey | string | `""` | secret key | +| config.minio.useSsl | bool | `false` | use ssl | +| config.notifiers | object | `{"elasticsearch":{"createIndexTemplate":true,"numberOfReplicas":1,"numberOfShards":1,"url":""},"loki":{"apiKey":"","customHeaders":[],"hostPort":"","tenant":"","user":""},"slack":{"footer":"https://github.com/falco-talon/falco-talon","format":"long","icon":"https://upload.wikimedia.org/wikipedia/commons/2/26/Circaetus_gallicus_claw.jpg","username":"Falco Talon","webhookUrl":""},"smtp":{"format":"html","from":"","hostPort":"","password":"","tls":false,"to":"","user":""},"webhook":{"url":""}}` | notifiers (See https://docs.falco-talon.org/docs/notifiers/list/ for the settings) | +| config.notifiers.elasticsearch | object | `{"createIndexTemplate":true,"numberOfReplicas":1,"numberOfShards":1,"url":""}` | elasticsearch | +| config.notifiers.elasticsearch.createIndexTemplate | bool | `true` | create the index template | +| config.notifiers.elasticsearch.numberOfReplicas | int | `1` | number of replicas | +| config.notifiers.elasticsearch.numberOfShards | int | `1` | number of shards | +| config.notifiers.elasticsearch.url | string | `""` | url | +| config.notifiers.loki | object | `{"apiKey":"","customHeaders":[],"hostPort":"","tenant":"","user":""}` | loki | +| config.notifiers.loki.apiKey | string | `""` | api key | +| config.notifiers.loki.customHeaders | list | `[]` | custom headers | +| config.notifiers.loki.hostPort | string | `""` | host:port | +| config.notifiers.loki.tenant | string | `""` | tenant | +| config.notifiers.loki.user | string | `""` | user | +| config.notifiers.slack | object | `{"footer":"https://github.com/falco-talon/falco-talon","format":"long","icon":"https://upload.wikimedia.org/wikipedia/commons/2/26/Circaetus_gallicus_claw.jpg","username":"Falco Talon","webhookUrl":""}` | slack | +| config.notifiers.slack.footer | string | `"https://github.com/falco-talon/falco-talon"` | footer | +| config.notifiers.slack.format | string | `"long"` | format | +| config.notifiers.slack.icon | string | `"https://upload.wikimedia.org/wikipedia/commons/2/26/Circaetus_gallicus_claw.jpg"` | icon | +| config.notifiers.slack.username | string | `"Falco Talon"` | username | +| config.notifiers.slack.webhookUrl | string | `""` | webhook url | +| config.notifiers.smtp | object | `{"format":"html","from":"","hostPort":"","password":"","tls":false,"to":"","user":""}` | smtp | +| config.notifiers.smtp.format | string | `"html"` | format | +| config.notifiers.smtp.from | string | `""` | from | +| config.notifiers.smtp.hostPort | string | `""` | host:port | +| config.notifiers.smtp.password | string | `""` | password | +| config.notifiers.smtp.tls | bool | `false` | enable tls | +| config.notifiers.smtp.to | string | `""` | to | +| config.notifiers.smtp.user | string | `""` | user | +| config.notifiers.webhook | object | `{"url":""}` | webhook | +| config.notifiers.webhook.url | string | `""` | url | +| config.otel | object | `{"collectorEndpoint":"","collectorPort":4317,"collectorUseInsecureGrpc":false,"metricsEnabled":false,"tracesEnabled":false}` | open telemetry parameters | +| config.otel.collectorEndpoint | string | `""` | collector endpoint | +| config.otel.collectorPort | int | `4317` | collector port | +| config.otel.collectorUseInsecureGrpc | bool | `false` | use insecure grpc | +| config.otel.metricsEnabled | bool | `false` | enable otel metrics | +| config.otel.tracesEnabled | bool | `false` | enable otel traces | +| config.printAllEvents | bool | `false` | print in stdout all received events, not only those which match a rule | +| config.rulesFiles | list | `["rules.yaml","rules_override.yaml"]` | list of rules to load | +| config.watchRules | bool | `true` | auto reload the rules when the files change | +| extraEnv | list | `[{"name":"LOG_LEVEL","value":"warning"}]` | extra env | +| image | object | `{"pullPolicy":"Always","registry":"falco.docker.scarf.sh","repository":"issif/falco-talon","tag":""}` | image parameters | +| image.pullPolicy | string | `"Always"` | The image pull policy | +| image.registry | string | `"falco.docker.scarf.sh"` | The image registry to pull from | +| image.repository | string | `"issif/falco-talon"` | The image repository to pull from | +| image.tag | string | `""` | Override the image tag to pull | +| imagePullSecrets | list | `[]` | one or more secrets to be used when pulling images | +| ingress | object | `{"annotations":{},"enabled":false,"hosts":[{"host":"falco-talon.local","paths":[{"path":"/"}]}],"tls":[]}` | ingress parameters | +| ingress.annotations | object | `{}` | annotations of the ingress | +| ingress.enabled | bool | `false` | enable the ingress | +| ingress.hosts | list | `[{"host":"falco-talon.local","paths":[{"path":"/"}]}]` | hosts | +| ingress.tls | list | `[]` | tls | +| nameOverride | string | `""` | override name | +| nodeSelector | object | `{}` | node selector | +| podAnnotations | object | `{}` | pod annotations | +| podSecurityContext | object | `{"fsGroup":1234,"runAsUser":1234}` | pod security context | +| podSecurityContext.fsGroup | int | `1234` | group | +| podSecurityContext.runAsUser | int | `1234` | user id | +| podSecurityPolicy | object | `{"create":false}` | pod security policy | +| podSecurityPolicy.create | bool | `false` | enable the creation of the PSP | +| priorityClassName | string | `""` | priority class name | +| rbac | object | `{"caliconetworkpolicies":["get","update","patch","create"],"ciliumnetworkpolicies":["get","update","patch","create"],"clusterroles":["get","delete"],"configmaps":["get","delete"],"daemonsets":["get","delete"],"deployments":["get","delete"],"events":["get","update","patch","create"],"leases":["get","update","patch","watch","create"],"namespaces":["get","delete"],"networkpolicies":["get","update","patch","create"],"nodes":["get","update","patch","watch","create"],"pods":["get","update","patch","delete","list"],"podsEphemeralcontainers":["patch","create"],"podsEviction":["get","create"],"podsExec":["get","create"],"podsLog":["get"],"replicasets":["get","delete"],"roles":["get","delete"],"secrets":["get","delete"],"statefulsets":["get","delete"]}` | rbac | +| replicaCount | int | `2` | number of running pods | +| resources | object | `{}` | resources | +| service | object | `{"annotations":{},"port":2803,"type":"ClusterIP"}` | service parameters | +| service.annotations | object | `{}` | annotations of the service | +| service.port | int | `2803` | port of the service | +| service.type | string | `"ClusterIP"` | type of service | +| serviceMonitor | object | `{"additionalLabels":{},"enabled":false,"interval":"30s","path":"/metrics","port":"http","relabelings":[],"scheme":"http","scrapeTimeout":"10s","targetLabels":[],"tlsConfig":{}}` | serviceMonitor holds the configuration for the ServiceMonitor CRD. | +| serviceMonitor.additionalLabels | object | `{}` | additionalLabels specifies labels to be added on the Service Monitor. | +| serviceMonitor.enabled | bool | `false` | enable the deployment of a Service Monitor for the Prometheus Operator. | +| serviceMonitor.interval | string | `"30s"` | interval specifies the time interval at which Prometheus should scrape metrics from the service. | +| serviceMonitor.path | string | `"/metrics"` | path at which the metrics are exposed | +| serviceMonitor.port | string | `"http"` | portname at which the metrics are exposed | +| serviceMonitor.relabelings | list | `[]` | relabelings configures the relabeling rules to apply the target’s metadata labels. | +| serviceMonitor.scheme | string | `"http"` | scheme specifies network protocol used by the metrics endpoint. In this case HTTP. | +| serviceMonitor.scrapeTimeout | string | `"10s"` | scrapeTimeout determines the maximum time Prometheus should wait for a target to respond to a scrape request. If the target does not respond within the specified timeout, Prometheus considers the scrape as failed for that target. | +| serviceMonitor.targetLabels | list | `[]` | targetLabels defines the labels which are transferred from the associated Kubernetes service object onto the ingested metrics. | +| serviceMonitor.tlsConfig | object | `{}` | tlsConfig specifies TLS (Transport Layer Security) configuration for secure communication when scraping metrics from a service. It allows you to define the details of the TLS connection, such as CA certificate, client certificate, and client key. Currently, the k8s-metacollector does not support TLS configuration for the metrics endpoint. | +| tolerations | list | `[]` | tolerations | + +## Configure Falcosidekick + +Once you have installed `Falco Talon` with Helm, you need to connect `Falcosidekick` by adding the flag `--set falcosidekick.config.webhook.address=http://falco-talon:2803` + +```shell +helm upgrade -i falco falco-talon/falco --namespace falco \ + --create-namespace \ + --set tty=true \ + --set falcosidekick.enabled=true \ + --set falcosidekick.config.talon.address=http://falco-talon:2803 +``` + +## License + +Falco Talon is licensed to you under the **Apache 2.0** open source license. + +## Author + +Thomas Labarussias (https://github.com/Issif) \ No newline at end of file diff --git a/charts/falco-talon/rules.yaml b/charts/falco-talon/rules.yaml new file mode 100644 index 00000000..dbc9f315 --- /dev/null +++ b/charts/falco-talon/rules.yaml @@ -0,0 +1,17 @@ +- action: Terminate Pod + actionner: kubernetes:terminate + +- action: Label Pod as Suspicious + actionner: kubernetes:label + parameters: + labels: + analysis/status: "suspicious" + +- rule: Terminal shell in container + match: + rules: + - Terminal shell in container + output_fields: + - k8s.ns.name!=kube-system, k8s.ns.name!=falco + actions: + - action: Label Pod as Suspicious diff --git a/charts/falco-talon/rules_override.yaml b/charts/falco-talon/rules_override.yaml new file mode 100644 index 00000000..a75af42c --- /dev/null +++ b/charts/falco-talon/rules_override.yaml @@ -0,0 +1,6 @@ +- action: Terminate Pod + actionner: kubernetes:terminate + parameters: + ignore_daemonsets: true + ignore_statefulsets: true + grace_period_seconds: 2 \ No newline at end of file diff --git a/charts/falco-talon/templates/_helpers.tpl b/charts/falco-talon/templates/_helpers.tpl new file mode 100644 index 00000000..70e9bb80 --- /dev/null +++ b/charts/falco-talon/templates/_helpers.tpl @@ -0,0 +1,64 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "falco-talon.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "falco-talon.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for ingress. +*/}} +{{- define "falco-talon.ingress.apiVersion" -}} + {{- if and (.Capabilities.APIVersions.Has "networking.k8s.io/v1") (semverCompare ">= 1.19-0" .Capabilities.KubeVersion.Version) -}} + {{- print "networking.k8s.io/v1" -}} + {{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}} + {{- print "networking.k8s.io/v1beta1" -}} + {{- else -}} + {{- print "extensions/v1beta1" -}} + {{- end -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "falco-talon.labels" -}} +helm.sh/chart: {{ include "falco-talon.chart" . }} +app.kubernetes.io/part-of: {{ include "falco-talon.name" . }} +app.kubernetes.io/managed-by: {{ .Release.Name }} +{{ include "falco-talon.selectorLabels" . }} +{{- if .Values.image.tag }} +app.kubernetes.io/version: {{ .Values.image.tag }} +{{- else }} +app.kubernetes.io/version: {{ .Chart.AppVersion }} +{{- end }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "falco-talon.selectorLabels" -}} +app.kubernetes.io/name: {{ include "falco-talon.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Return if ingress is stable. +*/}} +{{- define "falco-talon.ingress.isStable" -}} + {{- eq (include "falco-talon.ingress.apiVersion" .) "networking.k8s.io/v1" -}} +{{- end -}} + +{{/* +Return if ingress supports pathType. +*/}} +{{- define "falco-talon.ingress.supportsPathType" -}} + {{- or (eq (include "falco-talon.ingress.isStable" .) "true") (and (eq (include "falco-talon.ingress.apiVersion" .) "networking.k8s.io/v1beta1") (semverCompare ">= 1.18-0" .Capabilities.KubeVersion.Version)) -}} +{{- end -}} \ No newline at end of file diff --git a/charts/falco-talon/templates/clusterrole.yaml b/charts/falco-talon/templates/clusterrole.yaml new file mode 100644 index 00000000..9f940774 --- /dev/null +++ b/charts/falco-talon/templates/clusterrole.yaml @@ -0,0 +1,18 @@ +{{- if .Values.podSecurityPolicy.create }} +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "falco-talon.name" .}} + labels: + {{- include "falco-talon.labels" . | nindent 4 }} +rules: + - apiGroups: + - policy + resources: + - podsecuritypolicies + resourceNames: + - {{ template "falco-talon.name" . }} + verbs: + - use +{{- end }} \ No newline at end of file diff --git a/charts/falco-talon/templates/configmap.yaml b/charts/falco-talon/templates/configmap.yaml new file mode 100644 index 00000000..fcb0998e --- /dev/null +++ b/charts/falco-talon/templates/configmap.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "falco-talon.name" . }}-rules + labels: + {{- include "falco-talon.labels" . | nindent 4 }} +data: + rules.yaml: |- +{{- range $file := .Values.config.rulesFiles -}} +{{ $fileContent := $.Files.Get . }} +{{- $fileContent | nindent 4 -}} +{{- end -}} diff --git a/charts/falco-talon/templates/deployment.yaml b/charts/falco-talon/templates/deployment.yaml new file mode 100644 index 00000000..f4ac7891 --- /dev/null +++ b/charts/falco-talon/templates/deployment.yaml @@ -0,0 +1,94 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "falco-talon.name" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "falco-talon.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "falco-talon.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + {{- include "falco-talon.labels" . | nindent 8 }} + {{- if .Values.podAnnotations }} + {{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + annotations: + timestamp: {{ now }} + spec: + serviceAccountName: {{ include "falco-talon.name" . }} + {{- if .Values.priorityClassName }} + priorityClassName: "{{ .Values.priorityClassName }}" + {{- end }} + securityContext: + runAsUser: {{ .Values.podSecurityContext.runAsUser }} + fsGroup: {{ .Values.podSecurityContext.fsGroup }} + restartPolicy: Always + containers: + - name: {{ .Chart.Name }} + {{- if .Values.image.registry }} + image: "{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ default .Chart.AppVersion .Values.image.tag }}" + {{- else }} + image: "{{ .Values.image.repository }}:{{ default .Chart.AppVersion .Values.image.tag }}" + {{- end }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: ["server", "-c", "/etc/falco-talon/config.yaml", "-r", "/etc/falco-talon/rules.yaml"] + ports: + - name: http + containerPort: 2803 + protocol: TCP + - name: nats + containerPort: 4222 + protocol: TCP + livenessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 10 + periodSeconds: 5 + readinessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 10 + periodSeconds: 5 + {{- if .Values.extraEnv }} + env: + {{- toYaml .Values.extraEnv | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: "config" + mountPath: "/etc/falco-talon/config.yaml" + subPath: config.yaml + readOnly: true + - name: "rules" + mountPath: "/etc/falco-talon/rules.yaml" + subPath: rules.yaml + readOnly: true + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: "rules" + configMap: + name: "{{ include "falco-talon.name" . }}-rules" + - name: "config" + secret: + secretName: "{{ include "falco-talon.name" . }}-config" \ No newline at end of file diff --git a/charts/falco-talon/templates/ingress.yaml b/charts/falco-talon/templates/ingress.yaml new file mode 100644 index 00000000..7c158e67 --- /dev/null +++ b/charts/falco-talon/templates/ingress.yaml @@ -0,0 +1,50 @@ +{{- if .Values.ingress.enabled -}} +{{- $name := include "falco-talon.name" . -}} +{{- $ingressApiIsStable := eq (include "falco-talon.ingress.isStable" .) "true" -}} +{{- $ingressSupportsPathType := eq (include "falco-talon.ingress.supportsPathType" .) "true" -}} +--- +apiVersion: {{ include "falco-talon.ingress.apiVersion" . }} +kind: Ingress +metadata: + name: {{ $name }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "falco-talon.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if $ingressSupportsPathType }} + pathType: {{ default "ImplementationSpecific" .pathType }} + {{- end }} + backend: + {{- if $ingressApiIsStable }} + service: + name: {{ $name }} + port: + name: http + {{- else }} + serviceName: {{ $name }} + servicePort: http + {{- end }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/falco-talon/templates/podsecuritypolicy.yaml b/charts/falco-talon/templates/podsecuritypolicy.yaml new file mode 100644 index 00000000..840a7e27 --- /dev/null +++ b/charts/falco-talon/templates/podsecuritypolicy.yaml @@ -0,0 +1,32 @@ +{{- if .Values.podSecurityPolicy.create}} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "falco-talon.name" . }} + labels: + {{- include "falco-talon.labels" . | nindent 4 }} +spec: + privileged: false + allowPrivilegeEscalation: false + hostNetwork: false + readOnlyRootFilesystem: true + requiredDropCapabilities: + - ALL + fsGroup: + ranges: + - max: 65535 + min: 1 + rule: MustRunAs + runAsUser: + rule: MustRunAsNonRoot + seLinux: + rule: RunAsAny + supplementalGroups: + ranges: + - max: 65535 + min: 1 + rule: MustRunAs + volumes: + - configMap + - secret +{{- end }} \ No newline at end of file diff --git a/charts/falco-talon/templates/rbac.yaml b/charts/falco-talon/templates/rbac.yaml new file mode 100644 index 00000000..50080a12 --- /dev/null +++ b/charts/falco-talon/templates/rbac.yaml @@ -0,0 +1,209 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "falco-talon.name" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "falco-talon.labels" . | nindent 4 }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "falco-talon.name" . }} + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ include "falco-talon.name" . }} + helm.sh/chart: {{ include "falco-talon.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +rules: + {{- if .Values.rbac.namespaces }} + - apiGroups: + - "" + resources: + - namespaces + verbs: +{{ toYaml .Values.rbac.namespaces | indent 6 }} + {{- end }} + {{- if .Values.rbac.pods }} + - apiGroups: + - "" + resources: + - pods + verbs: +{{ toYaml .Values.rbac.pods | indent 6 }} + {{- end }} + {{- if .Values.rbac.podsEphemeralcontainers }} + - apiGroups: + - "" + resources: + - pods/ephemeralcontainers + verbs: +{{ toYaml .Values.rbac.podsEphemeralcontainers | indent 6 }} + {{- end }} + {{- if .Values.rbac.nodes }} + - apiGroups: + - "" + resources: + - nodes + verbs: +{{ toYaml .Values.rbac.nodes | indent 6 }} + {{- end }} + {{- if .Values.rbac.podsLog }} + - apiGroups: + - "" + resources: + - pods/log + verbs: +{{ toYaml .Values.rbac.podsLog | indent 6 }} + {{- end }} + {{- if .Values.rbac.podsExec }} + - apiGroups: + - "" + resources: + - pods/exec + verbs: +{{ toYaml .Values.rbac.podsExec | indent 6 }} + {{- end }} + {{- if .Values.rbac.podsEviction }} + - apiGroups: + - "" + resources: + - pods/eviction + verbs: +{{ toYaml .Values.rbac.podsEviction | indent 6 }} + {{- end }} + {{- if .Values.rbac.events }} + - apiGroups: + - "" + resources: + - events + verbs: +{{ toYaml .Values.rbac.events | indent 6 }} + {{- end }} + {{- if .Values.rbac.daemonsets }} + - apiGroups: + - "apps" + resources: + - daemonsets + verbs: +{{ toYaml .Values.rbac.daemonsets | indent 6 }} + {{- end }} + {{- if .Values.rbac.deployments }} + - apiGroups: + - "apps" + resources: + - deployments + verbs: +{{ toYaml .Values.rbac.deployments | indent 6 }} + {{- end }} + {{- if .Values.rbac.replicasets }} + - apiGroups: + - "apps" + resources: + - replicasets + verbs: +{{ toYaml .Values.rbac.replicasets | indent 6 }} + {{- end }} + {{- if .Values.rbac.statefulsets }} + - apiGroups: + - "apps" + resources: + - statefulsets + verbs: +{{ toYaml .Values.rbac.statefulsets | indent 6 }} + {{- end }} + {{- if .Values.rbac.networkpolicies }} + - apiGroups: + - "networking.k8s.io" + resources: + - networkpolicies + verbs: +{{ toYaml .Values.rbac.networkpolicies | indent 6 }} + {{- end }} + {{- if .Values.rbac.caliconetworkpolicies }} + - apiGroups: + - "projectcalico.org" + resources: + - caliconetworkpolicies + verbs: +{{ toYaml .Values.rbac.caliconetworkpolicies | indent 6 }} + {{- end }} + {{- if .Values.rbac.ciliumnetworkpolicies }} + - apiGroups: + - "cilium.io" + resources: + - ciliumnetworkpolicies + verbs: +{{ toYaml .Values.rbac.ciliumnetworkpolicies | indent 6 }} + {{- end }} + {{- if .Values.rbac.roles }} + - apiGroups: + - "rbac.authorization.k8s.io" + resources: + - roles + verbs: +{{ toYaml .Values.rbac.roles | indent 6 }} + {{- end }} + {{- if .Values.rbac.clusterroles }} + - apiGroups: + - "rbac.authorization.k8s.io" + resources: + - clusterroles + verbs: +{{ toYaml .Values.rbac.clusterroles | indent 6 }} + {{- end }} + {{- if .Values.rbac.configmaps }} + - apiGroups: + - "" + resources: + - configmaps + verbs: +{{ toYaml .Values.rbac.configmaps | indent 6 }} + {{- end }} + {{- if .Values.rbac.secrets }} + - apiGroups: + - "" + resources: + - secrets + verbs: +{{ toYaml .Values.rbac.secrets | indent 6 }} + {{- end }} + {{- if .Values.rbac.leases }} + - apiGroups: + - "coordination.k8s.io" + resources: + - leases + verbs: +{{ toYaml .Values.rbac.leases | indent 6 }} + {{- end }} +{{- if .Values.podSecurityPolicy.create }} +- apiGroups: + - policy + resources: + - podsecuritypolicies + resourceNames: + - {{ template "falco-talon.name" . }} + verbs: + - use +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "falco-talon.name" . }} + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ include "falco-talon.name" . }} + helm.sh/chart: {{ include "falco-talon.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "falco-talon.name" . }} +subjects: +- kind: ServiceAccount + name: {{ include "falco-talon.name" . }} + namespace: {{ .Release.Namespace }} \ No newline at end of file diff --git a/charts/falco-talon/templates/secrets.yaml b/charts/falco-talon/templates/secrets.yaml new file mode 100644 index 00000000..cd51d147 --- /dev/null +++ b/charts/falco-talon/templates/secrets.yaml @@ -0,0 +1,71 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "falco-talon.name" . }}-config + labels: + {{- include "falco-talon.labels" . | nindent 4 }} +stringData: + config.yaml: | + listen_address: {{ default "0.0.0.0" .Values.config.listenAddress }} + listen_port: {{ default 2803 .Values.config.listenPort }} + watch_rules: {{ default true .Values.config.watchRules }} + print_all_events: {{ default false .Values.config.printAllEvents }} + deduplication: + leader_election: {{ default true .Values.config.deduplication.leaderElection }} + time_window_seconds: {{ default 5 .Values.config.deduplication.timeWindowSeconds }} + + default_notifiers: + {{- range .Values.config.defaultNotifiers }} + - {{ . -}} + {{ end }} + + otel: + traces_enabled: {{ default false .Values.config.otel.tracesEnabled }} + metrics_enabled: {{ default false .Values.config.otel.metricsEnabled }} + collector_port: {{ default 4317 .Values.config.otel.collectorPort }} + collector_endpoint: {{ .Values.config.otel.collectorEndpoint }} + collector_use_insecure_grpc: {{ default false .Values.config.otel.collectorUseInsecureGrpc }} + + notifiers: + slack: + webhook_url: {{ .Values.config.notifiers.slack.webhookUrl }} + icon: {{ .Values.config.notifiers.slack.icon }} + username: {{ .Values.config.notifiers.slack.username }} + footer: {{ .Values.config.notifiers.slack.footer }} + format: {{ .Values.config.notifiers.slack.format }} + webhook: + url: {{ .Values.config.notifiers.webhook.url }} + smtp: + host_port: {{ .Values.config.notifiers.smtp.hostPort }} + from: {{ .Values.config.notifiers.smtp.from }} + to: {{ .Values.config.notifiers.smtp.to }} + user: {{ .Values.config.notifiers.smtp.user }} + password: {{ .Values.config.notifiers.smtp.password }} + format: {{ .Values.config.notifiers.smtp.format }} + tls: {{ .Values.config.notifiers.smtp.tls }} + loki: + url: {{ .Values.config.notifiers.loki.url }} + user: {{ .Values.config.notifiers.loki.user }} + api_key: {{ .Values.config.notifiers.loki.apiKey }} + tenant: {{ .Values.config.notifiers.loki.tenant }} + custom_headers: + {{- range .Values.config.notifiers.loki.customHeaders }} + - {{ . -}} + {{ end }} + elasticsearch: + url: {{ .Values.config.notifiers.elasticsearch.url }} + create_index_template: {{ .Values.config.notifiers.loki.createIndexTemplate }} + number_of_shards: {{ .Values.config.notifiers.loki.numberOfShards }} + number_of_replicas: {{ .Values.config.notifiers.loki.numberOfReplicas }} + + aws: + role_arn: {{ .Values.config.aws.roleArn }} + external_id: {{ .Values.config.aws.externalId }} + region: {{ .Values.config.aws.region }} + access_key: {{ .Values.config.aws.accessKey }} + secret_key: {{ .Values.config.aws.secretKey }} + minio: + endpoint: {{ .Values.config.minio.endpoint }} + access_key: {{ .Values.config.minio.accessKey }} + secret_key: {{ .Values.config.minio.secretKey }} + use_ssl: {{ .Values.config.minio.useSsl }} diff --git a/charts/falco-talon/templates/servicemonitor.yaml b/charts/falco-talon/templates/servicemonitor.yaml new file mode 100644 index 00000000..8a46726e --- /dev/null +++ b/charts/falco-talon/templates/servicemonitor.yaml @@ -0,0 +1,44 @@ +{{- if .Values.serviceMonitor.enabled }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: + {{- include "falco-talon.labels" . | nindent 4 }} + {{- with .Values.serviceMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + name: {{ include "falco-talon.name" . }} + namespace: {{ .Release.Namespace }} +spec: + endpoints: + - port: {{ .Values.serviceMonitor.port }} + {{- with .Values.serviceMonitor.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + honorLabels: true + path: {{ .Values.serviceMonitor.path }} + scheme: {{ .Values.serviceMonitor.scheme }} + {{- with .Values.serviceMonitor.tlsConfig }} + tlsConfig: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 6 }} + {{- end }} + jobLabel: "{{ .Release.Name }}" + selector: + matchLabels: + {{- include "falco-talon.selectorLabels" . | nindent 6 }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + {{- with .Values.serviceMonitor.targetLabels }} + targetLabels: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/falco-talon/templates/services.yaml b/charts/falco-talon/templates/services.yaml new file mode 100644 index 00000000..14d4ce5f --- /dev/null +++ b/charts/falco-talon/templates/services.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "falco-talon.name" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "falco-talon.labels" . | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "falco-talon.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/charts/falco-talon/values.yaml b/charts/falco-talon/values.yaml new file mode 100644 index 00000000..9da04342 --- /dev/null +++ b/charts/falco-talon/values.yaml @@ -0,0 +1,283 @@ +# Default values for falco-talon. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# -- number of running pods +replicaCount: 2 + +# -- image parameters +image: + # -- The image registry to pull from + registry: falco.docker.scarf.sh + # -- The image repository to pull from + repository: issif/falco-talon + # -- Override the image tag to pull + tag: "" + # -- The image pull policy + pullPolicy: Always + +# -- pod security policy +podSecurityPolicy: + # -- enable the creation of the PSP + create: false + +# -- pod security context +podSecurityContext: + # -- user id + runAsUser: 1234 + # -- group + fsGroup: 1234 + +# -- one or more secrets to be used when pulling images +imagePullSecrets: [] +# - registrySecretName + +# -- override name +nameOverride: "" + +# -- extra env +extraEnv: + - name: LOG_LEVEL + value: warning +# - name: AWS_REGION # Specify if running on EKS, ECS or EC2 +# value: us-east-1 + +# -- priority class name +priorityClassName: "" + +# -- pod annotations +podAnnotations: {} + +# -- service parameters +service: + # -- type of service + type: ClusterIP + # -- port of the service + port: 2803 + # -- annotations of the service + annotations: {} + # networking.gke.io/load-balancer-type: Internal + +# -- ingress parameters +ingress: + # -- enable the ingress + enabled: false + # -- annotations of the ingress + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # -- hosts + hosts: + - host: falco-talon.local + paths: + - path: / + # -- pathType (e.g. ImplementationSpecific, Prefix, .. etc.) + # pathType: Prefix + # -- tls + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +# -- resources +resources: {} + # -- limits + # limits: + # # -- cpu limit + # cpu: 100m + # # -- memory limit + # memory: 128Mi + # -- requests + # requests: + # # -- cpu request + # cpu: 100m + # # -- memory request + # memory: 128Mi + +# -- node selector +nodeSelector: {} + +# -- tolerations +tolerations: [] + +# -- affinity +affinity: {} + +# -- rbac +rbac: + namespaces: ["get", "delete"] + pods: ["get", "update", "patch", "delete", "list"] + podsEphemeralcontainers: ["patch", "create"] + nodes: ["get", "update", "patch", "watch", "create"] + podsLog: ["get"] + podsExec: ["get", "create"] + podsEviction: ["get", "create"] + events: ["get", "update", "patch", "create"] + daemonsets: ["get", "delete"] + deployments: ["get", "delete"] + replicasets: ["get", "delete"] + statefulsets: ["get", "delete"] + networkpolicies: ["get", "update", "patch", "create"] + caliconetworkpolicies: ["get", "update", "patch", "create"] + ciliumnetworkpolicies: ["get", "update", "patch", "create"] + roles: ["get", "delete"] + clusterroles: ["get", "delete"] + configmaps: ["get", "delete"] + secrets: ["get", "delete"] + leases: ["get", "update", "patch", "watch", "create"] + +# -- config of Falco Talon (See https://docs.falco-talon.org/docs/configuration/) +config: + # -- listen address + listenAddress: 0.0.0.0 + # -- listen port + listenPort: 2803 + + # -- default notifiers for all rules + defaultNotifiers: + # - slack + - k8sevents + + # -- auto reload the rules when the files change + watchRules: true + + # -- list of locale rules to load, they will be concatenated into a single config map + rulesFiles: + - rules.yaml + - rules_override.yaml + + # -- deduplication of the Falco events + deduplication: + # -- enable the leader election for cluster mode + leaderElection: true + # -- duration in seconds for the deduplication time window + timeWindowSeconds: 5 + + # -- print in stdout all received events, not only those which match a rule + printAllEvents: false + + # -- open telemetry parameters + otel: + # -- enable otel traces + tracesEnabled: false + # -- enable otel metrics + metricsEnabled: false + # -- collector port + collectorPort: 4317 + # -- collector endpoint + collectorEndpoint: "" + # -- use insecure grpc + collectorUseInsecureGrpc: false + + # -- notifiers (See https://docs.falco-talon.org/docs/notifiers/list/ for the settings) + notifiers: + # -- slack + slack: + # -- webhook url + webhookUrl: "" + # -- icon + icon: "https://upload.wikimedia.org/wikipedia/commons/2/26/Circaetus_gallicus_claw.jpg" + # -- username + username: "Falco Talon" + # -- footer + footer: "https://github.com/falco-talon/falco-talon" + # -- format + format: "long" + # -- webhook + webhook: + # -- url + url: "" + # -- smtp + smtp: + # -- host:port + hostPort: "" + # -- from + from: "" + # -- to + to: "" + # -- user + user: "" + # -- password + password: "" + # -- format + format: "html" + # -- enable tls + tls: false + # -- loki + loki: + # -- host:port + hostPort: "" + # -- user + user: "" + # -- api key + apiKey: "" + # -- tenant + tenant: "" + # -- custom headers + customHeaders: [] + # -- elasticsearch + elasticsearch: + # -- url + url: "" + # -- create the index template + createIndexTemplate: true + # -- number of shards + numberOfShards: 1 + # -- number of replicas + numberOfReplicas: 1 + + # -- aws + aws: + # -- role arn + roleArn: "" + # -- external id + externalId: "" + # -- region (if not specified, default region from provider credential chain will be used) + region: "" + # -- access key (if not specified, default access_key from provider credential chain will be used) + accesKey: "" + # -- secret key (if not specified, default secret_key from provider credential chain will be used) + secretKey: "" + + # -- minio + minio: + # -- endpoint + endpoint: "" + # -- access key + accessKey: "" + # -- secret key + secretKey: "" + # -- use ssl + useSsl: false + +# -- serviceMonitor holds the configuration for the ServiceMonitor CRD. +serviceMonitor: + # -- enable the deployment of a Service Monitor for the Prometheus Operator. + enabled: false + # -- portname at which the metrics are exposed + port: http + # -- path at which the metrics are exposed + path: /metrics + # -- additionalLabels specifies labels to be added on the Service Monitor. + additionalLabels: {} + # -- interval specifies the time interval at which Prometheus should scrape metrics from the service. + interval: "30s" + # -- scheme specifies network protocol used by the metrics endpoint. In this case HTTP. + scheme: http + # -- scrapeTimeout determines the maximum time Prometheus should wait for a target to respond to a scrape request. + # If the target does not respond within the specified timeout, Prometheus considers the scrape as failed for + # that target. + scrapeTimeout: "10s" + # -- relabelings configures the relabeling rules to apply the target’s metadata labels. + relabelings: [] + # -- targetLabels defines the labels which are transferred from the associated Kubernetes service object onto the ingested metrics. + targetLabels: [] + # -- tlsConfig specifies TLS (Transport Layer Security) configuration for secure communication when + # scraping metrics from a service. It allows you to define the details of the TLS connection, such as + # CA certificate, client certificate, and client key. Currently, the k8s-metacollector does not support + # TLS configuration for the metrics endpoint. + tlsConfig: {} + # insecureSkipVerify: false + # caFile: /path/to/ca.crt + # certFile: /path/to/client.crt + # keyFile: /path/to/client.key