Wir schließen die Lücken im Kubernetes-Cluster. Vortrag und Transkription von DevOpsConf

Pavel Selivanov, Lösungsarchitekt bei Southbridge und Dozent von Slurm, hielt einen Vortrag auf der DevOpsConf 2019. Dieser Vortrag ist Teil eines der Themen im vertieften Kurs zu Kubernetes "Slurm Mega".

Slurm Basis: Einführung in Kubernetes findet in Moskau vom 18. bis 20. November statt.
Slurm Mega: Ein Blick unter die Haube von Kubernetes — Moskau, 22. bis 24. November.
Slurm Online: beide Kurse zu Kubernetes sind jederzeit verfügbar.

Video abspielen

Nach dem Schnitt — die Transkription des Vortrags.

Guten Tag, Kollegen und Interessierte. Heute werde ich über Sicherheit sprechen.

Ich sehe, dass heute viele Sicherheitsfachleute im Raum sind. Ich entschuldige mich im Voraus, wenn ich Sicherheitsbegriffe nicht ganz so verwende, wie es bei Ihnen üblich ist.

Es ist so passiert, dass mir vor etwa einem halben Jahr ein öffentliches Kubernetes-Cluster in die Hände gefallen ist. Öffentlich bedeutet, dass es eine bestimmte Anzahl von Namespaces gibt, in diesen Namespaces gibt es Benutzer, die in ihrem eigenen Namespace isoliert sind. Alle diese Benutzer gehören unterschiedlichen Unternehmen. Nun, es wurde angenommen, dass dieses Cluster als CDN genutzt werden sollte. Das heißt, Ihnen wird ein Cluster gegeben, Sie erhalten einen Benutzer, Sie kommen in Ihren Namespace und deployen Ihre Frontends.

In meinem vorherigen Unternehmen wurde mir ein solcher Service angeboten. Und ich wurde gebeten, den Cluster zu testen, um herauszufinden, ob diese Lösung geeignet ist oder nicht.

Als ich in diesen Cluster kam, bekam ich eingeschränkte Rechte und einen beschränkten Namespace. Die Leute dort verstanden, was Sicherheit bedeutet. Sie hatten sich mit Role-based Access Control (RBAC) von Kubernetes beschäftigt und so eingestellt, dass ich Pods nicht unabhängig von Deployments starten konnte. Ich erinnere mich nicht an die Aufgabe, die ich zu lösen versuchte, als ich einen Pod ohne Deployment starten wollte, aber ich wollte einfach einen Pod starten. Ich entschied mich aus Interesse zu überprüfen, welche Rechte ich im Cluster habe, was ich kann und was nicht, und was sie dort eingestellt haben. Außerdem werde ich erzählen, was in ihrem RBAC falsch konfiguriert ist.

Nach zwei Minuten hatte ich Admin-Rechte für ihren Cluster erhalten, sah mir alle benachbarten Namespaces an und entdeckte dort laufende Produktions-Frontends von Unternehmen, die bereits den Service gekauft und deployed hatten. Ich konnte mich kaum zurückhalten, nicht zu jemandem ins Frontend zu gehen und auf die Startseite ein obszönes Wort zu setzen.

Ich werde anhand von Beispielen erklären, wie ich das gemacht habe und wie man sich davor schützen sollte.

Zunächst möchte ich mich vorstellen. Mein Name ist Pavel Selivanov. Ich bin Architekt bei der Firma Southbridge. Ich kenne mich gut mit Kubernetes, DevOps und anderen angesagten Technologien aus. Gemeinsam mit den Ingenieuren von Southbridge baue ich all das auf, während ich berate.

Neben unserer Haupttätigkeit haben wir vor kurzem Projekte gestartet, die wir Slërmy nennen. Unser Ziel ist es, unser Wissen über Kubernetes in die Breite zu tragen und andere Menschen darin zu schulen, ebenfalls mit K8s zu arbeiten.

Worüber ich heute sprechen werde. Das Thema meines Vortrags ist offensichtlich — die Sicherheit von Kubernetes-Clustern. Aber ich möchte gleich zu Beginn sagen, dass dieses Thema sehr umfangreich ist. Daher möchte ich klarstellen, worüber ich definitiv nicht sprechen werde. Ich werde keine abgedroschenen Begriffe behandeln, die im Internet schon hundertmal diskutiert wurden, wie RBAC und Zertifikate.

