Falco, the cloud-native runtime security tool, is designed to detect anomalous activity in your Kubernetes cluster by analyzing syscalls and container activity. Deploying it as a DaemonSet ensures that Falco agents are running on every node, providing comprehensive visibility.
Here’s how you can deploy Falco as a DaemonSet on your Kubernetes cluster:
1. Create a Namespace for Falco
It’s good practice to isolate Falco’s resources in its own namespace.
kubectl create namespace falco
2. Create a ConfigMap for Falco Configuration
Falco’s behavior is controlled by a configuration file. We’ll create a ConfigMap to hold this file.
apiVersion: v1
kind: ConfigMap
metadata:
name: falco-config
namespace: falco
data:
falco.yaml: |
# Global settings
log_level: info
keep_alive:
enabled: true
interval: 10s
# Load rules from the rules directory
rules_files:
- /etc/falco/rules.d/*.yaml
# Load additional rules from a file
# falco_rules_file: /etc/falco/falco_rules.yaml
# Output configuration
outputs:
- output: json_output
file: /tmp/falco_output.json
- output: alert_output
file: /tmp/falco_alerts.log
# JSON output format
json_output_layout:
- key: timestamp
value: "%(ts)"
- key: priority
value: "%(p)"
- key: rule
value: "%(r)"
- key: output
value: "%(m)"
- key: pid
value: "%(pid)"
- key: comm
value: "%(comm)"
- key: tty
value: "%(tty)"
- key: proc_name
value: "%(proc.name)"
- key: proc_exe
value: "%(proc.exe)"
- key: proc_cmdline
value: "%(proc.cmdline)"
- key: proc_ppid
value: "%(proc.ppid)"
- key: proc_loginuid
value: "%(proc.loginuid)"
- key: proc_cwd
value: "%(proc.cwd)"
- key: container_id
value: "%(container.id)"
- key: container_name
value: "%(container.name)"
- key: container_image
value: "%(container.image)"
- key: k8s_evt_user
value: "%(k8s.evt.user)"
- key: k8s_evt_source
value: "%(k8s.evt.source)"
- key: k8s_evt_object
value: "%(k8s.evt.object)"
- key: k8s_evt_namespace
value: "%(k8s.evt.namespace)"
- key: k8s_evt_name
value: "%(k8s.evt.name)"
- key: k8s_evt_uid
value: "%(k8s.evt.uid)"
- key: k8s_evt_request
value: "%(k8s.evt.request)"
# Alert output format
alert_output_layout:
- key: timestamp
value: "%(ts)"
- key: priority
value: "%(p)"
- key: rule
value: "%(r)"
- key: output
value: "%(m)"
- key: proc_name
value: "%(proc.name)"
- key: proc_exe
value: "%(proc.exe)"
- key: container_name
value: "%(container.name)"
- key: k8s_evt_user
value: "%(k8s.evt.user)"
- key: k8s_evt_namespace
value: "%(k8s.evt.namespace)"
- key: k8s_evt_name
value: "%(k8s.evt.name)"
# Rule configuration
# For a full list of rule options, see https://falco.org/docs/rules/
rules:
- rule: Unexpected outbound network connection
desc: An unexpected outbound network connection was detected.
condition: outbound and net
output: Unexpected outbound connection from %container.name (%container.image) to %fd.sip:%fd.sport
priority: warning
tags: [network, outbound]
- rule: Write to sensitive directories
desc: A process tried to write to a sensitive directory.
condition: syscall="open" and fd.flags contains "O_WRONLY" and fd.name startswith "/etc/kubernetes/" or fd.name startswith "/run/containerd/" or fd.name startswith "/var/lib/kubelet/"
output: Write to sensitive directory %fd.name by %container.name (%container.image)
priority: error
tags: [filesystem, security]
- rule: Suspicious shell in container
desc: A shell process was detected running in a container.
condition: container and proc.name = "sh" or proc.name = "bash" or proc.name = "zsh"
output: Suspicious shell '%proc.name' executed in container '%container.name' (%container.image)
priority: notice
tags: [container, security]
Apply this ConfigMap:
kubectl apply -f falco-configmap.yaml
3. Create a ServiceAccount for Falco
Falco needs a ServiceAccount to interact with the Kubernetes API.
apiVersion: v1
kind: ServiceAccount
metadata:
name: falco
namespace: falco
Apply this ServiceAccount:
kubectl apply -f falco-sa.yaml
4. Create a ClusterRole and ClusterRoleBinding for Falco
Falco needs read-only access to Kubernetes audit events.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: falco-clusterrole
rules:
- apiGroups: ["audit.k8s.io"]
resources: ["audits"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: falco-clusterrolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: falco-clusterrole
subjects:
- kind: ServiceAccount
name: falco
namespace: falco
Apply these RBAC resources:
kubectl apply -f falco-rbac.yaml
5. Create the Falco DaemonSet
This is the core of the deployment. The DaemonSet ensures Falco runs on every node.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: falco
namespace: falco
labels:
app: falco
spec:
selector:
matchLabels:
app: falco
template:
metadata:
labels:
app: falco
spec:
serviceAccountName: falco
hostNetwork: true # Falco needs host network access to capture syscalls
containers:
- name: falco
image: falcosecurity/falco:latest # Use the latest Falco image
ports:
- containerPort: 8765 # Default port for Falco's gRPC API
name: grpc
volumeMounts:
- name: falco-config-volume
mountPath: /etc/falco
- name: sys-kernel-debug
mountPath: /sys/kernel/debug
- name: var-run-containerd
mountPath: /run/containerd
- name: var-lib-docker
mountPath: /var/lib/docker # Only if using Docker
- name: var-log-pods
mountPath: /var/log/pods
- name: var-lib-kubelet
mountPath: /var/lib/kubelet
- name: dev
mountPath: /dev
securityContext:
privileged: true # Falco needs elevated privileges to capture syscalls
volumes:
- name: falco-config-volume
configMap:
name: falco-config
- name: sys-kernel-debug
hostPath:
path: /sys/kernel/debug
- name: var-run-containerd
hostPath:
path: /run/containerd
- name: var-lib-docker
hostPath:
path: /var/lib/docker # Only if using Docker
- name: var-log-pods
hostPath:
path: /var/log/pods
- name: var-lib-kubelet
hostPath:
path: /var/lib/kubelet
- name: dev
hostPath:
path: /dev
Apply the DaemonSet:
kubectl apply -f falco-daemonset.yaml
Verifying the Deployment
Check if the Falco pods are running on all your nodes:
kubectl get pods -n falco -o wide
You should see one Falco pod for each node in your cluster.
Accessing Falco Alerts
Falco logs alerts to /tmp/falco_alerts.log inside the container. To view them, you can use kubectl logs:
# Find the name of one of your falco pods
POD_NAME=$(kubectl get pods -n falco -l app=falco -o jsonpath='{.items[0].metadata.name}')
# View the logs
kubectl logs $POD_NAME -n falco
For more advanced integration, you can configure Falco to send alerts to other systems like Elasticsearch, Splunk, or a SIEM via its output plugins. You can also expose Falco’s gRPC API to query rules and events programmatically.
The next step is to tune Falco’s rules to reduce false positives and detect the specific threats relevant to your environment.