Wir schließen Lücken im Kubernetes-Cluster. Berichten und Transkription mit DevOpsConf

Pavel Selivanov, Southbridge-Lösungsarchitekt und Slurm-Lehrer, hielt auf der DevOpsConf 2019 einen Vortrag. Dieser Vortrag ist Teil eines der Themen des Slurm Mega Advanced Kubernetes-Kurses.

Slurm Basic: Einführung in Kubernetes findet vom 18. bis 20. November in Moskau statt.
Slurm Mega: Ein Blick unter die Haube von Kubernetes - Moskau, 22.-24. November.
Slurm Online: Beide Kubernetes-Kurse immer verfügbar.

Unter dem Schnitt - Abschrift des Berichts.

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

Ich sehe, dass heute viele Sicherheitsleute in der Halle sind. Ich entschuldige mich im Voraus bei Ihnen, wenn ich Begriffe aus der Welt der Sicherheit nicht ganz so verwende, wie Sie es normalerweise tun.

So kam es, dass mir vor etwa sechs Monaten ein öffentlicher Kubernetes-Cluster in die Hände fiel. Öffentlich – bedeutet, dass es die n-te Anzahl von Namespaces gibt. In diesen Namespaces gibt es Benutzer, die in ihrem Namespace isoliert sind. Alle diese Benutzer gehören verschiedenen Unternehmen an. Nun, es wurde angenommen, dass dieser Cluster als CDN verwendet werden sollte. Das heißt, sie geben Ihnen einen Cluster, geben dort einen Benutzer, Sie gehen dorthin in Ihrem Namensraum und stellen Ihre Fronten bereit.

Meine vorherige Firma hat versucht, einen solchen Service zu verkaufen. Und ich wurde gebeten, im Cluster zu diesem Thema zu stöbern – ob eine solche Lösung geeignet ist oder nicht.

Ich bin zu diesem Cluster gekommen. Mir wurden begrenzte Rechte und ein begrenzter Namensraum gegeben. Dort haben die Jungs verstanden, was Sicherheit ist. Sie haben gelesen, was rollenbasierte Zugriffskontrolle (RBAC) in Kubernetes ist – und sie haben es so verdreht, dass ich Pods nicht getrennt von Bereitstellungen ausführen konnte. Ich kann mich nicht an das Problem erinnern, das ich zu lösen versuchte, indem ich einen Pod ohne Bereitstellung laufen ließ, aber ich wollte eigentlich nur einen Pod laufen lassen. Ich habe mich zum Glück entschieden, um zu sehen, welche Rechte ich im Cluster habe, was ich kann, was nicht, was sie dort vermasselt haben. Gleichzeitig erzähle ich Ihnen, was sie in RBAC falsch konfiguriert haben.

So kam es, dass ich innerhalb von zwei Minuten einen Administrator für ihren Cluster bekam, mir alle benachbarten Namespaces ansah und die Produktionsfronten von Unternehmen sah, die den Dienst bereits gekauft und dort bereitgestellt hatten. Ich habe mich kaum zurückgehalten, um nicht zu jemandem nach vorne zu kommen und ein paar Schimpfwörter auf die Hauptseite zu setzen.

Ich werde Ihnen anhand von Beispielen erzählen, wie ich es gemacht habe und wie ich mich dagegen wehren kann.

Aber zunächst möchte ich mich vorstellen. Mein Name ist Pavel Selivanov. Ich bin Architekt für Southbridge. Ich verstehe Kubernetes, DevOps und alle möglichen ausgefallenen Dinge. Die Southbridge-Ingenieure und ich bauen alles und ich berate es.

Zusätzlich zu unseren Hauptaktivitäten haben wir kürzlich Projekte namens Slurms gestartet. Wir versuchen, unsere Fähigkeit, mit Kubernetes zu arbeiten, ein wenig der breiten Masse zugänglich zu machen, um auch anderen Menschen beizubringen, wie man mit K8s arbeitet.

Worüber werde ich heute sprechen? Das Thema des Berichts liegt auf der Hand – die Sicherheit des Kubernetes-Clusters. Aber ich möchte gleich sagen, dass dieses Thema sehr umfangreich ist – und deshalb möchte ich gleich klarstellen, worüber ich auf keinen Fall sprechen werde. Ich werde nicht über abgedroschene Begriffe sprechen, die im Internet bereits hundertfach überbeansprucht wurden. Alle RBAC und Zertifikate.

