Kubernetes Pod Security Policies (PSPs) are gone, and you’re looking to replace them with Falco rules. This isn’t just a simple substitution; it’s a shift from a declarative, Kubernetes-native admission controller to a dynamic, runtime security tool.

Let’s see Falco in action. Imagine a pod trying to execute a shell inside a sensitive directory like /etc.

# In a test pod:
ls /etc
# Falco Alert: Unexpected shell in sensitive directory

This is what we’re aiming for: catching deviations from expected behavior as they happen.

The core problem PSPs solved was enforcing security best practices at admission time. They prevented pods from being created with dangerous configurations, like running as root, having privileged access, or mounting sensitive host paths. Falco, on the other hand, operates at runtime. It watches kernel system calls and Kubernetes audit logs to detect suspicious activity after a pod has been scheduled. This means Falco doesn’t prevent a bad pod from starting, but it alerts you immediately when that pod does something it shouldn’t.

The mental model for Falco is a continuous, real-time security auditor. It’s constantly listening for events and comparing them against a set of rules. These rules are written in a specific YAML format, defining conditions based on event types, process arguments, file access, network connections, and more. When a rule’s conditions are met, Falco triggers an alert.

Here’s a breakdown of how you’d translate common PSP restrictions into Falco rules:

  • Disallowing Privileged Containers (privileged: true):

    • Falco Rule Concept: Alert when a container starts with the privileged capability enabled.
    • Falco Rule:
      - rule: Run privileged container
        desc: A privileged container can bypass most security restrictions.
        condition: container.privileged=true
        output: Privileged container detected (user: %(user.name) user_groups: %(user.groups) pod: %(k8s.pod.name) namespace: %(k8s.namespace.name) container_name: %(container.name))
        priority: critical
        tags: [kubernetes, cis, mitre_execution]
      
    • Why it works: Falco directly inspects container metadata derived from Kubernetes API events. container.privileged=true is a direct flag indicating the container is running with elevated host privileges.
  • Disallowing Host Network (hostNetwork: true):

    • Falco Rule Concept: Alert when a pod is created using the host’s network namespace.
    • Falco Rule:
      - rule: Use of hostNetwork
        desc: Pod using host networking is a security risk.
        condition: k8s.pod.hostnetwork=true
        output: Pod using hostNetwork detected (pod: %(k8s.pod.name) namespace: %(k8s.namespace.name))
        priority: critical
        tags: [kubernetes, cis]
      
    • Why it works: Similar to privileged containers, k8s.pod.hostnetwork=true is a field in the Kubernetes audit event that Falco can access.
  • Disallowing Host PID Namespace (hostPID: true):

    • Falco Rule Concept: Alert when a pod is created using the host’s PID namespace.
    • Falco Rule:
      - rule: Use of hostPID
        desc: Pod using host PID namespace can see all processes on the host.
        condition: k8s.pod.hostpid=true
        output: Pod using hostPID detected (pod: %(k8s.pod.name) namespace: %(k8s.namespace.name))
        priority: critical
        tags: [kubernetes, cis]
      
    • Why it works: This again leverages the k8s.pod.hostpid=true field from Kubernetes audit events.
  • Disallowing Host IPC Namespace (hostIPC: true):

    • Falco Rule Concept: Alert when a pod is created using the host’s IPC namespace.
    • Falco Rule:
      - rule: Use of hostIPC
        desc: Pod using host IPC namespace can access host IPC resources.
        condition: k8s.pod.hostipc=true
        output: Pod using hostIPC detected (pod: %(k8s.pod.name) namespace: %(k8s.namespace.name))
        priority: critical
        tags: [kubernetes, cis]
      
    • Why it works: Relies on the k8s.pod.hostipc=true field.
  • Restricting Read-Only Root Filesystem (readOnlyRootFilesystem: true):

    • Falco Rule Concept: Alert when a process attempts to write to a file in a container that is expected to have a read-only root filesystem. This is trickier as Falco doesn’t know the intent of the pod spec directly. Instead, you infer it from behavior.
    • Falco Rule:
      - rule: Write to read-only root filesystem
        desc: Attempting to write to a read-only root filesystem.
        condition: >
          writable_fs != "none" and
          openat.flags contains "O_WRONLY" and openat.flags contains "O_CREAT" and
          fd.typechar = 'f' and
          container.mounts.readonly = true
        output: Attempt to write to a read-only root filesystem (executable: %(proc.name) cmdline: %(proc.cmdline) file: %(openat.pathname) flags: %(openat.flags))
        priority: warning
        tags: [kubernetes, defense-in-depth]
      
    • Why it works: This rule monitors file write operations (openat.flags contains "O_WRONLY" and openat.flags contains "O_CREAT") on file descriptors (fd.typechar = 'f') where the container’s mount is explicitly marked as read-only (container.mounts.readonly = true). It requires Falco to be configured to parse container mount information.
  • Restricting Volume Mounts (e.g., /var/run/docker.sock):

    • Falco Rule Concept: Alert when a container mounts a sensitive host path, like the Docker socket.
    • Falco Rule:
      - rule: Mount sensitive host directory
        desc: Mounting sensitive host directories can lead to host compromise.
        condition: >
          k8s.audit.requestObject.spec.volumes[*] contains "hostPath.path=/var/run/docker.sock"
        output: Sensitive host directory mounted (pod: %(k8s.pod.name) namespace: %(k8s.namespace.name) path: %(k8s.audit.requestObject.spec.volumes[*].hostPath.path))
        priority: critical
        tags: [kubernetes, cis]
      
    • Why it works: This rule directly inspects the Kubernetes audit log for Pod creation or update events (k8s.audit.requestObject). It checks if any volume defined in the pod’s spec has a hostPath with the specific path /var/run/docker.sock.
  • Restricting Capabilities (e.g., CAP_SYS_ADMIN):

    • Falco Rule Concept: Alert when a container is started with excessive or dangerous Linux capabilities.
    • Falco Rule:
      - rule: Add dangerous capability
        desc: Adding dangerous capabilities like CAP_SYS_ADMIN can lead to privilege escalation.
        condition: >
          k8s.audit.requestObject.spec.containers[*].securityContext.capabilities.add contains "SYS_ADMIN"
        output: Dangerous capability added to container (pod: %(k8s.pod.name) namespace: %(k8s.namespace.name) capability: SYS_ADMIN)
        priority: critical
        tags: [kubernetes, cis, mitre_privilege_escalation]
      
    • Why it works: This rule also inspects Kubernetes audit logs, specifically looking at the securityContext.capabilities.add field for containers within a pod’s spec. It flags the addition of SYS_ADMIN or other specified dangerous capabilities.

The shift to Falco means you’re moving from a preventative model (PSPs) to a detective model (Falco). This is a more robust security posture because it catches all suspicious activity, not just what you explicitly configured to block. However, it also means you need to be diligent about tuning your Falco rules to avoid alert fatigue. You’ll want to start with a strong baseline of rules (like those derived from CIS Kubernetes benchmarks) and then layer on custom rules for your specific application needs.

One aspect often overlooked is how Falco correlates events. While a single system call might seem benign, Falco can chain multiple events together. For instance, it can detect a process spawning a shell (execve) and then that shell attempting to modify a sensitive system file (openat with write flags). This ability to understand sequences of actions is where Falco truly shines beyond simple configuration checks.

The next hurdle you’ll likely face is managing the lifecycle of these Falco rules, especially as your Kubernetes environment evolves.

Want structured learning?

Take the full Falco course →