Policy-Risiken verstehen. Fragen zu Policies in natürlicher Sprache stellen. Demo anfragen →

Published:

Fortgeschrittene Techniken zum Schutz von AWS ExternalID und kontenübergreifendem AssumeRole-Zugriff

by FireMon

Im vergangenen Monat hat Kesten Broughton von Praetorian Security eine umfangreiche Untersuchung zu Cloud-Sicherheitsprodukten von Drittanbietern veröffentlicht, die Amazons bevorzugte Technik für kontenübergreifende Verbindungen nutzen – AWS IAM Assume Role Vulnerabilities Found in Many Top Vendors. Der einleitende Absatz bietet einen fundierten Überblick über die Untersuchung:

In diesem ersten Blogbeitrag unserer Serie zu Cross-Account-Trust stellen wir die Ergebnisse aus 90 Anbietern vor: 37 % hatten die ExternalId nicht korrekt implementiert, um sich gegen Confused-Deputy-Angriffe zu schützen. Weitere 15 % der Anbieter hatten die AWS-Kontointegration in der Benutzeroberfläche korrekt umgesetzt, validierten den Parameter ExternalId jedoch nicht ordnungsgemäß im Backend, wodurch auch diese Seiten angreifbar waren. Abschließend erörtern wir die neuen Angriffsflächen, die durch den AWS Cross-Account-Assume-Role-Trust entstehen. Wir kommen zu dem Schluss, dass Anbieter und Kunden kritisch prüfen sollten, ob Role Trust der beste Vertrauensmechanismus für ihre mandantenfähige SaaS-Lösung ist.

Meine erste Reaktion beim Lesen der Untersuchung war: „Warum sollte jemand eine derart schlechte Entscheidung treffen?“ Tatsächlich ist jedoch das gesamte Konzept eines „Cloud-Sicherheitsexperten“ relativ neu, und obwohl AWS das Confused-Deputy-Problem durchaus angemessen behandelt, werden einige praktische Umsetzungsfragen nicht abgedeckt, an die man erst denkt, wenn das eigene Produkt mit dem Kunden in Kontakt kommt. Kontenübergreifende Verbindungen über AssumeRole lassen sich technisch unkompliziert lösen, doch ohne sauberes Threat Modeling sind die in Kestens Untersuchung dokumentierten Fehler außerordentlich leicht zu machen.

Wir bei DisruptOps haben auf Basis unseres anfänglichen Threat Modeling frühzeitig kluge Entscheidungen getroffen, die uns geschützt haben. Dennoch haben wir der Untersuchung einige Hinweise entnommen und härten unsere Umgebung weiter ab. Darüber hinaus arbeiten wir an einem Skunkworks-Projekt, das einen großen Teil des Problems ohnehin beseitigt und Automatisierung im großen Maßstab ermöglicht, ohne direkten Schreibzugriff auf Kundenumgebungen zu erfordern.

In einem wesentlichen Punkt widerspreche ich dem Beitrag allerdings. Ich ziehe automatisch rotierte Anmeldedaten jederzeit der Empfehlung vor, statische Anmeldedaten mit Vaulting einzusetzen. Für andere Cloud-Anbieter müssen wir sie weiterhin verwenden und suchen fortlaufend nach Wegen, statische Anmeldedaten NIRGENDWO in unserer Umgebung zu haben.

Das Problem

Zahlreiche unterschiedliche Anwendungstypen müssen sich heute direkt mit Cloud-APIs verbinden. Das kann so einfach sein wie der Zugriff auf einen S3-Bucket oder so komplex wie eine vollständig automatisierte Cloud-Detection-and-Response-Plattform (nur so als zufälliges Beispiel). Diese Anfragen erfordern Anmeldedaten in irgendeiner Form, und diese sind entweder statisch (wie Benutzername und Passwort oder ein IAM Access Key und Secret Key) oder dynamisch. Dynamische Anmeldedaten enthalten ein Token oder ein anderes kurzlebiges Attribut mit zeitlicher Begrenzung.

Statische Anwendungsanmeldedaten, die direkten Zugriff auf Ihre Cloud-Management-Ebene ermöglichen, sind … schlecht. Für Benutzer lässt sich das mit MFA lösen, doch das hilft bei automatisierten Anwendungen wie unserer nicht ganz so theoretischen Cloud-Detection-and-Response-Plattform nicht weiter. Vor einiger Zeit hat Amazon Web Services dieses Problem mit dem Konzept der IAM Role angegangen. Eine Role in AWS ist im Wesentlichen ein Container für Berechtigungen mit zwei Policies: was der Container tun darf und wer (oder was) die Role annehmen darf. Roles sind sitzungsbasiert: Nimmt eine autorisierte Entität die Role an, erhält sie einen Satz Anmeldedaten (Access Key, Secret Key und Session Token), die sie für die Dauer der Sitzung (1 bis 24 Stunden) nutzen kann.

