Pawel Seliwanow, architekt rozwiązań w Southbridge i wykładowca Slurm, wystąpił z prezentacją na DevOpsConf 2019. Ta prezentacja jest częścią jednego z tematów zaawansowanego kursu po Kubernetes „Slurm Mega”.
odbywa się w Moskwie w dniach 18-20 listopada.
— Moskwa, 22-24 listopada.
dostępne zawsze.

Pod katem znajduje się transkrypcja prezentacji.
Dzień dobry, koledzy i sympatycy. Dziś będę mówić o bezpieczeństwie.
Widzę, że na sali jest dziś wielu specjalistów ds. bezpieczeństwa. Z góry przepraszam, jeśli terminy z obszaru bezpieczeństwa będę używał nieco inaczej niż to jest u was przyjęte.
Tak się złożyło, że gdzieś pół roku temu w moje ręce trafił jeden publiczny klaster Kubernetes. Publiczny — oznacza to, że jest tam n-liczba namespaces, w tych namespaces są użytkownicy, izolowani we własnym namespaces. Wszyscy ci użytkownicy należą do różnych firm. Cóż, zakładano, że ten klaster ma być używany jako CDN. To znaczy, że dają ci klaster, dają tam użytkownika, przychodzisz do swojego namespace, deployujesz swoje fronty.
Mojej poprzedniej firmie próbowano sprzedać taką usługę. I poproszono mnie o przetestowanie klastra pod kątem tego, czy takie rozwiązanie odpowiada czy nie.
Wszedłem do tego klastra. Dano mi ograniczone prawa, ograniczony namespace. Tam chłopaki rozumieli, czym jest bezpieczeństwo. Czytali, czym jest Role-based access control (RBAC) w Kubernetes — i skonfigurowali to tak, że nie mogłem uruchamiać podów oddzielnie od deploymentów. Nie pamiętam zadania, które próbowałem rozwiązać, uruchamiając pod bez deploymentu, ale bardzo chciałem po prostu uruchomić pod. Postanowiłem sprawdzić, jakie mam prawa w klastrze, co mogę, czego nie mogę, co tam pokręcili. Przy okazji opowiem, co mają w RBAC skonfigurowane niepoprawnie.
Tak się złożyło, że po dwóch minutach uzyskałem dostęp administratora do ich klastra, zajrzałem do wszystkich sąsiednich namespaces, zobaczyłem tam uruchomione produkcyjne fronty firm, które już kupiły usługę i zdeployowały się. Ledwo powstrzymałem się, żeby nie przyjść do kogoś na front i nie umieścić na stronie głównej jakiegoś wulgaryzmu.
Opowiem na przykładach, jak to zrobiłem i jak należy się przed tym bronić.
Na początek pozwólcie, że się przedstawię. Nazywam się Paweł Seliwanow. Jestem architektem w firmie Southbridge. Znam się na Kubernetesie, DevOps i innych modnych rzeczach. My z inżynierami w Southbridge budujemy to wszystko, a ja doradzam.
Oprócz działalności głównej niedawno uruchomiliśmy projekty nazywane Slurmami. Staramy się wprowadzić nasze umiejętności z pracy z Kubernetesem do szerszego grona, ucząc innych, jak również pracować z K8s.
O czym dzisiaj będę mówił. Temat mojego wystąpienia jest oczywisty — bezpieczeństwo klastra Kubernetes. Ale od razu chcę zaznaczyć, że to bardzo obszerny temat — i dlatego chcę od razu wyjaśnić, o czym na pewno nie będę mówić. Nie zamierzam omawiać wyświechtanych terminów, które w internecie zostały już wielokrotnie przerobione, takich jak RBAC czy certyfikaty.
Będę mówił o tym, co moi koledzy i ja odczuwamy jako problemy związane z bezpieczeństwem klastra Kubernetes. Widzimy te problemy zarówno u dostawców, którzy oferują klastry Kubernetes, jak i u klientów, którzy do nas przychodzą. Nawet u klientów, którzy przychodzą do nas z innych firm konsultingowych. Tak więc skala problemu jest w rzeczywistości bardzo duża.
Właściwie trzy punkty, o których dzisiaj opowiem:
- Uprawnienia użytkowników vs uprawnienia podów. Uprawnienia użytkowników i uprawnienia podów to nie to samo.
- Zbieranie informacji o klastrze. Pokażę, że można zbierać wszystkie potrzebne informacje z klastra bez specjalnych uprawnień w tym klastrze.
- Atak DoS na klaster. Jeśli nie będziemy mogli zbierać informacji, mimo wszystko będziemy mogli zablokować klaster. Opowiem o atakach DoS na elementy zarządzające klastrem.
Jeszcze jedna ogólna rzecz, którą wspomnę — na czym testowałem to wszystko, na czym mogę z całą pewnością powiedzieć, że to działa.
Jako podstawę bierzemy instalację klastra Kubernetes za pomocą Kubespray. Jeśli ktoś nie wie, to jest to właściwie zestaw ról dla Ansible. Stosujemy go na co dzień w pracy. Jest dobry, ponieważ można go zainstalować wszędzie — zarówno na sprzęcie, jak i w chmurze. Jeden sposób instalacji w zasadzie pasuje do wszystkiego.
W tej klasie będziemy mieli Kubernetes v1.14.5. Cały klaster Kuby, który będziemy omawiać, jest podzielony na przestrzenie nazw, z których każda należy do innego zespołu, a członkowie tego zespołu mają dostęp tylko do swojej przestrzeni nazw. Nie mogą wchodzić do innych przestrzeni. Istnieje jednak konto administracyjne, które ma uprawnienia do całego klastra.

