Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Sicher auf AWS-Services aus Google Kubernetes Engine (GKE) zugreifen

By Alexei LedenevFeb 17, 20208 min read

Diese Seite ist auch in English, Español, Français, Italiano, 日本語 und Português verfügbar.

1 nxvyzhmtvz4ujcq1yadd7g

Es ist keine Seltenheit, dass eine Anwendung in Google Kubernetes Engine ( GKE) auf APIs von Amazon Web Services ( AWS) zugreifen muss. Jede Anwendung hat ihre Anforderungen: Sie soll vielleicht eine Analyseabfrage in Amazon Redshift ausführen, auf Daten in einem Amazon S3 Bucket zugreifen, Text mit Amazon Polly in Sprache umwandeln oder irgendeinen anderen AWS-Service nutzen. Solche Multi-Cloud-Szenarien sind heute Alltag, weil Unternehmen mit mehreren Cloud-Anbietern arbeiten.

1 nxvyzhmtvz4ujcq1yadd7g

Cloud-übergreifender Zugriff bringt eine neue Herausforderung mit sich: Wie verwaltet man die Credentials, die nötig sind, um von einem Cloud-Anbieter aus auf Services eines anderen zuzugreifen? Der naive Weg, Cloud-Provider-Secrets zu verteilen und zu speichern, ist nicht der sicherste. Langlebige Credentials an jeden Service zu verteilen, der AWS-Services ansprechen muss, ist schwer zu verwalten und ein potenzielles Sicherheitsrisiko.

Bestehende Lösungen

Jede Cloud bringt ihre eigene Lösung für dieses Problem mit, und wer nur mit einem einzigen Cloud-Anbieter arbeitet, kommt damit bestens zurecht.

Google Cloud hat Workload Identity vorgestellt – den empfohlenen Weg für GKE-Anwendungen, sich gegenüber anderen Google-Cloud-Services zu authentifizieren und diese zu nutzen. Workload Identity verknüpft Kubernetes Service Accounts mit Cloud IAM Service Accounts. So lässt sich mit Kubernetes-nativen Konzepten festlegen, welche Workloads unter welcher Identität laufen, und Ihre Workloads erhalten automatisch Zugriff auf andere Google-Cloud-Services – ganz ohne Verwaltung von Kubernetes Secrets oder IAM Service Account Keys. Mehr dazu im DoiT-Blogbeitrag Kubernetes GKE Workload Identity.

Amazon Web Services bietet eine vergleichbare Funktion mit IAM Roles for Service Accounts. Auf Amazon-EKS-Clustern lässt sich damit eine IAM-Rolle einem Kubernetes Service Account zuordnen. Dieser Service Account kann den Containern in jedem Pod, der ihn nutzt, AWS-Berechtigungen bereitstellen. Sie müssen der IAM-Rolle des Worker Node also keine erweiterten Rechte mehr geben, damit Pods auf diesem Node AWS-APIs aufrufen können.

Aber was, wenn Ihre Workloads auf einem GKE-Cluster laufen und Sie ohne Sicherheitskompromisse auf AWS-Services zugreifen wollen?

Use Case

Nehmen wir an, Sie haben bereits ein AWS-Konto und einen GKE-Cluster. Ihr Unternehmen hat sich entschieden, eine Microservice-basierte Anwendung auf dem GKE-Cluster zu betreiben, möchte aber weiterhin Ressourcen im AWS-Konto (Amazon S3 und SNS) nutzen, um sich mit anderen in AWS bereitgestellten Systemen zu integrieren.

Beispiel: Der Orchestration Job (bereitgestellt als Kubernetes Job) läuft in einem GKE-Cluster und soll eine Datendatei in einen S3 Bucket hochladen sowie eine Nachricht an ein Amazon SNS Topic senden. Auf der Kommandozeile sähe das so aus:

https://gist.github.com/90682305b879a96d273284df5d20fdcb

Ein recht einfaches Beispiel. Damit diese Befehle gelingen, braucht der Orchestration Job AWS-Credentials, mit denen er die entsprechenden API-Aufrufe absetzen darf.

Der naive (und unsichere) Ansatz: langlebige IAM-Credentials

Sie exportieren Access Key und Secret Key eines AWS-IAM-Users und reichen die AWS-Credentials in den Orchestration Job hinein – als Credentials-Datei oder über Umgebungsvariablen. Vermutlich nicht direkt, sondern über die Ressource Kubernetes Secrets, abgesichert mit einer RBAC-Authorization-Policy.

Das Risiko: Diese Credentials laufen nie ab. Sie müssen irgendwie aus der AWS- in die GCP-Umgebung gelangen, und in den meisten Fällen sollen sie auch noch irgendwo abgelegt werden, damit sich der Orchestration Job bei Bedarf später neu erstellen lässt.

Bei langlebigen AWS-Credentials gibt es viele Wege, wie Ihr AWS-Konto kompromittiert werden kann: versehentliche Commits in ein GitHub-Repository, Ablage in einem Wiki, Wiederverwendung über mehrere Services und Anwendungen hinweg, fehlende Zugriffsbeschränkungen und so weiter (Beispiele).

