Kapitel 4. Sicherheit

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Das Internet ist eine feindliche Umgebung. Sicherheit ist keine Option, sondern eine Notwendigkeit. Wenn du deine Anwendung entwirfst, muss die Sicherheit ein integraler Bestandteil des Entwurfs sein und nicht etwas, das du in einer späteren Phase hinzufügst. Wenn es um Sicherheit geht, ist das Ziel von Dapr, Anwendungen standardmäßig sicher zu machen. Das bedeutet, dass du standardmäßig bewährte Methoden für die Sicherheit erhältst und das System dann an deine Sicherheitsanforderungen anpassen kannst. Dapr ist noch ein junges Projekt, und wir sind auf dem Weg zu diesem Ziel noch lange nicht am Ziel. In diesem Kapitel wird jedoch vorgestellt, wie wir die Dapr-Komponenten so gestalten, dass wir Sicherheitsfunktionen einbauen und bewährte Methoden auf möglichst natürliche Weise in deine Anwendungen bringen können.

Absicherung einer verteilten Anwendung

Um ein System zu sichern, musst du mehrere Herausforderungen berücksichtigen, darunter Zugriffskontrolle, Datenschutz, gesicherte Kommunikation, Erkennung von Eindringlingen und Anomalien sowie die Privatsphäre der Benutzer. Das langfristige Ziel von Dapr ist es, dir zu helfen, diese Herausforderungen so weit wie möglich zu meistern, damit deine Anwendungen standardmäßig sicher sind.

Da Dapr noch in den Kinderschuhen steckt, haben wir noch einen langen Weg vor uns. In diesem Kapitel werden wir zunächst einige unserer Gedanken zum Thema Sicherheit erläutern, damit du einen Eindruck davon bekommst, in welche Richtung sich die Sicherheit von Dapr entwickelt. Dann geht es darum, was wir in Dapr implementiert haben. Wenn du diesen Text liest, wird Dapr dir wahrscheinlich noch mehr Sicherheitsfunktionen zur Verfügung stellen. Und natürlich, wenn du Feedback oder Vorschläge hast, reiche bitte Probleme im Dapr-Repository ein.

Beginnen wir mit dem offensichtlichsten Problembereich: der Zugriffskontrolle.

Zugriffskontrolle

Die Absicherung eines zentralen Servers ist relativ einfach, da du die volle Kontrolle über die Hosting-Umgebung hast. Du kannst zum Beispiel Firewall-Regeln und Load Balancer-Richtlinien einrichten, um den Zugriff auf bestimmte Client-IP-Segmente und Ports zu beschränken. Du kannst auch zentrale Identitätsanbieter wie Active Directory einbinden, um eine zentrale Authentifizierung und Autorisierung zu ermöglichen.

Tipp

Diese beiden Begriffe werden oft verwechselt. Einfach ausgedrückt beantwortet die Authentifizierung die Frage "Wer bist du?" und die Autorisierung die Frage "Was darfst du tun?"

Wenn du deine Anwendung in der Cloud hostest, solltest du die Sicherheitsfunktionen nutzen, die die Cloud-Plattform bietet. Moderne Cloud-Plattformen bieten Sicherheitsfunktionen, die denen vor Ort ähneln. So kannst du die Zugriffskontrolle mit bekannten Technologien und Konzepten wie Netzwerksicherheitsgruppen, RBAC, zertifikatsbasierter Authentifizierung und Firewalls verwalten.

Die Dinge werden komplizierter, wenn du versuchst, die Sicherheit eines verteilten Systems zu verwalten, denn du musst dich oft mit verstreuten Rechenressourcen, nicht vertrauenswürdigen Verbindungen und heterogenen Technologie-Stacks auseinandersetzen. Du wirst deine Strategien überdenken müssen, wenn es darum geht, gängige Sicherheitsherausforderungen zu bewältigen, wie z. B. die Feststellung der Identität, die Festlegung von Richtlinien für die Zugriffskontrolle und die Kommunikation über das Netzwerk.

Identität

Eine Anwendung muss mit zwei Arten von Identitäten umgehen: Benutzeridentität und Dienstidentität. Eine Benutzeridentität identifiziert einen bestimmten Benutzer, während eine Dienstidentität einen Dienst oder einen Prozess darstellt. Für beide Arten von Identitäten kannst du Richtlinien zur Zugriffskontrolle festlegen (siehe unten). So kannst du zum Beispiel einer Benutzeridentität Lesezugriff auf eine relationale Datenbanktabelle gewähren und eine Dienstidentität daran hindern, ausgehende Verbindungen herzustellen.

Mit Diensten wie Microsoft Azure Active Directory (AAD) kannst du Identitäten für Nutzer und Dienste einrichten und verwalten. In solchen Fällen wird AAD als vertrauenswürdiger Identitätsanbieter (IP) bezeichnet, und deine Anwendung ist eine vertrauenswürdige Partei (RP) des IP. Der IP gibt Sicherheits-Tokens an vertrauenswürdige RPs aus. Die RPs extrahieren Ansprüche aus den Token und treffen auf der Grundlage dieser Ansprüche Genehmigungsentscheidungen. Wenn du zum Beispiel ein Auto mieten willst, benötigt die Autovermietung (die RP) ein Sicherheitstoken, in diesem Fall deinen Führerschein, der von einer vertrauenswürdigen IP - dem Department of Motor Vehicles (DMV) - ausgestellt wurde. Ein Claim ist eine Aussage über eine bestimmte Eigenschaft des Tokens. Im Fall des Führerscheins ist der Name auf dem Führerschein eine Aussage des DMV über den Namen des Inhabers. Da der RP der IP und dem ausgestellten Sicherheits-Token vertraut, nimmt er jede Aussage des Tokens - Name, Adresse, Alter, Augenfarbe usw. - als wahr an. Dieses Konzept, bei dem die Authentifizierung an eine vertrauenswürdige IP delegiert wird, nennt man eine claimbasierte Architektur.