Ich werde darüber sprechen, was mir und meinen Kollegen an der Sicherheit in einem Kubernetes-Cluster schadet. Wir sehen diese Probleme sowohl bei Anbietern, die Kubernetes-Cluster bereitstellen, als auch bei Kunden, die zu uns kommen. Und sogar für Kunden, die von anderen Beratungs- und Verwaltungsunternehmen zu uns kommen. Das heißt, das Ausmaß der Tragödie ist tatsächlich sehr groß.

Im wahrsten Sinne des Wortes drei Punkte, über die ich heute sprechen werde:

  1. Benutzerrechte vs. Pod-Rechte. Benutzerrechte und Pod-Rechte sind nicht dasselbe.
  2. Sammlung von Informationen über den Cluster. Ich werde zeigen, dass Sie alle Informationen, die Sie benötigen, aus einem Cluster sammeln können, ohne über besondere Rechte in diesem Cluster zu verfügen.
  3. DoS-Angriff auf den Cluster. Wenn es uns nicht gelingt, Informationen zu sammeln, können wir den Cluster trotzdem platzieren. Ich werde über DoS-Angriffe auf Cluster-Kontrollelemente sprechen.

Eine weitere allgemeine Sache, die ich erwähnen möchte, ist, woran ich alles getestet habe, und ich kann mit Sicherheit sagen, dass alles funktioniert.

Als Grundlage nehmen wir die Installation eines Kubernetes-Clusters mittels Kubespray. Falls jemand es nicht weiß: Dies ist tatsächlich eine Reihe von Rollen für Ansible. Wir verwenden es ständig bei der Arbeit. Das Gute daran ist, dass man überall rollen kann – und zwar auf den Eisenstücken und irgendwo in der Wolke. Eine Installationsmethode ist grundsätzlich für alles geeignet.

In diesem Cluster werde ich Kubernetes v1.14.5 haben. Der gesamte Cube-Cluster, den wir betrachten werden, ist in Namespaces unterteilt, jeder Namespace gehört zu einem separaten Team, Mitglieder dieses Teams haben Zugriff auf jeden Namespace. Sie können nicht zu verschiedenen Namensräumen wechseln, sondern nur zu ihrem eigenen. Es gibt jedoch ein bestimmtes Administratorkonto, das Rechte für den gesamten Cluster hat.

Wir schließen Lücken im Kubernetes-Cluster. Berichten und Transkription mit DevOpsConf

Ich habe versprochen, dass wir als Erstes Administratorrechte für den Cluster erhalten. Wir benötigen einen speziell vorbereiteten Pod, der den Kubernetes-Cluster zerstört. Wir müssen es lediglich auf den Kubernetes-Cluster anwenden.

kubectl apply -f pod.yaml

Dieser Pod wird zu einem der Master des Kubernetes-Clusters kommen. Und der Cluster gibt danach gerne eine Datei namens admin.conf zurück. In Kuba werden in dieser Datei alle Admin-Zertifikate gespeichert und gleichzeitig die Cluster-API konfiguriert. So einfach ist es meiner Meinung nach, Administratorzugriff auf 98 % der Kubernetes-Cluster zu erhalten.

Auch dieser Pod wurde von einem Entwickler in Ihrem Cluster erstellt, der Zugriff auf die Bereitstellung seiner Vorschläge in einem kleinen Namespace hat. Er ist vollständig durch RBAC eingeschränkt. Er hatte keine Rechte. Aber trotzdem kam das Zertifikat zurück.

Und nun zu einem speziell vorbereiteten Herd. Wir starten auf jedem Bild. Nehmen wir als Beispiel debian:jessie.

Wir haben so etwas:

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

Was ist Toleranz? Master in einem Kubernetes-Cluster werden normalerweise mit einem sogenannten „Taint“ gekennzeichnet. Und der Kern dieser „Infektion“ besteht darin, dass Pods nicht Masterknoten zugewiesen werden können. Aber niemand macht sich die Mühe, in irgendeiner Schote darauf hinzuweisen, dass sie gegenüber der „Infektion“ tolerant ist. Im Abschnitt „Toleranz“ heißt es lediglich, dass unser Pod gegenüber einer solchen Infektion tolerant ist, wenn NoSchedule auf einem Knoten installiert ist – und es keine Probleme gibt.