Ich werde darüber berichten, was mir und meinen Kollegen bei der Sicherheit in Kubernetes-Clustern Sorgen bereitet. Wir sehen diese Probleme sowohl bei Anbietern, die Kubernetes-Cluster bereitstellen, als auch bei Kunden, die zu uns kommen. Und selbst bei Kunden, die von anderen Beratungs-Admin-Unternehmen zu uns kommen. Das Ausmaß der Tragödie ist tatsächlich sehr groß.

Wirklich drei Punkte, über die ich heute sprechen möchte:

  1. Benutzerrechte vs. Pod-Rechte. Benutzerrechte und Pod-Rechte sind nicht dasselbe.
  2. Informationssammlung über den Cluster. Ich werde zeigen, dass wir alle notwendigen Informationen aus dem Cluster sammeln können, ohne besondere Zugriffsrechte zu benötigen.
  3. DoS-Angriff auf den Cluster. Auch wenn wir keine Informationen sammeln können, können wir den Cluster dennoch zum Absturz bringen. Ich werde über DoS-Angriffe auf die Steuerelemente des Clusters sprechen.

Ein weiterer allgemeiner Punkt, auf den ich hinweisen möchte, ist, worauf ich all dies getestet habe und was ich mit Sicherheit sagen kann, dass es funktioniert.

Wir verwenden zur Grundlage die Installation eines Kubernetes-Clusters mit Kubespray. Wer es nicht weiß, das ist praktischerweise eine Sammlung von Rollen für Ansible. Wir nutzen es regelmäßig in unserer Arbeit. Es ist gut, da es überall eingesetzt werden kann – sowohl auf physischer Hardware als auch in der Cloud. Eine Installationsmethode eignet sich grundsätzlich für alles.

In diesem Cluster werde ich Kubernetes v1.14.5 haben. Der gesamte Kubernetes-Cluster, den wir betrachten werden, ist in Namespaces unterteilt, wobei jeder Namespace einem eigenen Team gehört und die Mitglieder dieses Teams Zugriff auf ihren eigenen Namespace haben. Sie können nicht zu anderen Namespaces gehen, nur in ihren eigenen. Es gibt jedoch ein Admin-Konto, das über Berechtigungen für den gesamten Cluster verfügt.

Wir schließen die Lücken im Kubernetes-Cluster. Vortrag und Transkription von DevOpsConf

Ich habe versprochen, dass wir zunächst Admin-Rechte für den Cluster erhalten werden. Wir brauchen einen speziell vorbereiteten Pod, der den Kubernetes-Cluster angreift. Alles, was wir tun müssen, ist, ihn im Kubernetes-Cluster anzuwenden.

kubectl apply -f pod.yaml

Dieser Pod wird auf einen der Master-Knoten des Kubernetes-Clusters gelangen. Und nach diesem Vorgang gibt uns der Cluster die Datei zurück, die admin.conf heißt. In dieser Datei sind alle Zertifikate des Admins gespeichert und zudem ist die API des Clusters konfiguriert. So einfach kann man Admin-Zugriff erhalten, ich denke, das gilt für 98% der Kubernetes-Cluster.

Nochmals, dieser Pod wurde von einem Entwickler in Ihrem Cluster erstellt, der Zugriff hat, um seine Vorschläge in einen kleinen Namespace zu deployen, dieser ist ganz durch RBAC eingeschränkt. Er hatte keine Rechte. Dennoch wurde das Zertifikat zurückgegeben.

Nun zu dem speziell vorbereiteten Pod. Wir starten mit jedem Image. Zum Beispiel nehmen wir debian:jessie.

Wir haben so etwas:

tolerations:
-   effect: NoSchedule 
    operator: Exists 
nodeSelector: 
    node-role.kubernetes.io/master: "" 