Aus der Sicht von Dapr ist die Feststellung der Identität des Nutzers eine Angelegenheit der Anwendung. Dapr kann Dienstprogramme wie die OAuth-Middleware, die du in Kapitel 1 kennengelernt hast, aufbauen, um Authentifizierungs- und Autorisierungsprozesse unter gängigen Protokollen wie OAuth 2.0, WS-Federation und dezentralen Identifikatoren (DIDs) zu erleichtern. Dapr hat jedoch keine Meinung dazu, wie deine Anwendungen Benutzer identifizieren und Zugriffskontrollrichtlinien durchsetzen.

Dapr hat das Potenzial, bei der Identifizierung von Diensten eine große Hilfe zu sein. Wie du in der Einführung gesehen hast, wird jede Dapr-Instanz durch einen eindeutigen Stringnamen identifiziert. Wenn wir den Namen härten können, können wir die Dapr-ID als Service-Identität der Anwendung verwenden, die der Dapr-Sidecar repräsentiert. Eine Möglichkeit ist zum Beispiel die Integration von Dapr in die AAD Pod Identity, die es Kubernetes-Anwendungen ermöglicht, mit AAD sicher auf Cloud-Ressourcen und -Dienste zuzugreifen.

Richtlinien für die Zugriffskontrolle

Da Dapr-Sidecars auf den Pfaden der Dienstaufrufe sitzen, kann Dapr mehr Unterstützung mit einer feinkörnigen Zugriffskontrolle bieten. Zum Beispiel kann Dapr eine Zugriffsrichtlinie auf eine /foo Route anwenden, um den Zugriff nur von explizit erlaubten Dapr-IDs über bestimmte HTTP-Verben (wie GET) zu erlauben. Bevor diese Funktion von der Dapr-Laufzeitumgebung selbst implementiert wird, kannst du eine benutzerdefinierte Middleware erstellen, die diese Filterung ermöglicht. Der folgende Pseudocode zeigt, wie ein Filter mit der Dapr-Middleware definiert werden kann:

func (m *Middleware) GetHandler(metadata middleware.Metadata) 
      (func(h fasthttp.RequestHandler) fasthttp.RequestHandler, error) {
    ...

    return func(h fasthttp.RequestHandler) fasthttp.RequestHandler {
        return func(ctx *fasthttp.RequestCtx) {
            if (ctx.IsGet() && ctx.Path == "/foo") {
                h(ctx);
            } else {
                // Deny access
            }
        }
    }, nil
}

Noch interessanter ist, dass Dapr ähnliche Richtlinien zur Zugriffskontrolle verstärken kann, wenn Messaging verwendet wird. Ein Dapr-Sidecar kann zum Beispiel Anfragen zur Veröffentlichung in bestimmten Topics ablehnen oder einer Anwendung verbieten, aus bestimmten Topics zu lesen.

Solche Richtlinien können durch Middleware-Konfigurationen oder andere Metadatenformate erfasst werden, und die Verstärkung der Richtlinien ist vollständig vom Anwendungscode getrennt. Dies ist genau die Art der Trennung von Belangen, die Dapr den Entwicklern verteilter Anwendungen bieten will. In Kombination mit der Tracing-Funktion von Dapr bietet ein solcher Mechanismus zur Zugriffskontrolle außerdem volle Transparenz darüber, wie der Zugriff gewährt oder verweigert wird.

Netzwerksicherheit

Zugriffskontrollen können auch auf der Netzwerkebene implementiert werden. Viele Microservice Systeme nutzen Service Meshes, um die dynamische Netzwerkumgebung zu verwalten. Dapr ist so konzipiert, dass es gut mit bestehenden Service-Mesh-Lösungen wie Consul und Istio zusammenarbeitet. Abbildung 4-1 zeigt, wie Dapr-Sidecars auf Service-Mesh-Envoys gelegt werden können, um zusätzliche Zugriffskontrolle und Filterung über die Netzwerkrichtlinien hinaus zu ermöglichen, die durch ein Service-Mesh verstärkt werden.

Dapr sidecar working with service mesh envoy
Abbildung 4-1. Dapr-Beiwagen arbeitet mit Service Mesh Envoy

Die folgenden, in der HashiCorp Configuration Language (HCL) geschriebenen Consul-Dienstregeln erlauben zum Beispiel Lesezugriff auf alle Dienste ohne Präfixe und Schreibzugriff auf die "app"-Dienste. Die Regeln verweigern außerdem jeglichen Zugriff auf den Dienst "admin". Diese Regeln werden von Consul durchgesetzt und Dapr (und die App) bleiben in diesem Fall unbemerkt:

service_prefix "" {
  policy = "read"
}
service "app" {
  policy = "write"
}
service "admin" {
  policy = "deny"
}

Eine Sache, die du beachten solltest, ist, dass Dapr gegenseitiges TLS bietet, eine Funktion, die in Servicemeshes üblich ist. Wenn du Dapr also für die Zusammenarbeit mit einem Servicenetz konfigurierst, solltest du eine der TLS-Schichten deaktivieren. Bitte konsultiere die Dapr-Dokumentation für Anweisungen und Empfehlungen.

