container security

Detecting Container Escape with Falco Rules

Detect container escape attempts in real-time using Falco runtime security rules that monitor syscalls, file access, and privilege escalation.

container-escapedetectionfalcokubernetesruntime-securitysyscall-monitoring
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

Falco is a CNCF-graduated runtime security tool that monitors Linux syscalls to detect anomalous container behavior. It uses a rules engine to identify container escape techniques such as mounting host filesystems, accessing sensitive host paths, loading kernel modules, and exploiting privileged container capabilities.

When to Use

  • When investigating security incidents that require detecting container escape with falco rules
  • When building detection rules or threat hunting queries for this domain
  • When SOC analysts need structured procedures for this analysis type
  • When validating security monitoring coverage for related attack techniques

Prerequisites

  • Linux host with kernel 5.8+ (for eBPF driver) or kernel module support
  • Kubernetes cluster (v1.24+) or standalone Docker/containerd
  • Helm 3 for Kubernetes deployment
  • Root or privileged access for driver installation

Installing Falco

Kubernetes Deployment with Helm

# Add Falco Helm chart
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
 
# Install Falco with eBPF driver
helm install falco falcosecurity/falco \
  --namespace falco --create-namespace \
  --set falcosidekick.enabled=true \
  --set falcosidekick.webui.enabled=true \
  --set driver.kind=ebpf \
  --set collectors.containerd.enabled=true \
  --set collectors.containerd.socket=/run/containerd/containerd.sock
 
# Verify
kubectl get pods -n falco
kubectl logs -n falco -l app.kubernetes.io/name=falco --tail=20

Standalone Installation (Debian/Ubuntu)

# Add Falco GPG key and repo
curl -fsSL https://falco.org/repo/falcosecurity-packages.asc | \
  sudo gpg --dearmor -o /usr/share/keyrings/falco-archive-keyring.gpg
 
echo "deb [signed-by=/usr/share/keyrings/falco-archive-keyring.gpg] https://download.falco.org/packages/deb stable main" | \
  sudo tee /etc/apt/sources.list.d/falcosecurity.list
 
sudo apt-get update
sudo apt-get install -y falco
 
# Start Falco
sudo systemctl enable falco
sudo systemctl start falco

Container Escape Detection Rules

Rule 1: Detect Host Mount from Container

- rule: Container Mounting Host Filesystem
  desc: Detect a container attempting to mount the host filesystem
  condition: >
    spawned_process and container and
    proc.name = mount and
    (proc.args contains "/host" or proc.args contains "nsenter")
  output: >
    Container mounting host filesystem
    (user=%user.name container_id=%container.id container_name=%container.name
     image=%container.image.repository command=%proc.cmdline %evt.args)
  priority: CRITICAL
  tags: [container, escape, T1611]

Rule 2: Detect nsenter Usage (Namespace Escape)

- rule: Nsenter Execution in Container
  desc: Detect nsenter being used to escape container namespaces
  condition: >
    spawned_process and container and proc.name = nsenter
  output: >
    nsenter executed in container - potential escape attempt
    (user=%user.name container_id=%container.id image=%container.image.repository
     command=%proc.cmdline parent=%proc.pname)
  priority: CRITICAL
  tags: [container, escape, namespace, T1611]

Rule 3: Detect Privileged Container Launch

- rule: Launch Privileged Container
  desc: Detect a privileged container being launched
  condition: >
    container_started and container and container.privileged=true
  output: >
    Privileged container started
    (user=%user.name container_id=%container.id container_name=%container.name
     image=%container.image.repository)
  priority: WARNING
  tags: [container, privileged, T1610]

Rule 4: Detect /proc/sysrq-trigger Write

- rule: Write to Sysrq Trigger
  desc: Detect writes to /proc/sysrq-trigger which can crash or control the host
  condition: >
    open_write and container and fd.name = /proc/sysrq-trigger
  output: >
    Write to /proc/sysrq-trigger from container
    (user=%user.name container_id=%container.id image=%container.image.repository
     command=%proc.cmdline)
  priority: CRITICAL
  tags: [container, escape, host-manipulation]

