Linux konténerbiztonság mesterfokon: Docker és Kubernetes védelmi stratégiák 2026-ban

Átfogó útmutató a Linux konténerbiztonság keményítéséhez: Docker és Kubernetes védelmi stratégiák, seccomp, AppArmor, rootless konténerek, képvizsgálat Trivy-vel, futásidejű védelem Falco-val, valamint hálózati szegmentáció és mTLS.

Bevezetés – Miért fontosabb a konténerbiztonság, mint valaha?

A konténerizáció már rég nem újdonság – a legtöbb vállalat éles környezetben használja a Docker-t és a Kubernetes-t. Ami viszont 2026-ban is változatlanul aktuális (és őszintén szólva, egyre sürgetőbb), az a biztonsági kérdések komolyan vétele. A konténerek nem mágikus védelmi buborékok. Ugyanazt a Linux kernelt használják, mint a gazdarendszer, és egyetlen félrekonfigurált paraméter elég ahhoz, hogy a támadó kitörjön a konténerből.

Hogy ez nem elméleti fenyegetés, azt a 2025-ös év sebezhetőségei fényesen bizonyítják.

2025 novemberében három súlyos runc sebezhetőséget publikáltak: a CVE-2025-31133, CVE-2025-52565 és CVE-2025-52881 mindegyike a /proc fájlrendszeren keresztüli írási műveletek kihasználásával tette lehetővé a konténerből való kitörést. A CVE-2025-31133 konkrétan a maskedPaths mechanizmus TOCTOU (Time-of-Check to Time-of-Use) versenyhelyét használta ki – a támadó a /proc/sysrq-trigger vagy a /proc/sys/kernel/core_pattern fájlba írva tudták összeomlasztani a gazdarendszert, vagy tetszőleges kódot futtatni rajta.

2025 augusztusában pedig a CVE-2025-9074 mutatta meg, hogy a Docker Desktop sem sérthetetlen: ez a 9.3-as CVSS pontszámú kritikus sebezhetőség lehetővé tette, hogy egy lokálisan futó konténer hitelesítés nélkül elérje a Docker Engine API-t a 192.168.65.7:2375 címen, és azon keresztül további konténereket indítson – akár a teljes gazda fájlrendszert felcsatolva. Elég ijesztő, nem?

Na, vágjunk bele. Ebben a cikkben végigvesszük azokat a védelmi rétegeket és gyakorlati technikákat, amelyekkel a konténerizált környezeteinket valóban biztonságossá tehetjük. Az izolációs alapoktól a futásidejű védelemig – mindent lefedve, gyakorlati példákkal.

A konténerizolációs alapok megértése

Mielőtt bármilyen „hardening" technikát alkalmaznánk, fontos megérteni, hogyan működik a konténerizoláció a Linux kernel szintjén. Két alapvető mechanizmusra épül: a namespaces (névterek) és a cgroups (vezérlőcsoportok). Ezek nélkül igazából nem beszélhetünk konténerekről.

Linux Namespaces – Az izoláció pillérei

A namespace-ek lényegében a rendszer erőforrásainak virtuális nézeteit hozzák létre. Minden konténer a saját „világát" látja, anélkül, hogy tudna a többi konténerről vagy a gazdarendszerről. A Linux jelenleg hét namespace típust támogat:

  • PID namespace – Folyamatazonosítók izolációja. A konténerben a főfolyamat PID 1-ként jelenik meg, és nem látja a gazdarendszer folyamatait.
  • NET namespace – Hálózati verem izolációja. Minden konténer saját hálózati interfészekkel, routing táblával és tűzfalszabályokkal rendelkezik.
  • MNT namespace – Fájlrendszer-felcsatolások izolációja. A konténer saját mount pontokkal rendelkezik.
  • UTS namespace – Hostname és domain név izolációja.
  • IPC namespace – Folyamatok közötti kommunikáció izolációja (shared memory, szemaforok).
  • USER namespace – Felhasználói és csoport azonosítók leképezése. Lehetővé teszi, hogy a konténerben root-ként futó folyamat a gazdarendszeren nem-privált felhasználóként fusson.
  • CGROUP namespace – A cgroup hierarchia nézetét izolálja, így a konténer csak a saját erőforrás-korlátait látja.

A namespace-ek állapotát bármikor ellenőrizhetjük:

# Egy futó konténer namespace-einek listázása
docker inspect --format '{{.State.Pid}}' my_container
# Tegyük fel, a PID 12345
ls -la /proc/12345/ns/
# Kimenet:
# lrwxrwxrwx 1 root root 0 ... cgroup -> 'cgroup:[4026532516]'
# lrwxrwxrwx 1 root root 0 ... ipc -> 'ipc:[4026532446]'
# lrwxrwxrwx 1 root root 0 ... mnt -> 'mnt:[4026532444]'
# lrwxrwxrwx 1 root root 0 ... net -> 'net:[4026532449]'
# lrwxrwxrwx 1 root root 0 ... pid -> 'pid:[4026532447]'
# lrwxrwxrwx 1 root root 0 ... user -> 'user:[4026531837]'
# lrwxrwxrwx 1 root root 0 ... uts -> 'uts:[4026532445]'

Cgroups v2 – Egységes erőforrás-kezelés

