Skip to main content
CleanStart

Knowledge Hub

Falco Rules Guide for CleanStart Container Security

document version: 1.0 audience: DevOps, Security Engineers, SRE reading time: 20 minutes updated: 2026-03-22.

Overview

Falco is an open-source runtime security tool that detects anomalous behavior in containers using eBPF (extended Berkeley Packet Filter). This guide provides custom Falco rules tuned for CleanStart containers and explains how to integrate runtime detection with CleanStart's supply chain security.

key integration points Detect shell spawning in distroless containers (should never happen) Monitor for file modifications in read-only filesystems (escalation attempts) Track network anomalies (unexpected connections) Correlate runtime alerts with CleanStart image attestations for forensics.

Section 1: Custom Falco Rules for CleanStart Images

Rule 1: Shell Process in Distroless Container (CRITICAL)

purpose: Distroless containers have no shell. Spawning /bin/bash, /bin/sh, or similar in a CleanStart container indicates compromise or misconfiguration.

rule yaml.

- rule: Shell in Distroless Container  desc: Detects shell process spawned in CleanStart distroless container  condition: >    spawned_process and    shell_procs and    container and    container.image.repository in (      "registry.cleanstart.com/cleanstart/*",      "cleanstart/*"    ) and    not container.privileged  output: >    CRITICAL: Shell spawned in distroless container    (user=%user.name command=%proc.cmdline container.id=%container.id    image=%container.image.repository:%container.image.tag)  priority: CRITICAL  tags: [distroless, shell, privilege_escalation]

detection logic spawned_process: Process creation system call (fork/exec) shell_procs: Known shell binaries (/bin/bash, /bin/sh, /bin/zsh, etc.) container: Process is in a container (cgroup-based detection) container.image.repository in ("registry.cleanstart.com/cleanstart/*", "cleanstart/*"): Image is from CleanStart registry. expected behavior CleanStart containers: Rule should never trigger If rule triggers: Immediate investigation required (possible breach or misconfigured image). example alert.

2026-03-22 14:32:15 CRITICAL: Shell spawned in distroless containeruser=nobody command=/bin/bash -i container.id=a1b2c3d4e5f6image=registry.cleanstart.com/cleanstart/python:3.11

response.

  1. Correlate timestamp with CleanStart image deployment logs
  2. Verify image signature: cosign verify registry.cleanstart.com/cleanstart/python:3.11
  3. Check SBOM for suspicious changes
  4. Kill container; do not allow process to continue

Rule 2: File Modifications in Read-Only Filesystem (HIGH)

purpose: CleanStart images have read-only root filesystem. Attempts to write to / indicate escalation attack or kernel exploit.

rule yaml.

- rule: Write to Read-Only Filesystem  desc: Detects write attempt to read-only root filesystem in CleanStart container  condition: >    write and    fd.name glob ("/etc/*", "/bin/*", "/lib/*", "/usr/*") and    container and    container.image.repository in (      "registry.cleanstart.com/cleanstart/*",      "cleanstart/*"    ) and    not proc.name in (rootkit_processes)  output: >    HIGH: Write attempt to read-only filesystem    (user=%user.name process=%proc.name file=%fd.name container.id=%container.id    image=%container.image.repository:%container.image.tag)  priority: HIGH  tags: [filesystem, integrity, privilege_escalation]

detection logic write: System call (write, writev, pwrite64) fd.name glob (...): Attempt to write to system directories container: Process is containerized not proc.name in (rootkit_processes): Exclude known problematic processes. expected behavior Should never trigger in running CleanStart container If triggered: Kernel exploit or misconfigured image. example alert.

2026-03-22 15:45:22 HIGH: Write attempt to read-only filesystemuser=nobody process=exploit_binary file=/etc/ld.so.preload container.id=x9y8z7w6v5u4image=registry.cleanstart.com/cleanstart/nodejs:18

rootkit detection.

rootkit_processes:  - "init-setup"  - "cloud-init"  # Note: Very few processes should write to /etc at runtime

Rule 3: Network Anomaly Detection (MEDIUM/HIGH)

purpose: Detect unexpected outbound connections that might indicate data exfiltration or C2 (command-and-control) communication.

rule yaml.

- rule: Unexpected Outbound Connection from Container  desc: Detects outbound network connection not in baseline for this container image  condition: >    outbound and    container and    container.image.repository in (      "registry.cleanstart.com/cleanstart/*",      "cleanstart/*"    ) and    not fd.sip in (allowed_internal_ips) and    not fd.sport in (dns_ports) and    not fd.dport in (allowed_outbound_ports) and    not (fd.saddr = container.ip and fd.daddr = "8.8.8.8")  output: >    MEDIUM: Unexpected outbound connection    (user=%user.name process=%proc.name container.image=%container.image.repository    src=%fd.sip:%fd.sport dst=%fd.dip:%fd.dport)  priority: MEDIUM  tags: [network, exfiltration, c2]

configuration (baseline).