Rule 5: Detect Kernel Module Loading from Container

- rule: Container Loading Kernel Module
  desc: Detect a container attempting to load a kernel module
  condition: >
    spawned_process and container and
    (proc.name in (insmod, modprobe) or
     (proc.name = init_module))
  output: >
    Kernel module loading from container
    (user=%user.name container_id=%container.id image=%container.image.repository
     command=%proc.cmdline)
  priority: CRITICAL
  tags: [container, escape, kernel, T1611]

Rule 6: Detect Container Breakout via cgroups

- rule: Write to Cgroup Release Agent
  desc: Detect writes to cgroup release_agent which is a known container escape vector
  condition: >
    open_write and container and
    fd.name endswith release_agent
  output: >
    Container writing to cgroup release_agent - escape attempt
    (user=%user.name container_id=%container.id image=%container.image.repository
     file=%fd.name command=%proc.cmdline)
  priority: CRITICAL
  tags: [container, escape, cgroup, CVE-2022-0492]

Rule 7: Detect Access to Host /etc/shadow

- rule: Container Reading Host Shadow File
  desc: Detect a container reading /etc/shadow on the host via mounted volume
  condition: >
    open_read and container and
    (fd.name = /etc/shadow or fd.name startswith /host/etc/shadow)
  output: >
    Container reading host shadow file
    (user=%user.name container_id=%container.id image=%container.image.repository
     file=%fd.name command=%proc.cmdline)
  priority: CRITICAL
  tags: [container, credential-access, T1003]

Rule 8: Detect Docker Socket Access

- rule: Container Accessing Docker Socket
  desc: Detect a container accessing the Docker socket which allows host control
  condition: >
    (open_read or open_write) and container and
    fd.name = /var/run/docker.sock
  output: >
    Container accessing Docker socket
    (user=%user.name container_id=%container.id image=%container.image.repository
     command=%proc.cmdline)
  priority: CRITICAL
  tags: [container, escape, docker-socket, T1610]

Complete Custom Rules File

# /etc/falco/rules.d/container-escape.yaml
- list: escape_binaries
  items: [nsenter, chroot, unshare, mount, umount, pivot_root]
 
- macro: container_escape_attempt
  condition: >
    spawned_process and container and
    proc.name in (escape_binaries)
 
- rule: Container Escape Binary Execution
  desc: Detect execution of binaries commonly used for container escape
  condition: container_escape_attempt
  output: >
    Escape-related binary executed in container
    (user=%user.name container=%container.name image=%container.image.repository
     command=%proc.cmdline parent=%proc.pname pid=%proc.pid)
  priority: CRITICAL
  tags: [container, escape, mitre_T1611]
 
- rule: Sensitive File Access from Container
  desc: Detect container access to sensitive host files
  condition: >
    (open_read or open_write) and container and
    (fd.name startswith /proc/1/ or
     fd.name = /etc/shadow or
     fd.name = /etc/kubernetes/admin.conf or
     fd.name startswith /var/lib/kubelet/)
  output: >
    Sensitive file accessed from container
    (container=%container.name image=%container.image.repository
     file=%fd.name command=%proc.cmdline user=%user.name)
  priority: CRITICAL
  tags: [container, sensitive-file, mitre_T1005]

Falco Configuration

# /etc/falco/falco.yaml (key settings)
rules_files:
  - /etc/falco/falco_rules.yaml
  - /etc/falco/rules.d/container-escape.yaml
 
json_output: true
json_include_output_property: true
json_include_tags_property: true
 
log_stderr: true
log_syslog: true
log_level: info
 
priority: WARNING
 
stdout_output:
  enabled: true
 
syslog_output:
  enabled: true
 
http_output:
  enabled: true
  url: http://falcosidekick:2801
  insecure: true
 