Weiter sagen wir, dass unsere Schote nicht nur tolerant ist, sondern den Meister auch gezielt angreifen will. Denn die Meister haben das Köstlichste, was wir brauchen – alle Zertifikate. Deshalb sagen wir „nodeSelector“ – und wir haben eine Standardbezeichnung auf den Mastern, die es Ihnen ermöglicht, aus allen Knoten des Clusters genau die Knoten auszuwählen, die Master sind.

Mit diesen beiden Abschnitten wird es definitiv zum Meister kommen. Und er wird dort leben dürfen.

Aber nur zum Meister zu kommen, reicht uns nicht. Es wird uns nichts bringen. Als nächstes haben wir diese beiden Dinge:

hostNetwork: true 
hostPID: true 

Wir geben an, dass unser Pod, den wir ausführen, im Kernel-Namespace, im Netzwerk-Namespace und im PID-Namespace leben wird. Sobald ein Pod auf dem Master ausgeführt wird, kann er alle echten Live-Schnittstellen dieses Knotens sehen, den gesamten Datenverkehr abhören und die PIDs aller Prozesse sehen.

Dann kommt es auf die kleinen Dinge an. Nehmen Sie etcd und lesen Sie, was Sie wollen.

Das Interessanteste ist diese Kubernetes-Funktion, die standardmäßig vorhanden ist.

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

Und das Wesentliche ist, dass wir in dem Pod, den wir starten, auch ohne Rechte für diesen Cluster sagen können, dass wir ein Volume vom Typ hostPath erstellen möchten. Nehmen Sie also den Pfad vom Host, auf dem wir starten werden – und nehmen Sie ihn als Volume. Und dann nennen wir es: Host. Wir mounten diesen gesamten HostPath im Pod. In diesem Beispiel in das Verzeichnis /host.

Ich werde es noch einmal wiederholen. Wir sagten dem Pod, er solle zum Master kommen, dort hostNetwork und hostPID abrufen – und das gesamte Stammverzeichnis des Masters in diesem Pod mounten.

Sie verstehen, dass in Debian Bash läuft und dieser Bash für uns als Root funktioniert. Das heißt, wir haben gerade den Root-Zugriff auf den Master erhalten, haben aber keinerlei Rechte im Kubernetes-Cluster.

Dann besteht die ganze Aufgabe darin, in das Verzeichnis /host/etc/kubernetes/pki zu gehen, wenn ich mich nicht irre, dort alle Master-Zertifikate des Clusters abzuholen und dementsprechend zum Cluster-Administrator zu werden.

So gesehen gehören dies zu den gefährlichsten Rechten in Pods, unabhängig davon, welche Rechte der Benutzer hat:
Wir schließen Lücken im Kubernetes-Cluster. Berichten und Transkription mit DevOpsConf

Wenn ich Rechte zum Ausführen eines Pods in einem Cluster-Namespace habe, verfügt dieser Pod standardmäßig über diese Rechte. Ich kann privilegierte Pods ausführen, was im Allgemeinen alle Rechte bedeutet, und praktisch einen Knoten rooten.

Mein Favorit ist der Root-Benutzer. Und Kubernetes verfügt über diese Option „Als Nicht-Root ausführen“. Dies ist eine Art Schutz gegen einen Hacker. Wissen Sie, was das „moldauische Virus“ ist? Wenn Sie plötzlich ein Hacker sind und zu meinem Kubernetes-Cluster kommen, dann fragen wir, arme Administratoren: „Bitte geben Sie in Ihren Pods an, mit denen Sie meinen Cluster hacken werden, und führen Sie ihn als Nicht-Root aus.“ Andernfalls stellt sich heraus, dass Sie den Prozess in Ihrem Pod unter der Wurzel starten, und es wird für Sie sehr einfach sein, mich zu hacken. Schützen Sie sich bitte.

Host-Pfadvolumen – meiner Meinung nach der schnellste Weg, um mit dem Kubernetes-Cluster das gewünschte Ergebnis zu erzielen.

Aber was tun mit all dem?

