Introductie: Waarom containerbeveiliging in 2026 topprioriteit moet zijn
Containers zijn de ruggengraat van moderne infrastructuur geworden. Of je nu microservices draait op Kubernetes, CI/CD-pipelines automatiseert of applicaties isoleert op een enkele Linux-server — ze zijn overal. Maar die populariteit heeft een keerzijde: containers zijn een aantrekkelijk doelwit voor aanvallers. En eerlijk gezegd? Ze worden in de praktijk veel te vaak slecht beveiligd.
De cijfers uit 2025 en begin 2026 zijn ronduit verontrustend. Uit onderzoek van Aqua Security blijkt dat 54% van alle containerimages op Docker Hub gevoelige informatie bevat — hardcoded API-sleutels, database-credentials, private keys, noem maar op. De Elastic Global Threat Report laat zien dat 89% van alle aanvalsgedrag op Linux-endpoints gerelateerd is aan brute-force pogingen, waarbij containeromgevingen steeds vaker het doelwit zijn.
En dan zijn er nog de runtime-kwetsbaarheden. Denk aan CVE-2024-21626 (runc container escape) of kernelkwetsbaarheden zoals Dirty Pipe. Die laten keer op keer zien dat containerisatie geen magische beveiligingsgrens is.
Het probleem is eigenlijk simpel: veel teams behandelen containers als zwarte dozen. Ze pullen een image, draaien docker run en gaan door met hun dag. Maar een container deelt de kernel van het hostsysteem. Eén verkeerde configuratie — een --privileged flag hier, een ontbrekend seccomp-profiel daar, of het draaien als root — en een aanvaller heeft directe toegang tot je host.
In deze gids laat ik je stap voor stap zien hoe je Linux-containers grondig beveiligt met Podman 5.8. We duiken in rootless containers, Linux capabilities, seccomp-filtering, SELinux-integratie, imagescanning met Trivy en netwerkisolatie. Alle voorbeelden zijn getest en productieklaar.
Waarom Podman in plaats van Docker?
Als je al jaren met Docker werkt, vraag je je misschien af waarom je zou overstappen. Het korte antwoord: Podman is architecturaal veiliger. Maar laten we dat concreet maken, want "veiliger" is een makkelijk woord.
De fundamentele architectuurverschillen
Docker draait traditioneel als een daemon met root-privileges. Elk containercommando gaat via deze centrale daemon die constant op de achtergrond draait. Dat betekent dat elke kwetsbaarheid in de Docker-daemon potentieel tot volledige host-compromise kan leiden. Het is één groot single point of failure.
Podman pakt dit fundamenteel anders aan:
- Daemonloos — Podman draait geen achtergrondproces. Containers worden direct als kindprocessen van de gebruiker gestart. Geen daemon = geen aanvalsoppervlak van een geprivilegieerd achtergrondproces.
- Rootless by design — Waar Docker rootless-modus als een opt-in feature heeft toegevoegd, is Podman er vanaf dag één voor ontworpen. Rootless containers werken gewoon out-of-the-box.
- Fork/exec-model — Containers worden beheerd via helper-processen:
conmonvoor procesmonitoring,slirp4netnsofpastavoor netwerking in rootless-modus, enfuse-overlayfsvoor opslaglagen. - Docker-compatibel — Podman biedt een Docker-compatibele CLI. In de meeste gevallen kun je simpelweg
alias docker=podmangebruiken en werken je bestaande scripts gewoon door.
Beveiligingsvergelijking in cijfers
Een concreet verschil dat direct impact heeft: Docker kent standaard 14 Linux capabilities toe aan containers, terwijl Podman er slechts 11 toekent. Dat klinkt misschien als een klein verschil, maar minder capabilities betekent minder aanvalsoppervlak — en dat is precies het principe van least privilege dat we willen hanteren.
De nieuwste versie, Podman 5.8.0 (uitgebracht op 12 februari 2026), brengt onder andere automatische migratie van BoltDB naar SQLite-databases, verbeterde Quadlet-ondersteuning voor OCI-artefacten, en nieuwe opties voor container-restore met actieve TCP-verbindingen.
Podman installeren en voorbereiden
Installatie per distributie
Op de meeste moderne Linux-distributies is Podman beschikbaar via de standaard packagemanager. Niets spannends hier — gewoon installeren en gaan:
# Ubuntu 22.04+ / Debian 12+
sudo apt update && sudo apt install -y podman
# RHEL 9 / AlmaLinux 9 / Rocky Linux 9
sudo dnf install -y podman
# Fedora 39+
sudo dnf install -y podman
# Arch Linux
sudo pacman -S podman
# Controleer de geïnstalleerde versie
podman --version
# Verwachte output: podman version 5.8.0
Rootless-vereisten controleren
Voordat je rootless containers kunt draaien, moet je controleren of je systeem correct is geconfigureerd. Dit is het stuk waar de meeste mensen vastlopen, dus neem even de tijd:
# Controleer of user namespaces zijn ingeschakeld
cat /proc/sys/user/max_user_namespaces
# Moet een waarde groter dan 0 tonen (bijv. 15000)
# Als het 0 is, schakel het in:
sudo sysctl -w user.max_user_namespaces=15000
# Maak het persistent:
echo "user.max_user_namespaces=15000" | sudo tee /etc/sysctl.d/99-userns.conf
# Controleer subordinate UID/GID-ranges voor je gebruiker
grep $USER /etc/subuid
grep $USER /etc/subgid
# Verwachte output: gebruikersnaam:100000:65536
# Als er geen ranges zijn geconfigureerd:
sudo usermod --add-subuids 100000-165535 $USER
sudo usermod --add-subgids 100000-165535 $USER
# Controleer of de benodigde tools aanwezig zijn
which newuidmap newgidmap
# Beide moeten een pad teruggeven
Podman-systeeminformatie controleren
# Bekijk de volledige systeemconfiguratie
podman info
# Controleer specifiek de beveiligingsconfiguratie
podman info --format '{{.Host.Security}}'
# Toont: AppArmor/SELinux status, seccomp, rootless, cgroupsversie
Rootless containers: de basis van je beveiliging
Rootless containers zijn het fundament van elke veilige containeromgeving. Het principe is simpel maar krachtig: als een aanvaller erin slaagt uit de container te ontsnappen, heeft hij alleen de rechten van een onbevoegde gebruiker op de host. Geen root-toegang, geen volledige systeemcompromittering. Dat scheelt nogal.
Hoe rootless containers werken
Podman gebruikt user namespaces om UID/GID-mapping te realiseren. Binnen de container kan een proces als root (UID 0) draaien, maar op de host wordt dit gemapped naar een onbevoegde UID (bijvoorbeeld 100000). Het mooie hiervan: de applicatie in de container denkt root te zijn, maar het hostsysteem behandelt het gewoon als een normale gebruiker.
# Start een rootless container en controleer de UID-mapping
podman run --rm -it alpine:latest id
# Output: uid=0(root) gid=0(root) — binnen de container
# Bekijk hoe dit er op de host uitziet
podman run --rm -d --name test-container alpine:latest sleep 300
podman top test-container huser,hpid,user,pid
# huser toont de echte host-UID (bijv. 1000), user toont de container-UID (0)
# Bekijk de UID-mapping van een draaiende container
podman inspect test-container --format '{{.HostConfig.IDMappings}}'
# Opruimen
podman stop test-container
Rootless versus rootful: de beveiligingsimplicaties
Laten we heel concreet zijn over wat rootless containers wel en niet beschermen:
- Container-escape wordt gemitigeerd — Als een aanvaller via een kwetsbaarheid in de container-runtime (zoals CVE-2024-21626 in runc) uit de container ontsnapt, krijgt hij alleen toegang als een onbevoegde gebruiker. Bij rootful containers zou dit root-toegang op de host betekenen. Groot verschil.
- Kernel blijft gedeeld — Dit is een belangrijke nuance. Rootless containers delen nog steeds de kernel met de host. Kernelkwetsbaarheden (zoals Dirty Pipe) kunnen ook vanuit rootless containers worden misbruikt. Dit is een inherente beperking van containerisatie in het algemeen.
- Bepaalde capabilities zijn beperkt — In een rootless container is
CAP_SYS_ADMINbeperkt tot de user namespace, niet tot de host. Dit voorkomt veel privilege-escalatie-aanvallen.
Linux capabilities: het principe van least privilege
Linux capabilities splitsen de monolithische root-privilege op in kleinere, individuele rechten. In plaats van een container volledige root-toegang te geven, ken je alleen de specifieke capabilities toe die de applicatie daadwerkelijk nodig heeft. Klinkt logisch, toch? Toch zie ik in de praktijk dat dit stap vaak wordt overgeslagen.
Standaard capabilities in Podman
Podman kent standaard 11 capabilities toe aan containers. Laten we eens kijken welke dat zijn:
# Bekijk de standaard capabilities van een container
podman run --rm alpine:latest grep Cap /proc/self/status
# CapEff: 00000000a80425fb
# Decodeer de capabilities
podman run --rm alpine:latest sh -c "apk add -q libcap && capsh --decode=00000000a80425fb"
De standaard capabilities zijn: CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_FOWNER, CAP_FSETID, CAP_KILL, CAP_NET_BIND_SERVICE, CAP_NET_RAW, CAP_SETFCAP, CAP_SETGID, CAP_SETPCAP en CAP_SETUID.
Capabilities beperken in de praktijk
De veiligste aanpak — en naar mijn mening de enige juiste aanpak — is: drop alles, voeg alleen toe wat nodig is.
# Drop ALLE capabilities en voeg alleen specifieke toe
podman run --rm \
--cap-drop=ALL \
--cap-add=CAP_NET_BIND_SERVICE \
nginx:alpine
# Voor een eenvoudige webapplicatie die geen speciale rechten nodig heeft:
podman run --rm \
--cap-drop=ALL \
--user 1000:1000 \
my-webapp:latest
# Controleer welke capabilities een draaiende container heeft
podman run --rm --cap-drop=ALL alpine:latest grep Cap /proc/self/status
# CapEff: 0000000000000000 — geen enkele capability
Veelvoorkomende capabilities en hun risico's
Enkele capabilities verdienen extra aandacht vanwege hun beveiligingsrisico:
- CAP_NET_RAW — Staat raw sockets toe. Nodig voor
ping, maar kan ook worden misbruikt voor ARP-spoofing en netwerksniffing. Drop deze tenzij je applicatie het echt nodig heeft. - CAP_SYS_ADMIN — De meest gevaarlijke capability, punt. Staat mount-operaties, namespace-manipulatie en tal van andere beheertaken toe. Gebruik dit nooit in productie tenzij het echt niet anders kan.
- CAP_DAC_OVERRIDE — Negeert bestandspermissies. Handig voor sommige initialisatiescripts, maar een flink beveiligingsrisico als het niet nodig is.
Seccomp-profielen: systeemaanroepen filteren
Oké, nu wordt het wat technischer. Seccomp (Secure Computing Mode) is een Linux-kernelfunctie waarmee je kunt beperken welke systeemaanroepen een container mag uitvoeren. Dit is een enorm krachtige beveiligingslaag, omdat letterlijk elke interactie tussen een container en de kernel via systeemaanroepen verloopt.
Het standaard seccomp-profiel
Podman wordt geleverd met een standaard seccomp-profiel dat gevaarlijke systeemaanroepen blokkeert, zoals reboot, mount, kexec_load en init_module. Goed nieuws, maar er is een "maar": dit profiel staat nog steeds meer dan 300 van de 435+ systeemaanroepen toe op een x86_64-systeem.
Volgens onderzoek van Aqua Security hebben de meeste containers slechts 40 tot 70 systeemaanroepen nodig. Er is dus flink wat ruimte voor verbetering.
Een aangepast seccomp-profiel genereren met eBPF
De meest effectieve manier om een seccomp-profiel te maken is door de daadwerkelijke systeemaanroepen van je applicatie te traceren en alleen díe toe te staan:
# Stap 1: Installeer de OCI seccomp BPF hook
# Op Fedora/RHEL:
sudo dnf install -y oci-seccomp-bpf-hook
# Stap 2: Draai je container met syscall-tracing ingeschakeld
# (vereist root voor de eBPF-hook)
sudo podman run --rm \
--annotation io.containers.trace-syscall=of:/tmp/my-app-seccomp.json \
my-webapp:latest
# Stap 3: Bekijk het gegenereerde profiel
cat /tmp/my-app-seccomp.json | python3 -m json.tool | head -30
# Stap 4: Gebruik het profiel voor je rootless container
podman run --rm \
--security-opt seccomp=/tmp/my-app-seccomp.json \
my-webapp:latest
Handmatig een strikt seccomp-profiel maken
Als je liever handmatig een profiel opstelt (of als de eBPF-methode niet beschikbaar is op je systeem), kun je beginnen met een restrictieve basis:
{
"defaultAction": "SCMP_ACT_ERRNO",
"defaultErrnoRet": 1,
"architectures": [
"SCMP_ARCH_X86_64",
"SCMP_ARCH_X86",
"SCMP_ARCH_AARCH64"
],
"syscalls": [
{
"names": [
"accept", "accept4", "access", "arch_prctl", "bind",
"brk", "clock_getres", "clock_gettime", "clone",
"close", "connect", "dup", "dup2", "dup3",
"epoll_create", "epoll_create1", "epoll_ctl",
"epoll_wait", "epoll_pwait", "execve", "exit",
"exit_group", "faccessat", "faccessat2", "fadvise64",
"fallocate", "fchmod", "fchown", "fcntl", "fdatasync",
"flock", "fstat", "fstatfs", "fsync", "ftruncate",
"futex", "getcwd", "getdents", "getdents64",
"getegid", "geteuid", "getgid", "getpeername",
"getpid", "getppid", "getrandom", "getsockname",
"getsockopt", "gettid", "gettimeofday", "getuid",
"ioctl", "listen", "lseek", "madvise", "memfd_create",
"mmap", "mprotect", "mremap", "munmap", "nanosleep",
"newfstatat", "open", "openat", "pipe", "pipe2",
"poll", "ppoll", "pread64", "preadv", "prlimit64",
"pwrite64", "read", "readlink", "readlinkat", "readv",
"recvfrom", "recvmsg", "rename", "renameat2",
"rt_sigaction", "rt_sigprocmask", "rt_sigreturn",
"sched_getaffinity", "sched_yield", "sendmsg",
"sendto", "set_robust_list", "set_tid_address",
"setgid", "setsockopt", "setuid", "shutdown",
"sigaltstack", "socket", "socketpair", "statfs",
"statx", "tgkill", "umask", "uname", "unlink",
"unlinkat", "wait4", "write", "writev"
],
"action": "SCMP_ACT_ALLOW"
}
]
}
Sla dit op als /etc/containers/seccomp-strict.json en pas het toe:
# Pas het strikte profiel toe op een container
podman run --rm \
--security-opt seccomp=/etc/containers/seccomp-strict.json \
my-webapp:latest
# Of stel het in als systeembreed standaardprofiel
# Bewerk /etc/containers/containers.conf (rootful) of
# ~/.config/containers/containers.conf (rootless):
# [containers]
# seccomp_profile = "/etc/containers/seccomp-strict.json"
SELinux- en AppArmor-integratie
Mandatory Access Control (MAC) vormt een extra beveiligingslaag bovenop de standaard Linux-permissies. Waar DAC (Discretionary Access Control) door de bestandseigenaar wordt beheerd, wordt MAC door het systeem afgedwongen — zelfs root kan de beperkingen niet omzeilen. En dat is precies waarom het zo waardevol is.
SELinux met Podman (RHEL/Fedora)
Op RHEL-gebaseerde distributies heeft Podman native SELinux-integratie. Containers worden automatisch gelabeld met het juiste SELinux-type, waardoor ze worden geïsoleerd van het hostsysteem en van elkaar.
# Controleer of SELinux actief is
getenforce
# Verwachte output: Enforcing
# Bekijk het SELinux-label van een container
podman run --rm alpine:latest cat /proc/self/attr/current
# Output: system_u:system_r:container_t:s0:c123,c456
# Het label container_t beperkt wat de container kan doen:
# - Geen toegang tot hostbestanden buiten gemounte volumes
# - Geen toegang tot /proc of /sys van de host
# - Geen mogelijkheid om andere containers te beïnvloeden
# Volume-mounts met SELinux-labels
# :z — privé label (alleen deze container heeft toegang)
podman run --rm -v /data/app:/app:z my-webapp:latest
# :Z — gedeeld label (meerdere containers kunnen toegang krijgen)
podman run --rm -v /data/shared:/shared:Z my-webapp:latest
AppArmor met Podman (Ubuntu/Debian)
Op Ubuntu en Debian gebruikt Podman AppArmor-profielen. Het standaardprofiel beperkt al veel gevaarlijke operaties, maar je kunt het nog verder aanscherpen:
# Controleer of AppArmor actief is
sudo aa-status
# Bekijk het actieve AppArmor-profiel van een container
podman run --rm alpine:latest cat /proc/self/attr/apparmor/current 2>/dev/null
# Een aangepast AppArmor-profiel voor een webapplicatie
# Sla op als /etc/apparmor.d/containers/webapp-profile:
cat <<'PROFILE'
#include <tunables/global>
profile webapp-container flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
# Sta netwerktoegang toe
network inet stream,
network inet6 stream,
# Sta leestoegang toe tot applicatiebestanden
/app/** r,
/app/bin/* ix,
# Blokkeer toegang tot gevoelige systeembestanden
deny /etc/shadow r,
deny /etc/passwd w,
deny /proc/sys/** w,
# Sta tmp-gebruik toe
/tmp/** rw,
}
PROFILE
# Laad het profiel
sudo apparmor_parser -r /etc/apparmor.d/containers/webapp-profile
# Gebruik het aangepaste profiel
podman run --rm \
--security-opt apparmor=webapp-container \
my-webapp:latest
Imagescanning met Trivy
Een container is slechts zo veilig als het image waarop hij is gebouwd. Je kunt alle seccomp-profielen en SELinux-labels van de wereld configureren, maar als je base image vol zit met bekende kwetsbaarheden, heb je alsnog een probleem.
Trivy (v0.68.2, begin 2026) van Aqua Security is naar mijn ervaring de beste tool voor het scannen van containerimages op kwetsbaarheden, misconfiguratiefouten en gelekte geheimen.
Trivy installeren en gebruiken
# Installeer Trivy
# Op RHEL/Fedora:
sudo dnf install -y trivy
# Op Ubuntu/Debian:
sudo apt install -y wget apt-transport-https gnupg lsb-release
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/trivy.list
sudo apt update && sudo apt install -y trivy
# Alternatief: via installatiescript
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
# Scan een containerimage op kwetsbaarheden
trivy image nginx:latest
# Scan alleen op HIGH en CRITICAL kwetsbaarheden
trivy image --severity HIGH,CRITICAL nginx:latest
# Scan inclusief geheimen en misconfiguratiefouten
trivy image --scanners vuln,secret,misconfig nginx:latest
# Genereer een SBOM in CycloneDX-formaat
trivy image --format cyclonedx --output nginx-sbom.cdx.json nginx:latest
Trivy integreren in je container-buildproces
De echte kracht van Trivy zit 'm in het integreren in je buildworkflow. Zo voorkom je dat kwetsbare images ooit in productie terechtkomen:
#!/bin/bash
# build-and-scan.sh — Bouw en scan een containerimage
IMAGE_NAME="my-webapp"
IMAGE_TAG="v1.0"
SEVERITY_THRESHOLD="HIGH,CRITICAL"
# Bouw het image
podman build -t ${IMAGE_NAME}:${IMAGE_TAG} .
# Scan het image — faal bij HIGH of CRITICAL kwetsbaarheden
trivy image \
--severity ${SEVERITY_THRESHOLD} \
--exit-code 1 \
--ignore-unfixed \
${IMAGE_NAME}:${IMAGE_TAG}
if [ $? -ne 0 ]; then
echo "FOUT: Image bevat kwetsbaarheden met severity ${SEVERITY_THRESHOLD}"
echo "Los de kwetsbaarheden op voordat je dit image deployt."
exit 1
fi
echo "Image ${IMAGE_NAME}:${IMAGE_TAG} is goedgekeurd."
Netwerkisolatie en beperking
Standaard kunnen containers vrij communiceren met het netwerk en met andere containers. Dat is handig voor ontwikkeling, maar in een productieomgeving wil je dit beperken tot het strikt noodzakelijke.
Geïsoleerde container-netwerken aanmaken
# Maak een intern netwerk aan (geen externe toegang)
podman network create \
--internal \
--subnet 10.89.1.0/24 \
backend-net
# Maak een netwerk met beperkte externe toegang
podman network create \
--subnet 10.89.2.0/24 \
--gateway 10.89.2.1 \
frontend-net
# Start containers in geïsoleerde netwerken
podman run -d \
--name database \
--network backend-net \
--cap-drop=ALL \
postgres:16-alpine
podman run -d \
--name webapp \
--network backend-net \
--network frontend-net \
--cap-drop=ALL \
--cap-add=CAP_NET_BIND_SERVICE \
-p 8080:8080 \
my-webapp:latest
# De database is alleen bereikbaar vanuit het backend-net
# De webapp kan zowel de database als het externe netwerk bereiken
# Bekijk de netwerkconfiguratie
podman network inspect backend-net
DNS en intercommunicatie beperken
# Schakel DNS-resolutie uit voor containers die het niet nodig hebben
podman run --rm \
--dns=none \
--network=none \
data-processor:latest /app/process-batch.sh
# Gebruik specifieke DNS-servers in plaats van de host-DNS
podman run --rm \
--dns=9.9.9.9 \
--dns=149.112.112.112 \
my-webapp:latest
Read-only bestandssystemen en tmpfs
Dit is eerlijk gezegd een van mijn favoriete beveiligingsmaatregelen, omdat hij zo simpel en effectief is. Een read-only rootbestandssysteem voorkomt dat een aanvaller bestanden kan wijzigen binnen de container — geen malware-injectie, geen configuratie-aanpassingen, geen backdoors.
# Start een container met een read-only rootbestandssysteem
podman run --rm \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=100m \
--tmpfs /run:rw,noexec,nosuid,size=50m \
--cap-drop=ALL \
nginx:alpine
# Voor applicaties die schrijftoegang nodig hebben tot specifieke mappen:
podman run --rm \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid \
-v app-data:/var/lib/app:rw \
--cap-drop=ALL \
my-webapp:latest
Podman Security Bench: geautomatiseerde beveiligingsaudit
Podman Security Bench is een open-source script dat tientallen best practices toetst, gebaseerd op de CIS Docker Benchmark v1.3.1. Handig om snel te zien of je iets over het hoofd hebt gezien.
# Clone en voer de security bench uit
git clone https://github.com/containers/podman-security-bench.git
cd podman-security-bench
sudo ./podman-security-bench.sh
# De output toont per categorie of je slaagt of faalt:
# [PASS] 1.1 - Ensure a separate partition for containers has been created
# [WARN] 1.2 - Ensure only trusted users are allowed to control Podman
# [PASS] 2.1 - Ensure network traffic is restricted between containers
# ...
Complete productieklare containerconfiguratie
Goed, tijd om alles samen te brengen. Laten we alle beveiligingslagen combineren in één productieklare configuratie:
# Stap 1: Bouw een minimaal image met een multi-stage build
# Containerfile (ook bekend als Dockerfile)
# --- Build stage ---
FROM golang:1.23-alpine AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app/server ./cmd/server
# --- Runtime stage ---
FROM scratch
COPY --from=builder /app/server /server
USER 65534:65534
ENTRYPOINT ["/server"]
# Stap 2: Bouw en scan het image
podman build -t my-secure-app:v1.0 .
trivy image --severity HIGH,CRITICAL --exit-code 1 my-secure-app:v1.0
# Stap 3: Maak een geïsoleerd netwerk aan
podman network create --internal --subnet 10.89.10.0/24 secure-backend
# Stap 4: Start de container met alle beveiligingslagen
podman run -d \
--name my-secure-app \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=50m \
--cap-drop=ALL \
--cap-add=CAP_NET_BIND_SERVICE \
--security-opt seccomp=/etc/containers/seccomp-strict.json \
--security-opt no-new-privileges \
--network secure-backend \
--memory 512m \
--cpus 1.0 \
--pids-limit 100 \
--user 65534:65534 \
-p 127.0.0.1:8080:8080 \
my-secure-app:v1.0
# Stap 5: Verifieer de beveiligingsconfiguratie
podman inspect my-secure-app --format '{{.HostConfig.SecurityOpt}}'
podman inspect my-secure-app --format '{{.HostConfig.CapDrop}}'
Overzicht van de beveiligingslagen
Even op een rijtje wat elke flag doet in onze productieklare configuratie:
- --read-only — Voorkomt schrijfbewerkingen naar het rootbestandssysteem
- --tmpfs /tmp — Biedt een beperkte schrijfbare tmpfs met noexec en nosuid
- --cap-drop=ALL — Verwijdert alle Linux capabilities
- --cap-add=CAP_NET_BIND_SERVICE — Voegt alleen de noodzakelijke capability toe
- --security-opt seccomp=... — Past een strikt seccomp-profiel toe
- --security-opt no-new-privileges — Voorkomt privilege-escalatie via setuid/setgid
- --network secure-backend — Isoleert de container in een intern netwerk
- --memory 512m — Beperkt geheugengebruik (voorkomt DoS)
- --cpus 1.0 — Beperkt CPU-gebruik
- --pids-limit 100 — Beperkt het aantal processen (voorkomt fork bombs)
- --user 65534:65534 — Draait als de nobody-gebruiker
- -p 127.0.0.1:8080:8080 — Bindt de poort alleen aan localhost
Monitoring en integratie met Wazuh
Beveiliging stopt niet bij configuratie — je moet ook runtime-anomalieën detecteren. Als je Wazuh al hebt draaien (zie onze Wazuh-installatiegids), kun je vrij eenvoudig containergebeurtenissen monitoren:
# Wazuh kan Podman-events monitoren via de audit-log
# Voeg deze regels toe aan /var/ossec/etc/ossec.conf op de Wazuh-agent:
<localfile>
<log_format>json</log_format>
<location>/var/log/containers/*.log</location>
</localfile>
# Podman genereert events die Wazuh kan analyseren:
# - Container starts/stops
# - Image pulls
# - Privileged container starts
# - Security-opt wijzigingen
# Bekijk Podman-events handmatig:
podman events --filter event=start --since 1h
Veelgestelde vragen
Is Podman een volledige vervanging voor Docker?
Voor de meeste gebruikssituaties: ja. Podman biedt een Docker-compatibele CLI, ondersteunt Dockerfiles (Containerfiles), Docker Compose (via podman-compose of de ingebouwde podman compose) en de meeste Docker-commando's. Het enige verschil dat echt impact kan hebben is het ontbreken van een daemon — tools die afhankelijk zijn van de Docker-socket moeten worden aangepast om de Podman-socket te gebruiken.
Zijn rootless containers langzamer dan rootful containers?
Er is een minimale overhead door user namespace-mapping en fuse-overlayfs voor opslag, maar in de praktijk merk je er weinig van. Voor de meeste workloads is het verschil verwaarloosbaar. Vanaf kernel 5.11+ met native overlay-ondersteuning in user namespaces wordt de prestatie-overhead nog verder gereduceerd.
Kan ik seccomp-profielen gebruiken in combinatie met SELinux?
Absoluut, en ik zou het zelfs sterk aanraden. Seccomp en SELinux zijn complementaire beveiligingslagen. Seccomp filtert systeemaanroepen op kernelniveau, terwijl SELinux toegang tot bestanden, netwerk en processen beheert via labels. Samen bieden ze defense-in-depth: als één laag wordt omzeild, vangt de andere het op.
Hoe beveilig ik geheimen (secrets) in Podman-containers?
Gebruik nooit environment-variabelen of hardcoded waarden voor gevoelige gegevens. Ik kan dat niet genoeg benadrukken. Podman biedt native secrets-ondersteuning via podman secret create en --secret flags. Voor productieomgevingen kun je integreren met HashiCorp Vault of Kubernetes Secrets. De geheimen worden gemount als bestanden in de container en verschijnen niet in podman inspect-output.
Hoe vaak moet ik mijn containerimages opnieuw scannen?
Scan images bij elke build in je CI/CD-pipeline, maar scan ook draaiende images minstens wekelijks. Nieuwe CVE's worden dagelijks gepubliceerd — een image dat vorige week veilig was, kan vandaag kritieke kwetsbaarheden bevatten. Automatiseer dit met Trivy in een cronjob of als onderdeel van je monitoringworkflow.