grpc:
  enabled: true
  bind_address: "unix:///run/falco/falco.sock"
  threadiness: 8
 
grpc_output:
  enabled: true

Alert Integration

Forward to Slack via Falcosidekick

# Falcosidekick values.yaml
config:
  slack:
    webhookurl: "https://hooks.slack.com/services/XXXXX"
    minimumpriority: "warning"
    messageformat: |
      *{{.Priority}}* - {{.Rule}}
      Container: {{.OutputFields.container_name}}
      Image: {{.OutputFields.container_image_repository}}
      Command: {{.OutputFields.proc_cmdline}}

Testing Rules

# Simulate container escape attempt (in a test container)
kubectl run test-escape --image=alpine --restart=Never -- sh -c "cat /etc/shadow"
 
# Simulate nsenter
kubectl run test-nsenter --image=alpine --restart=Never --overrides='{"spec":{"hostPID":true}}' -- nsenter -t 1 -m -u -i -n -- cat /etc/hostname
 
# Check Falco alerts
kubectl logs -n falco -l app.kubernetes.io/name=falco --tail=50 | grep -i escape

Best Practices

  1. Deploy Falco as DaemonSet to ensure coverage on all nodes
  2. Use eBPF driver over kernel module for safer operation
  3. Start with default rules (maturity_stable) then add custom rules
  4. Forward alerts to SIEM/SOAR via Falcosidekick
  5. Tag rules with MITRE ATT&CK technique IDs for correlation
  6. Test rules in permissive mode before enforcing
  7. Tune false positives by adding exception lists for known good processes
  8. Monitor Falco health with Prometheus metrics endpoint
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md2.3 KB

API Reference: Detecting Container Escape with Falco Rules

Falco CLI

falco --version                           # check version
falco --validate /path/to/rules.yaml      # validate rules syntax
falco -r /etc/falco/rules.d/escape.yaml   # load specific rules
falco --list                              # list all available fields
falco --list-events                       # list supported syscalls

Falco Rule Syntax

- rule: <name>
  desc: <description>
  condition: <filter expression>
  output: <alert message with fields>
  priority: <Emergency|Alert|Critical|Error|Warning|Notice|Informational|Debug>
  tags: [tag1, tag2]
  enabled: true

Key Falco Filter Fields

Field Description
container True if event is from a container
spawned_process True if new process spawned
proc.name Process name
proc.cmdline Full command line
proc.pname Parent process name
fd.name File descriptor name/path
container.name Container name
container.image.repository Image repository
container.privileged True if privileged
proc.is_exe_upper_layer Binary not in original image
evt.type Syscall type (setns, unshare, mount)

Falco JSON Output Format

{
  "time": "2024-01-15T10:30:00.000Z",
  "rule": "Container Escape Binary Execution",
  "priority": "Critical",
  "source": "syscall",
  "output": "Escape binary in container...",
  "output_fields": {
    "user.name": "root",
    "proc.cmdline": "nsenter -t 1 -m -u -i -n",
    "container.name": "attacker-pod"
  },
  "tags": ["container", "escape", "T1611"]
}

Falcosidekick Alert Routing

config:
  slack:
    webhookurl: "https://hooks.slack.com/services/XXX"
    minimumpriority: "critical"
  elasticsearch:
    hostport: "https://es:9200"
    index: "falco-alerts"

Helm Deployment

helm repo add falcosecurity https://falcosecurity.github.io/charts
helm install falco falcosecurity/falco \
  --namespace falco --create-namespace \
  --set driver.kind=ebpf \
  --set falcosidekick.enabled=true

CLI Usage

python agent.py --check-status
python agent.py --validate-rules /etc/falco/rules.d/escape.yaml
python agent.py --parse-alerts /var/log/falco/events.json --min-priority Warning
python agent.py --generate-rules > escape-rules.yaml
standards.md2.6 KB

Standards and References - Container Escape Detection with Falco

Industry Standards