Roles in AWS können über eine externe SAML-Verbindung (für Benutzer), interne „vertrauenswürdige“ Verbindungen (aus anderen AWS-Konten) oder AWS-Dienste (etwa eine EC2-Instanz oder eine Lambda-Funktion) angenommen werden. So lassen sich praktische Dinge umsetzen, etwa Code in einer Instanz auszuführen, ohne dass diese Instanz jemals statische Anmeldedaten speichert. Das erspart erheblichen Aufwand.

Verbindungen aus einem Konto zuzulassen, das Sie nicht kontrollieren, ist etwas anderes – insbesondere, wenn dieses Konto zu einer Plattform gehört, die mehrere Kunden bedient. Solche Plattformen (nun gut, wir) benötigen Zugriff auf Hunderte oder Tausende anderer AWS-Konten. Stellen Sie sich vor, ein Angreifer könnte die Plattform dazu bringen, etwas im falschen Konto auszuführen, etwa eine Konfigurationsbewertung für ein Konto, das dem aktuellen Benutzer nicht gehört. Das ist die Kurzfassung des Confused-Deputy-Problems – dem Deputy wird von mehreren Konten vertraut, und der Benutzer bringt den Deputy dazu, ihm Zugriff auf ein Konto zu gewähren, das er niemals berühren dürfte.

Am praktikabelsten lässt sich dies ausnutzen, wenn die Plattform es einem Benutzer erlaubt, die Konto-ID eines Kontos einzugeben, das er nicht kontrolliert, es seinem Profil hinzuzufügen und anschließend das der Plattform entgegengebrachte Vertrauen zu missbrauchen.

AWS bietet dagegen einen Schutzmechanismus, die AWS ExternalID. Dabei handelt es sich um ein beliebiges gemeinsames Geheimnis, das Plattformanbieter und Kunde außerhalb des Kanals austauschen. Diese ID wird als Attribut bei jeder Anfrage zur Annahme der Role im Kundenkonto übergeben, und die Role Trust Policy in diesem Konto enthält eine Bedingung, die prüft, ob das gemeinsame Geheimnis korrekt ist. Bei korrekter Umsetzung bedeutet das: Niemand kann einfach ein Konto hinzufügen, das er nicht kontrolliert, da der Angreifer das gemeinsame Geheimnis im Kundenkonto weder festlegen noch kennen kann.

Es sei denn …

Sie ahnen, worauf das hinausläuft. Praetorian hat eine große Zahl von Anbietern identifiziert, die standardmäßige AWS ExternalIds verwenden oder es Kunden erlauben, einen nicht eindeutigen ExternalId-Wert für ihr gesamtes Konto festzulegen. Zudem fanden sich Produkte, die nicht überprüften, ob der Kunde die External ID in seiner Role Trust Policy überhaupt erzwingt. Praetorian stieß auf Plattformen, die aktiv ausnutzbar waren und aufgrund unzureichender Sicherheit bei kontenübergreifenden Roles Confused-Deputy-Angriffe ermöglichten.

Härtung kontenübergreifender Verbindungen