Selbst wenn geeignete Richtlinien für die Zugriffskontrolle von Diensten vorhanden sind, müssen wir noch eine Ebene tiefer gehen und die Daten schützen, mit denen diese Dienste arbeiten. Wir werden uns als Nächstes mit dem Datenschutz befassen.

Datenschutz

Wenn es um den Schutz von Daten geht, müssen wir drei Bereiche berücksichtigen: data at rest, data in transit und data in use.

Schutz von Daten im Ruhezustand

Eine gängige Methode, um Daten im Ruhezustand zu schützen, ist die Verschlüsselung. Zum Zeitpunkt der Erstellung dieses Artikels bietet Dapr noch keine Verschlüsselung der Daten an, aber in Zukunft könnten automatische Ver- und Entschlüsselungsfunktionen zu seinem State Store hinzugefügt werden. Dapr hat auch eine eingebaute Funktion zur Verwaltung von Geheimnissen, die wir später in diesem Kapitel vorstellen werden. Mit dieser Funktion kannst du Verschlüsselungsschlüssel für Benutzerdaten verwalten.

Dapr kümmert sich nicht um die Datensicherung und -wiederherstellung; diese Verantwortung sollte unserer Meinung nach von der zugrundeliegenden Datenspeicherung oder von spezialisierten Sicherungs-/Wiederherstellungslösungen übernommen werden.

Schutz von Daten bei der Übertragung

Dapr-Seitenwagen verwenden SSL-Tunnel, wenn sie miteinander kommunizieren, so dass die Daten über sichere Kanäle ausgetauscht werden. Dadurch werden Bedrohungen wie Abhören und Man-in-the-Middle-Angriffe vermieden.

Wenn Dapr Nachrichten an einen Messaging-Backbone sendet und von diesem empfängt, authentifiziert es sich gegenüber dem entsprechenden Dienst mit der von diesem Dienst geforderten Authentifizierungsmethode. Die meisten dieser Dienste benötigen gesicherte Kanäle, wenn Daten ausgetauscht werden.

Falls gewünscht, können die Anwendungen zusätzliche Schutzmaßnahmen zur Datenintegration wie Verschlüsselung und digitale Signaturen anwenden. Dies ist eine Frage der Anwendung und wird von Dapr nicht abgedeckt.

Du fragst dich vielleicht, ob eine Verschlüsselungs-/Entschlüsselungs-Middleware entwickelt werden könnte um eine automatische Ver-/Entschlüsselung zu ermöglichen, bevor die Daten auf die Leitung gebracht werden. Das würde funktionieren, allerdings mit einer Einschränkung: Die Dapr-Tracing-Middleware wird ganz oben in den Middleware-Stack eingefügt. Das bedeutet, dass die Daten möglicherweise im Klartext protokolliert werden (wenn die Protokollierung des Nachrichtentextes aktiviert ist), bevor sie die Verschlüsselungsschicht erreichen. Wir halten dies für sinnvoll, da verschlüsselte Protokolle bei der Diagnose schwieriger zu verwenden sind. Wenn du sensible Daten verschlüsseln musst, bevor sie protokolliert werden, kannst du einen benutzerdefinierten Exporter schreiben, um bestimmte Datenfelder, wie z. B. personenbezogene Daten, zu verschleiern, bevor du das Protokoll in nachgelagerte Systeme schreibst.

Der beste Weg, Daten während der Übertragung zu schützen, ist, sie überhaupt nicht zu übertragen. Das Dapr-Akteursmodell ( ), das wir in Kapitel 5 vorstellen werden, ermöglicht die Kapselung von Zuständen, so dass der Zustand eines Akteurs nur vom Akteur selbst verwaltet wird. Anstatt zum Beispiel eine Bestellung über Dienste zu senden, kannst du eine Bestellung als Akteur kapseln. Alle möglichen Aktionen für die Bestellung werden über die Methoden des Akteurs ausgeführt.

Es gibt etablierte Methoden und Protokolle zum Schutz von Daten im Ruhezustand und zum Schutz von Daten bei der Übertragung. Der Schutz von Daten während der Nutzung, den wir im Folgenden kurz behandeln, ist viel schwieriger.

Schutz von Daten im Einsatz

Unabhängig davon, wie die Daten im Ruhezustand und während der Übertragung verschlüsselt und geschützt sind, werden sie normalerweise im Klartext verarbeitet. Die Wahrscheinlichkeit, dass sich ein Hacker Zugang zu einem laufenden Prozess verschafft, ist gering. Allerdings zielen solche Angriffe oft auf hochwertige Ziele wie Finanzdaten oder Zugangsschlüssel ab. Einige der schlimmsten Informationslecks wurden auf schurkische Insider zurückgeführt, die manchmal über administrative Rechte verfügten.

An den Kanten ist die Situation noch komplizierter. Eine einzigartige Herausforderung beim Edge Computing (im Vergleich zur Cloud) besteht darin, dass ein Angreifer ein manipuliertes Gerät mit der Computerebene verbinden kann, um sensible Nutzerdaten abzugreifen.

Zum Glück gibt es ein paar Möglichkeiten, Daten vor privilegierten Nutzern zu schützen. Zum Beispiel verwendet vertrauliche Datenverarbeitung eine vertrauenswürdige Ausführungsumgebung (TEE, auch Enklave genannt). Eine software- oder hardwarebasierte TEE schafft eine isolierte Ausführungsumgebung, die von niemandem, auch nicht vom Systemadministrator, von außen beobachtet werden kann. Ein TEE kann eine Bescheinigung anfordern (ein Mechanismus, mit dem Software ihre Identität nachweisen kann), um sicherzustellen, dass nur genehmigter Code ausgeführt wird.