Gedanken, die jedem normalen Administrator kommen sollten, der Kubernetes kennenlernt: „Ja, ich habe Ihnen gesagt, Kubernetes funktioniert nicht. Es hat Löcher darin. Und der ganze Cube ist Schwachsinn.“ Tatsächlich gibt es so etwas wie Dokumentation, und wenn Sie dort nachsehen, dann gibt es einen Abschnitt Pod-Sicherheitsrichtlinie.

Das ist so ein Yaml-Objekt – wir können es im Kubernetes-Cluster erstellen – das die Sicherheitsaspekte in der Beschreibung der Pods steuert. Das heißt, es steuert tatsächlich die Rechte zur Verwendung aller Hostnetzwerke, HostPIDs und bestimmter Volume-Typen, die sich beim Start in den Pods befinden. Mit Hilfe der Pod Security Policy lässt sich all dies beschreiben.

Das Interessanteste an der Pod-Sicherheitsrichtlinie ist, dass im Kubernetes-Cluster alle PSP-Installationsprogramme nicht einfach in irgendeiner Weise beschrieben werden, sondern einfach standardmäßig deaktiviert sind. Die Pod-Sicherheitsrichtlinie wird mithilfe des Zulassungs-Plugins aktiviert.

Okay, stellen wir die Pod-Sicherheitsrichtlinie im Cluster bereit. Nehmen wir an, wir haben einige Service-Pods im Namespace, auf die nur Administratoren Zugriff haben. Nehmen wir an, im Übrigen haben Pods nur begrenzte Rechte. Denn höchstwahrscheinlich müssen Entwickler keine privilegierten Pods auf Ihrem Cluster ausführen.

Und es scheint uns gut zu gehen. Und unser Kubernetes-Cluster kann nicht in zwei Minuten gehackt werden.

Es gibt ein Problem. Wenn Sie über einen Kubernetes-Cluster verfügen, ist die Überwachung höchstwahrscheinlich in Ihrem Cluster installiert. Ich gehe sogar davon aus, dass Ihr Cluster, wenn er über eine Überwachung verfügt, Prometheus heißt.

Was ich Ihnen jetzt sagen werde, gilt sowohl für den Prometheus-Operator als auch für Prometheus in seiner reinen Form. Die Frage ist: Wenn ich nicht so schnell einen Administrator für den Cluster gewinnen kann, bedeutet das, dass ich mehr suchen muss. Und ich kann mithilfe Ihrer Überwachung suchen.

Wahrscheinlich hat jeder die gleichen Artikel über Habré gelesen, und die Überwachung befindet sich im Monitoring-Namespace. Das Helmdiagramm heißt für alle ungefähr gleich. Ich vermute, dass Sie, wenn Sie helm install Stable/Prometheus ausführen, ungefähr die gleichen Namen erhalten. Und selbst höchstwahrscheinlich muss ich den DNS-Namen in Ihrem Cluster nicht erraten. Weil es Standard ist.

Wir schließen Lücken im Kubernetes-Cluster. Berichten und Transkription mit DevOpsConf

Als nächstes haben wir bestimmte Entwickler, in denen Sie einen bestimmten Pod ausführen können. Und dann ist es von diesem Pod aus ganz einfach, Folgendes zu tun:

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

prometheus-kube-state-metrics ist einer der Prometheus-Exporteure, der Metriken von der Kubernetes-API selbst sammelt. Dort sind viele Daten vorhanden, was in Ihrem Cluster läuft, was es ist, welche Probleme Sie damit haben.

Als einfaches Beispiel:

kube_pod_container_info{namespace="kube-system",pod="kube-apiserver-k8s-1",container="kube-apiserver",image=

„gcr.io/google-containers/kube-apserver:v1.14.5“

,image_id=»docker-pullable://gcr.io/google-containers/kube- apiserver@sha256:e29561119a52adad9edc72bfe0e7fcab308501313b09bf99df4a96 38ee634989″,container_id=»docker://7cbe7b1fea33f811fdd8f7e0e079191110268f2 853397d7daf08e72c22d3cf8b»} 1

Durch eine einfache Curl-Anfrage von einem nicht privilegierten Pod aus können Sie Informationen wie diese erhalten. Wenn Sie nicht wissen, welche Version von Kubernetes Sie verwenden, können Sie es leicht herausfinden.

Und das Interessanteste ist, dass Sie nicht nur auf Kube-State-Metriken zugreifen, sondern auch direkt auf Prometheus selbst zugreifen können. Von dort aus können Sie Metriken sammeln. Von dort aus können Sie sogar Metriken erstellen. Selbst theoretisch können Sie eine solche Abfrage aus einem Cluster in Prometheus erstellen, wodurch sie einfach deaktiviert wird. Und Ihre Überwachung vom Cluster aus wird im Allgemeinen nicht mehr funktionieren.

Und hier stellt sich bereits die Frage, ob eine externe Überwachung Ihre Überwachung überwacht. Ich habe gerade die Gelegenheit bekommen, in einem Kubernetes-Cluster zu arbeiten, ohne dass dies für mich irgendwelche Konsequenzen hätte. Sie werden nicht einmal wissen, dass ich dort arbeite, da es keine Überwachung mehr gibt.

Genau wie bei der PSP scheint das Problem darin zu liegen, dass all diese ausgefallenen Technologien – Kubernetes, Prometheus – einfach nicht funktionieren und voller Lücken sind. Nicht wirklich.

Es gibt so etwas - Netzwerkpolitik.

Wenn Sie ein normaler Administrator sind, wissen Sie höchstwahrscheinlich über Netzwerkrichtlinien, dass es sich um ein weiteres Yaml handelt, von dem es bereits Dofiga im Cluster gibt. Und Netzwerkrichtlinien sind definitiv nicht erforderlich. Und selbst wenn Sie lesen, was eine Netzwerkrichtlinie ist, was eine Kubernetes-Yaml-Firewall ist, mit der Sie Zugriffsrechte zwischen Namespaces und Pods einschränken können, dann haben Sie definitiv entschieden, dass die Yaml-Firewall in Kubernetes auf den nächsten Abstraktionen basiert ... Nein-nein. Es ist definitiv nicht notwendig.

Auch wenn Ihren Sicherheitsspezialisten nicht gesagt wurde, dass Sie mit Hilfe Ihres Kubernetes eine sehr einfache und sehr detaillierte Firewall erstellen können. Wenn sie das noch nicht wissen und Sie nicht ziehen: „Nun, geben Sie es, geben Sie es ...“, dann benötigen Sie auf jeden Fall eine Netzwerkrichtlinie, um den Zugriff auf einige Servicestellen zu blockieren, die Sie aus Ihrem Cluster ziehen können ohne jegliche Genehmigung.

Wie in dem Beispiel, das ich gegeben habe, können Sie Kube-Statusmetriken aus jedem Namespace im Kubernetes-Cluster abrufen, ohne dafür Rechte zu haben. Netzwerkrichtlinien haben den Zugriff von allen anderen Namespaces auf den Monitoring-Namespace und sozusagen alles geschlossen: kein Zugriff, keine Probleme. In allen existierenden Diagrammen, sowohl im Standard-Prometheus als auch im Prometheus im Operator, gibt es in den Helmwerten einfach eine Option, um einfach Netzwerkrichtlinien für sie zu aktivieren. Sie müssen es nur einschalten und sie werden funktionieren.

Hier gibt es wirklich ein Problem. Als normaler, bärtiger Administrator haben Sie höchstwahrscheinlich entschieden, dass Netzwerkrichtlinien nicht erforderlich sind. Und nachdem Sie alle möglichen Artikel über Ressourcen wie Habr gelesen haben, haben Sie entschieden, dass Flanell, insbesondere im Host-Gateway-Modus, das Beste ist, was Sie wählen können.

Was zu tun ist?

Sie können versuchen, die Netzwerklösung, die Sie in Ihrem Kubernetes-Cluster haben, erneut bereitzustellen und sie durch etwas Funktionelleres zu ersetzen. Zum Beispiel auf demselben Calico. Aber ich möchte gleich sagen, dass die Aufgabe, die Netzwerklösung im funktionierenden Kubernetes-Cluster zu ändern, keineswegs trivial ist. Ich habe es zweimal gelöst (beide Male allerdings theoretisch), aber wir haben sogar bei Slurms gezeigt, wie es geht. Für unsere Studierenden zeigten wir, wie man die Netzwerklösung in einem Kubernetes-Cluster ändert. Grundsätzlich können Sie versuchen sicherzustellen, dass es auf dem Produktionscluster zu keinen Ausfallzeiten kommt. Aber es wird Ihnen wahrscheinlich nicht gelingen.

Und das Problem ist eigentlich ganz einfach gelöst. Es gibt Zertifikate im Cluster und Sie wissen, dass Ihre Zertifikate in einem Jahr ungültig werden. Nun, und normalerweise eine normale Lösung mit Zertifikaten im Cluster - warum nehmen wir ein Dampfbad, wir werden einen neuen Cluster daneben errichten, ihn im alten verrotten lassen und alles neu verteilen. Wenn es verrottet, liegt zwar alles einen Tag lang da, aber dann entsteht ein neuer Cluster.

Wenn Sie einen neuen Cluster aufziehen, legen Sie gleichzeitig Kaliko anstelle von Flanell ein.

Was ist zu tun, wenn Ihre Zertifikate seit hundert Jahren ausgestellt sind und Sie den Cluster nicht erneut bereitstellen möchten? Es gibt so einen Kube-RBAC-Proxy. Dies ist eine sehr coole Entwicklung, die es Ihnen ermöglicht, sich als Sidecar-Container in jeden Pod in einem Kubernetes-Cluster einzubetten. Und es fügt diesem Pod tatsächlich eine Autorisierung durch den RBAC von Kubernetes selbst hinzu.

Es gibt ein Problem. Zuvor war diese Kube-RBAC-Proxy-Lösung in Prometheus des Betreibers integriert. Aber dann war er weg. Heutzutage verlassen sich moderne Versionen darauf, dass Sie über Netzwerkrichtlinien verfügen und schließen diese damit ab. Und deshalb muss man das Diagramm etwas umschreiben. In der Tat, wenn Sie dorthin gehen dieses RepositoryEs gibt Beispiele für die Verwendung als Beiwagen, und die Diagramme müssen minimal umgeschrieben werden.

Es gibt noch ein kleines Problem. Nicht nur Prometheus gibt seine Messwerte an jedermann preis. In unserem Fall sind auch alle Komponenten des Kubernetes-Clusters in der Lage, ihre Metriken anzugeben.

Aber wie gesagt: Wenn Sie nicht auf den Cluster zugreifen und keine Informationen sammeln können, können Sie zumindest Schaden anrichten.

Deshalb zeige ich Ihnen schnell zwei Möglichkeiten, wie ein Kubernetes-Cluster krank werden kann.

Sie werden lachen, wenn ich Ihnen sage, dass dies zwei Fälle aus dem wirklichen Leben sind.

Methode eins. Ressourcenerschöpfung.

Wir bringen einen weiteren speziellen Pod auf den Markt. Es wird diesen Abschnitt geben.

resources: 
    requests: 
        cpu: 4 
        memory: 4Gi 

Wie Sie wissen, handelt es sich bei Anfragen um die Menge an CPU und Speicher, die auf dem Host für bestimmte Anfrage-Pods reserviert ist. Wenn wir im Kubernetes-Cluster einen Vier-Kern-Host haben und dort vier CPU-Pods mit Anfragen ankommen, dann können keine weiteren Pods mit Anfragen an diesen Host kommen.

Wenn ich einen solchen Pod betreibe, gebe ich den Befehl aus:

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

Dann kann niemand anderes im Kubernetes-Cluster bereitstellen. Weil allen Knoten die Anfragen ausgehen werden. Und deshalb werde ich Ihren Kubernetes-Cluster stoppen. Wenn ich das abends mache, können die Einsätze für längere Zeit gestoppt werden.

Wenn wir uns die Kubernetes-Dokumentation noch einmal ansehen, werden wir so etwas namens Limit Range sehen. Es legt die Ressourcen für die Clusterobjekte fest. Sie können ein Limit Range-Objekt in Yaml schreiben, es auf bestimmte Namespaces anwenden – und weiter in diesem Namespace können Sie sagen, dass Sie über Ressourcen für Standard-, Maximum- und Minimum-Pods verfügen.

Mit Hilfe einer solchen Sache können wir Benutzern in bestimmten Teamprodukt-Namespaces die Möglichkeit verwehren, auf ihren Pods alle möglichen unangenehmen Dinge anzuzeigen. Aber selbst wenn Sie dem Benutzer sagen, dass Sie keine Pods mit Anforderungen für mehr als eine CPU ausführen können, gibt es leider einen wunderbaren Skalierungsbefehl, oder über das Dashboard können sie skalieren.

Und hier kommt Nummer zwei ins Spiel. Führen Sie 11 111 111 111 111 Pods aus. Es sind elf Milliarden. Das liegt nicht daran, dass ich mir eine solche Zahl ausgedacht habe, sondern daran, dass ich sie selbst gesehen habe.

Wahre Begebenheit. Am späten Abend wollte ich gerade das Büro verlassen. Ich schaue, eine Gruppe Entwickler sitzt in der Ecke und treibt hektisch etwas mit Laptops. Ich gehe auf die Jungs zu und frage: „Was ist mit dir passiert?“

Etwas früher, um neun Uhr abends, ging einer der Entwickler nach Hause. Und ich habe beschlossen: „Jetzt werde ich meine Bewerbung auf eins skalieren.“ Ich drückte eins und das Internet wurde etwas langweilig. Er drückte erneut die Eins, er drückte die Eins und drückte die Eingabetaste. Er stocherte, was er konnte. Dann erwachte das Internet zum Leben – und alles begann bis heute zu wachsen.

Diese Geschichte fand zwar nicht auf Kubernetes statt, damals war es Nomad. Es endete damit, dass Nomad nach einer Stunde unserer Versuche, Nomad von seinen hartnäckigen Skalierungsversuchen abzuhalten, antwortete, dass er mit der Skalierung nicht aufhören und nichts anderes tun würde. „Ich bin müde, ich gehe.“ Und drehte sich um.

Ich habe natürlich versucht, dasselbe auf Kubernetes zu tun. Elf Milliarden Pods gefielen Kubernetes nicht, er sagte: „Das kann ich nicht.“ Überschreitet interne Obergrenzen. Aber 1 Schoten könnten es.

Als Reaktion auf eine Milliarde zog sich der Würfel nicht in sich selbst zurück. Er begann wirklich zu skalieren. Je weiter der Prozess ging, desto länger dauerte es, neue Pods zu erstellen. Aber der Prozess ging trotzdem weiter. Das einzige Problem besteht darin, dass ich, wenn ich Pods in meinem Namespace unbegrenzt ausführen kann, auch ohne Anfragen und Einschränkungen mit einigen Aufgaben eine solche Anzahl von Pods ausführen kann, dass sich die Knoten mithilfe dieser Aufgaben aus dem Speicher summieren. auf der CPU. Wenn ich so viele Pods betreibe, müssen die Informationen von ihnen in den Speicher gelangen, also in etcd. Und wenn zu viele Informationen eingehen, gibt der Speicher zu langsam nach – und Kubernetes wird stumpf.

Und noch ein Problem ... Wie Sie wissen, sind Kubernetes-Kontrollen keine zentrale Sache, sondern mehrere Komponenten. Dort gibt es insbesondere einen Controller-Manager, einen Scheduler usw. Alle diese Leute werden gleichzeitig anfangen, unnötige dumme Arbeit zu leisten, was mit der Zeit immer mehr Zeit in Anspruch nehmen wird. Der Controller-Manager erstellt neue Pods. Der Scheduler wird versuchen, einen neuen Knoten für sie zu finden. Neue Knoten in Ihrem Cluster werden höchstwahrscheinlich bald erschöpft sein. Der Kubernetes-Cluster wird immer langsamer laufen.

Aber ich beschloss, noch weiter zu gehen. Wie Sie wissen, gibt es bei Kubernetes einen sogenannten Dienst. Nun, in Ihren Clustern funktioniert der Dienst höchstwahrscheinlich standardmäßig mit IP-Tabellen.

Wenn Sie beispielsweise eine Milliarde Pods ausführen und dann Kubernetis mithilfe eines Skripts dazu zwingen, neue Dienste 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 ungefähr gleichzeitig immer mehr neue iptables-Regeln generiert. Darüber hinaus werden für jeden Dienst eine Milliarde iptables-Regeln generiert.

Ich habe das Ganze an mehreren Tausend, bis zu einem Dutzend, überprüft. Und das Problem ist, dass es bereits bei diesem Schwellenwert ziemlich problematisch ist, SSH zum Knoten zu machen. Weil sich Pakete, die so viele Ketten durchlaufen, langsam nicht mehr so ​​gut anfühlen.

Und auch das alles wird mit Hilfe von Kubernetes gelöst. Es gibt ein solches Objektressourcenkontingent. Legt die Anzahl der verfügbaren Ressourcen und Objekte für den Namespace im Cluster fest. Wir können in jedem Kubernetes-Cluster-Namespace ein Yaml-Objekt erstellen. Mit Hilfe dieses Objekts können wir sagen, dass wir eine bestimmte Anzahl von Anfragen und Limits für diesen Namespace zugewiesen haben, und darüber hinaus können wir sagen, dass es möglich ist, 10 Dienste und 10 Pods in diesem Namespace zu erstellen. Und ein einzelner Entwickler kann sich abends sogar selbst vernichten. Kubernetes wird ihm sagen: „Sie können Ihre Pods nicht auf eine solche Menge skalieren, weil es das Ressourcenkontingent überschreitet.“ Das war's, Problem gelöst. Dokumentation hier.

In diesem Zusammenhang ergibt sich ein Problem. Sie spüren, wie schwierig es wird, in Kubernetes einen Namespace zu erstellen. Um es zu erstellen, müssen wir eine Reihe von Dingen berücksichtigen.

Ressourcenkontingent + Grenzbereich + RBAC
• Erstellen Sie einen Namensraum
• Innerhalb des Grenzbereichs erstellen
• Innerhalb einer Ressourcenquote erstellen
• Erstellen Sie ein Dienstkonto für CI
• Erstellen Sie eine Rollenbindung für CI und Benutzer
• Starten Sie optional die erforderlichen Service-Pods

Daher möchte ich diese Gelegenheit nutzen und meine Entwicklungen mit Ihnen teilen. Es gibt so etwas namens SDK-Operator. Auf diese Weise werden im Kubernetes-Cluster Anweisungen dafür geschrieben. Sie können Anweisungen mit Ansible schreiben.

Zuerst haben wir in Ansible geschrieben, und dann habe ich mir angeschaut, was der SDK-Operator ist, und die Ansible-Rolle in einen Operator umgeschrieben. Mit dieser Anweisung können Sie ein Objekt im Kubernetes-Cluster erstellen, das als Befehl bezeichnet wird. Innerhalb des Befehls können Sie die Umgebung für diesen Befehl in Yaml beschreiben. Und innerhalb der Teamumgebung können wir damit beschreiben, dass wir so viele Ressourcen zuweisen.

Wenig Moderator dieses komplexen Prozesses.

Und zum Schluss. Was tun mit all dem?
Erste. Die Pod-Sicherheitsrichtlinie ist gut. Und obwohl sie bis heute von keinem der Kubernetes-Installer verwendet werden, müssen Sie sie dennoch in Ihren Clustern verwenden.

Bei der Netzwerkrichtlinie handelt es sich nicht um eine weitere unnötige Funktion. Das ist es, was im Cluster wirklich benötigt wird.

LimitRange / ResourceQuota – es ist Zeit zu verwenden. Wir haben schon vor langer Zeit damit begonnen, es zu nutzen, und ich war mir lange sicher, dass ausnahmslos jeder es nutzt. Es stellte sich heraus, dass dies selten vorkommt.

Zusätzlich zu dem, was ich im Bericht erwähnt habe, gibt es undokumentierte Funktionen, die es Ihnen ermöglichen, den Cluster anzugreifen. Kürzlich veröffentlicht große Kubernetes-Schwachstellenanalyse.

Manche Dinge sind so traurig und verletzend. Beispielsweise können Cubelets in einem Kubernetes-Cluster unter bestimmten Bedingungen den Inhalt des Warlocks-Verzeichnisses an einen nicht autorisierten Benutzer weitergeben.

Hier Es gibt Anweisungen, wie man alles, was ich gesagt habe, reproduzieren kann. Es gibt Dateien mit Produktionsbeispielen, wie ResourceQuota und Pod Security Policy aussehen. Und das alles ist zum Anfassen.

Ich danke Ihnen allen.

Source: habr.com

Kommentar hinzufügen