NIST SP 800-190: Application Container Security Guide

  • Section 4.3: Container Runtime - Monitor containers for anomalous behavior at runtime
  • Section 5.4: Container Runtime Security - Implement runtime monitoring and alerting
  • Recommends syscall-level monitoring for escape detection

CIS Kubernetes Benchmark v1.8

  • 5.7.1: Create administrative boundaries between resources using namespaces
  • 5.7.2: Ensure that the seccomp profile is set to docker/default
  • 5.7.3: Apply Security Context to pods and containers
  • 5.7.4: The default namespace should not be used

MITRE ATT&CK for Containers

Technique ID Name Falco Detection
T1611 Escape to Host nsenter, mount, chroot detection
T1610 Deploy Container Privileged container launch detection
T1003 OS Credential Dumping /etc/shadow access from container
T1005 Data from Local System Sensitive file read detection
T1059 Command and Scripting Interpreter Shell spawn in container
T1068 Exploitation for Privilege Escalation Kernel exploit indicators

NSA/CISA Kubernetes Hardening Guide v1.2

  • Section 5: Audit Logging and Threat Detection
    • Enable runtime security monitoring
    • Detect anomalous container behavior in real-time
    • Monitor for privilege escalation attempts

Falco Rule Maturity Levels

Level Description Count
maturity_stable Production-ready, low false positives 25 rules
maturity_incubating Proven useful, may need tuning ~30 rules
maturity_sandbox Experimental, high false positive rate ~38 rules
maturity_deprecated Scheduled for removal Variable

Known Container Escape CVEs

CVE Description Falco Rule
CVE-2024-21626 runc process.cwd container breakout Detect use of /proc/self/fd to access host
CVE-2022-0492 cgroup v1 release_agent escape Write to Cgroup Release Agent
CVE-2022-0185 File system context exploit Detect unshare in container
CVE-2020-15257 containerd-shim API access Detect abstract socket connections
CVE-2019-5736 runc overwrite host binary Detect writes to /proc/self/exe

Compliance Mappings

PCI DSS v4.0

  • Requirement 10.6.1: Review logs for anomalies at least daily
  • Requirement 11.5: Deploy change-detection mechanisms

SOC 2 Type II

  • CC7.2: Monitor system components for anomalies
  • CC7.3: Evaluate security events to determine impact
workflows.md2.9 KB

Workflow - Detecting Container Escape with Falco Rules

Phase 1: Deploy Falco

Install on Kubernetes

helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
 
helm install falco falcosecurity/falco \
  --namespace falco --create-namespace \
  --set driver.kind=ebpf \
  --set falcosidekick.enabled=true \
  --set falcosidekick.webui.enabled=true \
  --set collectors.containerd.enabled=true
 
kubectl -n falco rollout status daemonset/falco --timeout=120s

Verify Deployment

kubectl get pods -n falco -o wide
kubectl logs -n falco -l app.kubernetes.io/name=falco --tail=10

Phase 2: Deploy Custom Escape Detection Rules

Create ConfigMap with Custom Rules

kubectl create configmap falco-escape-rules -n falco \
  --from-file=container-escape.yaml=/path/to/container-escape.yaml
 
# Restart Falco to load new rules
kubectl rollout restart daemonset/falco -n falco

Validate Rules Loaded

kubectl exec -n falco $(kubectl get pod -n falco -l app.kubernetes.io/name=falco -o jsonpath='{.items[0].metadata.name}') -- \
  falco --list | grep -i escape

Phase 3: Test Detection

Test 1 - Privileged Container

kubectl run escape-test-priv --image=alpine --restart=Never \
  --overrides='{"spec":{"containers":[{"name":"test","image":"alpine","command":["sleep","30"],"securityContext":{"privileged":true}}]}}'
 
# Check alert
kubectl logs -n falco -l app.kubernetes.io/name=falco --tail=5 | grep -i privileged
kubectl delete pod escape-test-priv