Auf der Ebene der Algorithmen ermöglicht die sichere Mehrparteienberechnung (MPC) mehreren Parteien, gemeinsam eine Funktion über ihre Eingaben zu berechnen, während die Eingaben geheim bleiben.

Zum Zeitpunkt der Erstellung dieses Artikels hat Dapr keine Pläne, um den Schutz von Daten während der Nutzung zu unterstützen. Eine Möglichkeit, wie Dapr bei der vertraulichen Datenverarbeitung helfen kann, ist die Integration mit dem Open Enclave SDK, um die Erstellung von Enklaven, die Bereitstellung von Code, die Bescheinigung und die Kommunikation zwischen vertrauenswürdigen und nicht vertrauenswürdigen Komponenten zu kapseln. Dapr kann auch erweitert werden, um bestimmte MPC-Szenarien zu unterstützen. Eine benutzerdefinierte Dapr-Middleware kann zum Beispiel homomorphe Verschlüsselung bieten, sodass Daten verschlüsselt verarbeitet werden können. Außerdem können einige Machine-Learning-Modelle so angepasst werden, dass sie verschlüsselte Daten verarbeiten und die verschlüsselten Ergebnisse nur vom Eigentümer der Originaldaten entschlüsselt werden können.

Gesicherte Kommunikation

Wir haben bereits über die sichere Kommunikation gesprochen, als wir im vorherigen Abschnitt den Schutz der Daten während der Übertragung besprochen haben. Es gibt jedoch noch einen weiteren Übertragungskanal, den wir berücksichtigen müssen: den Kommunikationskanal zwischen einem Dapr-Sidecar und dem Anwendungsprozess, den es bedient. In einer Sidecar-Architektur befinden sich das Sidecar und die Anwendung, an die es angehängt ist, in derselben Sicherheitsdomäne, in der sie im Klartext miteinander kommunizieren können. Wir haben jedoch von unseren Kunden gehört, dass sie einen tiefgreifenden Schutz mit gesicherten Kanälen zwischen dem Dapr-Sidecar und der Anwendung wünschen. Das macht Sinn, denn der Dapr-Sidecar arbeitet auch als unabhängiger Prozess. Zum Zeitpunkt der Erstellung dieses Artikels wurde diese Funktion auf die Roadmap gesetzt; bitte konsultiere die Online-Dokumentation für Updates.

Erkennung von Eindringlingen und Anomalien

Obwohl Dapr von Haus aus über keine Funktionen zur Erkennung von Eindringlingen oder Anomalien verfügt, ist die Integration mit solchen Systemen kein weit hergeholtes Ziel. Eine angepasste Dapr-Middleware kann zum Beispiel Datenpaketduplikate an ein auf maschinellem Lernen basierendes System zur Erkennung von Anomalien senden, um sie zu trainieren und daraus Schlüsse zu ziehen, ohne die Anwendung selbst zu beeinträchtigen.

Dapr bietet eine proaktive Ratenbegrenzung, um eine übermäßige Anzahl von Serviceanrufen zu vermeiden. Dies geschieht über eine von der Community bereitgestellte Middleware. Die Implementierung verwendet Tollbooth, eine generische Middleware zur Ratenbegrenzung von HTTP-Anfragen auf der Grundlage des Token Bucket Algorithmus. Der Algorithmus legt Token in einem imaginären Bucket mit einer festen Rate ab. Jede Anfrage verbraucht eine bestimmte Anzahl von Token, die proportional zur Größe der Nachricht ist. Wenn eine Anfrage eingeht und genügend Token im Eimer sind, um für die Anfrage "ausgegeben" zu werden, wird die Anfrage bearbeitet. Andernfalls wird die Anfrage abgelehnt. Wenn eine Anfrage abgelehnt wird, enthält die Antwort Kopfzeilen wie X-Rate-Limit-Limit mit dem maximalen Anfragelimit und X-Rate-Limit-Duration mit der Dauer des Ratenbegrenzers. Dies sind Signale an den Kunden, sich mit Anfragen zurückzuhalten.

Die Ratenbegrenzung kann zur Abwehr einiger Arten von Angriffen eingesetzt werden. Ein normaler Benutzer kann zum Beispiel seine Anmeldedaten nicht öfter als ein paar Mal pro Sekunde eingeben. Wenn du viele schnelle aufeinanderfolgende Anmeldeversuche siehst, wird dein Dienst wahrscheinlich von einem bösartigen Skript angegriffen, das versucht, das Passwort zu erraten; die Ratenbegrenzung kann vor einem solchen Brute-Force-Versuch schützen. Die Ratenbegrenzung kann jedoch ein zweischneidiges Schwert sein, da sie nicht zwischen legitimem und bösartigem Datenverkehr unterscheidet. Wenn deine Website von einem Denial-of-Service (DoS)- oder Distributed-Denial-of-Service (DDoS)-Angriff betroffen ist, kannst du die Ratenbegrenzung zwar einsetzen, um eine Überlastung deines Servers zu vermeiden, aber du wirst auch legitimen Datenverkehr abweisen, weil ein einfaches Ratenbegrenzungssystem nur den gesamten Datenverkehr kontrolliert.

Einige fortschrittliche Richtlinien zur Ratenbegrenzung, wie z. B. die Beschränkung auf nicht autorisierte Anfragen (z. B. durch die Überprüfung auf das Vorhandensein eines Autorisierungs-Headers), können einen besseren Schutz gegen DDoS-Angriffe bieten. Wir würden uns freuen, wenn Sicherheitsexperten in der Community uns helfen, die ratenbegrenzende Middleware weiter zu verbessern .