All dies war Teil unseres Threat Modeling bei DisruptOps, sodass wir gut aufgestellt sind – wenngleich wir noch die eine oder andere Idee zur Verbesserung mitgenommen haben. Gehen wir die von Praetorian identifizierten Punkte einzeln durch und betrachten die besten Optionen zur Sicherheitshärtung:

  • Die AWS ExternalID verwendet Standardeinstellungen: Wir verwenden eine zufällige ExternalID.
  • Die AWS ExternalID wird über mehrere Kundenkonten hinweg gemeinsam genutzt:Wir verwenden eine zufällige ExternalID pro Konto, nicht pro Kunde.
  • Die AWS ExternalID ist aufzählbar oder erratbar: Wir verwenden vollständig zufällige und lange AWS ExternalIDs. Um unsere PRNG-Wahl mache ich mir dank API-Ratenbegrenzung keine Sorgen (für die Krypto-Nerds unter Ihnen).
  • Kunden können ihre eigene ExternalID festlegen und dabei Werte wiederholen oder schwache ExternalIDs verwenden: Wir unterstützen es nicht, dass Kunden ihre eigene ExternalID festlegen, auch wenn wir diese Anfrage durchaus erhalten haben. Genau hier sind aus meiner Sicht einige andere Anbieter in Schwierigkeiten geraten. Kunden wünschen sich diese Möglichkeit, um die Produktbereitstellung selbst zu automatisieren; um das sicher umzusetzen, müssten wir jedoch validieren, dass die ExternalID die Anforderungen an Länge und Zufälligkeit erfüllt. Mit der richtigen Validierung lässt sich das vermutlich sicher realisieren.
  • Die Plattform erlaubt es, dasselbe AWS-Konto mehrfach bereitzustellen: Das lassen wir nicht zu.
  • Die IAM Role ist nicht auf eine einzelne Entität im Anbieterkonto beschränkt, sondern auf jede Role im Konto: Darauf sind wir in diesem Beitrag nicht eingegangen, doch Sie können entweder jeder Role im Konto Zugriff auf die „Worker“-Role im Kundenkonto gewähren oder den Zugriff auf eine einzelne Ressource oder Role beschränken. Wir beschränken unseren Zugriff auf die spezifischen Roles, die wir für den kontenübergreifenden Zugriff nutzen.
  • Der Name der IAM Role ist über alle Kundenkonten hinweg identisch: Das Risiko besteht im Wesentlichen darin, dass der Benutzername (Role-Name) erratbar ist. Ich halte das für kein Risiko, sofern nicht andere sehr grundlegende Fehler vorliegen. Ein Beispiel: Kennt ein Angreifer den Role-Namen und erlangt Zugriff auf das Kundenkonto, könnte er sich möglicherweise selbst zur Role Trust Policy hinzufügen und diese Berechtigungen nutzen (etwas Ähnliches vermittle ich in meinen Schulungen zur Incident Response). Das ist ein potenzielles Risiko, das wir jedoch als recht gering einstufen. Verfügt ein Angreifer über dieses Zugriffsniveau, kann er wahrscheinlich jede Role im Konto übernehmen.
  • Der Anbieter validiert nicht, dass die ExternalID als Zugriffsbedingung gesetzt wurde: Wir stellen Kunden für die Bereitstellung ein CloudFormation-Template zur Verfügung, das die korrekte Einstellung sicherstellt. Wir werden zudem eine Unterstützung ergänzen, die überprüft, ob sie erhalten bleibt – insbesondere, da wir weitere (nicht auf CloudFormation basierende) Bereitstellungsoptionen ergänzen, um Kundenanforderungen zu erfüllen.

Kesten scheint das Modell statischer Anmeldedaten in Verbindung mit gutem Vaulting auf Anbieterseite zur Absicherung der Verbindung zu bevorzugen. Ich persönlich sehe das anders und halte das AWS-Modell von vornherein für sicherer, sofern die grundlegenden Vorsichtsmaßnahmen eingehalten werden.

Über die Empfehlungen von Praetorian hinaus treffen wir derzeit zwei zusätzliche Vorkehrungen:

  • Wir maskieren die ExternalID in CloudFormation: Wir setzen die ExternalID als Parameter in unseren CloudFormation-Templates mit gesetzter Option NoEcho. Dadurch wird sie in der Konsole, in den Kommandozeilenwerkzeugen und in der API maskiert. Das verringert das Risiko einer Offenlegung gegenüber Personen, die CloudFormation ausführen dürfen, aber keine IAM-Berechtigungen besitzen.
  • Wir beschränken den Zugriff auf das CloudFormation-Template auf das Zielkonto: Das verringert das Risiko, dass jemand die ExternalID während des Bereitstellungsvorgangs abgreift.

Selbst wenn die ExternalID offengelegt wird, sollte dies keine Rolle spielen: Ihre Plattform sollte sicherstellen, dass ein Zielkonto nur einmal und nur mit einer zufälligen ExternalID registriert wird. Selbst wenn ein Angreifer den Role-Namen und die ExternalID kennt, kann er damit nichts anfangen, da es in der Plattform keine Stelle gibt, an der sich diese Informationen eingeben lassen, und AWS selbst erzwingt, dass die kontenübergreifende Verbindung aus dem vertrauenswürdigen Konto stammt. Das lässt sich nicht fälschen.

Hoffentlich liefert Ihnen unser Vorgehen Anregungen für Ihre eigenen Werkzeuge. Ich empfehle die Anforderungen an die Kontoregistrierung und an zufällige ExternalIDs auch dann, wenn Sie AWS Organizations einsetzen, da eine Bedingung, die den Zugriff auf Ihre eigene Organisation beschränkt, weiterhin Angriffe aus einem Konto mit niedrigerer auf ein Konto mit höherer Sicherheitsstufe ermöglichen kann.

Und bleiben Sie dran für das neue Skunkworks-Projekt! In einigen Monaten sollten wir darüber sprechen können – es verändert den Umgang mit dieser Art von Problemen grundlegend.

Fortgeschrittene Techniken zum Schutz der AWS ExternalID | FireMon