Test 2 - Sensitive File Access

kubectl run escape-test-shadow --image=alpine --restart=Never -- cat /etc/shadow
kubectl logs -n falco -l app.kubernetes.io/name=falco --tail=5 | grep -i shadow
kubectl delete pod escape-test-shadow

Test 3 - Shell Spawn

kubectl exec -it deploy/some-app -- /bin/sh
# In Falco logs, should see "Terminal shell in container"

Phase 4: Integrate Alerting

Configure Falcosidekick Outputs

# values-sidekick.yaml
config:
  slack:
    webhookurl: "https://hooks.slack.com/services/XXX/YYY/ZZZ"
    minimumpriority: "warning"
  elasticsearch:
    hostport: "https://elasticsearch:9200"
    index: "falco"
    minimumpriority: "notice"
  prometheus:
    enabled: true
helm upgrade falco falcosecurity/falco -n falco \
  -f values-sidekick.yaml

Phase 5: Tune and Maintain

Handle False Positives

# Add exceptions to rules
- rule: Terminal shell in container
  append: true
  exceptions:
    - name: known_shell_spawners
      fields: [container.image.repository]
      comps: [in]
      values:
        - [my-debug-image, kubectl-debug]

Regular Maintenance

  1. Update Falco rules weekly: falcoctl artifact install falco-rules
  2. Review new maturity_stable rules after each Falco release
  3. Correlate Falco alerts with Kubernetes audit logs
  4. Run escape simulation exercises monthly

Scripts 2

agent.py6.3 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Falco-based container escape detection agent.

Manages Falco rules, parses Falco alert output, and generates
escape detection reports from Falco JSON event streams.
"""

import argparse
import json
import subprocess
import sys
from datetime import datetime

ESCAPE_RULE_TAGS = ["container", "escape", "T1611", "T1610", "namespace",
                    "docker_socket", "cgroup", "kernel_module", "privileged"]

SEVERITY_MAP = {
    "Emergency": 0, "Alert": 1, "Critical": 2, "Error": 3,
    "Warning": 4, "Notice": 5, "Informational": 6, "Debug": 7
}


def check_falco_status():
    try:
        result = subprocess.run(["falco", "--version"],
                                capture_output=True, text=True, timeout=10)
        if result.returncode == 0:
            version = result.stdout.strip()
            return {"installed": True, "version": version}
    except FileNotFoundError:
        pass
    try:
        result = subprocess.run(["systemctl", "is-active", "falco"],
                                capture_output=True, text=True, timeout=5)
        return {"installed": True, "service_status": result.stdout.strip()}
    except FileNotFoundError:
        pass
    return {"installed": False}


def validate_rules_file(rules_path):
    try:
        result = subprocess.run(
            ["falco", "--validate", rules_path],
            capture_output=True, text=True, timeout=30)
        return {
            "valid": result.returncode == 0,
            "output": result.stdout.strip() if result.returncode == 0
                      else result.stderr.strip(),
        }
    except (FileNotFoundError, subprocess.TimeoutExpired) as e:
        return {"valid": False, "error": str(e)}


def parse_falco_alerts(filepath, min_priority="Warning"):
    min_level = SEVERITY_MAP.get(min_priority, 4)
    alerts = []
    escape_alerts = []

    with open(filepath, "r") as f:
        for line in f:
            line = line.strip()
            if not line:
                continue
            try:
                evt = json.loads(line)
            except json.JSONDecodeError:
                continue

            priority = evt.get("priority", "Informational")
            if SEVERITY_MAP.get(priority, 6) > min_level:
                continue

            alert = {
                "time": evt.get("time", ""),
                "rule": evt.get("rule", ""),
                "priority": priority,
                "source": evt.get("source", "syscall"),
                "output": evt.get("output", ""),
                "fields": evt.get("output_fields", {}),
                "tags": evt.get("tags", []),
            }
            alerts.append(alert)

            tags = set(evt.get("tags", []))
            if tags & set(ESCAPE_RULE_TAGS):
                escape_alerts.append(alert)

    return {"total_alerts": len(alerts), "escape_alerts": escape_alerts}


def generate_escape_rules_yaml():
    rules = """# Container Escape Detection Rules for Falco