allowed_internal_ips:  - "10.0.0.0/8"        # Private network  - "172.16.0.0/12"     # Private network  - "192.168.0.0/16"    # Private network dns_ports:  - 53                  # DNS allowed_outbound_ports:  - 443                 # HTTPS (common for APIs)  - 80                  # HTTP (if needed)  - 5432                # PostgreSQL (database)  - 6379                # Redis (cache)

expected behavior Applications connecting to internal services: Expected Unexpected connections to external IPs or suspicious ports: Alert. example alert.

2026-03-22 16:12:33 MEDIUM: Unexpected outbound connectionuser=appuser process=python container.image=registry.cleanstart.com/cleanstart/python:3.11src=10.0.1.42:50293 dst=185.92.75.30:4444

investigation.

  1. Verify if connection is legitimate (check application config)
  2. Check if IP 185.92.75.30 is on threat intelligence lists
  3. If confirmed malicious: Kill container, rotate secrets, check SBOM for supply chain compromise

Rule 4: Privilege Escalation Attempts (CRITICAL)

purpose: Detect attempts to escalate from non-root user to root (via sudo, setuid, etc.).

rule yaml.

- rule: Privilege Escalation Attempt in Container  desc: Detects privilege escalation attempts in CleanStart containers  condition: >    (proc_name in (sudo, su, capset) or     file_write and fd.name glob "*setuid*") and    container and    user.uid > 0 and    not proc.name in (whitelist_procs)  output: >    CRITICAL: Privilege escalation attempt detected    (user=%user.name process=%proc.name target_uid=%user.target_uid    container.id=%container.id image=%container.image.repository:%container.image.tag)  priority: CRITICAL  tags: [privilege_escalation, container_escape]

Whitelist (processes allowed to escalate):

whitelist_procs:  # Most CleanStart containers should have empty whitelist  # (no process should escalate privilege)

expected behavior Should never trigger in CleanStart container (non-root only, no sudo/su) If triggered: Compromised container or misconfigured image.

Rule 5: File Integrity Monitoring (MEDIUM)

purpose: Monitor for unauthorized modifications to critical application files.

rule yaml.

- rule: Critical File Modified in Container  desc: Detects modification of critical files in CleanStart containers  condition: >    (write or rename or delete) and    fd.name glob (      "/app/*",      "/srv/*",      "/opt/*"    ) and    container and    user.uid = 65532  # Non-root UID  output: >    MEDIUM: Critical file modified    (user=%user.name process=%proc.name file=%fd.name action=%syscall.type    container.id=%container.id image=%container.image.repository:%container.image.tag)  priority: MEDIUM  tags: [file_integrity, tampering]

configuration.

# Define protected directories per imageprotected_paths:  cleanstart/python: ["/app/", "/usr/local/lib/python3.11/"]  cleanstart/nodejs: ["/app/", "/usr/local/lib/node_modules/"]  cleanstart/go:     ["/app/", "/usr/local/lib/go/"]

example alert.

2026-03-22 17:05:15 MEDIUM: Critical file modifieduser=appuser process=curl file=/app/config.json action=writecontainer.id=abc123 image=registry.cleanstart.com/cleanstart/python:3.11

interpretation Expected: Configuration changes via application (e.g., app updating config) Unexpected: Manual curl/wget downloading and executing code (supply chain compromise?).

Section 2: Shell Detection and Debugging

How to Allow Debug Containers While Maintaining Security

problem: Distroless containers have no shell; debugging is hard. But spawning a shell means relaxing security.

solution: Use sidecar debug container with full shell access, while keeping production container secured.

configuration.

apiVersion: v1kind: Podmetadata:  name: app-with-debugspec:  containers:  # Production container: distroless, no shell  - name: app    image: registry.cleanstart.com/cleanstart/python:3.11    securityContext:      runAsNonRoot: true      runAsUser: 65532      allowPrivilegeEscalation: false      readOnlyRootFilesystem: true   # Debug container: full shell, isolated namespace  - name: debug    image: registry.cleanstart.com/cleanstart/python:3.11-debug    securityContext:      runAsNonRoot: true      runAsUser: 65532    volumeMounts:    - name: app-temp      mountPath: /tmp/app  # Shared temp for file inspection   volumes:  - name: app-temp    emptyDir: {}

Falco Configuration (allow debug container to have shell):

- rule: Shell in Debug Container  desc: Allow shell in debug-tagged containers only  condition: >    spawned_process and    shell_procs and    container and    container.image.repository endswith "-debug"  output: >    INFO: Shell in debug container (expected)    (user=%user.name command=%proc.cmdline)  priority: INFORMATIONAL  tags: [debug, expected]

Section 3: Integration with CleanStart Attestations

Correlation Workflow: Runtime Alert + Forensics

scenario: Falco detects shell process in container. Correlate with CleanStart evidence.

workflow.

