Von SSH zu REST: Die sicherheitsgetriebene Modernisierung von Slacks EMR-Datenpipelines
(slack.engineering)- Auf Slacks Datenplattform betreiben mehr als 700 SSH-basierte Operatoren zentrale Datenpipelines wie tägliche Suchindexierung und Analyse-Workloads; für alle Jobs war ein direkter SSH-Zugriff auf produktive AWS-EMR-Cluster erforderlich, was eine große Angriffsfläche schuf
- Diese SSH-Abhängigkeit war nicht nur ein Sicherheitsrisiko, sondern auch ein zentrales Hindernis für die Infrastrukturmodernisierung, darunter Spark on Kubernetes, der Wechsel zu EMR on EKS und der Abschluss der Whitecastle-Initiative
- Als Lösung nutzte Slack die YARN Distributed Shell, um selbst beliebige Shell-Befehle in YARN-Containern ausführen zu können, und bündelte alle Job-Submissions über das eigene REST-Gateway Quarry
- Mehr als 700 Jobs wurden ohne Downtime über 8 Datenregionen hinweg migriert, die vollständige Abschaffung von SSH wurde in drei Quartalen erreicht
- Das Ergebnis: kleinere Angriffsfläche, höhere Job-Zuverlässigkeit, bessere Sichtbarkeit sowie die Grundlage für den Abschluss von Whitecastle und die nächste Infrastruktur-Generation wie Spark on Kubernetes
Hintergrund: Entstehung einer SSH-basierten Datenplattform
- Die um 2017 aufgebaute Slack-Datenplattform entschied sich für SSH als direktesten Weg, damit Airflow Jobs auf EMR-Clustern ausführen konnte
- Verbindung zum EMR-Master-Node per
SSHOperator, anschließend Ausführung von Befehlen wiespark-submit
- Verbindung zum EMR-Master-Node per
- Danach entwickelten Teams für verschiedene Einsatzzwecke (nicht nur Spark, sondern auch MapReduce, AWS CLI und benutzerdefinierte Python-Skripte) eigene maßgeschneiderte SSH-basierte Operatoren
- Das Ergebnis war eine Ansammlung von mehr als 700 SSH-basierten Jobs in der Produktion
Die tatsächlichen Kosten des SSH-Ansatzes
-
Potenzielle Sicherheitsrisiken
- Direkter SSH-Zugriff auf Compute-Cluster vergrößerte die Angriffsfläche
- Verteilung und Rotation von Schlüsseln über Orchestrierungs-Worker hinweg erhöhten den operativen Aufwand
- Für granulare Audits war eine Korrelation von Logs aus mehreren Systemen nötig
- Zugriffssteuerung wurde durch dedizierte Security Groups und benutzerdefinierte Konfigurationen komplexer
-
Operative Probleme
- Jobs wurden nicht verteilt, sondern direkt auf dem EMR-Master-Node ausgeführt, was zu Ressourcenkonkurrenz führte
- Bei Neustarts von Kubernetes-Pods brachen SSH-Verbindungen ab und Jobs scheiterten
- Lang laufende Jobs liefen nach Verbindungsabbrüchen weiter und wurden zu Zombie-Prozessen
- Bei Verbindungsabbrüchen ließ sich nicht zuverlässig feststellen, ob ein Job erfolgreich oder fehlgeschlagen war
-
Blocker für die Modernisierung
- Kein Einstieg in Spark on Kubernetes und EMR on EKS (zuerst musste die SSH-Abhängigkeit entfernt werden)
- Der letzte EMR-Cluster im Hauptkonto konnte nicht in ein Child-Account verschoben werden, wodurch die Whitecastle-Initiative unvollständig blieb
- Whitecastle ist Slacks Initiative, AWS-Infrastruktur in Child-Accounts zu verlagern, um Sicherheit und Netzwerkisolation zu verbessern
- Eine angemessene Job-Überwachung und Sichtbarkeit ließ sich nicht umsetzen
-
Beispiel aus der Praxis — das Search-Infrastructure-Team
- Eine Pipeline zum Erstellen täglicher Solr-Suchindizes aus Daten im Terabyte-Bereich, zentral für Slacks Suchfunktion
- Aufgrund der SSH-basierten Job-Submissions war sie allen oben genannten Zuverlässigkeitsproblemen ausgesetzt
Grundidee von REST-basierter Job-Submission
-
Die grundlegenden Grenzen von SSH
- SSH-Verbindungen sind zustandsbehaftete Direktverbindungen; wenn sie etwa durch einen Pod-Neustart abbrechen, laufen Befehle weiter, schlagen fehl oder hinterlassen verwaiste Prozesse
- Es gibt kein verlässliches Mittel, sich erneut zu verbinden und den Status zu prüfen
-
Die REST-Alternative
- Moderne Compute-Engines wie YARN, Trino und Snowflake unterstützen Job-Submission per HTTP API
- POST einer Job-Anfrage → Rückgabe einer Job-ID
- GET des Job-Status → Prüfung auf laufend/abgeschlossen/fehlgeschlagen
- DELETE eines Jobs → sauberes Abbrechen
- Der Job-Lebenszyklus wird serverseitig verwaltet; auch wenn der Client neu startet, läuft der Job weiter und sein Status bleibt abrufbar
- Moderne Compute-Engines wie YARN, Trino und Snowflake unterstützen Job-Submission per HTTP API
-
Rolle und Grenzen von YARN
- Für Hadoop-Workloads (MapReduce, Spark, Hive) ist YARN Ressourcenmanager und stellt zugleich eine REST API bereit
- Für mehr als 300 CLI-basierte Jobs, die beliebige Shell-Befehle wie
aws s3 syncoderhadoop distcpausführen, gab es jedoch keine sofort nutzbare REST API - Der Schlüssel zur Lösung war die YARN Distributed Shell
Der Durchbruch: YARN Distributed Shell
- Für Spark existiert die Livy-REST-API, für Hive HiveServer2, daher war die Migration dort relativ einfach
- Dagegen waren MapReduce-Jobs und mehr als 300 CLI-basierte Jobs schwierig, weil keine direkt nutzbare REST API vorhanden war
-
Anforderungen
- Eine einfache REST-basierte Lösung, die natürlich zur Architektur passt
- Nutzung bestehender Authentifizierungs- und Autorisierungsmechanismen (keine eigene Sicherheitsschicht nötig)
- Einsatz eines Open-Source-Protokolls (Standard-YARN-API) statt einer proprietären Lösung
- Minimale Komplexität, um Aufbau und Betrieb einer eigenen Job-Ausführungsinfrastruktur zu vermeiden
-
Geprüfte und verworfene Ansätze
- Aufbau eines eigenen Wrapper-Service für Remote-Befehlsausführung
- Einsatz von Remote-Execution-Frameworks wie Ansible oder Salt
- Einen neuen Job-Typ in YARN von Grund auf ergänzen
- Alle Optionen erwiesen sich wegen übermäßiger Komplexität, eigener Sicherheitslogik und neuer Abhängigkeiten als ungeeignet
-
Entdeckung der YARN Distributed Shell
- Mit
org.apache.hadoop.yarn.applications.distributedshell.ApplicationMasterlassen sich beliebige Shell-Skripte in YARN-Containern ausführen - Diese Funktion ist bereits in YARN enthalten, nutzt dieselbe REST API und erfordert keine eigene Sicherheitsschicht
- Mit
-
Funktionsweise
- 1. Kommando-Skript nach S3 hochladen (z. B.
aws s3 sync /tmp/data/ s3://bucket/output/) - 2. Mit Distributed-Shell-Konfiguration an YARN übergeben
application-typewird aufMAPREDUCEgesetzt; inam-container-specstehen Umgebungsvariablen wieDISTRIBUTEDSHELLSCRIPTLOCATION,DISTRIBUTEDSHELLSCRIPTLENundDISTRIBUTEDSHELLSCRIPTTIMESTAMP
- 3. YARN weist einen Container zu, lädt das Skript herunter und führt es aus
- YARN verwaltet Ressourcenlimits wie Speicher und vCores, Container-Isolation, Retries und Fehlertoleranz, sauberes Abbrechen sowie Logging über die YARN-UI
- 1. Kommando-Skript nach S3 hochladen (z. B.
- Durch diese Entscheidung konnten nicht nur Hadoop-Workloads, sondern auch
aws s3 sync,hadoop distcpund benutzerdefinierte Python-Skripte vollständig in YARN-Containern ausgeführt werden
Die Lösung: Quarry
- Quarry ist Slacks REST-basiertes Gateway für Job-Submission, das Jobs an mehrere Compute-Engines wie EMR/YARN, Trino und Snowflake sendet
- Es hatte bereits Authentifizierung, Zuverlässigkeit und Sichtbarkeit gelöst und passte damit genau zur Abschaffung von SSH
-
Funktionen von Quarry
- Authentifizierung: Service-zu-Service-Tokens statt SSH-Schlüsseln
- Job-Submission: Versand an YARN, Trino und Snowflake per REST API
- Statusverfolgung: serverseitiges Monitoring des Job-Status
- Lebenszyklusverwaltung: sauberes Abbrechen und Aufräumen über die REST API
- Sichtbarkeit: strukturierte Logs, Metriken und Tracing für alle Job-Submissions
-
Architekturänderung
- Vorher:
Airflow → SSH Connection → EMR Master Node → Execute Command - Nachher:
Airflow → Quarry REST API → YARN ResourceManager → EMR Container - Airflow-Operatoren senden statt einer SSH-Verbindung HTTP-Anfragen an Quarry; Quarry submitttet an YARN und pollt den Status
- Auch bei Neustarts von Airflow-Pods bleiben Jobs bestehen, da Quarry die Verbindung serverseitig verwaltet
- Vorher:
-
Stärken von Quarry
- Durch die Unterstützung der YARN Distributed Shell wurde es zu einem universellen Gateway für Job-Submission
- Spark-Jobs, Hive-Abfragen und Shell-Skripte laufen alle über dieselbe REST API
- SSH-Credentials und direkter Cluster-Zugriff entfallen vollständig; verwendet werden nur REST-Aufrufe mit Authentifizierung und serverseitigem Job-Tracking
Der Weg der Migration
- Bei mehr als 700 Produktionsjobs über 8 unabhängige Datenregionen hinweg, jeweils mit unterschiedlichen Netzwerkkonfigurationen und Anforderungen an Datensouveränität sowie unterbrechungsfreien kritischen Workloads wie der Suchindexierung, war ein systematischer Plan nötig
-
Schrittweiser Ansatz
- Phase 1 – Proof of Concept (PoC): Validierung des Quarry-Ansatzes mit Pilotjobs, Entwicklung des ersten Quarry-Operators und Tests in der Dev-Umgebung
- Phase 2 – Sicherheitsprüfung: Zusammenarbeit mit dem Security-Team, um einen Plan zur Entfernung von Credentials zu erstellen und zu validieren, dass der REST-basierte Ansatz die Sicherheitsanforderungen erfüllt
- Phase 3 – OKR-getriebene Umsetzung: Als Key Result definiert, um Management-Sichtbarkeit zu schaffen; in dieser Phase wurde der 80-%-Migrationsmeilenstein erreicht
- Phase 4 – Massenmigration: Mehrere Teams wie Search Infrastructure, Data Engineering & Analytics und ML Services migrierten die verbleibenden Workloads parallel über alle Regionen
- Phase 5 – Abschlussarbeiten: Abschluss fehlender DAGs, Stilllegung aller Legacy-SSH-Operatoren und Erreichen von 100 %
-
Migrationszahlen
- Mehr als 700 Jobs über 7 Operator-Typen hinweg migriert
- Einführung in 8 unabhängigen Datenregionen mit koordiniertem Rollout
- 5 Teams wechselten auf die neuen Operatoren
- Keine Unterbrechung geschäftskritischer Services
- Vom ersten Pilot bis zur vollständigen SSH-Abschaffung in drei Quartalen abgeschlossen
Herausforderungen während der Migration
-
Challenge 1 — Ausfälle durch Virtual Memory Check
- Bei der Migration eines Datenexport-DAGs schlug ein Job, der unter SSH problemlos lief, plötzlich wegen eines vmem-Check-Fehlers fehl
- Ursache: Unter SSH lief der Job direkt auf dem Master-Node und umging damit die Ressourcenlimits von YARN; Quarry submitttet den Job korrekt an YARN, wodurch Container verworfen werden, die das virtuelle Speicherlimit überschreiten
- Lösung: Deaktivierung des vmem-Checks clusterweit gemäß AWS-Best Practices —
"yarn.nodemanager.vmem-check-enabled": "false"- Das entspricht der AWS-Empfehlung, da Linux-Virtual-Memory-Accounting unzuverlässig ist und physische Speicherlimits ausreichen
- Lehre: SSH hatte viele Probleme verdeckt; beim Wechsel zu korrekter YARN-Submission muss man mit bislang unsichtbaren Ressourcenlimit-Problemen rechnen und gründlich in Dev testen
-
Challenge 2 — Netzwerkisolation und EKM-Konnektivität
- Als ein Dev-Search-Infrastructure-Job von einem Dev-Cluster auf einen Staging-Analytics-Cluster migriert wurde, kam es zu Timeouts bei der EKM- (Enterprise Key Management) Verbindung
- Fehler:
Unable to execute HTTP request: Connect to sts.amazonaws.com:443 failed: connect timed out - Ursache: Der ursprüngliche Cluster hatte Netzwerk-Routing zum Key-Management-Endpunkt; der stärker segmentierte Staging-Analytics-Cluster hatte diese Konnektivität nicht, wodurch eine in der Job-Konfiguration nicht sichtbare Abhängigkeit von der Netzwerktopologie offengelegt wurde
- Lösung: Verlagerung der Search-Infrastructure-Workloads auf einen Dev-ETL-Cluster mit Routing zu Dev-Services; Jobs, die den produktiven Hive-Katalog benötigten, blieben in Staging; zusätzlich wurde der Dev-ETL-Cluster skaliert, um die zusätzliche Last aufzunehmen
- Lehre: Netzwerktopologie ist entscheidend; vor der Entscheidung, welcher Job auf welchem Cluster läuft, müssen Netzwerksegmentierung und Account-Grenzen verstanden werden
-
Challenge 3 — Komplexität durch mehrere Regionen
- Wegen Anforderungen an Datensouveränität liefen EMR-Cluster in 8 unabhängigen Datenregionen; die Abschaffung von SSH war damit faktisch 8 parallele Migrationen
-
Komplexitätsfaktoren
- Konfigurationsmanagement: Regionale Quarry-Konfigurationen, Cluster-Endpunkte und Regeln für Netzwerk-Routing waren nötig
- Testaufwand: Jede Codeänderung musste in allen 8 Regionen validiert werden
- Sequenzielle Ausrollung: Keine gleichzeitige Auslieferung möglich, sondern schrittweise pro Region
- Regionalspezifische Probleme: Unterschiede bei Netzwerkkonfigurationen, Datensouveränitätsregeln und Cluster-Versionen
-
Vorgehensweise
- Validierung in einer einzelnen Pilotregion (meist in den USA)
- Dokumentation regionsspezifischer Konfigurationsanforderungen
- Aufbau eines regionsbewussten Quarry-Operators
- Schrittweiser Rollout mit Übernahme der Lernpunkte pro Region
- Getrennte Nachverfolgung des Migrationsfortschritts je Region
- Lehre: Multi-Region-Infrastruktur ist nicht einfach nur N-mal größer, sondern durch regionsspezifische Ausfallmodi N-mal schwieriger; für regionenübergreifende Koordination und Debugging pro Region muss ausreichend Zeit eingeplant werden
Ergebnisse
- 100 % SSH-Abschaffung erreicht; alle Produktionsjobs wurden auf REST-basierte Submission über Quarry umgestellt
-
Sicherheitsergebnisse
- SSH-Zugriff auf produktive EMR-Cluster wurde in allen 8 unabhängigen Datenregionen entfernt, wodurch die Angriffsfläche deutlich schrumpfte
- Die Verteilung von SSH-Schlüsseln wurde durch Service-zu-Service-Token-Authentifizierung ersetzt, und REST-API-Logging ermöglichte ordnungsgemäße Audit-Trails
- Alle Job-Submissions verfügen über strukturierte Logs über Quarry
- Der letzte EMR-Cluster im AWS-Hauptkonto wurde in ein Child-Account verschoben, womit die Whitecastle-Initiative abgeschlossen wurde
- Der Wegfall spezieller Security Groups und komplexer Berechtigungsverwaltung vereinfachte Compliance
-
Operative Verbesserungen
- Ressourcenwettbewerb auf dem Master-Node entfiel; alle Nicht-Hadoop-Jobs laufen nun in verteilten YARN-Containern mit passender Ressourcenzuteilung
- Jobs überstehen Neustarts von Client-Kubernetes-Pods, was die Zuverlässigkeit deutlich erhöht; Zombie-Prozesse verschwanden, sauberes Beenden ist über die REST API möglich
- Die Quarry-API liefert strukturierte Job-Statusdaten, Logs und Metriken, sodass der gesamte Lebenszyklus verfolgt und mit YARN-Container-Logs gezielt debuggt werden kann
-
Grundlage für die Zukunft
- Durch das Ende der SSH-Abhängigkeit wurde die Migration zu Spark on Kubernetes möglich
- Die REST-basierte Architektur ist mit Cloud-Native-Praktiken kompatibel
- Gegenüber komplexen SSH-Setups ist der Quarry-Operator einfacher und leichter zu warten, was das Onboarding von Teams erleichtert
- Airflow wurde von den Details der EMR-Infrastruktur entkoppelt
- Alle Job-Submissions wurden auf Quarry standardisiert, was künftige Änderungen vereinfacht
- Zwei Jahre produktiver Betrieb nach Abschluss bestätigten die Architekturentscheidung: Sicherheit, operative Stabilität und Infrastrukturflexibilität wurden gleichermaßen verbessert
Gewonnene Erkenntnisse
-
Was gut funktioniert hat
- Schrittweise Migration: Sequenzieller Rollout von Dev → GovDev/CommDev → Prod sowie die Migration nach Operator-Typen ermöglichten Lernen in Etappen
- Starke Team-Zusammenarbeit: Bereichsübergreifende Kooperation zwischen Search, Analytics, Data Engineering, ML und Marketing mit schnellen Code-Reviews und Kommunikation über gemeinsame Kanäle
- Analysegestützte Fortschrittsverfolgung: Aufbau eines Dashboards zum Migrationsfortschritt über alle Regionen sowie Identifikation verbleibender SSH-basierter Aufgaben per Airflow-Datenbankabfragen
-
Was man beim nächsten Mal anders machen würde
- Netzwerktopologie früher erfassen: Probleme mit Netzwerkisolation wie bei der EKM-Konnektivität wurden erst spät entdeckt; Account-Grenzen und Netzwerk-Routing im Rahmen von Whitecastle sollten vor der Clustermigration dokumentiert werden
- Tests auf Ressourcenlimits früher durchführen: Das vmem-Check-Problem trat spät auf; bereits in der Pilotphase sollten YARN-Ressourcenlimit-Tests im Vergleich zu SSH enthalten sein
- Frühzeitigere Kommunikation über Operator-Einschränkungen: Als in der Endphase die Nutzung neuer
SSHOperator-Jobs eingeschränkt wurde, bemerkten einige Teams das nicht; eine breitere Vorabinformation an alle Airflow-Nutzer wäre nötig gewesen
-
Best Practices für Migrationen in großem Maßstab
- Monitoring vor der Migration aufbauen: Frühzeitig ein Dashboard bereitstellen, um verbleibende Arbeiten jederzeit sichtbar zu haben, und Airflow-DB-Abfragen nutzen
- Tests in mehreren Umgebungen: In Dev, CommDev und GovDev testen, um umgebungsspezifische Probleme vor der Produktion zu erkennen, besonders durch Tests über Account-Grenzen hinweg zur frühzeitigen Erkennung von Netzwerkisolationsproblemen
- Schrittweise Abschaffung von Operatoren: Operatoren wie CrunchExecOperator und S3SyncOperator einen nach dem anderen stilllegen; jede Phase als eigenes Mini-Projekt mit Tests und Validierung behandeln — langsamer, aber deutlich risikoärmer
Noch keine Kommentare.