A cgroups v2 (unified hierarchy) már az alapvető a modern Linux disztribúciókban. Szemben a v1-es verzióval, ahol minden erőforrástípus (CPU, memória, I/O) külön hierarchiában élt, a v2 egyetlen egységes fában kezel mindent. Ez nemcsak egyszerűbb, de biztonsági szempontból is előnyös, mert megakadályozza az inkonzisztens erőforrás-korlátok kialakítását.

# Cgroups v2 ellenőrzése
mount | grep cgroup2
# Kimenet: cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)

# Docker konténer erőforrás-korlátainak beállítása cgroups v2-vel
docker run -d \
  --memory="256m" \
  --memory-swap="512m" \
  --cpus="0.5" \
  --pids-limit=100 \
  --name secure_app \
  my_app:latest

Docker biztonsági keményítés

A Docker alapértelmezett konfigurációja a használhatóságra optimalizált, nem a maximális biztonságra. Ez teljesen érthető – senki sem akar egy vadonatúj telepítéssel órákig küzdeni. Viszont éles környezetben ez nem jó ötlet. Nézzük át azokat a beállításokat, amelyeket minden produkciós környezetben alkalmazni kellene.

Docker daemon biztonsági beállítások

A Docker daemon konfigurációja a /etc/docker/daemon.json fájlban történik. Íme egy biztonságilag keményített konfiguráció:

{
  "icc": false,
  "log-driver": "journald",
  "log-opts": {
    "tag": "{{.Name}}"
  },
  "no-new-privileges": true,
  "userland-proxy": false,
  "live-restore": true,
  "userns-remap": "default",
  "seccomp-profile": "/etc/docker/seccomp-strict.json",
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 64000,
      "Soft": 64000
    }
  }
}

A legfontosabb beállítások magyarázata:

  • icc: false – Letiltja a konténerek közötti közvetlen kommunikációt. Csak az explicit --link vagy hálózati kapcsolatokkal engedélyezett forgalom működik.
  • no-new-privileges: true – Megakadályozza, hogy a konténerben futó folyamatok új jogosultságokat szerezzenek (pl. setuid biten keresztül).
  • userns-remap: default – Bekapcsolja a user namespace leképezést, amiről részletesen beszélünk a következőkben.

Rootless Docker mód

A rootless Docker az egyik leghatékonyabb védelmi réteg, és személyes tapasztalatom szerint az egyik legegyszerűbben bevezethető is. A lényeg: a teljes Docker daemon nem-root felhasználóként fut. Ez azt jelenti, hogy még ha a támadó kitör is a konténerből, nem root jogosultságot kap a gazdarendszeren.

# Rootless Docker telepítése
# Előfeltételek: uidmap, dbus-user-session csomagok
sudo apt-get install -y uidmap dbus-user-session fuse-overlayfs

# Telepítés az aktuális felhasználónak
dockerd-rootless-setuptool.sh install

# Környezeti változók beállítása
export PATH=/usr/bin:$PATH
export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock

# Beállítás a .bashrc-be
echo 'export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock' >> ~/.bashrc

# Ellenőrzés
docker context use rootless
docker info | grep -i "rootless"
# Kimenet: rootless: true

Capabilities csökkentése

A Linux capabilities rendszere a root jogosultságokat kisebb, külön kezelhető egységekre bontja. A Docker alapértelmezetten 14 capability-t ad a konténereknek – ez jóval több, mint amennyire a legtöbb alkalmazásnak szüksége van. A legjobb gyakorlat egyszerű: mindent elveszünk, és csak a ténylegesen szükségeseket adjuk vissza.

# Minden capability eldobása, majd csak a szükségesek visszaadása
docker run -d \
  --cap-drop ALL \
  --cap-add NET_BIND_SERVICE \
  --cap-add CHOWN \
  --cap-add SETUID \
  --cap-add SETGID \
  --name secure_nginx \
  nginx:alpine

# Futó konténer capability-jeinek ellenőrzése
docker exec secure_nginx cat /proc/1/status | grep Cap
# CapPrm: 00000000a80c25fb  (alapértelmezett - sok jogosultság)
# vs.
# CapPrm: 00000000000c0400  (korlátozott - csak a szükségesek)

Csak olvasható fájlrendszer és no-new-privileges

A konténer fájlrendszerének csak olvashatóvá tétele megakadályozza, hogy a támadó módosítsa a fájlokat a konténerben. Gondoljunk bele: ha a fájlrendszer read-only, a támadó nem tud rosszindulatú binárist elhelyezni, nem tud konfigurációs fájlokat átírni. Persze az alkalmazásnak szüksége lehet írható könyvtárakra – erre valók a tmpfs mount-ok.

# Csak olvasható fájlrendszer + tmpfs az ideiglenes fájloknak
docker run -d \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  --tmpfs /var/run:rw,noexec,nosuid,size=16m \
  --tmpfs /var/cache/nginx:rw,noexec,nosuid,size=32m \
  --security-opt no-new-privileges:true \
  --cap-drop ALL \
  --cap-add NET_BIND_SERVICE \
  --name hardened_nginx \
  nginx:alpine

User namespace remapping

A user namespace remapping leképezi a konténer root felhasználóját egy magas UID-vel rendelkező, nem-privilegizált felhasználóra a gazdarendszeren. Ezt az egyik legfontosabb védelmi rétegnek tartom a konténer-kitörés ellen.

# User namespace remapping konfigurálása
# 1. Felhasználó létrehozása a leképezéshez
sudo useradd -r -s /bin/false dockremap