Wenn es um die Sicherheit geht, wollen wir offen und ehrlich sein. In den vorangegangenen Diskussionen haben wir dargelegt, wie Dapr bei bestimmten Sicherheitsaspekten jetzt helfen kann, wie es wahrscheinlich in Zukunft helfen kann und in welchen Bereichen die Hilfe der Community benötigt wird, um weitere Verbesserungen zu erreichen. Der Rest des Kapitels behandelt detaillierter, was Dapr heute bietet. Da Dapr schnell weiterentwickelt wird, solltest du die Online-Dokumentation konsultieren, um dich über die neuesten Aktualisierungen der Sicherheitsfunktionen zu informieren.

Dapr Sicherheitsmerkmale

Zum Zeitpunkt der Erstellung dieses Artikels bietet Dapr eine Handvoll Sicherheitsfunktionen, darunter geheime Speicher, eine geheime API und gegenseitiges TLS.

Geheime Läden

Geheimspeicher sind dafür gedacht, sensible Informationen wie Zertifikate und Passwörter zu speichern. Der Unterschied zwischen einer Datenbank und einem geheimen Speicher besteht darin, dass ein geheimer Speicher zusätzliche Mechanismen und Beschränkungen anwendet, um die gespeicherten Informationen weiter zu schützen, z. B:

Eingeschränkte API-Oberfläche und Zugriffskontrolle
Ein Secret Store erfordert oft bestimmte Anmeldedaten und Serverrollen.
Verschlüsselung im Ruhezustand
Einige Secret Stores verschlüsseln geheime Daten im Ruhezustand automatisch mit einem vom Store kontrollierten Schlüssel oder einem vom Benutzer bereitgestellten Schlüssel. Beachte, dass der Kubernetes-Geheimspeicher Geheimnisse als Base-64-kodierte Daten im zugrunde liegenden etcd-Speicher speichert. Die Daten sind standardmäßig nicht verschlüsselt, aber du kannst dich für eine Verschlüsselung im Ruhezustand entscheiden. Weitere Informationen findest du in der Kubernetes-Dokumentation.
Hardware-Schutz
Sicherheitsspeicher wie Azure Key Vault verwenden Hardware-Sicherheitsmodule (HSMs), um Geheimnisse mit spezieller Hardware zu schützen.

Wie andere Komponenten auch, unterstützt Dapr steckbare Geheimspeicher über eine Schnittstelle für Geheimspeicher. Zum Zeitpunkt der Erstellung dieses Artikels unterstützt Dapr die folgenden Geheimverzeichnisse:

  • Kubernetes Geheimlager

  • Azure Key Vault

  • HashiCorp Tresor

  • AWS Secrets Manager

  • Google Cloud KMS

  • Google Secret Manager

Dapr bietet eine eingebaute Unterstützung für den Kubernetes-Geheimspeicher, sodass keine spezielle Konfiguration erforderlich ist, um diesen einzurichten. Andere Geheimspeicher können durch Manifeste zur Beschreibung von Geheimspeichern beschrieben werden. Das folgende Manifest beschreibt zum Beispiel einen Azure Key Vault:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: azurekeyvault
spec:
  type: secretstores.azure.keyvault
  metadata:
  - name: vaultName
    value: "<your key vault name>"
  - name: spnTenantId
    value: "<your service principal tenant ID>"
  - name: spnClientId
    value: "<your service principal app ID>"
  - name: spnCertificateFile
    value : "<pfx certificate file local path>"

Sobald du einen Azure Key Vault definiert hast, kannst du Azure-Tools wie die Azure CLI verwenden, um darin Geheimnisse zu speichern. Das folgende Beispiel für einen Azure CLI-Befehl erstellt ein Geheimnis namens redisPassword in einem Azure Key Vault:

az keyvault secret set --name redisPassword --vault-name <your key vault name> 
--value "<your Redis password>"

Wenn du dann andere Komponenten definierst, kannst du auf die Geheimnisse in deinem geheimen Speicher verweisen, indem du ein secretKeyRef Element verwendest. Das folgende Beispiel-Komponentenmanifest definiert einen Redis-Status-Speicher. Das Passwort des Speichers wird in Azure Key Vault als redisPassword secret gespeichert und durch ein secretKeyRef Element referenziert:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
spec:
  type: state.redis
  metadata:
  - name: redisHost
    value: "redis-master:6379"
  - name: redisPassword
    secretKeyRef:
      name: redisPassword
auth:
    secretStore: azurekeyvault

Die Geheimhaltungsfunktion von Dapr wurde nur für den internen Gebrauch von Dapr entwickelt. Später forderten unsere Kunden eine Geheimnis-API, über die Anwendungscode auf gespeicherte Geheimnisse zugreifen kann. Wir werden diese API in Kürze vorstellen.

Es ist unwahrscheinlich, dass du selbst einen Geheimladen einrichten musst. Für den Fall, dass du es doch brauchst, findest du im folgenden Abschnitt eine kurze Einführung.

Einen Secret Store einrichten

Dapr definiert einen Geheimspeicher als eine einfache Schnittstelle, die eine Init Methode und eine GetSecret Methode enthält, wie im folgenden Codeschnipsel gezeigt:

type SecretStore interface {
    Init(metadata Metadata) error
    GetSecret(req GetSecretRequest) (GetSecretResponse, error)
}

