Prawdopodobnie słyszałeś żart, że Kubernetes to w zasadzie gigantyczna sterta plików YAML, trzymająca się razem dzięki nadziei i kilku bardzo zestresowanym SRE. Chociaż to pewna przesada, oddaje to podstawową prawdę: Kubernetes jest niezwykle złożony. To potężny orkiestrator, ale ta moc wiąże się ze stromą krzywą uczenia się. Kiedy działasz szybko — wdrażając aktualizacje wiele razy dziennie, skalując pody w różnych regionach i zarządzając siatkami usług — niemal nieuniknione jest, że coś zostanie błędnie skonfigurowane.
Problem polega na tym, że w środowisku cloud-native, drobna literówka w manifeście lub „tymczasowa” zmiana uprawnień może otworzyć ogromną lukę w Twoim bezpieczeństwie. Wszyscy to znamy. Chciałeś tylko, żeby pod się uruchomił, więc nadałeś mu uprawnienia cluster-admin „tylko na chwilę”, aby debugować problem z połączeniem. Potem o tym zapomniałeś. Sześć miesięcy później ten pod nadal działa i jest teraz złotym biletem dla każdego atakującego, któremu uda się uzyskać shell w Twoim kontenerze.
Naprawianie typowych błędnych konfiguracji w klastrach Kubernetes to nie tylko uruchamianie skanera bezpieczeństwa i odhaczanie pól. Chodzi o zrozumienie „dlaczego” stojącego za ryzykiem. Jeśli nie rozumiesz, jak uprzywilejowany kontener może doprowadzić do pełnego przełamania węzła, będziesz popełniać te same błędy za każdym razem, gdy napiszesz nowy plik wdrożeniowy.
W tym przewodniku omówimy najczęstsze błędy, które obserwujemy w praktyce, a co ważniejsze, dokładnie jak je naprawić. Przyjrzymy się wszystkiemu, od koszmarów związanych z kontrolą dostępu opartą na rolach (RBAC) po zagrożenia związane z domyślną przestrzenią nazw. Na koniec powinieneś mieć jasną mapę drogową, jak wzmocnić swój klaster bez uszkadzania aplikacji.
Niebezpieczeństwo nadmiernie uprzywilejowanych kont usług (RBAC)
Kontrola dostępu oparta na rolach (RBAC) to serce bezpieczeństwa Kubernetes. Dyktuje, kto może robić co i gdzie. Jednak to właśnie w RBAC większość ludzi zaczyna iść na skróty. Kiedy deweloper mówi: „Nie mogę sprawić, żeby mój potok CI/CD wdrożył aplikację”, najłatwiejszym rozwiązaniem jest często nadanie kontu usługi uprawnień cluster-admin.
To działa. Potok staje się zielony. Wszyscy są szczęśliwi. Ale właśnie stworzyłeś ogromną lukę w zabezpieczeniach. Jeśli Twój sekret CI/CD wycieknie, atakujący nie będzie miał dostępu tylko do jednej aplikacji; będzie miał klucze do całego Twojego królestwa.
Pułapka „Cluster-Admin”
Rola cluster-admin to wbudowana rola ClusterRole, która zapewnia nieograniczony dostęp do każdego zasobu w klastrze. Używanie jej dla kont usług na poziomie aplikacji to grzech główny bezpieczeństwa K8s.
Rozwiązanie: Zasada najmniejszych uprawnień (PoLP) Zamiast używać szerokich ról, musisz zdefiniować konkretne role, które zezwalają tylko na dokładnie wymagane działania.
Na przykład, jeśli pod potrzebuje tylko odczytywać ConfigMaps w swojej własnej przestrzeni nazw, aby się uruchomić, nie nadawaj mu ClusterRole. Nadaj mu Role (która jest ograniczona do przestrzeni nazw) tylko z czasownikami get i list dla configmaps.
Przykład zaostrzonej roli:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: app-namespace
name: config-reader
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
Unikanie domyślnego konta usługi
Domyślnie każda przestrzeń nazw ma konto usługi o nazwie default. Jeśli nie określisz konta usługi dla poda, Kubernetes przypisze mu to właśnie konto. Historycznie, domyślne konto usługi miało szerokie uprawnienia. Chociaż nowoczesne wersje są lepsze, wiele starszych klastrów nadal ma konto default powiązane z nadmiernie liberalnymi rolami.
Rozwiązanie: Jawne konta usług Nigdy nie polegaj na domyślnych ustawieniach. Utwórz dedykowane konto usługi dla każdej pojedynczej aplikacji.
- Utwórz
ServiceAccount. - Utwórz
Rolez minimalnymi niezbędnymi uprawnieniami. - Utwórz
RoleBinding, aby połączyć te dwa elementy. - Jawnie ustaw
serviceAccountNamew specyfikacji Podu.
Jeśli Twoja aplikacja w ogóle nie musi komunikować się z Kubernetes API (co dotyczy większości aplikacji webowych), idź o krok dalej. Ustaw automountServiceAccountToken: false w specyfikacji swojego podu. Zapobiega to zamontowaniu tokenu API w podzie, co oznacza, że nawet jeśli atakujący uzyska dostęp, nie będzie miał tokenu do wykorzystania do ruchu bocznego w klastrze.
Wzmacnianie kontekstu bezpieczeństwa Podu
Kiedy kontener działa, nie działa on tylko „w” klastrze; działa jako proces na węźle Linuxa. Jeśli ten proces działa jako użytkownik root i istnieje luka w środowisku uruchomieniowym kontenera lub w jądrze, atakujący może potencjalnie „uciec” z kontenera i uzyskać dostęp root do maszyny hosta. Jest to znane jako ucieczka z kontenera.
Problem z „Privileged: True”
Często zobaczysz privileged: true w plikach YAML. To zasadniczo nakazuje Kubernetesowi nadać kontenerowi niemal wszystkie możliwości maszyny hosta. Jest to rzadko konieczne dla standardowych aplikacji. Zazwyczaj jest to potrzebne tylko dla wyspecjalizowanych narzędzi systemowych (takich jak wtyczki CNI lub sterowniki pamięci masowej).
Rozwiązanie: Zaprzestań używania trybu uprzywilejowanego
Jeśli okaże się, że potrzebujesz privileged: true, zadaj sobie pytanie, dlaczego. Czy potrzebujesz tylko zmienić ustawienia sieciowe? Czy musisz zamontować konkretne urządzenie?
Zamiast pełnego trybu uprzywilejowanego, użyj możliwości. Możliwości Linuxa pozwalają rozbić uprawnienia root na mniejsze części. Na przykład, jeśli potrzebujesz tylko modyfikować interfejsy sieciowe, użyj CAP_NET_ADMIN zamiast nadawania podowi pełnego dostępu root.
Działanie jako Root
Wiele obrazów Docker jest domyślnie zbudowanych do działania jako root. Jeśli wdrożysz je w takiej formie, Twój proces będzie działał z UID 0. Jest to ogromne ryzyko.
Rozwiązanie: Użyj użytkownika innego niż root
Powinieneś wymusić wykonywanie jako użytkownik inny niż root zarówno w Dockerfile, jak i w securityContext Kubernetes.
W swoim pliku YAML wdrożenia dodaj sekcję securityContext:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
runAsNonRoot: true nakazuje Kubernetesowi sprawdzić, czy obraz próbuje działać jako root, i w przypadku próby uruchomienia jako root – przerwać start. To zmusza Twój zespół do budowania obrazów z dedykowanym użytkownikiem (np. USER 1000 w Dockerfile).
Systemy plików root tylko do odczytu
Większość aplikacji w rzeczywistości nie potrzebuje zapisywać do własnego systemu plików root. Zapisują do logów (które powinny trafiać do stdout/stderr) lub do zamontowanych woluminów. Jeśli atakujący uzyska dostęp do kontenera, pierwszą rzeczą, którą zazwyczaj robi, jest pobranie zestawu narzędzi lub skryptu na dysk lokalny. Jeśli system plików jest tylko do odczytu, ten wektor ataku jest zablokowany.
Rozwiązanie: Ustaw readOnlyRootFilesystem na true
securityContext:
readOnlyRootFilesystem: true
Jeśli Twoja aplikacja potrzebuje zapisywać pliki tymczasowe, nie wyłączaj systemu plików tylko do odczytu. Zamiast tego, zamontuj wolumin emptyDir do konkretnej ścieżki, gdzie aplikacja musi zapisywać (np. /tmp).
Zarządzanie powierzchnią ataku: Polityki sieciowe
Domyślnie Kubernetes ma "płaską" sieć. Oznacza to, że każdy pod w dowolnej przestrzeni nazw (namespace) może komunikować się z każdym innym podem w dowolnej innej przestrzeni nazw. Chociaż jest to świetne dla łączności, to koszmar dla bezpieczeństwa. Jeśli Twój serwer WWW frontend zostanie skompromitowany, atakujący może swobodnie skanować Twoją sieć wewnętrzną i znaleźć Twoją bazę danych, pamięć podręczną oraz wewnętrzne narzędzia administracyjne.
Brak segmentacji
Wyobraź sobie dom, w którym nie ma drzwi między pokojami — tylko jedna duża, otwarta przestrzeń. Jeśli włamywacz dostanie się przez przednie okno, ma natychmiastowy dostęp do sypialni, kuchni i sejfu. Dokładnie tak działa domyślny klaster K8s.
Rozwiązanie: Wprowadź politykę domyślnego odrzucania (Default-Deny Policy) Najbezpieczniejszym sposobem zarządzania ruchem sieciowym jest rozpoczęcie od zablokowania wszystkiego, a następnie jawne zezwolenie tylko na to, co jest niezbędne. Jest to podejście "Zero Trust".
Najpierw utwórz politykę, która odrzuca cały ruch przychodzący (ingress) i wychodzący (egress) dla przestrzeni nazw:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Gdy wszystko zostanie zablokowane, tworzysz specyficzne reguły "zezwalające". Na przykład, jeśli Twój pod frontend musi komunikować się z Twoim podem backend na porcie 8080, piszesz politykę, która wyraźnie zezwala na ruch z etykiety frontend do etykiety backend na tym porcie.
Kontrolowanie ruchu wychodzącego (Egress Traffic)
Większość ludzi skupia się na tym, kto może dostać się do ich klastra, ale zapominają o tym, co wychodzi. Jeśli pod zostanie skompromitowany, atakujący spróbuje "zadzwonić do domu" na serwer dowodzenia i kontroli (C2), aby otrzymać instrukcje lub wyfiltrować dane.
Rozwiązanie: Ogranicz ruch wychodzący (Egress) O ile Twój pod nie musi komunikować się z publicznym internetem (co jest rzadkością w przypadku usług backendowych), zablokuj cały ruch wychodzący. Jeśli potrzebuje dostępu do internetu (np. aby wywołać zewnętrzne API, takie jak Stripe lub Twilio), użyj service mesh, takiego jak Istio lub Linkerd, lub użyj Egress Gateway, aby umieścić na białej liście określone domeny zewnętrzne.
Pułapka "bezpieczeństwa punktowego" i ciągłe testowanie
Jedną z największych błędnych konfiguracji nie jest linia kodu — to proces. Wiele firm przeprowadza "audyt bezpieczeństwa" raz na kwartał. Zatrudniają firmę, firma znajduje dziesięć błędnych konfiguracji, zespół je naprawia, a wszyscy odetchną z ulgą.
Ale środowiska Kubernetes są dynamiczne. Jutro możesz zmienić ConfigMap, zaktualizować Helm chart lub dodać nowy sidecar container. Ten "czysty" audyt z zeszłego miesiąca jest teraz nieistotny. To właśnie nazywamy "bezpieczeństwem punktowym", a w świecie cloud-native jest to niebezpieczne.
W tym miejscu konieczne staje się przejście w kierunku ciągłego zarządzania ekspozycją na zagrożenia (Continuous Threat Exposure Management – CTEM). Nie możesz tylko skanować w poszukiwaniu luk; musisz symulować, jak atakujący faktycznie porusza się po Twoim klastrze.
Jeśli masz pod z nadmiernie liberalną rolą RBAC i błędnie skonfigurowaną Network Policy, prosty skan podatności może oznaczyć je jako dwa oddzielne ryzyka "średnie". Ale w rzeczywistości razem tworzą "krytyczną" ścieżkę: atakujący wykorzystuje lukę w aplikacji webowej, używa roli RBAC do listowania secrets, znajduje hasło do bazy danych i wykorzystuje otwartą sieć do zrzucenia Twoich danych.
Narzędzia takie jak Penetrify pomagają wypełnić tę lukę. Zamiast statycznego raportu, który zbiera kurz, Penetrify zapewnia testowanie bezpieczeństwa na żądanie, które skaluje się wraz z Twoim środowiskiem chmurowym. Pomaga zidentyfikować te „łańcuchy” błędnych konfiguracji — sposób, w jaki mały błąd RBAC łączy się z luką w sieci — zanim zrobi to złośliwy podmiot. Przechodząc na model „Penetration Testing as a Service” (PTaaS), przestajesz zgadywać, czy Twój klaster jest bezpieczny, a zaczynasz wiedzieć.
Zabezpieczanie serwera API i płaszczyzny sterowania
Serwer API to mózg Twojego klastra. Wszystko — od poleceń kubectl po wewnętrzną logikę kontrolera — przechodzi przez niego. Jeśli serwer API jest wystawiony lub błędnie skonfigurowany, cały Twój klaster jest zagrożony.
Publicznie dostępne serwery API
W pośpiechu, aby uruchomić klaster, niektóre zespoły pozostawiają serwer API otwarty na cały internet. Chociaż jest chroniony uwierzytelnianiem, wystawienie punktu końcowego pozwala atakującym na próby ataków brute-force, wykorzystanie luk typu Zero Day w samym serwerze API lub przeprowadzenie ataków typu odmowa usługi.
Rozwiązanie: Użyj prywatnych punktów końcowych i autoryzowanych sieci Jeśli używasz usługi zarządzanej, takiej jak EKS, GKE lub AKS, włącz opcję „Private Cluster”. Zapewnia to, że serwer API jest dostępny tylko z poziomu Twojej sieci VPC lub za pośrednictwem VPN/hosta Bastion. Jeśli musisz zachować go publicznie, użyj „Authorized Networks” (białej listy IP), aby ograniczyć dostęp tylko do adresu IP Twojego biura lub adresów IP Twoich runnerów CI/CD.
Uwierzytelnianie anonimowe
Niektóre starsze klastry lub niestandardowe instalacje mogą mieć włączone uwierzytelnianie anonimowe. Pozwala to na traktowanie nieuwierzytelnionych żądań do serwera API jako specjalnego użytkownika system:anonymous. W zależności od ustawień RBAC, ten użytkownik może przypadkowo mieć uprawnienia do przeglądania podów lub węzłów.
Rozwiązanie: Wyłącz uwierzytelnianie anonimowe
Upewnij się, że flaga --anonymous-auth=false jest ustawiona na Twoim kube-apiserverze. Jeśli z jakiegoś powodu nie możesz tego wyłączyć, upewnij się, że użytkownik system:anonymous nie jest przypisany do żadnych ról, które dostarczają informacji o Twoim klastrze.
Bezpieczeństwo Etcd
Etcd to baza danych, w której Kubernetes przechowuje cały swój stan. Jeśli atakujący uzyska dostęp do etcd, ma wszystko: każdy sekret, każdą konfigurację i możliwość modyfikacji stanu klastra bez przechodzenia przez serwer API.
Rozwiązanie: Szyfruj i izoluj etcd
- Szyfrowanie danych w spoczynku: Włącz szyfrowanie dla sekretów w etcd, aby w przypadku kradzieży lub dostępu do dysku, sekrety były bezużyteczne.
- Wzajemne TLS (mTLS): Upewnij się, że serwer API i etcd komunikują się za pomocą certyfikatów. Nikt nie powinien mieć możliwości komunikacji z etcd bez ważnego certyfikatu klienta.
- Izolacja sieciowa: etcd powinno znajdować się w całkowicie oddzielnej sieci lub być chronione ścisłymi regułami zapory sieciowej, tak aby tylko serwer API mógł do niego dotrzeć.
Zarządzanie sekretami bez „Sekretu”
Nazwa Secret w Kubernetesie jest nieco myląca. Domyślnie sekrety Kubernetes są tylko zakodowane w base64, a nie zaszyfrowane. Każdy, kto ma dostęp do API lub kopii zapasowej etcd, może odkodować Twoje hasło do bazy danych w około dwie sekundy, używając prostego polecenia terminala: echo "base64-string" | base64 --decode.
Przechowywanie sekretów w Git (Grzech Ostateczny)
Zdarza się to częściej, niż ludzie przyznają. Deweloper umieszcza plik secret.yaml w repozytorium Git „tylko na kilka minut”, aby pomóc koledze z zespołu, a następnie zapomina go usunąć. Teraz to hasło żyje w historii Git na zawsze.
Rozwiązanie: Zewnętrzne zarządzanie sekretami Przestań używać natywnych sekretów K8s do przechowywania wrażliwych danych. Zamiast tego użyj dedykowanego menedżera sekretów.
- HashiCorp Vault: Standard branżowy. Zapewnia dynamiczne sekrety i ścisłą kontrolę dostępu.
- AWS Secrets Manager / Azure Key Vault / GCP Secret Manager: Świetne, jeśli jesteś już związany z konkretnym dostawcą chmury.
Aby zintegrować je z Kubernetesem, użyj narzędzi takich jak External Secrets Operator (ESO) lub Secrets Store CSI Driver. Narzędzia te pobierają sekret z zewnętrznego skarbca i wstrzykują go do poda jako wolumin lub tymczasowy sekret K8s, zapewniając, że rzeczywiste "źródło prawdy" nigdy nie znajduje się w plikach YAML ani w Git.
Rotacja Sekretów
Większość zespołów ustawia hasło i pozostawia je na trzy lata. Jeśli to hasło wycieknie, atakujący ma stałe tylne drzwi.
Rozwiązanie: Automatyczna Rotacja Jeśli używasz zewnętrznego menedżera, takiego jak Vault, możesz wdrożyć automatyczną rotację. Menedżer sekretów aktualizuje hasło w bazie danych, a następnie aktualizuje wartość w Kubernetesie. Ponieważ aplikacja odczytuje sekret z woluminu lub poprzez API, pobiera nowe hasło bez konieczności pełnego ponownego wdrożenia.
Limity Zasobów i Problem "Hałaśliwego Sąsiada"
Chociaż nie jest to błąd konfiguracji "bezpieczeństwa" w tradycyjnym sensie, brak ustawienia limitów zasobów stanowi ryzyko dla stabilności i dostępności. W Kubernetesie, jeśli jeden pod zacznie działać nieprawidłowo i zużywać cały procesor lub pamięć RAM na węźle, może to pozbawić zasobów inne pody — w tym krytyczne komponenty systemowe — prowadząc do awarii węzła. Jest to w zasadzie samodzielnie wywołany atak typu Denial of Service (DoS).
Niebezpieczeństwo "Nieograniczonych" Podów
Jeśli nie zdefiniujesz resources.limits, pod może zużywać tyle zasobów węzła, ile chce. Jeśli masz wyciek pamięci w jednej ze swoich aplikacji, będzie ona powoli zużywać całą pamięć RAM na węźle, dopóki zabójca OOM (Out of Memory) systemu Linux nie zacznie zabijać procesów. Problem? Zabójca OOM może najpierw zabić Twój najważniejszy pod.
Rozwiązanie: Ustaw Żądania i Limity
Każdy kontener powinien mieć request (czego potrzebuje do uruchomienia) i limit (maksymalną ilość, jaką może zużyć).
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- Żądania (Requests): Używane przez harmonogram do znalezienia węzła z wystarczającą ilością miejsca.
- Limity (Limits): Egzekwowane przez środowisko uruchomieniowe kontenera, aby zapobiec zawłaszczaniu węzła przez pod.
Obsługa Dławienia Procesora (CPU Throttling)
Zachowaj ostrożność z limitami CPU. W przeciwieństwie do pamięci (gdzie osiągnięcie limitu zabija poda), osiągnięcie limitu CPU jedynie "dławi" poda. Twoja aplikacja zwolni, ale się nie zawiesi. Jeśli zauważysz wysokie opóźnienia w swoich aplikacjach, sprawdź metryki Prometheus pod kątem dławienia CPU. Może być konieczne zwiększenie limitów lub optymalizacja kodu.
Bezpieczeństwo Obrazów i Ryzyka Łańcucha Dostaw
Twój klaster jest tak bezpieczny, jak obrazy, które w nim uruchamiasz. Jeśli pobierasz my-app:latest z publicznego rejestru, zasadniczo uruchamiasz kod napisany przez obcą osobę na swojej infrastrukturze produkcyjnej.
Używanie Taga :latest
Używanie :latest to przepis na katastrofę. Nie masz pojęcia, która wersja kodu jest faktycznie uruchomiona. Gdy pod zostanie ponownie uruchomiony, może pobrać nową wersję obrazu, która zawiera zmianę powodującą niezgodność lub, co gorsza, złośliwy ładunek.
Rozwiązanie: Używaj Niezmiennych Tagów lub Skrótów (Digests)
Zawsze używaj konkretnego taga wersji (np. my-app:v1.2.3) lub, dla maksymalnego bezpieczeństwa, skrótu SHA256 obrazu. To gwarantuje, że za każdym razem wdrażane są dokładnie te same bajty.
Uruchamianie Obrazów z Niezaufanych Rejestrów
Publiczne rejestry są pełne obrazów "typo-squatted" — obrazów, które wyglądają jak popularne, ale zawierają złośliwe oprogramowanie.
Rozwiązanie: Prywatne repozytorium i skanowanie obrazów
- Użyj prywatnego repozytorium: Pobieraj publiczne obrazy, skanuj je, a następnie przesyłaj do własnego prywatnego repozytorium (takiego jak ECR, ACR lub Harbor).
- Automatyczne skanowanie: Użyj skanera, takiego jak Trivy lub Clair, aby sprawdzić obrazy pod kątem znanych CVE (Common Vulnerabilities and Exposures).
- Kontrolery dopuszczeń: Użyj narzędzia, takiego jak Kyverno lub OPA (Open Policy Agent), aby zapobiec wdrożeniu obrazu, jeśli nie został on zeskanowany lub zawiera "krytyczne" luki.
Kompleksowa lista kontrolna wzmacniania bezpieczeństwa Kubernetes
Aby ułatwić wdrożenie, przedstawiamy podsumowanie listy kontrolnej, którą możesz wykorzystać podczas kolejnego sprintu lub przeglądu bezpieczeństwa.
RBAC i dostęp
- Brak kont usług z uprawnieniami
cluster-admin(chyba że jest to absolutnie konieczne). - Brak aplikacji używających domyślnego konta usługi
default. -
automountServiceAccountToken: falseustawione dla podów, które nie potrzebują dostępu do API. - Serwer API nie jest otwarty na publiczny internet.
- Anonimowe uwierzytelnianie jest wyłączone na serwerze API.
Bezpieczeństwo podów
-
privileged: truejest zabronione dla podów aplikacji. -
runAsNonRoot: trueirunAsUsersą zdefiniowane dla wszystkich kontenerów. -
readOnlyRootFilesystem: truejest włączone tam, gdzie to możliwe. - Ustawione są
limitsirequestsdla CPU i pamięci dla każdego kontenera.
Bezpieczeństwo sieci
- Polityka sieciowa
default-deny-alljest wdrożona dla każdej przestrzeni nazw. - Jawne reguły "Allow" są używane dla niezbędnego ruchu między usługami.
- Ruch wychodzący jest ograniczony do znanych, wymaganych punktów końcowych.
Dane i sekrety
- Brak sekretów przechowywanych w repozytoriach Git.
- Sekrety są zarządzane za pomocą zewnętrznego skarbca (Vault, AWS SM itp.).
- Sekrety są szyfrowane w spoczynku w etcd.
- etcd jest izolowane i wymaga mTLS do komunikacji.
Łańcuch dostaw
- Obrazy są pobierane z prywatnego, zaufanego repozytorium.
- Żadne obrazy nie używają tagu
:latestw środowisku produkcyjnym. - Wszystkie obrazy są skanowane pod kątem CVE przed wdrożeniem.
- Kontroler dopuszczeń blokuje obrazy niezgodne z polityką.
Typowe scenariusze błędnej konfiguracji: Przed i Po
Aby przedstawić jaśniejszy obraz tego, jak te poprawki wyglądają w praktyce, przyjrzyjmy się kilku scenariuszom "Przed i Po".
Scenariusz 1: "Leniwe" wdrożenie
Przed: Deweloper wdraża proste API Node.js. Używa domyślnego konta usługi, działa jako root, nie ma limitów zasobów ani polityk sieciowych.
- Ryzyko: Luka w pakiecie Node umożliwia atakującemu uzyskanie powłoki. Ponieważ działa jako root i ma domyślny token, może sondować sieć wewnętrzną, znaleźć bazę danych i potencjalnie eskalować uprawnienia do węzła.
Po:
- Użyj niestandardowego
ServiceAccountbez uprawnień API. - Ustaw
runAsNonRoot: true. - Zdefiniuj limity
cpuimemory. - Zastosuj
NetworkPolicy, która zezwala na ruch tylko z Ingress Controller. - Rezultat: Nawet jeśli atakujący uzyska dostęp do powłoki, będzie użytkownikiem o niskich uprawnieniach, nie będzie mógł komunikować się z innymi podami i nie będzie w stanie zawiesić węzła, zużywając całą pamięć RAM.
Scenariusz 2: Wyciek "Sekretu"
Przed: Zespół przechowuje hasło do bazy danych w sekrecie Kubernetes utworzonym z lokalnego pliku YAML. Plik YAML został przypadkowo zatwierdzony w gałęzi funkcji.
- Ryzyko: Każdy, kto ma dostęp do odczytu historii Git, ma teraz hasło do produkcyjnej bazy danych.
Po:
- Przenieś hasło do AWS Secrets Manager.
- Zainstaluj External Secrets Operator.
- Sekret K8s jest teraz "cieniem" sekretu AWS i nigdy nie jest przechowywany w Git.
- Rezultat: Sekret jest scentralizowany, automatycznie rotowany i nigdy nie trafia na lokalny dysk dewelopera w postaci jawnego tekstu.
Często Zadawane Pytania (FAQ)
1. Czy ustawienie limitów zasobów nie spowoduje awarii moich podów?
Tak, jeśli ustawisz zbyt niski limit pamięci, Twój pod zostanie OOMKilled. Jest to w rzeczywistości dobra rzecz — lepiej, aby jeden pod uległ awarii i uruchomił się ponownie, niż aby jeden pod spowodował awarię całego fizycznego węzła. Sztuczka polega na monitorowaniu rzeczywistego zużycia aplikacji za pomocą narzędzi takich jak Prometheus i Grafana, a następnie ustawieniu limitów nieco powyżej szczytowego zużycia.
2. Czy naprawdę konieczne jest użycie Service Mesh do bezpieczeństwa sieci?
Dla małych klastrów Service Mesh (takich jak Istio) może być przesadą. Standardowe NetworkPolicies Kubernetes zazwyczaj wystarczają, aby osiągnąć 80% celu. Jednak jeśli potrzebujesz zaawansowanych funkcji, takich jak wzajemne TLS (mTLS) między wszystkimi usługami lub złożone dzielenie ruchu, Service Mesh jest właściwym rozwiązaniem.
3. Jak znaleźć wszystkie moje bieżące błędne konfiguracje bez sprawdzania każdego pliku YAML?
Ręczne wykonanie tego jest niemożliwe, gdy masz więcej niż kilka aplikacji. Powinieneś użyć zautomatyzowanych narzędzi. Narzędzia takie jak kube-bench (które sprawdzają zgodność z benchmarkami CIS) i kube-hunter są świetne do znajdowania luk. Aby uzyskać bardziej ciągły "widok z perspektywy atakującego" na Twój klaster, platforma taka jak Penetrify może automatycznie mapować Twoją powierzchnię ataku i znajdować ścieżki, którymi faktycznie podążyłby atakujący.
4. Czy runAsNonRoot działa, jeśli obraz został zbudowany jako root?
Jeśli ustawisz runAsNonRoot: true i metadane obrazu wskazują, że działa on jako root (UID 0), Kubernetes odmówi uruchomienia poda. Musisz wrócić do Dockerfile i dodać użytkownika (np. RUN useradd -u 1000 appuser && USER appuser).
5. Czy mogę zastosować te ustawienia bezpieczeństwa do istniejącego klastra bez przestojów?
Tak, ale rób to ostrożnie. Nie stosuj polityki sieciowej default-deny-all do całej przestrzeni nazw produkcyjnych jednocześnie, bo wyłączysz całą swoją witrynę. Stosuj polityki po jednej usłudze na raz. Podobnie, testuj zmiany w securityContext w środowisku stagingowym, aby upewnić się, że Twoja aplikacja nie potrzebuje konkretnych uprawnień roota do zapisu w folderze.
Przejście od bezpieczeństwa reaktywnego do proaktywnego
Naprawianie błędnych konfiguracji to ciągła walka. W miarę dodawania kolejnych usług, deweloperów i bardziej złożonych integracji, "powierzchnia bezpieczeństwa" Twojego klastra rośnie. Jeśli polegasz na ręcznej liście kontrolnej lub audycie raz w roku, zasadniczo grasz w grę "uderz kreta", gdzie kret ma wyrzutnię rakiet.
Celem powinno być przejście od stanu reaktywnego — gdzie naprawiasz rzeczy po ich zgłoszeniu — do stanu proaktywnego. Oznacza to integrację bezpieczeństwa z Twoim potokiem CI/CD (DevSecOps) i stosowanie ciągłego testowania.
Automatyzacja to jedyny sposób, aby nadążyć za szybkością Kubernetes. Kiedy możesz automatycznie skanować swoje manifesty pod kątem privileged: true, zanim jeszcze trafią do klastra, wygrałeś połowę bitwy. Kiedy używasz narzędzia takiego jak Penetrify do ciągłego symulowania ataków na Twoje środowisko, nie zgadujesz już, czy Twoje polityki sieciowe działają — masz dowód.
Pamiętaj, bezpieczeństwo to nie cel; to proces redukcji ryzyka. Nigdy nie będziesz mieć klastra "100% bezpiecznego", ale naprawiając te typowe błędne konfiguracje, sprawiasz, że dla atakującego staje się to tak kosztowne i trudne, że prawdopodobnie przeniesie się on na łatwiejszy cel.
Gotowy, aby przestać zgadywać o bezpieczeństwie Twojego klastra? Nie czekaj na naruszenie, aby dowiedzieć się, że Twój RBAC jest zbyt otwarty lub Twoje polityki sieciowe mają luki. Odwiedź Penetrify, aby odkryć, jak zautomatyzowane, testowanie bezpieczeństwa na żądanie może pomóc Ci znaleźć i naprawić luki w czasie rzeczywistym, utrzymując Twoją infrastrukturę cloud-native naprawdę bezpieczną.