Alle Artikel
16. Oktober 2026
12 mins

Data Mesh auf AWS mit SageMaker Unified Studio: was ich aus der Praxis mitnehme

Von Tim Rutte, Cloud & Software ArchitectThemaAWS & Cloud

Ein überladener Schlüsselring mit dreißig meist angelaufenen Schlüsseln, drei davon blau.

Data Mesh klingt nach Organisationstheorie: Domänen besitzen ihre Daten, Daten werden als Produkt behandelt, eine Plattform macht Selbstbedienung möglich, und Governance ist föderiert. Auf Folien ist das schnell erklärt. In einem AWS-Account bleiben davon am Ende ein paar sehr konkrete Dinge übrig: eine Glue-Tabelle, eine Lake-Formation-Berechtigung, ein Eintrag im Katalog und jemand, der ein Abonnement freigibt.

Ich betreue seit einiger Zeit die Datenseite einer Plattform, deren Kennzahlen mehrere Abteilungen in eigenen AWS-Accounts brauchen. Angefangen hat das mit Amazon DataZone, heute läuft es über Amazon SageMaker Unified Studio, kurz SMUS, das auf DataZone aufsetzt. Dieser Artikel ist kein Überblick über alle Funktionen. Er beschreibt, was im Alltag tatsächlich zählt, wo es still scheitert und was ich beim nächsten Mal von Anfang an anders machen würde.

Meine Kurzfassung vorweg: SMUS ist ein gutes Schaufenster und ein guter Freigabeprozess. Das eigentliche Data Mesh liegt darunter, in Glue und Lake Formation, und dort entscheidet sich, ob es funktioniert.

Warum überhaupt ein Data Mesh

Die Ausgangslage kennen viele: Umsatz- und Nutzungsdaten liegen in S3 und werden mit Athena ausgewertet. Andere Teams wollen dieselben Zahlen, also bekommen sie einen CSV-Export, eine Bucket-Policy oder eine IAM-Rolle mit Lesezugriff auf ein Präfix. Nach zwei Jahren weiß niemand mehr genau, wer welche Daten liest, in welchem Format und ob er sich darauf verlässt.

Das Problem ist dabei selten die Technik. Das Problem ist, dass niemand eine Frage beantworten kann, die irgendwann jeder stellt: Wenn ich diese Spalte ändere, wer merkt es? Ein Data Mesh beantwortet sie durch Struktur. Wer Daten bereitstellt, veröffentlicht sie als Datenprodukt in einem Katalog. Wer sie nutzen will, abonniert sie dort. Die Freigabe ist dokumentiert, die Berechtigung entsteht daraus automatisch, und der Produzent sieht, wer abonniert hat.

Was Data Mesh auf AWS konkret bedeutet

Die erste Hürde ist sprachlich, und sie hat mich mehr Zeit gekostet, als ich zugeben möchte. In der Data-Mesh-Literatur ist eine Domäne ein fachlicher Bereich mit eigener Datenverantwortung, etwa „Vertrieb“ oder „Logistik“. In DataZone und SMUS ist eine Domain dagegen der gesamte Rahmen: ein Katalog, ein Portal, eine Benutzerverwaltung, oft eine für das ganze Unternehmen. Was im Data-Mesh-Sinn eine Domäne ist, entspricht in SMUS eher einem Projekt oder einer Domain Unit.

Wer das nicht früh klärt, führt Gespräche, in denen beide Seiten „Domain“ sagen und Verschiedenes meinen. Ich halte die Zuordnung inzwischen schriftlich fest:

Data-Mesh-BegriffAuf AWS
Datendomäne mit VerantwortungSMUS-Projekt, meist mit eigenem AWS-Account
DatenproduktGlue-Tabelle, im Katalog als Asset veröffentlicht
SelbstbedienungsplattformSMUS-Portal mit Suche, Abonnement und Abfrage
Föderierte GovernanceFreigabe des Abonnements durch den Produzenten, umgesetzt als Lake-Formation-Berechtigung
Zugriff über AccountgrenzenLake-Formation-Berechtigungen auf den Glue Data Catalog