Man kann zwar eine saubere Credentials-Verwaltung für ausgegebene IAM-User-Credentials aufsetzen – nötig wäre das aber gar nicht, wenn man solche langlebigen Credentials erst gar nicht erzeugt.

Der vorgeschlagene Ansatz

Die Grundidee: Einem GKE Pod eine AWS IAM Role zuweisen – ähnlich wie es die cloud-spezifischen Features Workload Identity und EKS IAM Roles for Service Accounts tun.

Praktischerweise erlaubt AWS, eine IAM-Rolle für OpenID Connect Federation (OIDC) Identity Provider statt für IAM-User anzulegen. Google wiederum stellt einen OIDC Provider bereit und integriert ihn über das Feature Workload Identity eng mit GKE: Ein GKE Pod, der unter einem mit einem Google Cloud Service Account verknüpften Kubernetes Service Account läuft, erhält ein gültiges OIDC-Token. Genau das hilft uns, einen sicheren Zugriff von GKE nach AWS umzusetzen.

OIDC Access Token gegen ID Token tauschen

Ein Puzzleteil fehlt noch. Mit korrekt eingerichtetem Workflow Identity erhält ein GKE Pod ein OIDC-Access Token, mit dem er auf Google-Cloud-Services zugreifen kann. Um temporäre AWS-Credentials vom AWS Security Token Service (STS) zu bekommen, braucht es allerdings ein gültiges OIDC-ID Token.

Das AWS SDK (und das Tool aws-cli) fordern automatisch temporäre AWS-Credentials beim STS-Service an, sobald die folgenden Umgebungsvariablen korrekt gesetzt sind:

  • AWS_WEB_IDENTITY_TOKEN_FILE – Pfad zur Web-Identity-Token-Datei (OIDC ID Token)
  • AWS_ROLE_ARN – der ARN der Rolle, die von Pod-Containern angenommen werden soll
  • AWS_ROLE_SESSION_NAME – der Name dieser Assume-Role-Session

Klingt erst mal komplex – ich gebe Ihnen aber eine Schritt-für-Schritt-Anleitung an die Hand und stelle das passende Open-Source-Projekt dointl/gtoken bereit, das die Einrichtung vereinfacht.

gtoken-webhook: Kubernetes Mutating Admission Webhook

Der gtoken-webhook ist ein Kubernetes Mutating Admission Webhook, der jeden K8s Pod modifiziert, der unter einem speziell annotierten Kubernetes Service Account läuft (Details siehe unten).

Ablauf der gtoken-webhook-Mutation

Der gtoken-webhook injiziert einen gtoken``initContainer in den Ziel-Pod sowie einen zusätzlichen gtoken-Sidekick-Container (der das OIDC ID Token kurz vor Ablauf erneuert), bindet ein Token-Volume ein und setzt drei AWS-spezifische Umgebungsvariablen. Der gtoken-Container erzeugt ein gültiges GCP OIDC ID Token und schreibt es in das Token-Volume. Außerdem setzt er die nötigen AWS-Umgebungsvariablen.

Das AWS SDK ruft dann automatisch AssumeRoleWithWebIdentity bei AWS STS auf. Es übernimmt das In-Memory-Caching und erneuert die Credentials bei Bedarf.

1 7usxylt69dwxddxzi50teg

Anleitung zur Konfiguration

gtoken-webhook bereitstellen

  1. Um den gtoken-webhook-Server bereitzustellen, legen wir einen Webhook-Service und ein Deployment im Kubernetes-Cluster an. Bis auf einen Punkt – die TLS-Konfiguration des Servers – ist das ziemlich geradlinig. Ein Blick in die Datei deployment.yaml zeigt: Zertifikat und privater Schlüssel werden über Kommandozeilen-Argumente eingelesen, und der Pfad zu diesen Dateien stammt aus einem Volume Mount, der auf ein Kubernetes Secret verweist:

https://gist.github.com/b9fc2fe5acb556e3b48ee89af7db368e

Wichtig: Hinterlegen Sie später in der Webhook-Konfiguration das passende CA-Zertifikat, damit der apiserver es akzeptiert. Vorerst nutzen wir das ursprünglich vom Istio-Team geschriebene Skript, um eine Certificate Signing Request zu erzeugen. Anschließend schicken wir die Anfrage an die Kubernetes-API, holen das Zertifikat ab und legen daraus das benötigte Secret an.

Führen Sie zuerst das Skript webhook-create-signed-cert.sh aus und prüfen Sie, ob das Secret mit Zertifikat und Schlüssel angelegt wurde:

https://gist.github.com/91d2bd8cddf116aa0fa8cefbf3208bcd

Sobald das Secret existiert, legen wir Deployment und Service an. Es handelt sich um ganz normale Kubernetes-Ressourcen für Deployments und Services. Bis hierhin haben wir lediglich einen HTTP-Server, der Anfragen über einen Service auf Port 443 entgegennimmt:

https://gist.github.com/34ec56018700a610f37a09a9e846eecb

Mutating Admission Webhook konfigurieren