Was ist eine Toleranz? Master-Knoten im Kubernetes-Cluster sind normalerweise mit etwas gekennzeichnet, das als Taint bezeichnet wird. Und der Sinn dieses „Taints“ ist, dass auf Master-Knoten keine Pods zugewiesen werden dürfen. Aber niemand hindert uns daran, in einem beliebigen Pod anzugeben, dass er gegen den „Taint“ tolerant ist. Der Abschnitt Toleration sagt genau das: Wenn auf einem Knoten NoSchedule steht, ist unser Pod tolerant gegenüber diesem Taint — und es gibt keine Probleme.

Darüber hinaus sagen wir, dass unser Pod nicht nur tolerant ist, sondern auch speziell auf den Master gelangen möchte. Denn auf den Mastern befinden sich die wertvollsten Dinge, die wir brauchen — alle Zertifikate. Daher geben wir nodeSelector an — und wir haben ein Standardlabel auf den Mastern, das es ermöglicht, aus allen Knoten des Clusters gerade die Knoten auszuwählen, die Master sind.

Mit diesen beiden Abschnitten wird der Pod auf jeden Fall auf dem Master ankommen. Und er wird dort wohnen dürfen.

Es reicht nicht aus, einfach zum Master zu kommen. Das bringt uns nichts. Daher haben wir zwei Dinge:

hostNetwork: true 
hostPID: true 

Wir geben an, dass unser Pod, den wir starten, im Namespace des Kernels sowie im Netzwerk- und PID-Namespace leben wird. Sobald der Pod auf dem Master läuft, kann er alle echten, aktiven Interfaces dieses Nodes sehen, den gesamten Traffic abhören und die PIDs aller Prozesse einsehen.

Jetzt kommt das Wesentliche. Nehmen Sie etcd und lesen Sie, was Sie möchten.

Das Interessanteste ist, dass diese Möglichkeit in Kubernetes standardmäßig vorhanden ist.

volumeMounts:
- mountPath: /host 
  name: host 
volumes:
- hostPath: 
    path: / 
    type: Directory 
  name: host 

Und die Essenz davon ist, dass wir im Pod, den wir starten, sogar ohne Berechtigungen für diesen Cluster sagen können, dass wir ein Volume vom Typ hostPath erstellen möchten. Das bedeutet, den Pfad vom Host, auf dem wir starten, zu nehmen und ihn als Volume zu verwenden. Wir nennen es dann name: host. Dieses ganze hostPath mounten wir innerhalb des Pods, in diesem Beispiel im Verzeichnis /host.

Um es noch einmal zu wiederholen. Wir haben dem Pod gesagt, dass er zum Master kommen, hostNetwork und hostPID beziehen und das gesamte Root des Masters in diesen Pod mounten soll.

Sie verstehen, dass wir in Debian bash laufen haben, und dieses Bash läuft unter root. Das heißt, wir haben gerade root auf dem Master erhalten, ohne irgendwelche Berechtigungen im Kubernetes-Cluster zu haben.

Die gesamte Aufgabe besteht dann darin, in das Pod-Verzeichnis /host/etc/kubernetes/pki zu gelangen, wenn ich mich nicht irre, und dort alle Master-Zertifikate des Clusters abzuholen und somit Administrator des Clusters zu werden.

Wenn man darüber nachdenkt, sind das einige der gefährlichsten Berechtigungen in Pods — unabhängig davon, welche Berechtigungen der Benutzer hat:
Wir schließen die Lücken im Kubernetes-Cluster. Vortrag und Transkription von DevOpsConf

Wenn ich das Recht habe, ein Pod in einem bestimmten Namespace des Clusters zu starten, dann hat dieses Pod diese Berechtigungen standardmäßig. Ich kann privilegierte Pods starten, und das sind praktisch alle Berechtigungen, quasi root auf dem Node.

Mein Favorit ist der Root-Benutzer. Kubernetes bietet jedoch die Option „Run As Non-Root“. Das ist so eine Art Schutz vor Hackern. Wissen Sie, was ein „moldawisches Virus“ ist? Wenn Sie zufällig ein Hacker sind und in mein Kubernetes-Cluster eindringen, dann bitten wir, die armen Administratoren: „Bitte geben Sie in Ihren Pods, mit denen Sie mein Cluster hacken werden, an, dass Sie als Nicht-Root ausführen. Andernfalls werden Sie den Prozess in Ihrem Pod als Root ausführen und es wird sehr einfach sein, mich zu hacken. Schützen Sie sich bitte selbst.“