Obiecałem, że pierwszym krokiem będzie uzyskanie praw administratora do klastra. Potrzebujemy specjalnie przygotowanego poda, który będzie przełamywał klaster Kubernetes. Wszystko, co musimy zrobić, to zastosować go w klastrze Kubernetes.
kubectl apply -f pod.yamlTen pod przyjedzie na jeden z masterów klastra Kubernetes. A klaster radośnie zwróci nam plik o nazwie admin.conf. W tym pliku Kuby zawarte są wszystkie certyfikaty administratora, a także skonfigurowane jest API klastra. W ten sposób można uzyskać dostęp do administracji, myślę, że do 98% klastrów Kubernetes.
Powtarzam, ten pod stworzył jeden programista w waszym klastrze, który ma dostęp do wdrażania swoich propozycji w małej przestrzeni nazw, jest on zupełnie zablokowany przez RBAC. Nie miał żadnych uprawnień. Niemniej jednak certyfikat został zwrócony.
A teraz o specjalnie przygotowanym podzie. Uruchamiamy na dowolnym obrazie. Dla przykładu weźmy debian:jessie.
Mamy coś takiego:
tolerations:
- effect: NoSchedule
operator: Exists
nodeSelector:
node-role.kubernetes.io/master: "" Czym jest toleracja? Masterzy w klastrze Kubernetes są zazwyczaj oznaczeni czymś, co nazywa się taint ("zarażenie" po angielsku). Sens tego "zarażenia" polega na tym, że nie można przypisywać podów do węzłów master. Ale nikt nie zabrania w dowolnym podzie wskazać, że jest on tolerancyjny wobec "zarażenia". Sekcja Toleration wskazuje, że jeśli na jakimś węźle ustalono NoSchedule, to nasz pod jest tolerancyjny wobec takiego zarażenia — i nie ma z tym problemów.
Następnie mówimy, że nasz pod nie tylko jest tolerancyjny, ale również chce specjalnie trafić do mastera. Ponieważ na masterach znajduje się to, co jest dla nas najważniejsze — wszystkie certyfikaty. Dlatego mówimy nodeSelector — i mamy standardową etykietę na masterach, która pozwala wybrać spośród wszystkich węzłów klastra te, które są masterami.
Z takimi dwoma sekcjami pod z pewnością trafi na mastera. I dostanie zezwolenie na życie tam.
Jednak samo przybycie na mastera to za mało. To nam nic nie da. Dlatego później mamy takie dwa elementy:
hostNetwork: true
hostPID: true Wskazujemy, że nasz pod, który uruchamiamy, będzie działał w przestrzeni nazw jądra, w przestrzeni nazw sieci i w przestrzeni nazw PID. Gdy tylko pod wystartuje na masterze, będzie mógł zobaczyć wszystkie prawdziwe, aktywne interfejsy tego węzła, nasłuchiwać cały ruch i widzieć PID wszystkich procesów.
Teraz pozostaje niewiele do zrobienia. Bierzemy etcd i odczytujemy, co chcemy.
Najciekawsze jest to, że ta funkcjonalność Kubernetes jest dostępna domyślnie.
volumeMounts:
- mountPath: /host
name: host
volumes:
- hostPath:
path: /
type: Directory
name: host I istota tego polega na tym, że możemy w podzie, który uruchamiamy, nawet bez praw do tego klastra, powiedzieć, że chcemy stworzyć volume typu hostPath. Oznacza to, że weźmiemy ścieżkę z hosta, na którym się uruchomimy — i wykorzystamy ją jako volume. Następnie nazywamy go name: host. Cały ten hostPath montujemy wewnątrz podu. W tym przykładzie w katalogu /host.
Jeszcze raz powtórzę. Powiedzieliśmy podowi przybyć na mastera, uzyskać hostNetwork i hostPID — i zamontować cały root mastera wewnątrz tego podu.
Rozumiesz, że na debianie uruchamiamy bash, a ten bash działa z uprawnieniami roota. Oznacza to, że właśnie uzyskaliśmy roota na masterze, nie posiadając przy tym żadnych praw w klastrze Kubernetes.
Dalej cała sprawa polega na tym, aby wejść do podu w katalogu /host /etc/kubernetes/pki, jeśli się nie mylę, zabrać tam wszystkie główne certyfikaty klastra i w ten sposób stać się administratorem klastra.
Jeśli na to spojrzeć, to są jedne z najniebezpieczniejszych uprawnień w podach — niezależnie od tego, jakie prawa ma użytkownik:

Jeśli mam prawo uruchomić pod w jakiejś przestrzeni nazw klastra, to ten pod ma te prawa domyślnie. Mogę uruchamiać uprzywilejowane pody, a to praktycznie wszystkie prawa, prawie root na węźle.
Moim ulubionym jest użytkownik Root. A Kubernetes ma taką opcję Uruchom jako nie-root. To jest rodzaj ochrony przed hakerami. Wiecie, co to jest „mołdawski wirus”? Jeśli nagle jesteście hakerem i weszliście do mojego klastra Kubernetes, to my, biedni administratorzy, prosimy: «Proszę, określcie, w waszych podach, które zhackują mój klaster, run as non-root. Bo może się zdarzyć, że uruchomicie proces w swoim podzie jako root, co bardzo ułatwi mi włamanie. Proszę, chrońcie się sami».
Volume host path — moim zdaniem, najszybszy sposób na osiągnięcie pożądanego wyniku w klastrze Kubernetes.
Ale co z tym wszystkim zrobić?
Myśli, które powinny przychodzić do głowy każdemu normalnemu administratorowi, który ma do czynienia z Kubernetesem: „Aha, mówiłem, Kubernetes nie działa. Ma luki. Cały Kubernetes to bzdura”. W rzeczywistości istnieje coś takiego jak dokumentacja, a jeśli się w nią zaglądniesz, znajdziesz rozdział .
To taki obiekt yaml — możemy go tworzyć w klastrze Kubernetes — który kontroluje aspekty bezpieczeństwa w opisie podów. Oznacza to, że faktycznie kontroluje on prawa do użycia różnych hostNetwork, hostPID, określonych typów wolumenów, które są dostępne w podach podczas uruchamiania. Dzięki Pod Security Policy można to wszystko opisać.
Najnowsze w Pod Security Policy to, że w klastrze Kubernetes żaden z instalatorów PSP nie jest po prostu opisany, a domyślnie są one wyłączone. Pod Security Policy włącza się za pomocą wtyczki admission.
OK, wdrożymy Pod Security Policy w klastrze, powiedzmy, że mamy usłużne pody w namespace, do którego mają dostęp tylko administratorzy. Powiedzmy, że w innych podach prawa są ograniczone. Ponieważ prawdopodobnie deweloperzy nie muszą uruchamiać uprawnionych podów w Twoim klastrze.
I wszystko wydaje się w porządku. Nasz klaster Kubernetes nie może zostać zhakowany w dwie minuty.
Jest problem. Prawdopodobnie, jeśli masz klaster Kubernetes, to masz w nim monitoring. Nawet odważam się przewidzieć, że jeśli w twoim klastrze jest monitoring, to nazywa się on Prometheus.
To, co teraz opowiem, będzie ważne zarówno dla operatora Prometheus, jak i dla Prometheus zainstalowanego w czystej wersji. Pytanie jest takie, że jeśli nie mogę tak szybko uzyskać administratora w klastrze, oznacza to, że muszę więcej szukać. A mogę szukać za pomocą twojego monitoringu.
Prawdopodobnie wszyscy czytali te same artykuły na Habrze, a monitoring znajduje się w namespace monitoring. Helm chart ma wszyscy nazywa na mniej więcej tak samo. Zakładam, że jeśli zrobisz helm install stable/prometheus, to otrzymasz mniej więcej te same nazwy. A nawet prawdopodobnie nie będę musiał zgadywać nazwy DNS w twoim klastrze. Ponieważ jest standardowa.