Die Struktur GetSecretRequest enthält einen Schlüssel und eine Sammlung von Schlüssel/Wertpaaren, die als Metadaten an die Anfrage angehängt werden:

type GetSecretRequest struct {
    Name     string            `json:"name"`
    Metadata map[string]string `json:"metadata"`
}

Dapr interpretiert die Metadaten nicht in irgendeiner Weise. Stattdessen übergibt es einfach alle angehängten Metadaten an die Implementierung des Secret Store. Dieses Design dient dazu, Fälle zu behandeln, in denen ein Secret Store mehr Informationen als den Namen des Geheimschlüssels benötigt, um auf ein Geheimnis zuzugreifen. Die Abfrage solcher Metadaten macht den Code, der deinen Security Store nutzt, weniger portabel. Obwohl andere Speicher die Metadaten ignorieren können und wie gewohnt funktionieren, können dieselben Metadatenschlüssel versehentlich von mehreren Geheimspeichern ausgewählt und von verschiedenen Speichern unterschiedlich interpretiert werden, was zu unvorhersehbaren Fehlern führt. Es wird dringend empfohlen, in der Methode Init genügend Informationen zu erfassen, damit die Geheimnisse nur über den Namen des Geheimschlüssels abgerufen werden können.

Die Struktur GetSecretResponse enthält ein Schlüssel/Wert-Paar mit geheimen Daten:

type GetSecretResponse struct {
    Data map[string]string `json:"data"`
}

Wenn der angeforderte Schlüssel nicht gefunden wird, sollte dein Code ein error Objekt zurückgeben.

Wie bereits erwähnt, kannst du bei der Definition eines Dapr-Manifests das Element secretKeyRef verwenden, um auf Geheimnisse zu verweisen. Dapr hat auch eine API für Geheimnisse eingeführt, mit der Anwendungen über ihren Code auf Geheimnisse zugreifen können. Wir werden diese API im nächsten Abschnitt vorstellen .

Die geheime API

Dapr stellt eine geheime API zur Verfügung, die eine Anwendung nutzen kann, um ein Geheimnis aus einem geheimen Speicher am Endpunkt abzurufen v1.0/secrets/<secret store name>/<secret key name>.

Diese praktische API macht es einer Anwendung leicht, Geheimnisse abzurufen und sie in ihrem Code zu verwenden. Sie soll Entwicklern helfen, sensible Informationen wie Passwörter und Verbindungszeichenfolgen nicht in ihrem Code zu speichern. Die API ist schreibgeschützt, d. h. der Anwendungscode kann keine geheimen Schlüssel erstellen oder aktualisieren. Andererseits können die Vorgänge die Geheimnisse nach Bedarf aktualisieren, indem sie direkt Änderungen an den geheimen Speichern vornehmen, ohne den Code zu beeinflussen. Sie können zum Beispiel Zertifikate austauschen, Passwörter aktualisieren und die Verbindungszeichenfolge zu einem Datenbankkonto mit den entsprechenden Zugriffsrechten ändern.

Ironischerweise ist der Nachteil dieser API genau ihr Komfort. Einmal konfiguriert, kann der Anwendungscode beliebige geheime Schlüssel ohne Authentifizierung anfordern. Wie bereits erwähnt, werden bei der Sidecar-Architektur der Dapr-Sidecar und der Anwendungscode als in der gleichen Sicherheitsdomäne befindlich betrachtet. Daher ist es nicht unbedingt falsch, den direkten Zugriff auf die Geheimnisse zu erlauben. Es besteht jedoch eine potenzielle Gefahr: Wenn der Anwendungscode kompromittiert wird, kann der Angreifer Zugang zu allen Geheimnissen im Geheimspeicher erhalten.

Durch die Integration von Dienstidentitäten (siehe "Identität") ist Dapr in der Lage, einige automatische Authentifizierungs- und Autorisierungsmechanismen anzubieten, um den Zugriff auf Geheimnisse einzuschränken. Es kann zum Beispiel eine Richtlinie durchsetzen, die einer Anwendung nur den Zugriff auf einen bestimmten geheimen Speicher oder sogar bestimmte geheime Schlüssel erlaubt. Selbst wenn eine Anwendung kompromittiert wird, kann der Angreifer die Anwendung nicht nutzen, um Zugang zu den Geheimnissen anderer Anwendungen zu erhalten, die denselben Geheimspeicher nutzen.

Das ist so ziemlich alles, was Dapr in Bezug auf die Verwaltung von Geheimnissen bietet. Als Nächstes werden wir uns damit beschäftigen, wie Dapr die Kommunikation zwischen Dapr und Dapr durch TLS sichert.

Gegenseitiges TLS (mTLS)

Transport Layer Security (TLS), das das veraltete Secure Sockets Layer (SSL) Protokoll ersetzt, ist ein kryptografisches Protokoll, das für die sichere Kommunikation zwischen Clients und Servern verwendet wird. Standardmäßig weist TLS die Identität des Servers gegenüber dem Kunden mit einem X.509-Zertifikat des Servers nach. Optional kann es auch die Identität des Clients gegenüber dem Server mit Hilfe eines X.509-Zertifikats des Clients nachweisen. Dies wird als gegenseitiges TLS bezeichnet. Mutual TLS (mTLS) wird oft in verteilten Systemen eingesetzt, weil es in solchen Systemen schwer ist, einen Server oder einen Client zu identifizieren. Stattdessen rufen sich die Komponenten in einem Netz gegenseitig auf, so dass jede Komponente sowohl ein Server als auch ein Client sein kann. Mutual TLS stellt sicher, dass alle Dienstaufrufe zwischen den Komponenten auf beiden Seiten authentifiziert werden, indem die Zertifikate gegengeprüft werden.