Der Host-Pfad-Volume ist meiner Meinung nach der schnellste Weg, um das gewünschte Ergebnis aus dem Kubernetes-Cluster zu erzielen.

Aber was soll man mit alledem machen?

Gedanken, die jedem normalen Administrator durch den Kopf gehen sollten, der mit Kubernetes konfrontiert wird: „Aha, ich habe es gesagt, Kubernetes funktioniert nicht. Es hat Lücken. Und das ganze Zeug ist Müll.“ In Wirklichkeit gibt es so etwas wie Dokumentation, und wenn man dort nachschaut, gibt es einen Abschnitt Pod-Sicherheitsrichtlinie.

Das ist ein YAML-Objekt, das wir in einem Kubernetes-Cluster erstellen können und das die Sicherheitsaspekte in der Pod-Beschreibung steuert. Es kontrolliert im Wesentlichen die Berechtigungen zur Verwendung von hostNetwork, hostPID und bestimmten Typen von Volumes, die beim Starten in Pods vorhanden sind. Mit der Pod Security Policy kann all dies beschrieben werden.

Das Interessanteste an der Pod Security Policy ist, dass alle PSP-Installationen im Kubernetes-Cluster nicht nur nicht beschrieben sind, sondern standardmäßig einfach deaktiviert sind. Die Pod Security Policy wird durch ein Admission-Plugin aktiviert.

Okay, wir deployen die Pod Security Policy in den Cluster und sagen, dass wir einige Dienst-Pods im Namespace haben, auf den nur Administratoren Zugriff haben. In allen anderen Pods gelten eingeschränkte Berechtigungen. Denn wahrscheinlich müssen Entwickler keine privilegierten Pods in Ihrem Cluster starten.

Und anscheinend ist alles in Ordnung. Und unser Kubernetes-Cluster kann nicht in zwei Minuten gehackt werden.

Es gibt ein Problem. Wahrscheinlich haben Sie ein Kubernetes-Cluster, in dem Überwachung eingerichtet ist. Ich wage sogar die Vorhersage, dass es in Ihrem Cluster als Prometheus bekannt ist.

Was ich jetzt erzähle, gilt sowohl für den Prometheus-Operator als auch für Prometheus in seiner reinen Form. Die Frage ist, wenn ich im Cluster nicht so schnell einen Administrator bekommen kann, bedeutet das, dass ich mehr suchen muss. Und ich kann mit Ihrer Überwachung suchen.

Wahrscheinlich haben alle die gleichen Artikel auf Habré gelesen, und die Überwachung befindet sich im Namespace monitoring. Das Helm-Chart hat bei allen ähnliche Namen. Ich gehe davon aus, dass wenn Sie helm install stable/prometheus machen, Sie ungefähr die gleichen Bezeichnungen erhalten. Und wahrscheinlich muss ich den DNS-Namen in Ihrem Cluster nicht erraten, denn er ist standardmäßig.

Wir schließen die Lücken im Kubernetes-Cluster. Vortrag und Transkription von DevOpsConf

Dann haben wir einen bestimmten Dev-Namespace, in dem man einen Pod starten kann. Und aus diesem Pod heraus ist es sehr einfach, Folgendes zu machen:

$ curl http://prometheus-kube-state-metrics.monitoring 

prometheus-kube-state-metrics ist einer der Exporter von Prometheus, der Metriken aus der Kubernetes-API sammelt. Dort gibt es viele Daten darüber, was in Ihrem Cluster läuft, wie es aussieht und welche Probleme Sie damit haben.

Ein einfaches Beispiel:

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:e29561119a52adad9edc72bfe0e7fcab308501313b09bf99df4a96 38ee634989″,container_id=»docker://7cbe7b1fea33f811fdd8f7e0e079191110268f2 853397d7daf08e72c22d3cf8b»} 1

Durch einen einfachen Curl-Befehl aus einem nicht privilegierten Pod können Sie solche Informationen abrufen. Wenn Sie nicht wissen, welche Version von Kubernetes Sie verwenden, wird es Ihnen dies ganz leicht mitteilen.