Unser Webhook-Server läuft – jetzt kann er Anfragen vom apiserver entgegennehmen. Vorher legen wir aber noch ein paar Konfigurationsressourcen in Kubernetes an. Wir starten mit dem Validating Webhook und konfigurieren den Mutating Webhook anschließend. In der Webhook-Konfiguration finden Sie einen Platzhalter für CA_BUNDLE:

https://gist.github.com/d40101fba8203cc77d62629dde4d6a8f

Ein kleines Skript ersetzt den CA_BUNDLE-Platzhalter in der Konfiguration durch diese CA. Führen Sie diesen Befehl aus, bevor Sie die Validating-Webhook-Konfiguration anlegen:

https://gist.github.com/5e0ed44892fc7a21709ac18b381cb5f6

Mutating-Webhook-Konfiguration anlegen:

https://gist.github.com/a545e146e1168f3b88d04b3f4c490d68

RBAC für gtoken-webhook konfigurieren

Legen Sie einen Kubernetes Service Account für gtoken-webhook an:

https://gist.github.com/aabfa30bc005ae8654b360814523c9bc

Definieren Sie die RBAC-Berechtigungen für den Webhook Service Account:

https://gist.github.com/5ceb8a6e1ca19d9be3b8ed2d810ddc96

Variablen im Ablauf

Einige der folgenden Variablen geben Sie selbst vor, andere werden automatisch erzeugt und in den nächsten Schritten weiterverwendet.

  • PROJECT_ID – GCP-Projekt-ID (selbst festzulegen)
  • CLUSTER_NAME – Name des GKE-Clusters (selbst festzulegen)
  • GSA_NAME – Name des Google Cloud Service Accounts (selbst festzulegen)
  • GSA_ID – eindeutige ID des Google Cloud Service Accounts (von Google erzeugt)
  • KSA_NAME – Name des Kubernetes Service Accounts (selbst festzulegen)
  • KSA_NAMESPACE – Kubernetes-Namespace (selbst festzulegen)
  • AWS_ROLE_NAME – Name der AWS-IAM-Rolle (selbst festzulegen)
  • AWS_POLICY_NAME – AWS-IAM-Policy, die der IAM-Rolle zugewiesen wird (selbst festzulegen)
  • AWS_ROLE_ARN – ARN der AWS-IAM-Rolle (von AWS erzeugt)

Google Cloud: GKE Workload Identity aktivieren

Legen Sie einen neuen GKE-Cluster mit aktivierter Workload Identity an:

https://gist.github.com/0fcbc309cd1967edac19bac6795d651d

… oder aktualisieren Sie einen bestehenden Cluster:

https://gist.github.com/05a94c349aa4a274fc27daae45448be9

Google Cloud: Google Cloud Service Account anlegen

Legen Sie einen Google Cloud Service Account an:

https://gist.github.com/1790d9e61c63123937d01c8146c1a67d

Versehen Sie den Google Service Account GSA_NAME mit folgenden Rollen:

  • roles/iam.workloadIdentityUser – Service Accounts aus GKE-Workloads impersonieren
  • roles/iam.serviceAccountTokenCreator – Service Accounts impersonieren, um OAuth2 Access Tokens zu erstellen sowie Blobs oder JWT-Tokens zu signieren

https://gist.github.com/19570300e584798d4d5c3a234ceb0d62

AWS: AWS-IAM-Rolle mit Google OIDC Federation anlegen

Bereiten Sie ein Role Trust Policy Document für den Google OIDC Provider vor:

https://gist.github.com/d80514354a5270bd0f6766dee7947902

Legen Sie eine AWS-IAM-Rolle mit Google Web Identity an:

https://gist.github.com/94f0ce213cf60cfce6ac987af51afbed

Weisen Sie der AWS-Rolle die gewünschten Policies zu:

https://gist.github.com/afd9ecc776cfba5148137769aaf71a5f

Lesen Sie den AWS Role ARN aus, der in der Annotation des K8s-SA verwendet wird:

https://gist.github.com/d407769dffd4eb276ed22f7b723cbdc4

GKE: Kubernetes Service Account anlegen

K8s-Namespace anlegen:

https://gist.github.com/59dafb6baf1223552eb7d9fc3c3cbea3

K8s Service Account anlegen:

https://gist.github.com/58fd6924e79270857f39d924a0f12011

K8s Service Account mit GKE Workload Identity annotieren (E-Mail des GCP Service Accounts):

https://gist.github.com/0be380a02ff228a38b2a9e5400b75dcb

K8s Service Account mit dem AWS Role ARN annotieren:

https://gist.github.com/01620978944525a8df6c3d76ddc1fb67

Demo starten

Starten Sie einen neuen K8s Pod mit dem K8s ``${KSA_NAME}``` Service Account:

https://gist.github.com/9c5a30f5dd3825d5c3bc6adc14b76fbc

Weiterführende Links


Fazit

Ich hoffe, dieser Beitrag ist für Sie hilfreich. Über Ihre Kommentare und Fragen freue ich mich.

Lust auf mehr? Schauen Sie in unseren Blog oder folgen Sie Alexei auf Twitter.