# Deploy to /etc/falco/rules.d/container-escape.yaml

- list: escape_binaries
  items: [nsenter, unshare, mount, umount, pivot_root, chroot, modprobe, insmod]

- macro: container_escape_binary
  condition: spawned_process and container and proc.name in (escape_binaries)

- rule: Container Escape Binary Execution
  desc: Detect execution of binaries commonly used for container escape
  condition: container_escape_binary
  output: "Escape binary in container (user=%user.name cmd=%proc.cmdline container=%container.name image=%container.image.repository)"
  priority: CRITICAL
  tags: [container, escape, T1611]

- rule: Docker Socket Access from Container
  desc: Container accessing Docker socket enables full host control
  condition: (open_read or open_write) and container and fd.name = /var/run/docker.sock
  output: "Docker socket accessed (user=%user.name container=%container.name cmd=%proc.cmdline)"
  priority: CRITICAL
  tags: [container, escape, docker_socket, T1610]

- rule: Cgroup Release Agent Write
  desc: Writing to cgroup release_agent is a known container escape vector
  condition: open_write and container and fd.name endswith release_agent
  output: "Cgroup escape attempt (user=%user.name container=%container.name file=%fd.name)"
  priority: CRITICAL
  tags: [container, escape, cgroup]

- rule: Kernel Module Load from Container
  desc: Container attempting to load kernel module
  condition: spawned_process and container and proc.name in (modprobe, insmod, rmmod)
  output: "Kernel module load (user=%user.name container=%container.name cmd=%proc.cmdline)"
  priority: CRITICAL
  tags: [container, escape, kernel_module]

- rule: Sensitive Proc Access from Container
  desc: Container accessing sensitive /proc or /sys paths
  condition: open_read and container and (fd.name startswith /proc/sysrq-trigger or fd.name startswith /proc/kcore or fd.name startswith /proc/kallsyms)
  output: "Sensitive proc access (container=%container.name path=%fd.name cmd=%proc.cmdline)"
  priority: CRITICAL
  tags: [container, escape, proc_access]
"""
    return rules


def main():
    parser = argparse.ArgumentParser(description="Falco Container Escape Detection")
    parser.add_argument("--check-status", action="store_true", help="Check Falco installation")
    parser.add_argument("--validate-rules", help="Validate a Falco rules file")
    parser.add_argument("--parse-alerts", help="Parse Falco JSON alert log")
    parser.add_argument("--min-priority", default="Warning",
                        choices=list(SEVERITY_MAP.keys()))
    parser.add_argument("--generate-rules", action="store_true",
                        help="Output escape detection rules YAML")
    args = parser.parse_args()

    results = {"timestamp": datetime.utcnow().isoformat() + "Z"}

    if args.check_status:
        results["falco_status"] = check_falco_status()

    if args.validate_rules:
        results["validation"] = validate_rules_file(args.validate_rules)

    if args.parse_alerts:
        parsed = parse_falco_alerts(args.parse_alerts, args.min_priority)
        results["alert_summary"] = {
            "total_alerts": parsed["total_alerts"],
            "escape_alerts_count": len(parsed["escape_alerts"]),
        }
        results["escape_alerts"] = parsed["escape_alerts"]

    if args.generate_rules:
        print(generate_escape_rules_yaml())
        return

    print(json.dumps(results, indent=2))


if __name__ == "__main__":
    main()
process.py8.3 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
Falco Container Escape Rule Manager - Generate, validate, and deploy
custom Falco rules for container escape detection.
"""

import json
import subprocess
import sys
import argparse
from pathlib import Path
from datetime import datetime