Der Ablauf ist danach einfach zu beschreiben. Das produzierende Projekt hat eine Datenquelle, die regelmäßig eine Glue-Datenbank einliest und jede passende Tabelle als Asset in den Katalog übernimmt. Das Asset wird veröffentlicht. Ein konsumierendes Projekt findet es, stellt eine Abonnementanfrage, der Produzent gibt frei, und SMUS legt die nötigen Lake-Formation-Berechtigungen für die Rolle des konsumierenden Projekts an. Ab da fragt der Konsument die Tabelle mit Athena ab, ohne dass jemand eine Bucket-Policy angefasst hat.

So weit die Theorie. Die folgenden Abschnitte handeln davon, was an jeder dieser Stationen schiefgehen kann.

Eine eigene Datenbank als Schaufenster

Die wichtigste Entscheidung habe ich zum Glück früh getroffen: Was geteilt wird, liegt in einer eigenen Glue-Datenbank. Die internen Tabellen der Anwendung liegen in einer Datenbank, die Datenprodukte in einer anderen. Die zweite ist das Schaufenster, und nur was dort steht, kann überhaupt ein Asset werden.

Das klingt nach Ordnungsliebe, hat aber zwei handfeste Vorteile. Erstens kann eine interne Tabelle nicht versehentlich im Katalog landen, weil eine Datenquelle zu großzügig filtert. Zweitens lassen sich die Berechtigungen über die ganze Datenbank vergeben. Die accountübergreifenden Grants stehen bei uns als Wildcard über alle Tabellen der Schaufenster-Datenbank in Terraform:

resource "aws_lakeformation_permissions" "konsument_tabellen" {
  for_each  = toset(var.konsumenten_account_ids)
  principal = each.value

  permissions                   = ["SELECT", "DESCRIBE"]
  permissions_with_grant_option = ["SELECT", "DESCRIBE"]

  table {
    database_name = aws_glue_catalog_database.produkte.name
    wildcard      = true
  }
}

Ein neues Datenprodukt braucht dadurch keine einzige zusätzliche Berechtigung. Die Tabelle entsteht, erbt die Grants, und der Rest läuft über den Katalog. Das with_grant_option ist dabei kein Detail: Erst damit kann der Konsumenten-Account die Rechte an seine eigenen Rollen weitergeben, also an die Rolle seines SMUS-Projekts.

Ein Datenprodukt schneidet man über den Pfad

Das erste Datenprodukt, das ich für ein anderes Team gebaut habe, waren die Zahlen eines einzelnen Geschäftspartners. Die naheliegende Lösung wäre gewesen, die vorhandene Tabelle mit den Zahlen aller Partner zu teilen und den Konsumenten zu bitten, nach Partner zu filtern. Das wäre schnell gewesen und falsch.

Die vorhandene Tabelle war nach Jahr, Monat und Tag partitioniert. Der Partner stand unter dem Tag im Pfad und war für Glue nur eine gewöhnliche Spalte. Eine Glue-Tabelle kann man aber nur auf ein Präfix setzen, nicht auf ein Muster mittendrin. Wer sie teilt, teilt also jeden Partner, und jeder Abonnent hätte die Zahlen aller anderen Partner lesen können.

Lake Formation kennt für solche Fälle Datenfilter auf Zeilen und Spalten. Ich habe mich trotzdem dagegen entschieden, weil es eine einfachere Lösung gab: Die Anwendung schrieb dieselben Daten ohnehin ein zweites Mal für einen Export, und dort stand der Partner vor dem Datum im Pfad:

s3://…/partner=a/jahr=2026/monat=10/tag=15/…

Eine Tabelle, die auf partner=a/ zeigt, kann nichts anderes enthalten als diesen Partner. Kein View, kein Filter, keine Zeilenregel, die jemand später aus Versehen lockert. Ein Datenprodukt, das falsche Daten gar nicht enthalten kann, ist leichter zu prüfen als eines, das sie herausfiltert. Das ist dieselbe Denkweise wie bei Berechtigungen generell: lieber eine Grenze, die durch Konstruktion hält, als eine, die durch Konfiguration hält.

Wenn Sie also das erste Datenprodukt planen, schauen Sie zuerst auf die Pfadstruktur in S3. Sie entscheidet darüber, wie fein Sie schneiden können, und ein Umbau der Partitionierung ist meistens teurer als eine zweite, passend geschnittene Kopie.

