Celem tego labu było praktyczne przetestowanie open-source'owych narzędzi do monitorowania bezpieczeństwa Kubernetes — sprawdzenie jak działają, co wykrywają i gdzie są granice każdego z nich. Postawiliśmy celowo dziurawy klaster i zobaczyliśmy co narzędzia faktycznie potrafią wychwycić — zarówno na poziomie statycznej konfiguracji, jak i w czasie rzeczywistym.
Warstwa 1 — Statyczna
Misconfiguracje i CVE wykrywane przed uruchomieniem: privileged containers, HostPath mount, wildcard RBAC, sekrety w env vars. Narzędzia: Trivy Operator, Kubescape.
Warstwa 2 — Runtime
Podejrzane zachowania w czasie rzeczywistym: odczyt /etc/shadow, uruchomienie shella w kontenerze, skanowanie sieci. Narzędzia: Falco (detekcja), Tetragon (enforcement + SIGKILL).
Środowisko testowe
Do tej konfiguracji doszliśmy iteracyjnie — zaczęliśmy od e2-small, potem e2-medium, ale cztery operatory jednocześnie generują znacznie więcej resource requests niż się wydaje i pody zostawały w stanie Pending. Finalnie e2-standard-2 + Ubuntu node pool (wymagany przez Tetragon ze względu na bug BTF w kernelu GKE 6.12+).
| Krok | Komenda / akcja | Status |
|---|---|---|
| Włączenie GKE API | gcloud services enable container.googleapis.com |
OK |
| Tworzenie klastra | gcloud container clusters create kubescape-vulnerable-lab --zone=europe-west1-b --machine-type=e2-standard-2 |
OK |
| Node pool Ubuntu | --image-type=UBUNTU_CONTAINERD (wymagane dla Tetragon) |
OK |
| Podatne workloady | kubectl apply -f vulnerable-workloads.yaml |
OK |
| kubectl + helm | Instalacja przez gcloud components install kubectl + brew install helm |
OK |
Podatne workloady:
| Deployment | Podatność | Kontrolka |
|---|---|---|
privileged-container | Privileged container | C-0017 |
hostpath-mount | HostPath mount na / | C-0045 |
hardcoded-secrets | Sekrety w env vars (AWS, DB, GitHub token) | C-0012 |
run-as-root | runAsUser: 0, allowPrivilegeEscalation | C-0044 |
wildcard-clusterrole | RBAC */*/* | C-0034 |
Trivy Operator to pierwsza linia obrony — skanuje wszystko co jest w klastrze zanim cokolwiek złego się wydarzy. Po zainstalowaniu automatycznie wykrywa każdy nowy workload i uruchamia skan. Wyniki lądują jako CRDs w klastrze, więc można je odpytywać przez kubectl jak każdy inny zasób. Skonfigurowaliśmy go żeby skupiał się tylko na HIGH i CRITICAL — żeby nie tonąć w szumie przy pierwszym przeglądzie.
Kubescape patrzy na klaster z innej perspektywy niż Trivy — zamiast CVE w obrazach, sprawdza czy konfiguracja klastra jest zgodna z frameworkami bezpieczeństwa: CIS Benchmark, NSA-CISA, MITRE ATT&CK. Daje "duży obraz" — jaki procent zasobów spełnia wymagania i które konkretnie kontrolki są naruszone. Operator skanuje cyklicznie (ustawiony na 02:00), do testów uruchamialiśmy go ręcznie przez job.
| Severity | Kontrolka | Opis | Workload |
|---|---|---|---|
| HIGH | C-0017 | Privileged container | privileged-container |
| HIGH | C-0045 | HostPath mount | hostpath-mount |
| HIGH | C-0012 | Misplaced secrets (env vars) | hardcoded-secrets |
| HIGH | C-0034 | Wildcard RBAC */*/* | wildcard-clusterrole |
| HIGH | C-0009 | Brak CPU/memory limits | wszystkie |
| HIGH | CIS-5.7.3 | Brak security context (0% pass rate) | wszystkie |
| MEDIUM | C-0044 | Non-root containers | run-as-root |
| MEDIUM | — | Ingress/Egress not blocked (0% pass rate) | wszystkie |
Trivy i Kubescape działają statycznie — mówią co jest źle skonfigurowane. Falco wchodzi w grę gdy klaster już działa i trzeba łapać podejrzane zachowania w czasie rzeczywistym. Działa przez eBPF, podpina się do kernela i obserwuje syscalle ze wszystkich kontenerów bez modyfikowania obrazów. Tylko wykrywa i alarmuje — nie blokuje, co pozwala włączyć go w trybie obserwacji bez ryzyka dla produkcji. Użyliśmy Falcosidekick do rozsyłania alertów i jego wbudowanego WebUI. Problem z instalacją: legacy eBPF driver nie miał prebuilt binarki dla kernela GKE 6.12.55+ — fix to przełączenie na modern_ebpf.
Falcosidekick WebUI:
Tetragon idzie krok dalej niż Falco — zamiast tylko alarmować, potrafi aktywnie blokować przez SIGKILL zanim cokolwiek złego się stanie. Też eBPF, overhead poniżej 1% CPU. Polityki (TracingPolicy) można targetować po syscallu, namespace, labelu poda. Poważniejszy problem z instalacją niż Falco: crashował na domyślnym nodzie GKE (COS) z błędem BTF dla modułu nls_cp437 — bug obecny we wszystkich wersjach 1.4–1.6. Jedynym obejściem było użycie node poola z UBUNTU_CONTAINERD.
TracingPolicy — blokowanie shell w podach z labelem app: privileged-container:
Narzędzia są zasobożerne — bardziej niż się wydaje
Każde z czterech narzędzi działa jako osobny operator lub DaemonSet i definiuje własne resource requests. Gdy uruchomimy je wszystkie na raz, suma tych requestów szybko przekracza pojemność małego noda — scheduler K8s zaczyna zostawiać nowe pody w stanie Pending. Nie chodzi o faktyczne zużycie CPU czy RAM w danej chwili, ale o zarezerwowaną pojemność.
Najbardziej zasobożerny moment w całym labie to była chwila, gdy działały jednocześnie: Trivy Operator skanujący wszystkie 5 deploymentów — każdy skan to osobny tymczasowy Job, w sumie do 5 równoległych podów ściągających obraz Trivy i analizujących manifesty; Kubescape Operator wykonujący pierwsze, pełne skanowanie klastra (inicjalny skan jest zawsze najbardziej intensywny) — w tym momencie działały jednocześnie: główny operator, node-agent DaemonSet, kollector, gateway i synchronizer; Falco jako DaemonSet stale monitorujący syscalle przez eBPF; Tetragon jako DaemonSet z kernel-level eBPF hooks.
Suma resource.requests przekroczyła allocatable CPU i RAM na e2-small i e2-medium. Dopiero e2-standard-2 (2 vCPU, ~6.5 GB allocatable) dał wystarczający margines. Przy planowaniu produkcyjnym warto zarezerwować dedykowane nody dla narzędzi monitorujących i nie mieszać ich z workloadami aplikacyjnymi — szczególnie podczas inicjalnych skanów.
Tetragon wymaga Ubuntu — nie działa na domyślnym obrazie GKE
GKE domyślnie używa Container-Optimized OS (COS). Tetragon na tym systemie nie uruchamia się poprawnie ze względu na problem z metadanymi BTF modułu kernela nls_cp437 — znany bug obecny w Tetragon 1.4–1.6, niezależny od wersji GKE. Obejście: node pool z obrazem UBUNTU_CONTAINERD, gdzie kernel ma kompletne BTF i Tetragon startuje bez problemów.
Falco wymaga nowszego sterownika eBPF na GKE
Domyślny driver eBPF Falco (legacy) wymaga prebuilt binarki pod konkretną wersję kernela. GKE regularnie aktualizuje kernele i bywa że dla najnowszych prebuilt binarki jeszcze nie ma. Rozwiązanie: modern_ebpf — sterownik wbudowany bezpośrednio w kernel (Linux 5.13+), który nie wymaga żadnych zewnętrznych plików i działa na wszystkich aktualnych wersjach GKE.
Co działało dobrze
Wszystkie cztery narzędzia wykryły to co miały wykryć. Celowo złe konfiguracje pojawiły się w wynikach Trivy i Kubescape bez dodatkowej konfiguracji. Falco od razu łapał podejrzane syscalle. Tetragon po wgraniu TracingPolicy skutecznie blokował shell (exit 137), podczas gdy inne pody działały normalnie.
Szczególnie warte uwagi: Falco wychwycił aktywność Kubescape node-agenta (połączenia do K8s API Server) jako podejrzaną. W produkcji trzeba skonfigurować białe listy dla własnych operatorów.
Różnice między narzędziami
Trivy i Kubescape pokrywają podobny obszar (statyczna analiza), ale z różnych kątów. Trivy jest bardziej szczegółowy na poziomie pojedynczego workloadu i CVE. Kubescape daje lepszy obraz compliance całego klastra i mapowanie na frameworki (CIS, MITRE) — przydatne przy audytach.
Falco i Tetragon też się uzupełniają: Falco jest lepszy do szerokiej detekcji i integracji z zewnętrznymi systemami (Splunk, Slack), Tetragon do precyzyjnego enforcement na poziomie konkretnych procesów i namespaces.
Co sprawiło trudność
Główne wyzwania były infrastrukturalne, nie związane z samymi narzędziami:
Dalsze kroki
To co przetestowaliśmy to punkt startowy — jeden klaster, cztery narzędzia, ręczna weryfikacja. W środowisku kilkudziesięciu lub kilkuset klastrów potrzebne są dwa niezależne pipeline'y: jeden do agregacji podatności CVE, drugi do routingu runtime eventów do SIEMa.
Agregacja CVE — jeden raport z całego środowiska
Trivy Operator tworzy VulnerabilityReport CRDs lokalnie w każdym klastrze. Żeby zebrać je w jedno miejsce i wygenerować CSV dla całego środowiska, potrzebna jest warstwa agregacyjna:
VulnerabilityReports (format SARIF/JSON) do centralnego DefectDojo przez REST API. Eksport CSV, filtrowanie po severity/klastrze/namespace, śledzenie trendu w czasie.kubectl get vulnerabilityreports -A -o json, agregacja do jednego pliku. Szybkie, ale nie skaluje się i wymaga dostępu sieciowego do każdego API Servera.Runtime eventy do SIEMa
Falcosidekick obsługuje dziesiątki outputów out-of-the-box:
falcosidekick.config.splunk.hostport + token.Przy setkach klastrów: centralny Falcosidekick jako deployment poza klastrami aplikacyjnymi — każdy Falco wysyła alerty do jednego miejsca zamiast lokalnego sidekicka. Konieczny enrichment metadanych (cluster name, environment) w konfiguracji Falcosidekick, inaczej w SIEMie nie będzie wiadomo z którego klastra przyszedł event. Tetragon JSON logs przez fluentd/fluent-bit jako dodatkowe źródło zdarzeń na poziomie kernela.