Container Security: Falco, Trivy, and Snyk Container in Practice
Secure your containers with Falco runtime detection, Trivy image scanning, and Snyk vulnerability management. Practical examples for CI/CD pipelines and...
The Three Pillars of Container Security
Container security operates at three levels:
<div style="margin:2.5rem auto;max-width:600px;width:100%;text-align:center;"><svg viewBox="0 0 600 220" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;"><rect width="600" height="220" rx="12" fill="#1a1a2e"/><path d="M300,25 L380,55 L380,120 Q380,170 300,195 Q220,170 220,120 L220,55 Z" fill="none" stroke="#6366f1" stroke-width="2.5"/><path d="M300,40 L365,65 L365,118 Q365,160 300,180 Q235,160 235,118 L235,65 Z" fill="#6366f1" opacity="0.15"/><rect x="280" y="95" width="40" height="30" rx="4" fill="#6366f1" opacity="0.9"/><path d="M288,95 L288,82 Q288,72 300,72 Q312,72 312,82 L312,95" fill="none" stroke="#6366f1" stroke-width="2.5"/><circle cx="300" cy="110" r="4" fill="#ffffff"/><text x="90" y="60" text-anchor="middle" fill="#3b82f6" font-size="10" font-family="system-ui">Firewall</text><line x1="130" y1="57" x2="218" y2="57" stroke="#3b82f6" stroke-width="1" stroke-dasharray="3,3"/><text x="90" y="100" text-anchor="middle" fill="#a855f7" font-size="10" font-family="system-ui">WAF</text><line x1="110" y1="97" x2="220" y2="85" stroke="#a855f7" stroke-width="1" stroke-dasharray="3,3"/><text x="90" y="140" text-anchor="middle" fill="#2dd4bf" font-size="10" font-family="system-ui">SSO / MFA</text><line x1="130" y1="137" x2="222" y2="120" stroke="#2dd4bf" stroke-width="1" stroke-dasharray="3,3"/><text x="510" y="60" text-anchor="middle" fill="#f59e0b" font-size="10" font-family="system-ui">TLS/SSL</text><line x1="470" y1="57" x2="382" y2="57" stroke="#f59e0b" stroke-width="1" stroke-dasharray="3,3"/><text x="510" y="100" text-anchor="middle" fill="#3b82f6" font-size="10" font-family="system-ui">RBAC</text><line x1="490" y1="97" x2="380" y2="85" stroke="#3b82f6" stroke-width="1" stroke-dasharray="3,3"/><text x="510" y="140" text-anchor="middle" fill="#a855f7" font-size="10" font-family="system-ui">Audit Logs</text><line x1="470" y1="137" x2="378" y2="120" stroke="#a855f7" stroke-width="1" stroke-dasharray="3,3"/></svg><p style="margin-top:0.75rem;font-size:0.85rem;color:#94a3b8;font-style:italic;line-height:1.4;">Defense in depth: multiple security layers protect your infrastructure from threats.</p></div>
1. Build time: Scan images for known vulnerabilities before deployment 2. Deploy time: Enforce policies on what can run in your environment 3. Runtime: Detect anomalous behavior in running containers
Each pillar needs different tools. Here is how Trivy, Snyk Container, and Falco cover all three.
Trivy: Image Scanning in CI/CD
Trivy by Aqua Security is the fastest and most comprehensive container image scanner. It detects vulnerabilities in OS packages, language-specific packages, misconfigurations, and secrets.
# Scan a Docker image
trivy image python:3.12-slim
# Output (abbreviated):
# python:3.12-slim (debian 12.5)
# Total: 45 (UNKNOWN: 0, LOW: 25, MEDIUM: 15, HIGH: 4, CRITICAL: 1)
#
# +-----------+------------------+----------+-------------------+
# | Library | Vulnerability | Severity | Fixed Version |
# +-----------+------------------+----------+-------------------+
# | libexpat | CVE-2024-50602 | CRITICAL | 2.5.0-1+deb12u2 |
# | openssl | CVE-2024-9143 | HIGH | 3.0.15-1~deb12u1 |
# +-----------+------------------+----------+-------------------+Trivy in a Gitea Actions CI pipeline:
# .gitea/workflows/security-scan.yml
name: Security Scan
on: [push, pull_request]
jobs:
trivy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t my-app:scan .
- name: Run Trivy vulnerability scanner
run: |
trivy image --exit-code 1 --severity CRITICAL,HIGH \
--ignore-unfixed \
--format table \
my-app:scan
- name: Run Trivy config scanner
run: |
trivy config --exit-code 1 --severity HIGH,CRITICAL .
- name: Run Trivy secret scanner
run: |
trivy fs --scanners secret --exit-code 1 .Trivy Dockerfile scanning catches misconfigurations:
trivy config Dockerfile
# Findings:
# - DS002: Image user should not be 'root' (HIGH)
# - DS026: No HEALTHCHECK defined (LOW)
# - DS001: ':latest' tag used (MEDIUM)Snyk Container: Developer-Friendly Vulnerability Management
Snyk Container focuses on the developer workflow. It integrates into your IDE, Git repository, and CI/CD pipeline to catch vulnerabilities early and suggest fixes.
# Scan image with Snyk
snyk container test python:3.12-slim --severity-threshold=high
# Monitor image for new vulnerabilities
snyk container monitor python:3.12-slim --org=techsaas
# Test a Dockerfile before building
snyk container test --file=Dockerfile .What makes Snyk different from Trivy:
# Snyk suggests base image upgrades
snyk container test my-app:latest
# Output includes:
# Tested 125 dependencies for known issues
# Found 12 issues (3 critical, 4 high, 5 medium)
#
# Base Image Recommendations:
# Current: python:3.12-slim (45 vulnerabilities)
# Recommended: python:3.12-slim-bookworm (12 vulnerabilities)
# Alternative: python:3.12-alpine (3 vulnerabilities)Snyk proactively tells you which base image has fewer vulnerabilities.
<div style="margin:2.5rem auto;max-width:600px;width:100%;text-align:center;"><svg viewBox="0 0 600 180" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;"><rect width="600" height="180" rx="12" fill="#1a1a2e"/><circle cx="60" cy="90" r="20" fill="none" stroke="#3b82f6" stroke-width="2"/><text x="60" y="94" text-anchor="middle" fill="#3b82f6" font-size="11" font-family="system-ui">User</text><rect x="120" y="65" width="95" height="50" rx="8" fill="#6366f1" opacity="0.85"/><text x="167" y="85" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">Identity</text><text x="167" y="100" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">Verify</text><rect x="250" y="65" width="95" height="50" rx="8" fill="#a855f7" opacity="0.85"/><text x="297" y="85" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">Policy</text><text x="297" y="100" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">Engine</text><rect x="380" y="65" width="95" height="50" rx="8" fill="#2dd4bf" opacity="0.85"/><text x="427" y="85" text-anchor="middle" fill="#1a1a2e" font-size="10" font-family="system-ui">Access</text><text x="427" y="100" text-anchor="middle" fill="#1a1a2e" font-size="10" font-family="system-ui">Proxy</text><rect x="510" y="65" width="60" height="50" rx="8" fill="#f59e0b" opacity="0.85"/><text x="540" y="94" text-anchor="middle" fill="#1a1a2e" font-size="10" font-family="system-ui">App</text><defs><marker id="arrow5" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6" fill="#e2e8f0"/></marker></defs><line x1="82" y1="90" x2="118" y2="90" stroke="#e2e8f0" stroke-width="1.5" marker-end="url(#arrow5)"/><line x1="217" y1="90" x2="248" y2="90" stroke="#e2e8f0" stroke-width="1.5" marker-end="url(#arrow5)"/><line x1="347" y1="90" x2="378" y2="90" stroke="#e2e8f0" stroke-width="1.5" marker-end="url(#arrow5)"/><line x1="477" y1="90" x2="508" y2="90" stroke="#e2e8f0" stroke-width="1.5" marker-end="url(#arrow5)"/><text x="167" y="140" text-anchor="middle" fill="#94a3b8" font-size="9" font-family="system-ui">MFA + Device</text><text x="297" y="140" text-anchor="middle" fill="#94a3b8" font-size="9" font-family="system-ui">Least Privilege</text><text x="427" y="140" text-anchor="middle" fill="#94a3b8" font-size="9" font-family="system-ui">Encrypted Tunnel</text><text x="300" y="165" text-anchor="middle" fill="#6366f1" font-size="11" font-family="system-ui" font-weight="bold">Never Trust, Always Verify</text></svg><p style="margin-top:0.75rem;font-size:0.85rem;color:#94a3b8;font-style:italic;line-height:1.4;">Zero Trust architecture: every request is verified through identity, policy, and access proxy layers.</p></div>
Trivy vs Snyk: Comparison
|---------|-------|----------------|
Our recommendation: Use Trivy in CI/CD (free, fast, offline-capable) and Snyk for developer workflow (IDE integration, base image recommendations, auto-fix PRs).
Falco: Runtime Security Detection
Falco is a CNCF project that detects anomalous behavior in running containers using kernel-level syscall monitoring. Think of it as an intrusion detection system for containers.
# Falco deployment with Docker Compose
services:
falco:
image: falcosecurity/falco:latest
container_name: falco
privileged: true
volumes:
- /var/run/docker.sock:/host/var/run/docker.sock:ro
- /proc:/host/proc:ro
- /etc:/host/etc:ro
- ./falco/rules:/etc/falco/rules.d:ro
environment:
- FALCO_BPF_PROBE=""
mem_limit: 256mCustom Falco rules:
# falco/rules/custom-rules.yaml
# Detect shell spawned in a container
- rule: Shell Spawned in Container
desc: Detect shell execution in a running container
condition: >
spawned_process and container and
proc.name in (bash, sh, zsh, dash, ash) and
not proc.pname in (cron, containerd-shim)
output: >
Shell spawned in container
(user=%user.name container=%container.name shell=%proc.name
parent=%proc.pname cmdline=%proc.cmdline image=%container.image.repository)
priority: WARNING
tags: [container, shell]
# Detect sensitive file access
- rule: Read Sensitive File in Container
desc: Detect reading of sensitive files like /etc/shadow
condition: >
open_read and container and
fd.name in (/etc/shadow, /etc/passwd, /etc/sudoers) and
not proc.name in (sshd, login, su, sudo)
output: >
Sensitive file read in container
(user=%user.name file=%fd.name container=%container.name image=%container.image.repository)
priority: ERROR
tags: [container, filesystem]
# Detect outbound connection to unexpected port
- rule: Unexpected Outbound Connection
desc: Detect containers making outbound connections to non-standard ports
condition: >
outbound and container and
not fd.sport in (80, 443, 5432, 6379, 27017, 53, 8080, 3000) and
not container.name in (cloudflared, traefik)
output: >
Unexpected outbound connection from container
(container=%container.name image=%container.image.repository
connection=%fd.name port=%fd.sport)
priority: NOTICE
tags: [container, network]Building a Complete Security Pipeline
Here is the full container security pipeline we implement at TechSaaS:
Developer writes code
↓
IDE: Snyk plugin warns about vulnerable dependencies
↓
Git push triggers CI pipeline
↓
CI Step 1: Trivy scans Dockerfile for misconfigurations
CI Step 2: Docker build
CI Step 3: Trivy scans built image for vulnerabilities
CI Step 4: Trivy scans for leaked secrets
CI Step 5: Block deployment if CRITICAL/HIGH found
↓
Deploy to production
↓
Runtime: Falco monitors syscalls for anomalous behavior
Runtime: CrowdSec monitors network for attacks
↓
Alert: Ntfy notification → Investigate → Remediate<div style="margin:2.5rem auto;max-width:600px;width:100%;text-align:center;"><svg viewBox="0 0 600 200" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;"><rect width="600" height="200" rx="12" fill="#1a1a2e"/><text x="80" y="25" text-anchor="middle" fill="#94a3b8" font-size="10" font-family="system-ui">Input</text><circle cx="80" cy="50" r="14" fill="none" stroke="#3b82f6" stroke-width="2"/><circle cx="80" cy="100" r="14" fill="none" stroke="#3b82f6" stroke-width="2"/><circle cx="80" cy="150" r="14" fill="none" stroke="#3b82f6" stroke-width="2"/><text x="230" y="25" text-anchor="middle" fill="#94a3b8" font-size="10" font-family="system-ui">Hidden</text><circle cx="230" cy="45" r="14" fill="#6366f1" opacity="0.8"/><circle cx="230" cy="85" r="14" fill="#6366f1" opacity="0.8"/><circle cx="230" cy="125" r="14" fill="#6366f1" opacity="0.8"/><circle cx="230" cy="165" r="14" fill="#6366f1" opacity="0.8"/><text x="380" y="25" text-anchor="middle" fill="#94a3b8" font-size="10" font-family="system-ui">Hidden</text><circle cx="380" cy="55" r="14" fill="#a855f7" opacity="0.8"/><circle cx="380" cy="100" r="14" fill="#a855f7" opacity="0.8"/><circle cx="380" cy="145" r="14" fill="#a855f7" opacity="0.8"/><text x="520" y="25" text-anchor="middle" fill="#94a3b8" font-size="10" font-family="system-ui">Output</text><circle cx="520" cy="80" r="14" fill="none" stroke="#2dd4bf" stroke-width="2"/><circle cx="520" cy="130" r="14" fill="none" stroke="#2dd4bf" stroke-width="2"/><line x1="94" y1="50" x2="216" y2="45" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="50" x2="216" y2="85" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="50" x2="216" y2="125" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="50" x2="216" y2="165" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="100" x2="216" y2="45" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="100" x2="216" y2="85" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="100" x2="216" y2="125" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="100" x2="216" y2="165" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="150" x2="216" y2="45" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="150" x2="216" y2="85" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="150" x2="216" y2="125" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="150" x2="216" y2="165" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="45" x2="366" y2="55" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="45" x2="366" y2="100" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="45" x2="366" y2="145" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="85" x2="366" y2="55" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="85" x2="366" y2="100" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="85" x2="366" y2="145" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="125" x2="366" y2="55" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="125" x2="366" y2="100" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="125" x2="366" y2="145" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="165" x2="366" y2="55" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="165" x2="366" y2="100" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="165" x2="366" y2="145" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="394" y1="55" x2="506" y2="80" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="394" y1="55" x2="506" y2="130" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="394" y1="100" x2="506" y2="80" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="394" y1="100" x2="506" y2="130" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="394" y1="145" x2="506" y2="80" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="394" y1="145" x2="506" y2="130" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/></svg><p style="margin-top:0.75rem;font-size:0.85rem;color:#94a3b8;font-style:italic;line-height:1.4;">Neural network architecture: data flows through input, hidden, and output layers.</p></div>
Practical Dockerfile Hardening
Apply these fixes before scanning catches them:
# BAD: Running as root, using latest tag
FROM python:latest
COPY . /app
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
# GOOD: Non-root user, pinned version, multi-stage, healthcheck
FROM python:3.12-slim-bookworm AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
FROM python:3.12-slim-bookworm
RUN groupadd -r appuser && useradd -r -g appuser appuser
WORKDIR /app
COPY --from=builder /root/.local /home/appuser/.local
COPY --chown=appuser:appuser . .
ENV PATH=/home/appuser/.local/bin:$PATH
USER appuser
HEALTHCHECK --interval=30s --timeout=5s \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')"
EXPOSE 8080
CMD ["python", "app.py"]Container security is not optional — it is a continuous process. Start with Trivy in your CI pipeline (it takes 5 minutes to set up), then add Falco for runtime detection, and use Snyk when you want developer-friendly vulnerability management. At TechSaaS, we run Trivy CI scans on all our Gitea repositories and CrowdSec for runtime intrusion prevention.
Need help with security?
TechSaaS provides expert consulting and managed services for cloud infrastructure, DevOps, and AI/ML operations.