Bevor wir dir erklären, wie mTLS funktioniert, brauchen wir eine kurze Erklärung der Zertifikate und der damit verbundenen Konzepte. Wenn du mit diesen Konzepten bereits vertraut bist, kannst du die folgenden Unterabschnitte auslassen.

X.509-Zertifikate

Ein X.509-Zertifikat ist ein digitales Zertifikat, das den internationalen Standard X.509 Public Key Infrastructure (PKI) verwendet. Ein Zertifikat wird von einer vertrauenswürdigen Zertifizierungsstelle (CA) ausgestellt und enthält Informationen über die vertretene Entität wie den verifizierten Entitätsnamen und die Gültigkeitsdauer des Zertifikats. Ein Zertifikat enthält außerdem den öffentlichen Schlüssel des Unternehmens und eine Signatur, die mit dem privaten Schlüssel des Unternehmens verschlüsselt wurde. Der PKI-Standard garantiert, dass die Daten mit dem privaten Schlüssel des Dateneigentümers verschlüsselt wurden, wenn man den öffentlichen Schlüssel zum Entschlüsseln der Daten verwenden kann.

Wenn du mit deinem Browser über HTTPS auf eine Website zugreifst, überprüft dein Browser das Zertifikat des Servers. Dabei wird überprüft, ob das Zertifikat von einer vertrauenswürdigen Zertifizierungsstelle ausgestellt wurde und ob der im Zertifikat enthaltene Domainname mit der Adresse übereinstimmt, auf die du zuzugreifen versuchst. Wenn beide Prüfungen erfolgreich sind, zeigt der Browser einen visuellen Hinweis an (z. B. das grüne Vorhängeschloss in Abbildung 4-2), um dir zu signalisieren, dass du sicher mit einem legitimen Server verbunden bist.

A verified HTTPS connection
Abbildung 4-2. Eine verifizierte HTTPS-Verbindung

Wenn die Zertifikatsprüfung fehlschlägt, warnt dich ein moderner Browser wahrscheinlich, dass deine Verbindung zum Server nicht sicher ist. Abbildung 4-3 zeigt ein Beispiel für eine fehlgeschlagene Zertifikatsüberprüfung. In diesem Fall ist das Zertifikat, das mit www.test.com verknüpft ist, abgelaufen (der Screenshot wurde am 29. Februar 2020 aufgenommen), so dass die Zertifikatsprüfung fehlgeschlagen ist.

Tipp

Greife immer über HTTPS auf Websites zu und überprüfe, ob ihre Zertifikate gültig sind. Auf diese Weise kannst du einige Phishing-Angriffe verhindern, bei denen ein Angreifer mit einer gefälschten Website, die eine legitime Website imitiert, versucht, dich dazu zu bringen, deine persönlichen Daten (Bankkonto- oder Kreditkartennummer, E-Mail-Adresse, Passwort usw.) an den Angreifer weiterzugeben. Wenn du in deinem Anwendungscode auf einen Webdienst zugreifst, stelle sicher, dass dein Code ebenfalls HTTPS verwendet. Wenn du einen öffentlichen Dienst anbietest, achte darauf, dass er einen HTTPS-Endpunkt hat und halte dein Zertifikat auf dem neuesten Stand.

An unverified HTTPS connection
Abbildung 4-3. Eine nicht verifizierte HTTPS-Verbindung

Eine CA wird auch durch ein Zertifikat identifiziert. Das Zertifikat wird in den Zertifikatsspeicher auf deinem Computer importiert. Es kann mehrere CA-Ebenen geben; eine Behörde ohne übergeordnete Stelle wird als Root-CA bezeichnet. Die Zertifikate der Stammzertifizierungsstellen werden in den Speicher der vertrauenswürdigen Stammzertifizierungsstellen importiert. Eine untergeordnete CA benötigt ein Ausstellerzertifikat von ihrer übergeordneten CA, um neue Zertifikate auszustellen. Diese Zertifikate werden miteinander verknüpft, wobei das Stammzertifikat von der Stammzertifizierungsstelle ausgestellt wird. Wenn du ein Zertifikat validierst, musst du die Zertifikatskette bis zu einem validierten Stammzertifikat verfolgen .

Beantragung eines X.509-Zertifikats

Um ein Zertifikat bei einer CA anzufordern, erstellt der Antragsteller zunächst ein öffentliches/privates Schlüsselpaar. Dann erstellt er eine Zertifikatsignierungsanforderung (CSR), die seinen öffentlichen Schlüssel und die angeforderten Felder, wie den Domänennamen, enthält. Er signiert die CSR mit seinem eigenen privaten Schlüssel und sendet die CSR an die CA. Die CA prüft die CSR mit dem öffentlichen Schlüssel des Antragstellers. Dann erstellt sie ein digitales Zertifikat, das die angeforderten Felder, den öffentlichen Schlüssel des Antragstellers und den öffentlichen Schlüssel der CA enthält. Das digitale Zertifikat wird mit dem privaten Schlüssel der CA signiert und an den Antragsteller zurückgeschickt.

Jetzt, wo du ein Verständnis für Zertifikate hast, können wir zu Dapr mTLS übergehen.

Dapr mTLS