Dalej mamy jakiś dev ns, w którym można uruchomić jakiś pod. I dalej z tego poda bardzo łatwo zrobić to:
$ curl http://prometheus-kube-state-metrics.monitoring prometheus-kube-state-metrics to jeden z eksporterów Prometheusa, który zbiera metryki z API samego Kubernetes. Zawiera wiele danych o tym, co działa w Twoim klastrze, jakie jest, jakie masz z nim problemy.
Jako prosty przykład:
kube_pod_container_info{namespace="kube-system",pod="kube-apiserver-k8s-1",container="kube-apiserver",image=
"gcr.io/google-containers/kube-apiserver:v1.14.5"
,image_id="docker-pullable://gcr.io/google-containers/kube-apiserver@sha256:e29561119a52adad9edc72bfe0e7fcab308501313b09bf99df4a9638ee634989",container_id="docker://7cbe7b1fea33f811fdd8f7e0e079191110268f2853397d7daf08e72c22d3cf8b"} 1
Wykonując prosty żądanie curl z nieuprzywilejowanego poda, można uzyskać takie informacje. Jeśli nie wiesz, w której wersji Kubernetes jesteś uruchomiony, to łatwo Ci to powie.
A co ciekawe, obok tego, że zwracasz się do kube-state-metrics, możesz równie dobrze zwrócić się bezpośrednio do samego Prometheusa. Możesz zebrać metryki stamtąd. Możesz nawet zbudować metryki. Teoretycznie możesz zbudować takie zapytanie z klastra do Prometheusa, które go po prostu wyłączy. I twój monitoring całkowicie przestanie działać.
I tutaj pojawia się pytanie, czy jakiś zewnętrzny monitoring monitoruje Twój monitoring. Właśnie zyskałem możliwość działania w klastrze Kubernetes bez jakichkolwiek konsekwencji dla siebie. Nawet nie dowiesz się, że tam działam, ponieważ monitoringu już nie ma.
Dokładnie tak samo, jak z PSP, wrażenie jest takie, że problem polega na tym, że wszystkie te modne technologie — Kubernetes, Prometheus — po prostu nie działają i są pełne luk. W rzeczywistości tak nie jest.
Jest coś takiego — .
Jeśli jesteś normalnym adminem, to prawdopodobnie wiesz, że Network Policy to kolejny yaml, których w klastrze jest już mnóstwo. A jakieś Network Policies z pewnością nie są potrzebne. A nawet jeśli przeczytałeś, czym jest Network Policy, że jest to yamlowy firewalla Kubernetes, który pozwala ograniczać uprawnienia dostępu między namespace'ami, między podami, to na pewno stwierdziłeś, że firewall w formacie yaml w Kubernetes na kolejnych abstrakcjach… Nie, nie. To zdecydowanie nie jest potrzebne.
Nawet jeśli Twoi specjaliści ds. bezpieczeństwa nie wiedzą, że za pomocą Kubernetes można bardzo łatwo stworzyć granulatowy firewall. Jeśli jeszcze tego nie wiedzą i nie dopytują: „No dajcie, dajcie…” To w każdym razie potrzebujesz Network Policy, aby zablokować dostęp do niektórych zasobów systemowych, które można podłączyć do klastra bez żadnej autoryzacji.
Jak w przykładzie, który podałem, można uzyskać kube state metrics z dowolnej przestrzeni nazw w klastrze Kubernetes, nie mając do tego żadnych uprawnień. Polityki sieciowe zablokowały dostęp z wszystkich innych przestrzeni nazw do przestrzeni nazw monitorowania i jakby wszystko: brak dostępu, brak problemów. We wszystkich chartach, które są, zarówno standardowym Prometeuszu, jak i tym w operatorze, wystarczy w values Helma włączyć polityki sieciowe dla nich. Trzeba tylko włączyć, a będą działać.
Jest tu jednak jeden problem. Będąc normalnym adminem, prawdopodobnie zdecydowałeś, że polityki sieciowe są niepotrzebne. Przeczytawszy różne artykuły na stronach takich jak Habr, uznałeś, że Flannel, zwłaszcza w trybie host-gateway, to najlepsze, co możesz wybrać.
Co robić?
Możesz spróbować prze-deployować rozwiązanie sieciowe, które masz w klastrze Kubernetes, i zastąpić je czymś bardziej funkcjonalnym. Na przykład tym samym Calico. Ale od razu chcę powiedzieć, że zmiana rozwiązania sieciowego w działającym klastrze Kubernetes to dość nietrywialne zadanie. Rozwiązywałem je dwa razy (oba razy teoretycznie), ale nawet na Slurmach pokazywaliśmy, jak to zrobić. Dla naszych uczniów pokazywaliśmy, jak zmienić rozwiązanie sieciowe w klastrze Kubernetes. W zasadzie możesz spróbować tak zrobić, aby w klastrze produkcyjnym nie było przestojów. Ale prawdopodobnie nic z tego nie wyjdzie.
A problem w rzeczywistości rozwiązuje się bardzo prosto. W klastrze są certyfikaty, a Ty wiesz, że certyfikaty za rok wygasną. Cóż, zwykle normalne rozwiązanie z certyfikatami w klastrze - po co mamy się martwić, to obok wzniesiemy nowy klaster, a w starym niech wygasa i wszystko przenieśmy. Prawda, kiedy on wygaśnie, wszystkiego dnia leży, ale przynajmniej nowy klaster.
Kiedy będziesz podnosić nowy klaster, od razu wstaw Calico zamiast Flannela.
Co zrobić, jeśli masz certyfikaty ważne przez sto lat, a klastra nie zamierzasz przedeptywać? Istnieje takie narzędzie jak Kube-RBAC-Proxy. To bardzo fajny projekt, który pozwala wbudować się jako kontener sidecar do dowolnego poda w klastrze Kubernetes. W rzeczywistości dodaje ono do tego poda autoryzację przez RBAC samego Kubernetes.
Jest jeden problem. Kiedyś w operatorze Prometheus to rozwiązanie Kube-RBAC-Proxy było wbudowane. Ale potem zostało usunięte. Aktualne wersje opierają się na tym, że masz politykę sieci (network policy) i zamykasz je za ich pomocą. Dlatego będziesz musiał nieco przerobić chart. Tak naprawdę, jeśli wejdziesz w , znajdziesz przykłady, jak to wykorzystać jako sidecary, a chartery będą musiały być przerobione minimalnie.
Jest jeszcze jeden drobny problem. Nie tylko Prometheus udostępnia swoje metryki komukolwiek. Wszystkie komponenty klastra Kubernetes również potrafią udostępniać swoje metryki.
Ale jak już mówiłem, jeśli nie możesz uzyskać dostępu do klastra i zebrać informacje, to przynajmniej możesz zaszkodzić.
Tak więc szybko pokażę dwa sposoby, jak można zaszkodzić zdrowiu klastra Kubernetes.
Będziesz się śmiał, kiedy to opowiem, to dwa przypadki z prawdziwego życia.
Sposób pierwszy. Wyczerpanie zasobów.
Uruchamiamy jeszcze jeden specjalny pod. Będzie miał taką sekcję.
resources:
requests:
cpu: 4
memory: 4Gi Jak wiesz, requests to ilość CPU i pamięci, która jest rezerwowana na hoście dla konkretnych podów z requests. Jeśli mamy czterordzeniowy host w klastrze Kubernetes, a tam przyjeżdża pod z requestami na cztery CPU, to znaczyć, że żaden inny pod z requests na ten host nie będzie mógł się przeładować.
Jeśli uruchomię taki pod, potem wykonam polecenie:
$ kubectl scale special-pod --replicas=...To nikt inny w klastrze Kubernetes nie będzie mógł się wdrożyć. Ponieważ na wszystkich węzłach skończą się requests. W ten sposób zatrzymam twój klaster Kubernetes. Jeśli zrobię to wieczorem, wdrożenia mogę wstrzymać na dość długi czas.
Jeśli raz jeszcze spojrzymy na dokumentację Kubernetes, zobaczymy coś, co nazywa się Limit Range. Ustala on zasoby dla obiektów klastra. Możesz napisać obiekt Limit Range w formacie yaml, zastosować go w określonych przestrzeniach nazw — a następnie w tej przestrzeni nazw możesz określić, że masz domyślne, maksymalne i minimalne zasoby dla podów.
Dzięki takiej funkcji możemy ograniczyć użytkowników w określonych przestrzeniach nazw produktów w możliwościach wskazywania w swoich podach na różne niepożądane elementy. Ale niestety, nawet jeśli powiesz użytkownikowi, że nie może uruchamiać podów z żądaniami większymi niż jeden CPU, istnieje taka wspaniała komenda scale, lub przez dashboard mogą realizować skalowanie.
I stąd pochodzi sposób numer dwa. Uruchamiamy 11 111 111 111 111 podów. To jedenaście miliardów. Nie dlatego, że wymyśliłem taką liczbę, ale dlatego, że sam to widziałem.
Prawdziwa historia. Późnym wieczorem już miałem zamiar wyjść z biura. Patrzę, w rogu siedzi grupka programistów i coś gorączkowo robi z laptopami. Podchodzę do chłopaków i pytam: „Co się stało?”
Trochę wcześniej, około dziewiątej wieczorem, jeden z programistów szykował się do powrotu do domu. I postanowił: „Teraz skaluję moją aplikację do jedynki”. Nacisnął jedynkę, a internet trochę się spowolnił. Nacisnął jeszcze raz na jedynkę, przycisnął jedynkę, kliknął Enter. Próbował wszystkiego, co mógł. Wtedy internet ożył — i wszystko zaczęło się skalować do tej liczby.
Prawda jest taka, że ta historia miała miejsce nie na Kubernetes, w tamtym czasie był to Nomad. Zakończyło się to tym, że po godzinie naszych prób zatrzymania Nomada przed uporczywymi próbami skalowania, Nomad odpowiedział, że nie przestanie się skalować i nie zajmie się niczym innym. „Jestem zmęczony, odchodzę”. I się wyłączył.
Oczywiście próbowałem to samo zrobić na Kubernetesie. Jedenaście miliardów podów nie ucieszyło Kubernetesa, powiedział: „Nie mogę. Przekracza wewnętrzne limity”. Ale 1 000 000 000 podów udało mu się uruchomić.
W odpowiedzi na jeden miliard podów Kubernetes nie skalał się. On naprawdę zaczął się skalować. Im dalej postępował proces, tym więcej czasu zajmowało mu tworzenie nowych podów. Ale i tak proces przebiegał. Jedynym problemem jest to, że jeśli mogę w swoim namespace'ie uruchamiać nieograniczoną ilość podów, to nawet bez requestów i limitów mogę uruchomić na przykład taką ilość podów, że w wyniku tych zadań węzły zaczną przeładowywać pamięć i CPU. Kiedy uruchamiam tyle podów, informacje z nich muszą trafić do magazynu, czyli etcd. A gdy za dużo informacji tam trafia, magazyn zaczyna zbyt wolno odpowiadać — i Kubernetes zaczyna się zacinać.
A jest jeszcze jeden problem… Jak wiecie, komponenty zarządzające Kubernetesem to nie jeden centralny element, lecz kilka komponentów. W szczególności jest tam kontroler menedżer, scheduler i tak dalej. Wszyscy ci goście zaczynają jednocześnie wykonywać niepotrzebną i bezsensowną pracę, która z czasem zaczyna zajmować coraz więcej czasu. Kontroler menedżer będzie tworzył nowe pody. Scheduler będzie próbował znaleźć dla nich nowy węzeł. Nowe węzły w klastrze prawdopodobnie wkrótce się skończą. Klastrowi Kubernetes będzie działać coraz wolniej.
Ale postanowiłem pójść jeszcze dalej. Jak wiecie, w Kubernetesie jest coś, co nazywa się usługą. No i domyślnie w waszych klastrach, prawdopodobnie, usługa działa za pomocą iptables.
Jeśli uruchomić miliard podów, na przykład, a potem za pomocą skryptu zmusić Kubernetes do tworzenia nowych usług:
for i in {1..1111111}; do
kubectl expose deployment test --port 80
--overrides="{"apiVersion": "v1",
"metadata": {"name": "nginx$i"}}";
done Na wszystkich węzłach klastra w przybliżeniu w tym samym czasie będą generowane nowe reguły iptables. I dla każdej usługi będą generowane po miliard reguł iptables.
Sprawdzałem to na kilku tysiącach, do dziesiątki. I problem polega na tym, że już na tym etapie SSH na węzeł staje się dość problematyczne. Ponieważ pakiety, przechodząc przez taką ilość łańcuchów, zaczynają źle się czuć.
I to również można rozwiązać za pomocą Kubernetesa. Istnieje taki obiekt jak Resource quota. Ustala on ilość dostępnych zasobów i obiektów dla namespace w klastrze. Możemy stworzyć obiekt YAML w każdym namespace klastra Kubernetesa. Dzięki temu obiektowi możemy powiedzieć, że dla tego namespace przydzielono określoną liczbę requestów, limitów, a następnie możemy określić, że w tym namespace można stworzyć 10 usług i 10 podów. A programista może sobie spokojnie pracować wieczorami. Kubernetes powie mu: „Nie możesz skalować swoich podów do takiej liczby, ponieważ przekracza to limit zasobów”. I problem rozwiązany. .
Jednak pojawia się jeden problem w związku z tym. Czujesz, jak trudno stało się stworzyć namespace w Kubernetesa. Aby go stworzyć, musimy wziąć pod uwagę wiele rzeczy.
Resource quota + Limit Range + RBAC
• Tworzymy namespace
• Tworzymy w środku limitrange
• Tworzymy wewnątrz resourcequota
• Tworzymy serviceaccount dla CI
• Tworzymy rolebinding dla CI i użytkowników
• Opcjonalnie uruchamiamy potrzebne usługi podów
Dlatego korzystając z okazji, chciałbym podzielić się moimi opracowaniami. Istnieje jedna rzecz, która nazywa się operator SDK. To sposób pisania operatorów dla klastra Kubernetesa. Możesz pisać operatorzy za pomocą Ansible.
Najpierw napisaliśmy to w Ansible, a potem zobaczyłem, że istnieje operator SDK i przepisałem rolę Ansible na operatora. Ten operator pozwala stworzyć w klastrze Kubernetesa obiekt, który nazywa się komenda. Wewnątrz komendy pozwala opisać w YAML środowisko dla tej komendy. A wewnątrz środowiska komendy pozwala określać, ile zasobów przydzielamy.
Mały .
I na zakończenie. Co z tym wszystkim zrobić?
Po pierwsze. Polityka bezpieczeństwa poda — to dobrze. I mimo że żaden z instalatorów Kubernetesa do tej pory ich nie używa, to wciąż należy je stosować w Twoich klastrach.
Polityka sieciowa — to nie jest jakaś inna niepotrzebna funkcjonalność. To to, co jest naprawdę potrzebne w klastrze.
LimitRange/ResourceQuota — czas, aby z nich korzystać. Od dawna już zaczęliśmy z tego korzystać, a ja długo byłem przekonany, że wszyscy to stosują. Okazało się, że to rzadkość.
Oprócz tego, co wspomniałem podczas prezentacji, istnieją nieudokumentowane funkcje, które umożliwiają atak na klaster. Niedawno wyszedł .
Niektóre rzeczy są na tyle smutne i przykre. Na przykład, w pewnych warunkach kubelety w klastrze Kubernetes mogą ujawniać zawartość katalogu warlocks, i to użytkownikowi nieautoryzowanemu.
znajdują się instrukcje, jak odtworzyć wszystko, co mówiłem. Są tam pliki z produkcyjnymi przykładami, jak wyglądają ResourceQuota i Pod Security Policy. I to wszystko można sprawdzić.
Dziękuję wszystkim.
Źródło: habr.com