Lake Formation ist das eigentliche Mesh

Im SMUS-Portal sieht ein Abonnement nach einem Klick aus. Darunter liegt Lake Formation, und dort lagen fast alle Probleme, die mich Zeit gekostet haben. Drei davon würde ich jedem mitgeben.

Hybrid Access Mode braucht ein Opt-in

Wer einen bestehenden Data Lake nachträglich unter Lake Formation stellt, nimmt meistens den Hybrid Access Mode. Die bisherigen IAM-Berechtigungen gelten weiter, Lake Formation kommt dazu. Das ist für eine Migration genau richtig, hat aber eine Eigenheit: Lake-Formation-Berechtigungen wirken für einen Principal erst, wenn er für die Ressource eingeschaltet ist. Ohne dieses Opt-in ist ein Grant da, sichtbar und korrekt, und bewirkt nichts.

In der Praxis sieht das so aus: Das Abonnement ist freigegeben, SMUS meldet Erfolg, und der Konsument bekommt in Athena trotzdem keine Daten. Keine Fehlermeldung, die auf das fehlende Opt-in zeigt. Bei uns steht es deshalb neben den Grants in Terraform, für die Datenbank und für alle Tabellen:

resource "aws_lakeformation_opt_in" "konsument_tabellen" {
  for_each = toset(var.konsumenten_account_ids)

  principal {
    data_lake_principal_identifier = each.value
  }

  resource_data {
    table {
      catalog_id    = data.aws_caller_identity.current.account_id
      database_name = aws_glue_catalog_database.produkte.name
      wildcard      = true
    }
  }

  depends_on = [aws_lakeformation_opt_in.konsument_datenbank]
}

Zwei Details stecken darin. Die catalog_id steht ausdrücklich da, weil die API sie sonst selbst setzt und Terraform die Ressource bei jedem Plan ersetzen will. Und das depends_on serialisiert die Opt-ins für Datenbank und Tabellen, weil die API gleichzeitige Änderungen mit einer ConcurrentModificationException ablehnt.

Die Liste der Administratoren ist vollständig oder gefährlich

Um Opt-ins und Grants per Terraform zu setzen, muss die Deploy-Rolle Data-Lake-Administrator sein. IAM-Rechte wie lakeformation:* reichen dafür nicht, das ist eine eigene Ebene. Die Terraform-Ressource dafür, aws_lakeformation_data_lake_settings, ist aber autoritativ: Die Liste der Admins ersetzt die vorhandene vollständig.

Wer dort nur die eigene Deploy-Rolle einträgt, entzieht beim nächsten Apply allen anderen die Admin-Rechte. Dazu gehören die SSO-Rollen der Menschen und die Service-Rollen, die DataZone und SMUS selbst angelegt haben. Danach funktioniert zuerst die Veröffentlichung nicht mehr, und dann kommt niemand mehr in die Konsole, um es zu reparieren.

Ich lese die aktuelle Liste deshalb vor der ersten Übernahme mit aws lakeformation get-data-lake-settings aus, importiere die Ressource und lasse den Plan an einer Bedingung scheitern, wenn die Liste in Produktion leer ist oder einen Platzhalter enthält:

lifecycle {
  precondition {
    condition = (
      var.environment != "prod" || length(var.lf_admins) > 0
    ) && alltrue([
      for a in var.lf_admins :
      can(regex("^arn:aws:iam::[0-9]{12}:(role|user)/", a))
    ])
    error_message = "Die Admin-Liste ist unvollständig."
  }
}

Ein Kommentar im Code hätte denselben Zweck gehabt, aber Kommentare halten niemanden auf. Eine Bedingung im Plan schon.

Admin-Rechte wieder wegnehmen

Die Kehrseite: Im Lauf der Jahre sammeln sich Admins an. Bei uns hatte eine alte Deploy-Rolle, die längst etwas anderes tat, noch Data-Lake-Admin. Bevor ich sie entfernt habe, habe ich in CloudTrail nachgesehen, welche Aufrufe ihre Sitzungen tatsächlich machen. Es waren ausschließlich Aufrufe für Container-Deployments, kein einziger Lake-Formation-Aufruf. Damit war die Entscheidung keine Vermutung mehr. Das Vorgehen dahinter beschreibe ich ausführlicher in IAM aufräumen im gewachsenen AWS-Account.