# Container escape detection rule templates
ESCAPE_RULES = {
    "mount_host_fs": {
        "rule": "Container Mounting Host Filesystem",
        "desc": "Detect a container attempting to mount the host filesystem",
        "condition": 'spawned_process and container and proc.name = mount and (proc.args contains "/host" or proc.args contains "nsenter")',
        "priority": "CRITICAL",
        "tags": ["container", "escape", "T1611"],
    },
    "nsenter_usage": {
        "rule": "Nsenter Execution in Container",
        "desc": "Detect nsenter being used to escape container namespaces",
        "condition": "spawned_process and container and proc.name = nsenter",
        "priority": "CRITICAL",
        "tags": ["container", "escape", "namespace", "T1611"],
    },
    "privileged_container": {
        "rule": "Launch Privileged Container",
        "desc": "Detect a privileged container being launched",
        "condition": "container_started and container and container.privileged=true",
        "priority": "WARNING",
        "tags": ["container", "privileged", "T1610"],
    },
    "cgroup_escape": {
        "rule": "Write to Cgroup Release Agent",
        "desc": "Detect writes to cgroup release_agent - known escape vector",
        "condition": "open_write and container and fd.name endswith release_agent",
        "priority": "CRITICAL",
        "tags": ["container", "escape", "cgroup", "CVE-2022-0492"],
    },
    "docker_socket": {
        "rule": "Container Accessing Docker Socket",
        "desc": "Detect container accessing Docker socket for host control",
        "condition": "(open_read or open_write) and container and fd.name = /var/run/docker.sock",
        "priority": "CRITICAL",
        "tags": ["container", "escape", "docker-socket", "T1610"],
    },
    "kernel_module": {
        "rule": "Container Loading Kernel Module",
        "desc": "Detect a container attempting to load a kernel module",
        "condition": "spawned_process and container and proc.name in (insmod, modprobe)",
        "priority": "CRITICAL",
        "tags": ["container", "escape", "kernel", "T1611"],
    },
    "shadow_file": {
        "rule": "Container Reading Host Shadow File",
        "desc": "Detect container reading /etc/shadow",
        "condition": 'open_read and container and (fd.name = /etc/shadow or fd.name startswith /host/etc/shadow)',
        "priority": "CRITICAL",
        "tags": ["container", "credential-access", "T1003"],
    },
    "sysrq_trigger": {
        "rule": "Write to Sysrq Trigger from Container",
        "desc": "Detect writes to /proc/sysrq-trigger from container",
        "condition": "open_write and container and fd.name = /proc/sysrq-trigger",
        "priority": "CRITICAL",
        "tags": ["container", "escape", "host-manipulation"],
    },
}


def generate_rule_yaml(rule_key: str, rule_data: dict) -> str:
    """Generate a single Falco rule in YAML format."""
    tags_str = ", ".join(rule_data["tags"])
    output_fields = (
        "user=%user.name container_id=%container.id "
        "container_name=%container.name image=%container.image.repository "
        "command=%proc.cmdline"
    )
    return f"""- rule: {rule_data['rule']}
  desc: {rule_data['desc']}
  condition: >
    {rule_data['condition']}
  output: >
    {rule_data['desc']}
    ({output_fields})
  priority: {rule_data['priority']}
  tags: [{tags_str}]
"""


def generate_all_rules() -> str:
    """Generate complete Falco rules file for container escape detection."""
    header = f"""# Container Escape Detection Rules for Falco
# Generated: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC')}
# Deploy to: /etc/falco/rules.d/container-escape.yaml

- list: escape_binaries
  items: [nsenter, chroot, unshare, mount, umount, pivot_root]

- macro: container_escape_binary
  condition: spawned_process and container and proc.name in (escape_binaries)

"""
    rules = ""
    for key, data in ESCAPE_RULES.items():
        rules += generate_rule_yaml(key, data) + "\n"

    return header + rules