Das Interessanteste ist, dass Sie neben kube-state-metrics auch direkt auf Prometheus zugreifen können. Sie können Metriken von dort abrufen. Sie können sogar Metriken von dort erstellen. Theoretisch können Sie sogar eine Anfrage von einem Cluster an Prometheus stellen, die ihn einfach abschaltet. Dadurch funktioniert Ihre Überwachung im Cluster überhaupt nicht mehr.

Hier stellt sich die Frage, ob eine externe Überwachung Ihre Überwachung überwacht. Gerade hatte ich die Möglichkeit, im Kubernetes-Cluster zu agieren, ohne irgendwelche Konsequenzen für mich zu haben. Sie werden nicht einmal erfahren, dass ich dort tätig bin, da die Überwachung bereits nicht mehr existiert.

Es fühlt sich ähnlich an wie mit PSP, als ob das Problem darin liegt, dass all diese modernen Technologien – Kubernetes, Prometheus – einfach nicht funktionieren und voller Löcher sind. In Wirklichkeit ist das nicht so.

Es gibt so etwas wie – Network Policy.

Wenn Sie ein normaler Administrator sind, wissen Sie wahrscheinlich, dass Network Policy ein weiteres YAML ist, von denen es im Cluster ohnehin schon viele gibt. Und Network Policies sind sicherlich nicht unbedingt erforderlich. Selbst wenn Sie gelesen haben, was eine Network Policy ist, dass es eine YAML-Firewall von Kubernetes ist, die den Zugriff zwischen Namespaces und Pods einschränkt, dann haben Sie sicherlich beschlossen, dass eine Firewall im YAML-Format in Kubernetes bei den nächsten Abstraktionen… Nein, nein. Das ist auf jeden Fall nicht nötig.

Selbst wenn Ihren Sicherheitsexperten nicht gesagt wurde, dass Sie mit Ihrem Kubernetes ganz einfach und unkompliziert eine sehr granulare Firewall erstellen können. Falls sie das noch nicht wissen und nicht fragen: „Na, geben Sie, geben Sie…“ Brauchen Sie in jedem Fall eine Network Policy, um den Zugriff auf bestimmte administrative Stellen zu sperren, die Sie aus Ihrem Cluster abrufen können, ohne jegliche Autorisierung.

Wie im Beispiel, das ich angeführt habe, kann kube state metrics aus jedem Namespace im Kubernetes-Cluster abgerufen werden, ohne dafür irgendwelche Berechtigungen zu haben. Die Netzwerkrichtlinien haben den Zugang von allen anderen Namespaces zum Monitoring-Namespace gesperrt, und das war's: kein Zugang, kein Problem. In allen Charts, sowohl in der Standard-Prometheus-Implementation als auch in der Prometheus-Version, die im Operator verwendet wird, gibt es einfach die Option in den Helm-Values, die Netzwerkrichtlinien zu aktivieren. Man muss sie nur aktivieren, und sie werden funktionieren.

Es gibt allerdings ein Problem. Als normaler, erfahrener Administrator haben Sie wahrscheinlich beschlossen, dass Netzwerkrichtlinien nicht notwendig sind. Und nachdem Sie verschiedene Artikel auf Plattformen wie Habr gelesen haben, haben Sie entschieden, dass Flannel, insbesondere im Host-Gateway-Modus, das Beste ist, was Sie wählen können.

Was tun?

Sie können versuchen, die Netzwerklösung, die Sie in Ihrem Kubernetes-Cluster haben, neu bereitzustellen und sie durch etwas Funktionaleres zu ersetzen, zum Beispiel durch das gleiche Calico. Aber ich möchte gleich sagen, dass die Aufgabe, die Netzwerklösung in einem produktiven Kubernetes-Cluster zu ändern, ziemlich komplex ist. Ich habe das zweimal gelöst (beide Male zwar theoretisch), aber wir haben sogar in Slërms gezeigt, wie das geht. Für unsere Schüler haben wir gezeigt, wie man die Netzwerklösung in einem Kubernetes-Cluster ändert. Im Grunde können Sie versuchen, dies so zu machen, dass es im Produktiv-Cluster keine Ausfallzeiten gibt. Aber wahrscheinlich wird es Ihnen nicht gelingen.