Die Datenquelle entscheidet, was sichtbar wird

Eine Glue-Tabelle ist noch kein Asset. Sie wird eines, wenn eine Datenquelle des Projekts sie beim nächsten Lauf einliest. Jede Datenquelle hat einen Tabellenfilter, und was nicht hineinpasst, taucht im Katalog nie auf. Auch hier ohne Fehlermeldung.

Bei uns waren die Datenquellen des produzierenden Projekts ursprünglich von Hand in DataZone angelegt, nicht in Terraform. Nach der Umstellung ließen sie sich im Portal nicht mehr bearbeiten. Übrig blieb eine einzige Quelle, die noch täglich gegen die Schaufenster-Datenbank lief, und ihr Filter passte nur auf Tabellen mit einem bestimmten Präfix, das aus dem ersten Anwendungsfall stammte.

Die neue Tabelle hatte dieses Präfix nicht und wurde deshalb nie ein Asset. Die pragmatische Lösung war, sie umzubenennen, damit sie in den Filter passt. Das Präfix ist seitdem ein reines Routing-Mittel und sagt nichts mehr über den Inhalt, was ich im Terraform-Code ausdrücklich dazugeschrieben habe. Sonst hält es der nächste Leser für einen Fehler.

Selbst das Umbenennen war in Terraform nicht trivial. Eine Glue-Tabelle umzubenennen bedeutet, sie zu ersetzen, und unsere Pipeline lässt keinen Plan durch, der eine solche Ressource löscht. Ich habe deshalb die neue Tabelle als neue Ressource angelegt und die alte nur aus dem State entlassen:

removed {
  from = aws_glue_catalog_table.partner_kennzahlen
  lifecycle {
    destroy = false
  }
}

Der verwaiste Glue-Eintrag hatte keine Abonnenten und wurde danach von Hand entfernt. Die Lehre daraus ist aber eine andere: Datenquellen gehören vom ersten Tag an in den Code, und ihr Filter sollte eine Konvention beschreiben, nicht die Herkunft des ersten Datensatzes. Ein Präfix wie produkt__ hätte das Problem nie entstehen lassen. Warum ich solche Ressourcen meistens mit Terraform beschreibe, steht in Terraform oder AWS CDK?

Ein Datenprodukt ist ein Vertrag

Sobald jemand eine Tabelle abonniert hat, ist ihr Schema ein Vertrag. Das klingt selbstverständlich und wird trotzdem ständig gebrochen, weil eine Glue-Tabelle sich nicht wie eine API anfühlt.

Ein Beispiel aus der Praxis: Die Daten liegen als CSV vor, und Glue liest CSV mit dem LazySimpleSerDe. Der ordnet Spalten nach Position zu, nicht nach dem Namen in der Kopfzeile. Die Spaltenreihenfolge der Tabelle muss also exakt der Reihenfolge entsprechen, in der die Anwendung schreibt, einschließlich einer veralteten Spalte, die niemand mehr lesen soll, die aber noch in der Datei steht. Wer sie in der Tabelle „aufräumt“, verschiebt alle folgenden Werte um eine Spalte. Die Abfrage läuft weiter, die Zahlen sind falsch.

Ich behandle Datenprodukte deshalb nach drei Regeln:

  • Jede Spalte hat einen Kommentar, der im Katalog sichtbar ist: Einheit, Währung, Bedeutung von Sonderwerten. Steht dort, was ein Leerwert bedeutet, fragt niemand nach.
  • Erweitern ja, umbauen nein. Als dieselben Zahlen zusätzlich in einer feineren Aufteilung gebraucht wurden, habe ich nicht die bestehende Tabelle umgebaut, die ein anderer Konsument schon nutzte. Es gibt jetzt ein zweites Datenprodukt mit eigener Tabelle. Das bestehende blieb unverändert.
  • Der Produzent liest mit. Ein Monitor auf die Aktualität der Daten gehört zum Produkt, nicht zum Konsumenten. Wer ein Datenprodukt anbietet, sollte vor seinen Abonnenten merken, dass gestern nichts angekommen ist.