Gegenseitiges TLS erfordert, dass sich jede Partei mit einem Zertifikat identifiziert,. Um ein Zertifikat zu erhalten, musst du mit einer vertrauenswürdigen CA zusammenarbeiten. Die Einrichtung einer Zertifizierungsstelle und die Beantragung von Zertifikaten ist nicht kompliziert, aber etwas, das Entwicklern oft keinen Spaß macht. An dieser Stelle kommt Dapr ins Spiel. Es hostet selbst einen CA-Dienst, automatisiert den Prozess der Zertifikatserstellung und stellt einen sicheren Kommunikationskanal zwischen den Dapr-Sidecars her. Wenn dein Anwendungscode Dapr-Sidecars zur Kommunikation nutzt, wird der gesamte Datenverkehr automatisch über den gesicherten HTTPS-Kanal gesendet, ohne dass du etwas Besonderes in deinem Code tun musst.

Die mTLS-Architektur von Dapr ist so konzipiert, dass sie sowohl im Kubernetes-Modus als auch im Standalone-Modus funktioniert. Der Hauptunterschied zwischen den beiden Modi besteht darin, wo das Root-Zertifikat gespeichert wird, wie im folgenden Abschnitt erklärt wird.

Dapr mTLS Architektur

Dapr wird mit einer Systemkomponente namens Sentry ausgeliefert, die als CA fungiert. Die CA nimmt ein vom Benutzer bereitgestelltes Stammzertifikat oder erstellt ein selbst signiertes Zertifikat als Stammzertifikat. Wenn ein neuer Dapr-Sidecar startet, wird das Stammzertifikat als vertrauenswürdiges Stammzertifikat in den Sidecar injiziert. Dann fordert der Dapr-Sidecar ein neues Workload-Zertifikat von Sentry an. Schließlich authentifizieren sich zwei Dapr-Sidecars gegenseitig mit den entsprechenden Workload-Zertifikaten. Abbildung 4-4 veranschaulicht, wie der gesamte Prozess abläuft, und die Schritte werden hier etwas ausführlicher beschrieben:

  1. Optional kann ein Betreiber ein Stammzertifikat in den Kubernetes-Geheimspeicher (im Kubernetes-Modus) oder in ein Dateisystem laden.

  2. Sentry liest das vom Benutzer bereitgestellte Stammzertifikat oder erstellt bei Bedarf ein selbstsigniertes Zertifikat als Stammzertifikat selbst. Wenn das Stammzertifikat ersetzt wird, übernimmt Sentry automatisch das neue Zertifikat und baut die Vertrauenskette neu auf.

  3. Wenn der Sidecar-Injektor ein Dapr-Sidecar injiziert, ruft er das Stammzertifikat ab und injiziert es in das Dapr-Sidecar.

  4. Wenn der Dapr-Sidecar initialisiert wird, prüft er, ob TLS aktiviert ist. Wenn ja, sendet es eine CSR an Sentry. Sentry stellt ein Workload-Zertifikat aus, das 24 Stunden lang gültig ist und standardmäßig eine Zeitverschiebung von 15 Minuten zulässt. Die Zeitverschiebung dient dazu, Fehler bei der Zertifikatsvalidierung aufgrund von Zeitverschiebungen zu vermeiden.

  5. Dapr-Sidecars verwenden Workload-Zertifikate, um sich gegenseitig zu authentifizieren und einen sicheren, verschlüsselten Kommunikationskanal aufzubauen.

Dapr’s mutual TLS architecture
Abbildung 4-4. Die gegenseitige TLS-Architektur von Dapr

Sentry konfigurieren

Die Konfiguration von Sentry wird durch eine Dapr-Konfigurationsdatei beschrieben, die in etwa so aussieht:

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: default
spec:
  mtls:
    enabled: true
    workloadCertTTL: "24h"
    allowedClockSkew: "15m"

Wenn du im Kubernetes-Modus arbeitest, kannst du kubectl verwenden, um Dapr-Konfigurationen anzuzeigen und zu aktualisieren:

kubectl get configurations/<configuration name> --namespace <Dapr namespace> 
-o yaml
kubectl edit configurations/<configuration name> --namespace <Dapr namespace>

Lösche dann den Sentry Pod, damit der Ersatz-Pod die neue Konfiguration übernehmen kann :

kubectl delete pod --selector=app=dapr-sentry --namespace <Dapr namespace>

Im Standalone-Modus können Sie den Sentry-Prozess mit dem Schalter --issuer-certificate starten, um ein Root-Zertifikat zu laden, und den Schalter --config verwenden, um eine benutzerdefinierte Konfigurationsdatei zu laden:

./sentry --issuer-credentials $HOME/.dapr/certs --trust-domain cluster.local 
--config=./my-config.yaml

Um Anwendungscode mit aktiviertem mTLS zu starten, musst du eine Dapr-Konfigurationsdatei mit aktiviertem mTLS bereitstellen:

dapr run --app-id myapp --config ./mtls-config.yaml node myapp.js

Dapr mTLS bietet sichere Kommunikationskanäle zwischen Dapr-Sidecars. Es verbirgt die Komplexität der Zertifikatsverwaltung vor den Entwicklern.

Zusammenfassung

Zum Zeitpunkt der Erstellung dieses Artikels bietet Dapr eine Reihe grundlegender Sicherheitsfunktionen, darunter die Verwaltung von Geheimnissen, eine geheime API und gegenseitige TLS-Unterstützung. Einige zusätzliche Sicherheitsfunktionen sind in Planung und wir würden uns über dein Feedback und deine Beiträge freuen.

Damit ist unsere Diskussion über die Grundlagen von Dapr abgeschlossen. Der Rest des Buches wird sich auf verschiedene Anwendungsszenarien und Entwurfsmuster mit Dapr konzentrieren.

Get Dapr lernen now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.