# 2. UID/GID leképezés beállítása
echo "dockremap:100000:65536" | sudo tee /etc/subuid
echo "dockremap:100000:65536" | sudo tee /etc/subgid

# 3. Docker daemon konfigurálása (/etc/docker/daemon.json)
# "userns-remap": "dockremap"

# 4. Docker daemon újraindítása
sudo systemctl restart docker

# 5. Ellenőrzés
docker run --rm alpine id
# uid=0(root) gid=0(root) -- a konténerben root-nak tűnik
# De a gazdagépen:
ps aux | grep "alpine"
# A folyamat UID 100000-ként fut a gazdagépen!

Seccomp profilok használata

A Seccomp (Secure Computing Mode) a Linux kernel egy olyan funkciója, amely lehetővé teszi a rendszerhívások (syscalls) szűrését. Miért olyan fontos ez? Azért, mert a kernel sebezhetőségek túlnyomó többségét rendszerhívásokon keresztül lehet kihasználni. Ha egy rendszerhívás el van tiltva, a rá épülő exploit egyszerűen nem működik.

Docker alapértelmezett seccomp profil

A Docker alapértelmezetten használ seccomp profilt, amely körülbelül 44–51 rendszerhívást blokkol a 300+-ból. Ez magában foglalja a veszélyes hívásokat, mint az unshare (namespace létrehozás), mount, reboot, kexec_load és az io_uring családot, amelyek számos kernel sebezhetőség forrásai. Az alapértelmezett profil allowlist alapú: a SCMP_ACT_ERRNO az alapértelmezett akció, és csak a külön engedélyezett hívások hajthatók végre.

Egyedi seccomp profil létrehozása

A legtöbb alkalmazásnak jóval kevesebb rendszerhívásra van szüksége, mint amennyit az alapértelmezett profil engedélyez. Érdemes tehát egy szorított profilt készíteni – ez egy kicsit munkaigényes, de megéri.