#!/bin/bash # 1. Falco alert provides:CONTAINER_ID="a1b2c3d4e5f6"IMAGE="registry.cleanstart.com/cleanstart/python:3.11" # 2. Query Kubernetes for pod detailsPOD_NAME=$(docker inspect $CONTAINER_ID | jq -r '.[0].Name')kubectl get pod $POD_NAME -o json > pod-metadata.json # 3. Download image attestationcosign download attestation $IMAGE > image-attestation.json # 4. Extract SBOMcosign download sbom $IMAGE > image-sbom.json # 5. Verify image signaturecosign verify --key https://keys.cleanstart.com/prod.pub $IMAGE# Expected: Signature valid (proves image was built by CleanStart) # 6. Check SBOM for suspicious packagesjq '.components[] | select(.name | contains("bash")) | .name' image-sbom.json# Expected: No bash found in CleanStart distroless image # 7. If bash found: Image was tampered with post-build# Investigation: How did unsigned/modified image get deployed? # 8. Check pod creation timestamp vs. image build timestampPOD_CREATED=$(jq -r '.metadata.creationTimestamp' pod-metadata.json)SBOM_BUILD_TIME=$(jq -r '.components[] | select(.name=="build-metadata") | .properties[0].value' image-sbom.json) # 9. Generate incident reportcat > incident-report.md <<EOF# Runtime Security Incident Report ## Alert Summary- **Time**: $(date -u)- **Container ID**: $CONTAINER_ID- **Image**: $IMAGE- **Alert Type**: Shell in distroless container (CRITICAL) ## Forensic Analysis- **Image Build Time**: $SBOM_BUILD_TIME- **Pod Created**: $POD_CREATED- **Image Signature**: VALID- **SBOM Packages**: $(jq '.components | length' image-sbom.json)- **Packages with CVEs**: $(jq '[.components[] | select(.vulnerabilities != null)] | length' image-sbom.json) ## Conclusions[Investigation findings]EOF

Section 4: Deploying Falco with CleanStart

Installation and Configuration

helm deploy.

helm repo add falcosecurity https://falcosecurity.github.io/chartshelm repo update helm install falco falcosecurity/falco \  --values falco-values.yaml \  --namespace falco \  --create-namespace

values.yaml (CleanStart-specific):

falco:  rules:  # Load custom CleanStart rules  - /etc/falco/rules.d/cleanstart-rules.yaml   # Falco configuration  json_output: true  http_output:    enabled: true    url: http://siem.company.com:8080/falco   # Alert only on CleanStart images to reduce noise  base_syscall_rules:    enabled: false  # Disable verbose syscall rules   grpc:    enabled: true    bind_address: "unix:///run/falco.sock" ebpf:  enabled: true  # eBPF for better performance serviceAccount:  create: true  name: falco podSecurityPolicy:  create: false falcoctl:  enabled: true  indexes:  - name: falcosecurity    url: https://falcosecurity.github.io/falcoctl/index.yaml

SIEM Integration (Datadog / Splunk / ELK)

syslog output.

syslog_output:  enabled: true  endpoint: "syslog.company.com:514"  format: "RFC5424"  facility: "LOG_LOCAL0"  priority: "LOG_ALERT"

datadog integration.

# Configure Falco to send alerts to Datadogfile_output:  enabled: false network_output:  enabled: true  type: "HTTP"  url: "https://api.datadoghq.com/v1/input/event"  headers:    "DD-API-KEY": "${DATADOG_API_KEY}"    "Content-Type": "application/json"

Section 5: Performance and Tuning

CPU/Memory Overhead

Falco using eBPF has minimal overhead: CPU: <2% per node Memory: 50-100MB resident Syscall Capture: ~100μs per syscall (eBPF performance).

Rule Tuning for Production

start conservative.

# Week 1: Detect obvious issues only- rule: Shell in Distroless Container (CRITICAL)- rule: File Modifications in Read-Only Filesystem (HIGH) # Week 2-3: Add network and privilege escalation- rule: Privilege Escalation Attempts (CRITICAL)- rule: Unexpected Outbound Connections (MEDIUM) # Week 4+: Add file integrity monitoring- rule: Critical File Modified in Container (MEDIUM)

whitelist false positives.

- macro: known_good_processes  condition: (proc.name in (systemd, docker, containerd)) - rule: Shell in Distroless Container  condition: >    ... and    not known_good_processes

Section 6: Alerting and Response

Alert Routing

# Critical alerts -> PagerDuty immediately- rule: Shell in Distroless Container  priority: CRITICAL  tags: [escalate_pagerduty] - rule: Privilege Escalation Attempt  priority: CRITICAL  tags: [escalate_pagerduty] # High alerts -> Slack (security channel)- rule: File Modifications in Read-Only Filesystem  priority: HIGH  tags: [escalate_slack] # Medium alerts -> SIEM (searchable, not immediate alert)- rule: Unexpected Outbound Connection  priority: MEDIUM  tags: [log_siem_only]

Playbook: How to Respond to Falco Alert

When Falco triggers CRITICAL alert: 1. [Immediate] Acknowledge alert in PagerDuty2. [0-5 min] Kill the container (kubectl delete pod ...)3. [5-15 min] Correlate with CleanStart image attestations4. [15-30 min] Check SBOM for package modifications5. [30-60 min] Determine if supply chain compromise or exploitation6. [1-24 hrs] Forensic investigation + root cause analysis7. [Follow-up] Patch or rebuild image if needed

further reading Falco Official Documentation eBPF and Runtime Security Container Runtime Security Best Practices.

maintained by: Security Engineering Team last updated: 2026-03-22.