Abbauen gehört dazu

Ein Katalog wächst. Irgendwann gibt es Assets, die durch bessere ersetzt wurden, und Tabellen, die nur noch existieren, weil niemand sicher ist, ob sie gebraucht werden. Hier zeigt sich ein Vorteil des Katalogs, den man beim Aufbau leicht übersieht: Er weiß, wer abonniert hat.

Ohne Katalog beginnt das Stilllegen einer Tabelle mit Detektivarbeit: Zugriffsprotokolle lesen, Teams fragen, abwarten, wer sich beschwert. Mit Katalog beginnt es mit einem Blick auf die Abonnements. Erst wenn dort niemand mehr steht, verschwinden Asset, Glue-Tabelle und am Ende die Daten in S3, in dieser Reihenfolge. So lässt sich auch ein Datenprodukt stilllegen, das ein besseres überflüssig gemacht hat, ohne dass irgendwo etwas bricht.

Wann sich das lohnt und wann nicht

SMUS ist kein kleines Werkzeug. Es bringt eine Domain, Projekte, Service-Rollen, ein Portal und eine Menge Begriffe mit, und an einigen Stellen merkt man, dass das Produkt noch reift: Datenquellen, die sich nach einer Migration nicht mehr bearbeiten lassen, Fehler, die ohne Meldung bleiben, und eine Terraform-Abdeckung, die hinter der Konsole herläuft.

Ich würde es deshalb nicht für jede Datenfreigabe empfehlen:

SituationMeine Empfehlung
Ein Team, ein Account, Auswertungen mit AthenaGlue und Athena reichen, kein Katalog nötig
Ein zweiter Account braucht eine TabelleLake-Formation-Grant über Accountgrenzen, sauber in Terraform
Mehrere Teams und Accounts lesen dieselben Datenhier lohnt sich SMUS, vor allem für Freigabe und Nachvollziehbarkeit
Daten mit Vertraulichkeitsstufen, Audit-PflichtenSMUS plus Datenfilter oder getrennt geschnittene Produkte
Niemand will Verantwortung für ein Datenprodukt übernehmenkein Werkzeug löst das, erst die Verantwortung klären

Der letzte Punkt ist der wichtigste. Ein Data Mesh ohne Produzenten, die ihre Daten wirklich besitzen, ist ein teurer Katalog mit veralteten Einträgen. SMUS macht Verantwortung sichtbar, es schafft sie nicht.

Womit ich heute anfangen würde

Würde ich das Ganze noch einmal aufbauen, ginge ich in dieser Reihenfolge vor:

  1. Eine eigene Glue-Datenbank für Datenprodukte, getrennt von allen internen Tabellen.
  2. Lake Formation als Code: Admin-Liste vollständig importiert und abgesichert, S3-Pfade registriert, Grants und Opt-ins als Wildcard über die Produkt-Datenbank.
  3. Datenquellen in Terraform, mit einem Filter, der eine Namenskonvention beschreibt und nicht den ersten Anwendungsfall.
  4. Das erste Datenprodukt über den S3-Pfad schneiden, nicht über einen Filter, und jede Spalte kommentieren.
  5. Einmal den ganzen Weg testen, mit einem echten Konsumenten-Account: veröffentlichen, abonnieren, freigeben, in Athena abfragen. Erst wenn dort Zeilen zurückkommen, funktioniert es.
  6. Aktualität überwachen, beim Produzenten, mit einem Alarm, der jemanden erreicht.

Nichts davon ist spektakulär. Aber jeder dieser Schritte steht für einen Fehler, der bei uns ohne Meldung durchgelaufen ist. Ein Data Mesh auf AWS scheitert selten laut. Es scheitert daran, dass eine Tabelle nicht im Katalog auftaucht, ein Abonnement keine Daten liefert oder eine Spalte verrutscht, und niemand es merkt. Wer diese stillen Stellen von Anfang an in Code und Prüfungen fasst, bekommt mit SMUS ein Werkzeug, das Datenfreigabe tatsächlich einfacher macht.