{
  "defaultAction": "SCMP_ACT_ERRNO",
  "archMap": [
    {
      "architecture": "SCMP_ARCH_X86_64",
      "subArchitectures": [
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
      ]
    }
  ],
  "syscalls": [
    {
      "names": [
        "accept", "accept4", "access", "bind", "brk",
        "clock_getres", "clock_gettime", "clone", "close",
        "connect", "dup", "dup2", "epoll_create", "epoll_ctl",
        "epoll_wait", "execve", "exit", "exit_group",
        "fchmod", "fchown", "fcntl", "fstat", "futex",
        "getcwd", "getdents64", "getegid", "geteuid",
        "getgid", "getpid", "getppid", "getsockname",
        "getsockopt", "getuid", "ioctl", "listen",
        "lseek", "madvise", "mmap", "mprotect", "munmap",
        "nanosleep", "newfstatat", "open", "openat",
        "pipe", "poll", "prctl", "pread64", "pwrite64",
        "read", "readlink", "recvfrom", "recvmsg",
        "rt_sigaction", "rt_sigprocmask", "rt_sigreturn",
        "sendmsg", "sendto", "set_robust_list",
        "set_tid_address", "setsockopt", "shutdown",
        "sigaltstack", "socket", "stat", "statfs",
        "sysinfo", "uname", "unlink", "wait4", "write",
        "writev"
      ],
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}

Mentés után alkalmazzuk a profilt:

# Egyedi seccomp profil alkalmazása Docker konténerre
docker run -d \
  --security-opt seccomp=/etc/docker/seccomp-nginx-strict.json \
  --name nginx_strict \
  nginx:alpine

# Seccomp profil ellenőrzése futó konténeren
docker inspect nginx_strict | jq '.[0].HostConfig.SecurityOpt'

# Tipp: Az OCI seccomp-bpf-hook segítségével automatikusan
# generálhatunk profilt az alkalmazás tényleges syscall használata alapján
sudo dnf install oci-seccomp-bpf-hook  # RHEL/Fedora
docker run --annotation io.containers.trace-syscall="of:/tmp/nginx.json" \
  nginx:alpine

Seccomp Kubernetes-ben

A Kubernetes-ben a seccomp profilt a Pod Security Context-ben adjuk meg:

apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: profiles/nginx-strict.json
  containers:
  - name: nginx
    image: nginx:alpine
    securityContext:
      allowPrivilegeEscalation: false
      runAsNonRoot: true
      runAsUser: 101

A profil fájlnak a kubelet --seccomp-profile-root könyvtárában kell lennie (alapértelmezetten /var/lib/kubelet/seccomp). Alternatív megoldásként a RuntimeDefault típus a konténer-runtime alapértelmezett profilját használja – ez az egyszerűbb út, ha nem akarsz egyedi profilt karbantartani.

AppArmor profilok konténerekhez

Az AppArmor (Application Armor) egy Linux kernel biztonsági modul, amely a Mandatory Access Control (MAC) elvén működik. A seccomp-pal ellentétben, amely rendszerhívás szinten szűr, az AppArmor fájlrendszer-hozzáféréseket, hálózati műveleteket és capability-ket szabályoz finomabban. A kettő együtt igazán hatékony párost alkot.

Docker alapértelmezett AppArmor profil

A Docker automatikusan alkalmazza a docker-default AppArmor profilt minden konténerre (feltéve, hogy az AppArmor elérhető a rendszeren). Ez a profil a következőket teszi:

  • Megakadályozza a /proc és /sys érzékeny részeinek írását
  • Tiltja a mount rendszerhívást
  • Korlátozza a signal küldést más folyamatoknak
  • Megakadályozza a ptrace használatát
# Aktuális AppArmor állapot ellenőrzése
sudo aa-status

# Docker konténer AppArmor profiljának ellenőrzése
docker inspect --format='{{.AppArmorProfile}}' my_container
# Kimenet: docker-default

Egyedi AppArmor profil nginx konténerhez

Hozzunk létre egy szorított AppArmor profilt kifejezetten nginx konténerekhez. Ez a profil sokkal szigorúbb, mint az alapértelmezett, és pontosan az nginx igényeire van szabva:

# /etc/apparmor.d/docker-nginx
#include <tunables/global>

profile docker-nginx flags=(attach_disconnected,mediate_deleted) {
  #include <abstractions/base>
  #include <abstractions/nameservice>

  # Hálózati hozzáférés
  network inet tcp,
  network inet udp,
  network inet6 tcp,
  network inet6 udp,

  # Nginx binárisok
  /usr/sbin/nginx ix,
  /usr/lib/nginx/modules/*.so mr,

  # Konfigurációs fájlok (csak olvasás)
  /etc/nginx/** r,

  # Naplófájlok
  /var/log/nginx/** rw,

  # PID fájl
  /var/run/nginx.pid rw,

  # Webszerver tartalom (csak olvasás)
  /usr/share/nginx/html/** r,

  # Ideiglenes fájlok
  /var/cache/nginx/** rw,
  /tmp/** rw,

  # Proc fájlrendszer (korlátozott)
  /proc/*/status r,
  /proc/sys/net/** r,

  # Mindent más tiltunk
  deny /proc/sysrq-trigger rw,
  deny /proc/sys/kernel/** w,
  deny /proc/kcore r,
  deny /sys/** w,
  deny /etc/shadow r,
  deny /etc/passwd w,

  # Capability-k
  capability net_bind_service,
  capability setuid,
  capability setgid,
  capability dac_override,

  # Signal kezelés
  signal (send,receive) peer=docker-nginx,
}

A profil betöltése és alkalmazása:

# Profil betöltése
sudo apparmor_parser -r /etc/apparmor.d/docker-nginx

# Konténer indítása az egyedi profillal
docker run -d \
  --security-opt apparmor=docker-nginx \
  --cap-drop ALL \
  --cap-add NET_BIND_SERVICE \
  --read-only \
  --tmpfs /var/cache/nginx:rw,noexec \
  --tmpfs /var/run:rw,noexec \
  --tmpfs /tmp:rw,noexec \
  --name nginx_hardened \
  nginx:alpine

# Ellenőrzés: próbáljunk meg tiltott műveletet
docker exec nginx_hardened cat /etc/shadow
# Kimenet: cat: can't open '/etc/shadow': Permission denied

Bane – Automatikus AppArmor profil generálás

Ha nem akarsz kézzel írni AppArmor profilokat (és tegyük hozzá, ki akar?), a Bane egy nyílt forráskódú eszköz, amely leegyszerűsíti az egész folyamatot. TOML formátumú konfigurációból generál AppArmor profilt:

# bane-nginx.toml
Name = "docker-nginx-bane"

[Filesystem]
# Engedélyezett olvasási útvonalak
AllowExec = [
  "/usr/sbin/nginx"
]

ReadOnlyPaths = [
  "/etc/nginx/",
  "/usr/share/nginx/html/"
]

WritablePaths = [
  "/var/log/nginx/",
  "/var/cache/nginx/",
  "/var/run/"
]

DenyPaths = [
  "/etc/shadow",
  "/proc/kcore"
]

[Network]
Raw = false
Packet = false
Protocols = [
  "tcp",
  "udp"
]

[Capabilities]
Allow = [
  "net_bind_service"
]
Deny = [
  "sys_admin",
  "sys_ptrace",
  "sys_rawio"
]
# Bane telepítése és profil generálása
go install github.com/genuinetools/bane@latest
sudo bane bane-nginx.toml

# A generált profil automatikusan betöltődik
docker run -d \
  --security-opt apparmor=docker-nginx-bane \
  --name nginx_bane \
  nginx:alpine

Kubernetes Pod Security Standards

A Kubernetes 1.25-től kezdve a Pod Security Admission (PSA) váltotta fel az előzőleg használt (és már deprecated) PodSecurityPolicy-t. Ha még mindig PSP-t használsz, itt az ideje váltani. A PSA három előre definiált biztonsági szintet kínál, amelyeket névterekre (namespace) alkalmazhatunk.

Három biztonsági szint

  • Privileged – Teljesen korlátozásmentes. Csak olyan namespace-ekre használjuk, ahol tényleg szükség van rá (pl. rendszerszintű konténerek, monitoring ágensek).
  • Baseline – Minimális korlátozások, amelyek megakadályozzák az ismert jogosultság-eszkalációs technikákat. A legtöbb alkalmazás működik vele módosítás nélkül.
  • Restricted – Erősen korlátozó, a jelenlegi Pod hardening legjobb gyakorlatait érvényesíti. Nem root futtatás, minden capability elvétele, seccomp profil kötelező. Ezt ajánlom produkciós környezetbe.

Minden szinthez három módot rendelhetünk:

  1. enforce – A szabályt sértő Pod-ok létrehozását elutasítja
  2. audit – A sértéseket naplózza, de engedi a Pod-ot
  3. warn – Figyelmeztetést küld a felhasználónak, de engedi a Pod-ot
# Namespace létrehozása Restricted biztonsági szinttel
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/audit-version: latest
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/warn-version: latest
# Alkalmazás kubectl-lel
kubectl apply -f namespace-restricted.yaml

# Tesztelés: privilegizált Pod létrehozási kísérlet
kubectl run test-priv --image=nginx --privileged -n production
# Kimenet: Error from server (Forbidden): pods "test-priv" is forbidden:
# violates PodSecurity "restricted:latest"

Security Context konfigurálása

A restricted szintnek megfelelő Pod definíció így néz ki. Érdemes ezt sablonként kezelni az új alkalmazásoknál:

apiVersion: v1
kind: Pod
metadata:
  name: secure-app
  namespace: production
spec:
  automountServiceAccountToken: false
  securityContext:
    runAsNonRoot: true
    runAsUser: 10001
    runAsGroup: 10001
    fsGroup: 10001
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: my-registry.io/app:v2.1.0@sha256:abc123...
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop:
          - ALL
    resources:
      limits:
        memory: "256Mi"
        cpu: "500m"
      requests:
        memory: "128Mi"
        cpu: "250m"
    volumeMounts:
    - name: tmp
      mountPath: /tmp
    - name: cache
      mountPath: /var/cache
  volumes:
  - name: tmp
    emptyDir:
      sizeLimit: "64Mi"
  - name: cache
    emptyDir:
      sizeLimit: "128Mi"

Nézzük a legfontosabb elemeket:

  • runAsNonRoot: true – Biztosítja, hogy a konténer ne root-ként fusson
  • readOnlyRootFilesystem: true – Csak olvasható root fájlrendszer
  • allowPrivilegeEscalation: false – Tiltja a jogosultság-növelést
  • capabilities.drop: ALL – Minden Linux capability elvétele
  • seccompProfile: RuntimeDefault – Alkalmazza a futási környezet alapértelmezett seccomp profilját
  • automountServiceAccountToken: false – Nem csatolja automatikusan a ServiceAccount tokent, csökkentve a támadási felületet
  • Image digest (@sha256:...) – Az image tag helyett digest-et használunk a supply chain támadások megelőzésére

Fokozatos bevezetés stratégiája

Ne próbáld meg egy csapásra minden namespace-re ráerőltetni a restricted módot – az katasztrófa receptje. Inkább fokozatosan vezesd be:

# 1. lépés: Audit és warn módban indulunk
kubectl label namespace staging \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted

# 2. lépés: Ellenőrizzük a meglévő workload-okat
kubectl get pods -n staging -o json | \
  kubectl auth can-i --list --namespace=staging

# 3. lépés: Javítjuk a nem megfelelő Pod-okat

# 4. lépés: Enforce módra váltás
kubectl label namespace staging \
  pod-security.kubernetes.io/enforce=restricted \
  --overwrite

Konténerképek biztonsági vizsgálata

A konténerbiztonság nem ér véget a futási környezet keményítésével. Magát a konténerképet is alaposan meg kell vizsgálni – különben az egész eddig felépített védelmi rendszer egy lyukas csónakba épített széf lesz. Egy sebezhetó alap-image vagy egy ismert CVE-t tartalmazó függőség pont olyan veszélyes, mint egy félrekonfigurált futási környezet.

Trivy – Átfogó sebezhetőség-vizsgáló

A Trivy (az Aqua Security nyílt forráskódú projektje) az egyik legnépszerűbb konténerkép-vizsgáló eszköz. Sebezhetőségeket, félrekonfigurációkat és titkos kulcsokat keres képekben, fájlrendszerekben és IaC konfigurációkban.

# Trivy telepítése
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin

# Konténerkép vizsgálata
trivy image nginx:alpine

# Csak CRITICAL és HIGH sebezhetőségek
trivy image --severity CRITICAL,HIGH nginx:alpine

# Vizsgálat és kilépés hibakóddal, ha van CRITICAL sebezhetőség
trivy image --exit-code 1 --severity CRITICAL nginx:alpine

# JSON kimenet további feldolgozáshoz
trivy image --format json --output results.json nginx:alpine

# SBOM generálása CycloneDX formátumban
trivy image --format cyclonedx --output sbom.json nginx:alpine

Grype – Gyors és pontos sebezhetőség-vizsgálat

A Grype (az Anchore nyílt forráskódú projektje) egy másik kiváló választás, különösen ha a Syft által generált SBOM-okat szeretnénk vizsgálni. Tapasztalatom szerint a Grype néha más sebezhetőségeket talál, mint a Trivy – ezért érdemes mindkettőt futtatni.

# Grype telepítése
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin

# Konténerkép vizsgálata
grype nginx:alpine

# SBOM generálása Syft-tel és vizsgálata Grype-pal
syft nginx:alpine -o spdx-json > nginx-sbom.spdx.json
grype sbom:nginx-sbom.spdx.json

# Csak fixelhető sebezhetőségek mutatása
grype nginx:alpine --only-fixed

SBOM generálás Syft-tel

Az SBOM (Software Bill of Materials) a konténerkép összes összetevőjének listája – tulajdonképpen egy „alkatrészjegyzék". A Syft az Anchore eszköze, amely részletes SBOM-ot generál:

# Syft telepítése
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin

# SBOM generálása különböző formátumokban
syft nginx:alpine -o syft-json > nginx-sbom.json
syft nginx:alpine -o cyclonedx-json > nginx-cyclonedx.json
syft nginx:alpine -o spdx-json > nginx-spdx.json

CI/CD integráció

Az igazi erő a képvizsgálat automatizálásában rejlik. Íme egy GitHub Actions workflow példa, amely a képépítés során automatikusan vizsgálja a konténerképet:

# .github/workflows/container-security.yml
name: Container Security Scan
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build-and-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build Docker image
        run: docker build -t my-app:${{ github.sha }} .

      - name: Run Trivy vulnerability scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'my-app:${{ github.sha }}'
          format: 'sarif'
          output: 'trivy-results.sarif'
          severity: 'CRITICAL,HIGH'
          exit-code: '1'

      - name: Upload scan results to GitHub Security
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: 'trivy-results.sarif'

      - name: Generate SBOM
        uses: anchore/sbom-action@v0
        with:
          image: 'my-app:${{ github.sha }}'
          format: 'cyclonedx-json'
          output-file: 'sbom.cyclonedx.json'

      - name: Scan SBOM with Grype
        uses: anchore/scan-action@v4
        with:
          sbom: 'sbom.cyclonedx.json'
          fail-build: true
          severity-cutoff: high

Minimális támadási felület multi-stage build-ekkel

A konténerkép méretének csökkentése közvetlenül csökkenti a támadási felületet is. Kevesebb bináris = kevesebb potenciális sebezhetőség. A multi-stage build-ek csak a futáshoz ténylegesen szükséges fájlokat tartalmazó végső képet hoznak létre:

# Multi-stage Dockerfile - Go alkalmazás példa
# --- Build fázis ---
FROM golang:1.23-alpine AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app ./cmd/server

# --- Futtatási fázis ---
FROM scratch
# Nem-root felhasználó beállítása
COPY --from=builder /etc/passwd /etc/passwd
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /app /app

# Nem-root felhasználóként futtatás
USER 10001:10001

EXPOSE 8080
ENTRYPOINT ["/app"]

A scratch alap-image használata a minimális támadási felület – nincs benne shell, nincs csomagkezelő, nincsenek felesleges binárisok. Ha kell egy kicsivel több (pl. debug célokra), alternatívaként használhatjuk a distroless képeket (pl. gcr.io/distroless/static-debian12), amelyek minimális futási környezetet biztosítanak.

Futásidejű védekezés Falco-val

Eddig a megelőzésről beszéltünk – de mi történik, ha a megelőzés nem elég? Mert sajnos, bármennyire is keményítjük a rendszert, 100%-os biztonság nem létezik. Itt jön képbe a Falco, a CNCF (Cloud Native Computing Foundation) graduált projektje, amely valós idejű futásidejű biztonsági monitorozást biztosít eBPF technológiával.

Hogyan működik a Falco?

A Falco az eBPF (extended Berkeley Packet Filter) technológiát használja a rendszerhívások kernel szintű megfigyelésére. Az eBPF programok közvetlenül a kernelben futnak, így minimális teljesítményveszteséggel (jellemzően 5% CPU alá) figyel meg másodpercenként akár 10 000+ eseményt. A hagyományos kernel modul helyett az eBPF biztonságosabb, mert a kernel verifier ellenőrzi a kódot betöltés előtt.

Falco telepítése Kubernetes-be

# Falco telepítése Helm chart-tal
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update

# Telepítés eBPF driver-rel
helm install falco falcosecurity/falco \
  --namespace falco \
  --create-namespace \
  --set driver.kind=modern_ebpf \
  --set falcosidekick.enabled=true \
  --set falcosidekick.config.slack.webhookurl="https://hooks.slack.com/services/XXX" \
  --set tty=true

# Telepítés ellenőrzése
kubectl get pods -n falco
kubectl logs -n falco -l app.kubernetes.io/name=falco

Egyedi Falco szabályok írása

A Falco igazi ereje az egyedi szabályokban rejlik. YAML formátumban íródnak és feltételeken (conditions) alapulnak. Íme néhány gyakorlati példa, amelyeket érdemes beépíteni:

# /etc/falco/rules.d/custom-rules.yaml

# 1. szabály: Shell indítás konténerben
- rule: Shell Spawned in Container
  desc: Detektálja, ha shell indul egy konténerben
  condition: >
    spawned_process and
    container and
    proc.name in (bash, sh, ash, zsh, ksh, dash) and
    not container.image.repository in (allowed_shell_images)
  output: >
    Shell indítva konténerben
    (felhasználó=%user.name konténer=%container.name
    kép=%container.image.repository parancs=%proc.cmdline
    pid=%proc.pid)
  priority: WARNING
  tags: [container, shell, mitre_execution]

# 2. szabály: Érzékeny fájl olvasása konténerben
- rule: Sensitive File Read in Container
  desc: Érzékeny fájlok olvasásának detektálása
  condition: >
    open_read and
    container and
    fd.name in (/etc/shadow, /etc/sudoers, /root/.ssh/authorized_keys,
                /root/.bash_history, /etc/kubernetes/admin.conf) and
    not proc.name in (sshd, sudo)
  output: >
    Érzékeny fájl olvasása konténerben
    (fájl=%fd.name felhasználó=%user.name konténer=%container.name
    kép=%container.image.repository)
  priority: CRITICAL
  tags: [container, filesystem, mitre_credential_access]

# 3. szabály: Kriptobányász tevékenység detektálása
- rule: Crypto Mining Activity Detected
  desc: Ismert kriptobányász pool-okhoz való csatlakozás
  condition: >
    container and
    ((evt.type = connect and
      fd.sip.name in (pool.minergate.com, xmr.pool.minergate.com,
                      stratum.antpool.com, xmr-eu1.nanopool.org)) or
    (spawned_process and
      proc.name in (xmrig, minerd, minergate-cli, cpuminer)))
  output: >
    Kriptobányász tevékenység detektálva
    (konténer=%container.name kép=%container.image.repository
    folyamat=%proc.cmdline kapcsolat=%fd.name)
  priority: CRITICAL
  tags: [container, cryptomining, mitre_resource_hijacking]

# 4. szabály: Kubernetes API titkos hozzáférés
- rule: K8s ServiceAccount Token Access
  desc: Konténerből a ServiceAccount token olvasásának detektálása
  condition: >
    open_read and
    container and
    fd.name startswith /var/run/secrets/kubernetes.io/
  output: >
    Kubernetes ServiceAccount token hozzáférés
    (fájl=%fd.name konténer=%container.name felhasználó=%user.name
    parancs=%proc.cmdline)
  priority: WARNING
  tags: [container, kubernetes, mitre_credential_access]

# Segéd lista az engedélyezett képekhez
- list: allowed_shell_images
  items: [debug-container, maintenance-tools]

Integráció riasztási rendszerekkel

A Falcosidekick az események továbbításáért felel. Támogatja többek között a Slack-et, a PagerDuty-t, az Elasticsearch-öt és a Prometheus-t. Íme egy konfiguráció több kimenettel:

# Falcosidekick konfigurálása több kimenettel
# values.yaml a Helm telepítéshez
falcosidekick:
  enabled: true
  config:
    slack:
      webhookurl: "https://hooks.slack.com/services/T00/B00/XXX"
      minimumpriority: "warning"
      messageformat: "Falco Alert: {{ .Rule }} - {{ .Output }}"

    elasticsearch:
      hostport: "https://elasticsearch.monitoring:9200"
      index: "falco-alerts"
      minimumpriority: "notice"

    prometheus:
      extralabels: "cluster:production,env:prod"

    alertmanager:
      hostport: "http://alertmanager.monitoring:9093"
      minimumpriority: "critical"

Hálózati biztonság konténerizált környezetben

A hálózati réteg az egyik leggyakrabban elhanyagolt biztonsági terület konténerizált környezetben – és őszintén szólva, ez érthetetlen számomra. Alapértelmezetten a legtöbb konténer-orchesztrátor (beleértve a Kubernetes-t is) minden Pod számára engedélyezi a kommunikációt minden más Pod-dal. Ez támadás esetén katasztrofális: egyetlen kompromittált konténer szabad mozgást kap a teljes klaszterben (lateral movement).

Docker hálózati szegmentáció

# Izolált hálózatok létrehozása
docker network create --driver bridge frontend_net
docker network create --driver bridge backend_net
docker network create --driver bridge db_net --internal

# Konténerek indítása elkülönített hálózatokon
docker run -d --name nginx --network frontend_net nginx:alpine
docker run -d --name api --network backend_net my-api:latest
docker run -d --name postgres --network db_net postgres:16-alpine

# Az API konténer mindkét hálózathoz csatlakozik (a frontend és backend között közvetít)
docker network connect frontend_net api

# A --internal flag biztosítja, hogy a db_net-ről nincs kimenő forgalom
# Az adatbázis csak a backend_net-en érhető el:
docker network connect db_net api

Kubernetes NetworkPolicy

A Kubernetes NetworkPolicy erőforrás lehetővé teszi a Pod-ok közötti forgalom szabályozását. Egy fontos megjegyzés: a NetworkPolicy működéséhez a CNI plugin-nak (pl. Calico, Cilium, Weave Net) támogatnia kell azt. Ha alapértelmezett CNI-t használsz, lehet, hogy a NetworkPolicy-k egyszerűen nem lépnek életbe.

# 1. Alapértelmezett tiltás (deny-all) az egész namespace-re
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
# 2. Specifikus forgalom engedélyezése a webalkalmazásnak
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-web-traffic
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: web-frontend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: ingress-nginx
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: api-backend
    ports:
    - protocol: TCP
      port: 3000
  - to:  # DNS engedélyezése
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
# 3. Adatbázis elérés korlátozása
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-access-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: postgresql
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api-backend
    ports:
    - protocol: TCP
      port: 5432

Service Mesh – Istio mTLS

A Service Mesh (különösen az Istio) egy magasabb szintű hálózati biztonsági réteget ad hozzá a mTLS (mutual TLS) megvalósításával. Ez biztosítja, hogy a szolgáltatások közötti kommunikáció minden esetben titkosított és hitelesített legyen – mindezt az alkalmazás kódjának módosítása nélkül.

# Istio mTLS szigorú módba állítása az egész mesh-re
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: default
  namespace: istio-system
spec:
  mtls:
    mode: STRICT
# Finom hangolás: Authorization Policy
# Csak a frontend szolgáltatás érheti el az API-t
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: api-access-policy
  namespace: production
spec:
  selector:
    matchLabels:
      app: api-backend
  action: ALLOW
  rules:
  - from:
    - source:
        principals:
        - "cluster.local/ns/production/sa/web-frontend"
    to:
    - operation:
        methods: ["GET", "POST"]
        paths: ["/api/v1/*"]

Az Istio használatával a mTLS automatikusan megoldott. Nem kell az alkalmazás kódjában TLS-t implementálni – a sidecar proxy (Envoy) átlátszóan kezeli a titkosítást és a tanúsítványkezelést. Ez hatalmas könnyebbség a fejlesztőknek.

Gyakorlati ellenőrzőlista és összefoglalás

Végül foglaljuk össze az összes tárgyalt védelmi réteget egy áttekinthető ellenőrzőlistában. Személyes tapasztalatból mondom: nyomtasd ki és tedd a falra. Használjuk ezt referenciaként minden új konténerizált alkalmazás üzembeállításakor:

Docker / Konténer-runtime szint

  • ☐ Rootless Docker mód – A Docker daemon fut nem-root felhasználóként, vagy legalább user namespace remapping be van kapcsolva
  • ☐ Capabilities csökkentése--cap-drop ALL és csak a szükséges capability-k visszaadása
  • ☐ Csak olvasható fájlrendszer--read-only flag használata tmpfs mount-okkal az írható könyvtárakhoz
  • ☐ No-new-privileges--security-opt no-new-privileges:true beállítás
  • ☐ Seccomp profil – Legalább az alapértelmezett profil aktív, ideálisan egyedi szorított profillal
  • ☐ AppArmor profil – Egyedi AppArmor profil az alkalmazáshoz igazítva
  • ☐ Erőforrás-korlátok – Memória, CPU és PID limitek beállítva (cgroups v2)
  • ☐ Inter-container communication tiltva"icc": false a daemon konfigurációban
  • ☐ Docker socket védelme – Soha ne csatoljuk a Docker socketet konténerekbe, kivéve ha feltétlenül szükséges

Konténerkép szint

  • ☐ Minimális alap-imagescratch, distroless vagy alpine használata
  • ☐ Multi-stage build – Csak a futáshoz szükséges fájlok a végső képben
  • ☐ Nem-root felhasználóUSER utasítás a Dockerfile-ban nem-root felhasználóval
  • ☐ Image digest – Tag helyett @sha256:... digest használata éles környezetben
  • ☐ Sebezhetőség-vizsgálat – Trivy vagy Grype integrálva a CI/CD pipeline-ba
  • ☐ SBOM generálás – Syft-tel generált SBOM minden kiadásnál
  • ☐ Megbízható registry – Privát registry használata image aláírással (Cosign/Notary)

Kubernetes szint

  • ☐ Pod Security Admissionrestricted szint enforce módban a termelési namespace-eken
  • ☐ Security ContextrunAsNonRoot, readOnlyRootFilesystem, allowPrivilegeEscalation: false
  • ☐ ServiceAccount tokenautomountServiceAccountToken: false ahol nem szükséges
  • ☐ NetworkPolicy – Default deny-all szabály, majd explicit engedélyezések
  • ☐ RBAC – Minimális jogosultságú ServiceAccount-ok és Role-ok
  • ☐ Secrets kezelés – External Secrets Operator vagy Vault használata a natív Secrets helyett

Monitoring és reagálás

  • ☐ Falco – eBPF alapú futásidejű monitorozás telepítve és konfigurálva
  • ☐ Egyedi szabályok – Az alkalmazás-specifikus viselkedési szabályok megírva
  • ☐ Riasztási integráció – Falcosidekick összekötve a riasztási rendszerrel (Slack, PagerDuty)
  • ☐ Audit naplózás – Kubernetes audit logging bekapcsolva és centrálisan gyűjtve
  • ☐ Rendszeres ellenőrzés – Docker Bench for Security és kube-bench rendszeres futtatása

Hálózati biztonság

  • ☐ Hálózati szegmentáció – Külön hálózatok a frontend, backend és adatbázis rétegnek
  • ☐ mTLS – Service mesh (Istio/Linkerd) a szolgáltatások közötti titkosított kommunikációhoz
  • ☐ Egress korlátozás – Kimenő forgalom explicit engedélyezése, alapértelmezett tiltás

A konténerbiztonság nem egyszeri feladat, hanem folyamatos folyamat. A fenyegetések fejlődnek – ahogy a 2025-ös runc és Docker Desktop sebezhetőségek is mutatják –, és a védelmi stratégiáinknak is lépést kell tartaniuk velük. A fent bemutatott rétegzett védelem (defense in depth) megközelítés biztosítja, hogy egyetlen meghiúsult védelmi réteg ne jelentsen azonnali kompromittálódást.

Tartsuk naprakészen a konténer-runtime-okat (a runc sebezhetőségeket az 1.2.8, 1.3.3 és 1.4.0-rc.3 verziók javították), a Docker Desktopot (minimum 4.44.3), és alkalmazzuk a fenti ellenőrzőlista minden pontját. A biztonság nem opció – alapkövetelmény. És ha ez a cikk segített eligazodni a konténerbiztonság világában, máris közelebb vagy a biztonságosabb infrastruktúrához.

# Végső ellenőrzés: Docker Bench for Security futtatása
docker run --rm --net host --pid host \
  --userns host --cap-add audit_control \
  -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
  -v /var/lib:/var/lib:ro \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  -v /usr/lib/systemd:/usr/lib/systemd:ro \
  -v /etc:/etc:ro \
  docker/docker-bench-security

# Kubernetes: kube-bench futtatása CIS Benchmark ellenőrzéshez
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
kubectl logs job/kube-bench
A Szerzőről Editorial Team

Our team of expert writers and editors.