Das Problem lässt sich tatsächlich sehr einfach lösen. Im Cluster gibt es Zertifikate, und Sie wissen, dass Ihre Zertifikate in einem Jahr ablaufen werden. Nun, und normalerweise ist die übliche Lösung mit Zertifikaten im Cluster — warum sich damit belasten? Wir heben einfach einen neuen Cluster daneben hoch, der alte kann ablaufen, und wir deployen alles neu. Natürlich, wenn es abläuft, liegt alles einen Tag lang still, aber das neue Cluster steht bereit.

Wenn Sie den neuen Cluster erstellen, fügen Sie gleich Calico anstelle von Flannel ein.

Was tun, wenn Sie Zertifikate für hundert Jahre ausgestellt haben und das Cluster nicht neu bereitstellen möchten? Es gibt eine Lösung namens Kube-RBAC-Proxy. Diese großartige Entwicklung ermöglicht es, sich als Sidecar-Container in jeden Pod im Kubernetes-Cluster einzufügen und fügt diesem Pod tatsächlich eine Autorisierung über das RBAC von Kubernetes hinzu.

Es gibt ein Problem. Früher war die Lösung Kube-RBAC-Proxy im Prometheus-Operator integriert. Das ist nicht mehr der Fall. Aktuelle Versionen setzen voraus, dass Sie eine Netzwerkpolice haben und diese verwenden. Daher müssen die Charts ein wenig umgeschrieben werden. Wenn Sie tatsächlich auf dieses Repository erstellen,, schauen, gibt es Beispiele, wie man es als Sidecar verwenden kann, und die Charts müssen nur minimal umgeschrieben werden.

Es gibt noch ein weiteres kleines Problem. Nicht nur Prometheus gibt seine Metriken an beliebige Empfänger weiter. Auch alle Komponenten im Kubernetes-Cluster können ihre eigenen Metriken bereitstellen.

Aber wie ich bereits sagte, wenn Sie keinen Zugang zum Cluster haben und keine Informationen sammeln können, können Sie wenigstens etwas Schaden anrichten.

Ich werde Ihnen also schnell zwei Methoden zeigen, wie man die Gesundheit eines Kubernetes-Clusters beeinträchtigen kann.

Sie werden lachen, wenn ich das erzähle, es sind zwei Fälle aus dem wirklichen Leben.

Erste Methode. Ressourcenerschöpfung.

Wir starten einen weiteren speziellen Pod. Er wird so eine Sektion haben.

resources: 
    requests: 
        cpu: 4 
        memory: 4Gi 

Wie Sie wissen, sind requests die Menge an CPU und Speicher, die auf dem Host für bestimmte Pods mit Requests reserviert ist. Wenn wir einen vierkernigen Host im Kubernetes-Cluster haben und ein Pod mit einem Request von vier CPU ankommt, dann kann kein weiterer Pod mit Requests auf diesem Host ankommen.

Wenn ich solch einen Pod starte, mache ich dann den Befehl:

$ kubectl scale special-pod --replicas=...

Dann kann niemand mehr im Kubernetes-Cluster deployen. Denn in allen Nodes gehen die Requests aus. Auf diese Weise würde ich Ihren Kubernetes-Cluster zum Stillstand bringen. Wenn ich das am Abend mache, kann ich die Deployments ziemlich lange stoppen.

Wenn wir ein weiteres Mal in die Kubernetes-Dokumentation schauen, sehen wir etwas, das als Limit Range bezeichnet wird. Es legt die Ressourcen für Clusterobjekte fest. Sie können ein YAML-Objekt für den Limit Range schreiben und es in bestimmten Namespaces anwenden — und dann in diesem Namespace können Sie angeben, dass Sie Standard-, Maximal- und Minimalressourcen für Pods haben.