def parse_falco_alerts(log_file: str) -> list:
    """Parse Falco JSON alerts from log file."""
    alerts = []
    path = Path(log_file)
    if not path.exists():
        print(f"Log file not found: {log_file}", file=sys.stderr)
        return alerts

    for line in path.read_text().splitlines():
        line = line.strip()
        if not line:
            continue
        try:
            alert = json.loads(line)
            alerts.append({
                "time": alert.get("time", ""),
                "rule": alert.get("rule", ""),
                "priority": alert.get("priority", ""),
                "output": alert.get("output", ""),
                "tags": alert.get("tags", []),
                "container_name": alert.get("output_fields", {}).get("container.name", ""),
                "container_image": alert.get("output_fields", {}).get("container.image.repository", ""),
            })
        except json.JSONDecodeError:
            continue

    return alerts


def summarize_alerts(alerts: list) -> dict:
    """Summarize Falco alerts by rule and severity."""
    summary = {"total": len(alerts), "by_priority": {}, "by_rule": {}, "escape_attempts": []}

    for alert in alerts:
        pri = alert["priority"]
        rule = alert["rule"]
        summary["by_priority"][pri] = summary["by_priority"].get(pri, 0) + 1
        summary["by_rule"][rule] = summary["by_rule"].get(rule, 0) + 1

        if any(tag in alert.get("tags", []) for tag in ["escape", "T1611", "T1610"]):
            summary["escape_attempts"].append(alert)

    return summary


def check_falco_health() -> dict:
    """Check if Falco is running and healthy."""
    result = subprocess.run(
        ["kubectl", "get", "pods", "-n", "falco", "-l", "app.kubernetes.io/name=falco",
         "-o", "json"],
        capture_output=True, text=True,
    )
    if result.returncode != 0:
        return {"healthy": False, "error": result.stderr}

    pods = json.loads(result.stdout)
    pod_status = []
    for pod in pods.get("items", []):
        name = pod["metadata"]["name"]
        phase = pod["status"]["phase"]
        node = pod["spec"].get("nodeName", "unknown")
        pod_status.append({"name": name, "phase": phase, "node": node})

    all_running = all(p["phase"] == "Running" for p in pod_status)
    return {"healthy": all_running, "pods": pod_status}


def main():
    parser = argparse.ArgumentParser(description="Falco Container Escape Rule Manager")
    subparsers = parser.add_subparsers(dest="command")

    subparsers.add_parser("generate", help="Generate container escape detection rules")

    parse_cmd = subparsers.add_parser("parse-alerts", help="Parse Falco alert logs")
    parse_cmd.add_argument("--log-file", required=True, help="Path to Falco JSON log file")

    subparsers.add_parser("health", help="Check Falco deployment health")

    deploy_cmd = subparsers.add_parser("deploy", help="Deploy rules to Kubernetes")
    deploy_cmd.add_argument("--namespace", default="falco", help="Falco namespace")

    args = parser.parse_args()

    if args.command == "generate":
        print(generate_all_rules())

    elif args.command == "parse-alerts":
        alerts = parse_falco_alerts(args.log_file)
        summary = summarize_alerts(alerts)
        print(json.dumps(summary, indent=2))

    elif args.command == "health":
        health = check_falco_health()
        print(json.dumps(health, indent=2))

    elif args.command == "deploy":
        rules_yaml = generate_all_rules()
        proc = subprocess.run(
            ["kubectl", "create", "configmap", "falco-escape-rules",
             "-n", args.namespace, "--from-literal=container-escape.yaml=" + rules_yaml,
             "--dry-run=client", "-o", "yaml"],
            capture_output=True, text=True,
        )
        apply = subprocess.run(
            ["kubectl", "apply", "-f", "-"],
            input=proc.stdout, capture_output=True, text=True,
        )
        print(apply.stdout)
        if apply.returncode == 0:
            print("Rules deployed. Restart Falco to load:")
            print(f"  kubectl rollout restart daemonset/falco -n {args.namespace}")

    else:
        parser.print_help()


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 1.9 KB
Keep exploring