Mit so einem Mechanismus können wir Benutzer in bestimmten Produktnamespaces von Teams darin beschränken, jeglichen Unsinn in ihren Pods anzugeben. Aber leider, selbst wenn Sie dem Benutzer sagen, dass er Pods mit Requests von mehr als einer CPU nicht starten kann, gibt es diesen wunderbaren Befehl scale, oder über das Dashboard können sie die Skalierung durchführen.

Und hieraus ergibt sich die zweite Methode. Wir starten 11 111 111 111 111 Pods. Das sind elf Milliarden. Das liegt nicht daran, dass ich mir diese Zahl ausgedacht habe, sondern weil ich es selbst gesehen habe.

Echte Geschichte. Spät abends wollte ich bereits das Büro verlassen. Ich sah in einer Ecke eine Gruppe von Entwicklern, die hektisch an ihren Laptops arbeiteten. Ich ging zu den Jungs und fragte: „Was ist denn los bei euch?“

Kurz nach neun Uhr abends wollte einer der Entwickler nach Hause gehen. Er dachte sich: „Ich werde jetzt meine Anwendung auf eins skalieren“. Er drückte auf eins, aber das Internet stockte ein wenig. Er drückte erneut auf eins, drückte darauf und klackte auf Enter. Er tippte auf alles, was er konnte. Plötzlich lebte das Internet wieder auf — und alles begann, auf diese Zahl zu skalieren.

Allerdings geschah diese Geschichte nicht auf Kubernetes, zu diesem Zeitpunkt war es Nomad. Das endete damit, dass nach einer Stunde unserer Versuche, Nomad von seinen hartnäckigen Skalierungsversuchen abzuhalten, Nomad antwortete, dass es nicht aufhören würde zu skalieren und sich mit nichts anderem beschäftigen würde. „Ich bin müde, ich gehe“. Und zog sich zurück.

Natürlich versuchte ich, dasselbe auf Kubernetes zu tun. Elf Milliarden Pods freuten Kubernetes nicht, es sagte: „Ich kann nicht. Überschreitet die internen Limits“. Aber 1 000 000 000 Pods konnten skaliert werden.

Als Reaktion auf eine Milliarden Pods hat sich Kubernetes nicht verabschiedet. Es hat tatsächlich begonnen, zu skalieren. Je weiter der Prozess voranschritt, desto mehr Zeit benötigte er, um neue Pods zu erstellen. Aber der Prozess lief trotzdem weiter. Das einzige Problem ist, dass ich in meinem Namespace unbegrenzt Pods starten kann. Selbst ohne Requests und Limits kann ich Aufgaben so viele Pods starten, dass die Knoten anfangen, hinsichtlich Speicher und CPU zu überlasten. Wenn ich so viele Pods starte, müssen die Informationen darin in den Speicher gelangen, sprich etcd. Und wenn zu viele Informationen dort ankommen, beginnt der Speicher, zu langsam zu antworten — und Kubernetes bekommt Verzögerungen.

Ein weiteres Problem… Wie Sie wissen, sind die Kubernetes-Steuerelemente nicht eine zentrale Einheit, sondern mehrere Komponenten. Dazu gehören unter anderem der Controller-Manager, der Scheduler und so weiter. All diese Komponenten beginnen gleichzeitig mit unnötiger und ineffizienter Arbeit, die im Laufe der Zeit immer mehr Zeit in Anspruch nehmen wird. Der Controller-Manager wird neue Pods erstellen. Der Scheduler wird versuchen, ihnen einen neuen Node zuzuweisen. Die neuen Nodes in Ihrem Cluster werden wahrscheinlich bald ausgehen. Der Kubernetes-Cluster wird immer langsamer arbeiten.

Aber ich habe mich entschieden, noch weiter zu gehen. Wie Sie wissen, gibt es in Kubernetes etwas, das Services genannt wird. Standardmäßig funktioniert der Service in Ihren Clustern wahrscheinlich über IP-Tabellen.

Wenn Sie beispielsweise eine Milliarde Pods starten und dann mit einem Skript Kubernetes anweisen, neue Services zu erstellen:

for i in {1..1111111}; do
    kubectl expose deployment test --port 80  
        --overrides="{"apiVersion": "v1", 
           "metadata": {"name": "nginx$i"}}"; 
done 

Auf allen Knoten des Clusters werden gleichzeitig ständig neue iptables-Regeln generiert. Für jeden Dienst werden jeweils eine Milliarde iptables-Regeln erstellt.

Ich habe das Ganze bei mehreren Tausend bis hin zu einem Dutzend überprüft. Und das Problem ist, dass es bereits an diesem Punkt ziemlich schwierig ist, eine SSH-Verbindung zu einem Knoten herzustellen. Da Pakete durch so viele Ketten laufen, beginnen sie, sich nicht besonders gut zu verhalten.

Auch das lässt sich mit Kubernetes lösen. Es gibt ein Objekt, das Resource Quota heißt. Es legt die Anzahl der verfügbaren Ressourcen und Objekte für einen Namespace im Cluster fest. Wir können ein YAML-Objekt in jedem Namespace des Kubernetes-Clusters erstellen. Mit diesem Objekt können wir angeben, dass für diesen Namespace eine bestimmte Anzahl an Requests und Limits zugewiesen ist, und wir können dann festlegen, dass in diesem Namespace 10 Dienste und 10 Pods erstellt werden können. Und der Entwickler kann sich am Abend damit beschäftigen. Kubernetes wird ihm sagen: „Es ist nicht möglich, Ihre Pods auf diese Anzahl zu skalieren, da dies das Ressourcenquota überschreitet.“ Problem gelöst. Dokumentation hier.

Ein problematischer Punkt ergibt sich dabei. Sie spüren, wie schwierig es wird, einen Namespace in Kubernetes zu erstellen. Um ihn zu erstellen, müssen wir eine Menge Aspekte berücksichtigen.

Ressourcenkontingent + Limitbereich + RBAC
• Namespace erstellen
• Limitbereich innerhalb erstellen
• Ressourcenkontingent innerhalb erstellen
• Servicekonto für CI erstellen
• RoleBinding für CI und Benutzer erstellen
• Optional benötigte Hilfspods starten

Deshalb möchte ich die Gelegenheit nutzen, um meine Entwicklungen zu teilen. Es gibt etwas, das nennt sich Operator SDK. Damit können Sie im Kubernetes-Cluster Operatoren schreiben. Sie können Operatoren mit Ansible erstellen.

Zuerst hatten wir es in Ansible geschrieben, dann habe ich gesehen, dass es das Operator SDK gibt und ich die Ansible-Rolle in einen Operator umgeschrieben habe. Dieser Operator ermöglicht es, im Kubernetes-Cluster ein Objekt zu erstellen, das als Command bezeichnet wird. Innerhalb des Commands erlaubt es, die Umgebung für diesen Command in YAML zu beschreiben. Und innerhalb der Umgebung des Commands ermöglicht es, die Ressourcen, die wir zuweisen, anzugeben.

Klein Erleichterung dieses gesamten komplexen Prozesses.

Und abschließend. Was machen wir jetzt mit all dem?
Zuerst: Eine Pod Security Policy ist wichtig. Und obwohl bis heute keiner der Kubernetes-Installer sie verwendet, sollten sie dennoch in Ihren Clustern genutzt werden.

Eine Network Policy ist keine unnötige Funktion. Sie ist tatsächlich notwendig für den Cluster.

LimitRange/ResourceQuota sollten definitiv eingesetzt werden. Wir nutzen das schon lange, und ich war lange Zeit überzeugt, dass jeder das anwendet. Es stellte sich heraus, dass das eher selten ist.

Neben dem, was ich in meinem Vortrag erwähnt habe, gibt es undocumented Features, die Angriffe auf den Cluster ermöglichen. Neu veröffentlicht wurde eine umfangreiche Analyse von Kubernetes-Sicherheitslücken..

Einige Dinge sind so traurig und frustrierend. Beispielsweise können unter bestimmten Bedingungen die Kubelets im Kubernetes-Cluster den Inhalt des Verzeichnisses warlocks an nicht autorisierte Benutzer ausgeben.

Hier Es gibt Anleitungen zur Reproduzierung alles, was ich erklärt habe. Dort liegen Dateien mit Produktionsbeispielen, wie ResourceQuota und Pod Security Policy aussehen. Und all das kann man ausprobieren.

Danke an alle.

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster