Wir bringen eine Java-Anwendung in die Cloud - Teil 5

Migration nach AWS: Verschlüsselung für Java-Entwickler

Steffen Grunwald

©Shutterstock / Yabresse

In den vier vorangegangenen Teilen dieser Serie haben wir uns mit der schrittweisen Optimierung einer Anwendung hin zu einer Serverless Architecture beschäftigt. Dieser Teil legt den Fokus auf eine der wichtigsten Sicherheitsmaßnahmen jeder Anwendung: Verschlüsselung von Daten.

Bei Amazon Web Services (AWS) empfehlen wir das Architekturprinzip „Encrypt Everything“. Es war selten so kostengünstig und einfach, eben dieses Prinzip auf hohem Standard zu verwenden, wie nun mit Cloud-Diensten. Dieser Artikel zeigt, wie Daten auf verschiedenen Ebenen verschlüsselt werden können – und welche AWS-Dienste diesbezüglich relevant sind. Dabei arbeiten wir uns von der einfachen One-Click-Lösung vor bis hin zur Verschlüsselung auf Feldebene in einer Datenbank.

Artikelserie

Teil 1: Warum wechseln?

Teil 2: Verwendung von Managed Services

Teil 3: Verwendung von Containern

Teil 4: Serverless mit AWS Lambda

Teil 5: Verschlüsselung für Java-Entwickler

Teil 6: Optimierung der Architektur

Verschlüsselung ist ein wichtiges Werkzeug, das Nutzern der Cloud hohe Sicherheit gibt, den alleinigen Zugriff auf ihre Daten zu kontrollieren. Auch regulatorische und industriespezifische Anforderungen legen nahe, sensible Daten durch eine Anwendung vor unautorisiertem Zugriff oder Veränderung zu schützen.

Im Allgemeinen wird unterschieden zwischen Verschlüsselung at rest (zur Persistierung) und in transit (zur Übertragung). Dieser Artikel konzentriert sich auf die Verschlüsselung persistenter Daten. Sie gilt als zusätzlicher Schutz neben der Berechtigungsvergabe von Aktionen für bestimmte Ressourcen mit Hilfe von AWS Identity and Access Management (IAM) und z. B. Berechtigungen, die bei einer relationalen Datenbank für Benutzer vergeben werden.

Die große Herausforderung bei Verschlüsselung ist, dass wirklich alles richtig gemacht werden muss. Ein kleiner Fehler bei der Wahl des Schlüssels und des Verschlüsselungsverfahrens kann dazu führen, dass der Schutz, der durch Verschlüsselung erreicht werden soll, nicht effektiv ist. Durch eine falsche Handhabung des Schlüssels kann dieser in fremde Hände gelangen oder verloren gehen. Im ersten Fall werden damit möglicherweise Daten offenbart. Im anderen können die Daten nicht mehr entschlüsselt werden und sind für immer nutzlos.

Key Management mit Hardware Security Modules

Bevor wir in die Verwendung von Schlüsseln eintauchen, betrachten wir die Erzeugung und Speicherung von Schlüsseln. Zu diesem Zweck gibt es Hard- und Softwarelösungen, die an Kriterien wie Wartbarkeit, Kosten, Ausfallsicherheit, Skalierbarkeit, Schutz vor Schlüsselextraktion und Manipulation, Integration in andere Lösungen und Auditierbarkeit gemessen werden. Hardware Security Modules (HSM) bieten einen sehr hohen Schutz vor Schlüsselextraktion. Ver- und Entschlüsselung finden in dem Modul statt und werden protokolliert. Erkennt das Modul Anzeichen physischer Manipulation, werden die Schlüssel automatisch vernichtet. Viele Kunden entscheiden sich wegen des hohen Schutzniveaus bei der Verwaltung des Schlüsselmaterials im selbstverwalteten Rechenzentrum für eine derartige Lösung und erwarten eine solche auch in der Cloud.

Schlüsselverwaltung im AWS Key Management Service

In AWS können Kunden Schlüssel durch den AWS Key Management Service (KMS) verwalten. Sie legen darin sogenannte Customer Master Keys (CMK) an (Kasten: „Arten von Customer Master Keys“). Ein CMK enthält Metadaten, die Verbindung zu dem IAM-System sowie sogenannte HSM Backing Keys (HBK). Die HBKs sind das Schlüsselmaterial, mit dem KMS effektiv operiert und mit dem Inhalte durch KMS ver- und entschlüsselt werden. AWS übernimmt die Skalierung und Wartung der an das KMS Frontend angeschlossenen HSMs. KMS bietet über sein Application Programming Interface (API) eine hohe Integration mit derzeit über fünfzig anderen AWS-Diensten [1], wie zum Beispiel Amazon Elastic Block Store Volumes (EBS) oder dem Amazon Relational Database Service (RDS). Es kann mit Hilfe eines AWS Software Developer Kits (SDK) auch direkt aus einer Anwendung heraus genutzt werden. Jede Verwendung von CMKs wird lückenlos in AWS CloudTrail protokolliert – zwecks Auditierung davon, wann und von wem welcher Schlüssel wie für welche Ressource verwendet wurde. Diese Eigenschaften werden regelmäßig von unabhängigen Prüfern validiert und zertifiziert, zum Beispiel in den Compliance-Programmen FIPS 140-2 und SOC, die über AWS Artifact [2] einsehbar sind. Für mehr Informationen zu KMS sei hier auf das Whitepaper zu KMS Cryptographic Details [3] verwiesen.

Abb. 1: Schematischer Aufbau des AWS Key Management Service

Abb. 1: Schematischer Aufbau des AWS Key Management Service

Arten von Customer Master Keys

CMK werden in den folgenden Varianten von AWS-Diensten verwendet:

  • AWS-owned CMKs werden von AWS außerhalb des Kunden-AWS-Accounts verwaltet. Tabellen in der NoSQL-Datenbank Amazon DynamoDB werden z. B. immer mit einem solchen CMK verschlüsselt, wenn der Kunde keinen anderen CMK bestimmt. Die CMKs sind regionsspezifisch (z. B. für Frankfurt oder Irland), werden aber für mehrere AWS-Accounts verwendet.

  • AWS-managed CMKs werden von AWS verwaltet. Sie sind kunden-, regions- und Service-spezifisch, d. h. der CMK, der sich zum Beispiel hinter dem Alias aws/s3 verbirgt, wird in nur einem AWS-Account und in einer Region verwendet.

  • Customer-managed CMKs werden vom Kunden verwaltet. Im Gegensatz zu den zuvor genannten CMKs kann der Kunde hier selbst über die Key Policy Deaktivierung, Löschung und Rotation bestimmen.

  • Customer-managed CMKs with imported key material erlauben dem Kunden, eigenes Schlüsselmaterial zu importieren. Der Kunde kann es bei Bedarf löschen und zu einem späteren Zeitpunkt wieder importieren.

Die Wahl einer CMK-Variante ist abhängig von den Anforderungen und dem Service. Oft fällt die Wahl auf Customer-managed CMKs, wenn ein Kunde den Lebenszyklus des CMKs voll kontrollieren will und Berechtigungen feingranular erteilen möchte. Dem stehen im Vergleich zu einem selbst verwalteten HSM geringe Kosten von derzeit einem US-Dollar pro Monat und Schlüsselversion gegenüber. Hinzu kommen nur noch die Kosten für die Anzahl der Anfragen – z. B. 0,03 US-Dollar pro 10 000 Anfragen in der EU-Regio (Frankfurt) von AWS.

Envelope Encryption

Eine einzige Ver- oder Entschlüsselungsoperation von KMS kann bis zu vier Kilobyte Daten verschlüsseln. Anwendungen verschlüsseln aber oft Daten nicht direkt mit KMS, sondern nutzen Envelope Encryption. Dabei erzeugt KMS einen Data Key und gibt diesen unter einem CMK verschlüsselt und im Klartext an die Anwendung. Die Anwendung verschlüsselt die Daten mit dem Data Key, speichert den verschlüsselten Data Key zusammen mit den verschlüsselten Daten und löscht deren jeweilige Klartexte aus dem Speicher. Dieser Mechanismus vermeidet Latenz bei der Datenübertragung: Die erzeugten 256-Bit-Schlüssel sind meist kleiner und schneller zu übermitteln als die zu verschlüsselnden Daten. Außerdem ist für die Verschlüsselung von Objekten, die größer als vier Kilobyte sind, nur ein einziger Aufruf in KMS erforderlich.

Abb. 2: Bei der Envelope Encryption liefert KMS den Data Key, die Anwendung speichert ihn zusammen mit den Daten verschlüsselt ab

Abb. 2: Bei der Envelope Encryption liefert KMS den Data Key, die Anwendung speichert ihn zusammen mit den Daten verschlüsselt ab

Volumes und Datenbanken mit einem Klick verschlüsseln

Ähnlich wie im vorangegangenen Beispiel verschlüsselt auch Amazon EBS Volumes einer EC2-Instanz mit Hilfe von Envelope Encryption und KMS. Der Benutzer wählt dazu bei der Erstellung einer EC2-Instanz den CMK aus. Das EBS-Subsystem generiert durch KMS individuell für jedes Volume einen verschlüsselten Data Key und übergibt diesen an den EC2-Host. Der Host nutzt KMS bei jedem Start der EC2-Instanz, um den Data Key zu entschlüsseln. Nur der verschlüsselte Data Key wird dauerhaft gespeichert. Bei der Erstellung einer Datenbank in Amazon RDS greift derselbe Mechanismus. Amazon RDS nutzt die Amazon-EBS-Verschlüsselung, um Datenbank-Volumes vollständig zu verschlüsseln.

Um eine generelle Verschlüsselung von EC2 Volumes für eine Region zu erzwingen, wählt ein Benutzer einen CMK in den EC2-Settings [4] aus und legt fest, dass EC2 in der jeweiligen Region ausschließlich verschlüsselte Volumes erstellen darf.

Abb. 3: Die Verschlüsselung eines EBS Volumes in der AWS Console mit einem Klick

Abb. 3: Die Verschlüsselung eines EBS Volumes in der AWS Console mit einem Klick

Feingranulare Verschlüsselung von Daten in der Anwendung

Mit der zuvor beschriebenen Verschlüsselung der Datenbank auf Volume-Ebene sind Daten des Volume nur lesbar, wenn der Zugriff von RDS auf den CMK erteilt wurde, der bei der Erstellung der Datenbank vergeben wurde. Ist die Datenbank gestartet, kann eine Anwendung jedoch alle Daten in der Datenbank im Klartext lesen – entsprechende Datenbankberechtigungen vorausgesetzt.

Eine Anwendung kann zusätzlich KMS nutzen, um Daten auf Feldebene mit Envelope Encryption zu verschlüsseln. Zum Beispiel könnten die Passwörter in einem Passwortmanager so individuell verschlüsselt werden. Der Vorteil ist der feingranulare Schutz mit einem individuellen Schlüssel pro Datensatz, eine umfangreiche Protokollierung aller Schlüsseloperationen und der Nachweis der Integrität der Daten.

Die Schritte, die eine Anwendung zur Verschlüsselung machen muss, sind folgende:

  1. Die Anwendung fordert einen neuen Data Key zu einem CMK in KMS an. KMS liefert den Data Key sowohl im Klartext als auch verschlüsselt mit dem CMK an die Anwendung.

  2. Die Anwendung verschlüsselt ein Feld mit dem Data Key mit einem geeigneten Verschlüsselungsalgorithmus.

  3. Das verschlüsselte Feld und der verschlüsselte Data Key werden von der Anwendung in einem einzigen Chiffriertext enkodiert.

  4. Die Anwendung speichert den Chiffriertext in der Datenbank.

  5. Die Anwendung löscht den unverschlüsselten Data Key aus dem Speicher.

Die Anwendung könnte zwar direkt das KMS API nutzen. Das AWS Encryption SDK for Java [5] erleichtert jedoch die Schritte 1 bis 3 mit wenigen Zeilen Code, wie in Listing 1 zu sehen ist.

String password = "verysecret";
AwsCrypto crypto = new AwsCrypto();
Map<String, String> encContext = Collections.singletonMap("USER", "steffeng");
KmsMasterKeyProvider keyProvider = KmsMasterKeyProvider.builder()
  .withDefaultRegion("eu-central-1")
  .withKeysForEncryption("arn:aws:kms:eu-central-1:<ACCOUNT_ID>:alias/prod/passwordManager")
  .build();
CryptoResult<String, KmsMasterKey> cryptoResult =
  crypto.encryptString(keyProvider, password, encContext);
String cipherText = cryptoResult.getResult();

Das AWS Encryption SDK (AwsCrypto) verschlüsselt das geheime Passwort in Frankfurt (eu-central-1) unter dem Schlüssel mit dem Alias prod/passwordManager. Dabei wird der Encryption Context mit dem Benutzernamen des Passwortbesitzers mit in den Chiffriertext eingebunden. cipherText ist ein langer String wie z. B. AYADeE74xUvbUyPPx9[…].

Mit den Defaulteinstellungen aus dem Codebeispiel verwendet das AWS Encryption SDK zur Verschlüsselung den Advanced Encryption Standard (AES) im Galois Counter Mode (GCM) mit 256-Bit-Schlüsseln.

Encryption Context

In der dritten Codezeile fällt der Encryption Context auf, der einen zusätzlichen Schutzmechanismus bietet. Wenn ein Angreifer die Datenbank unseres Passwortmanagers vollständig unter Kontrolle brächte, könnte er alle Werte auslesen und verändern. Ohne CMK-Berechtigung sind die Informationen nutzlos. Tauscht er jedoch ein eigenes verschlüsseltes Passwort gegen das eines anderen Benutzers aus, ist ihm der Zugriff auf den Klartext des Passworts über die Anwendung möglich. Der Encryption Context schützt vor diesem Szenario. Die Verschlüsselung bindet den optionalen Encryption Context als sogenannte Additionally Authenticated Data in den Chiffriertext ein. Beim Entschlüsseln wird damit eine Manipulation erkannt. Im Codebeispiel ist der Benutzername, dem das Passwort gehört, in den Encryption Context eingebunden. Es lassen sich aber noch weitere Informationen wie die ID der Passwortseite oder der Umgebungsname hinzufügen.

Ein Codebeispiel für eine Entschlüsselungsoperation ist in Listing 2 aufgeführt. Sollte der Encryption Context nach der Entschlüsselung abweichen, deutet das auf einen Fehler oder eine Manipulation hin. Auf keinen Fall sollte dann der Wert im Klartext dem Benutzer gezeigt werden.

String cipherText = "AYADeE74xUvbUyPPx9RlzvlAEJ0AbwACAARVU0VSAAhzdGVmZmVuZwAVYXdzLWNyeXB0by1wdWJ[...]";
AwsCrypto crypto = new AwsCrypto();
Map<String, String> encContext = Collections.singletonMap("USER", "steffeng");
KmsMasterKeyProvider keyProvider = KmsMasterKeyProvider.builder()
  .withDefaultRegion("eu-central-1")
  .withKeysForEncryption("arn:aws:kms:eu-central-1:<ACCOUNT_ID>:alias/prod/passwordManager")
  .build();
CryptoResult<String, KmsMasterKey> cryptoResult =
  crypto.decryptString(keyProvider, cipherText);
boolean contextMatch = encContext.entrySet().stream()
  .allMatch(entry -> entry.getValue()
  .equals(cryptoResult.getEncryptionContext().get(entry.getKey())));
String password = cryptoResult.getResult();

Der Chiffriertext wird vom AWS Encryption SDK entschlüsselt. Nach der Verschlüsselung ermittelt der Code, ob der entschlüsselte Encryption Context die erwarteten Werte enthält, dargestellt durch die Variable contextMatch.

Nicht nur das AWS Encryption SDK, sondern auch das KMS API für Ver- und Entschlüsselung unterstützen einen Encryption Context. Im Unterschied zum eigenen Anwendungscode wird der Encryption Context automatisch von KMS nach der Entschlüsselung abgeglichen, und es besteht keine Möglichkeit, den Klartext bei Abweichungen von KMS zu erhalten.

Berechtigungen auf Schlüssel feingranular vergeben

Wie bei vielen AWS-Ressourcen ist eine explizite Vergabe von Berechtigungen notwendig. Ohne Berechtigung darf kein Benutzer, keine Rolle und auch kein AWS-Dienst einen Schlüssel verwenden.

Berechtigungen werden über eine dedizierte Key Policy an jedem Customer-managed CMK vergeben. Jeder CMK, der über die AWS Management Console angelegt wird, erhält eine Key Policy, die die Berechtigungen an IAM delegiert. Das heißt, jeder Benutzer mit entsprechenden IAM-Berechtigungen kann den Schlüssel verwenden. Durch Änderung der Key Policy lassen sich Verantwortlichkeiten teilen und sehr genau eingrenzen. Werden Aktionen für feste Benutzer und Rollen festgelegt, darf z. B. nur ein bestimmter Benutzer den CMK administrieren oder löschen, während nur eine den Produktionsservern zugeordnete Rolle den CMK zur Ver- oder Entschlüsselung nutzen darf.

Zur Entschlüsselung eines Volumes braucht sogar Amazon EBS die Berechtigung, einen CMK zu nutzen. Vor der Verwendung eines Volumes vergibt der Benutzer einen sogenannten Grant für die Entschlüsselung eines Data Keys an Amazon EBS. Der Grant schreibt über den Encryption Context vor, dass die Entschlüsselung ausschließlich für dieses Volume stattfinden darf.

Fazit

AWS Key Management Service (KMS) ist derzeit mit über fünfzig AWS-Diensten integriert. So ist für die Verschlüsselung von Amazon EBS Volumes und Datenbanken nur ein einziger Klick notwendig. Je nach Schutzbedarf lässt sich das KMS API auch in der Anwendung nutzen. Das AWS Encryption SDK for Java vereinfacht die Verschlüsselung sensibler Daten auf Feldebene. KMS nutzt Hardware Security Modules, bietet lückenlose Protokollierung aller Ver- und Entschlüsselungsoperationen und ein feingranulares Rechtemanagement. Damit ist es möglich, mit minimalem Aufwand auf hohem Standard alles zu verschlüsseln.

 

Geschrieben von
Steffen Grunwald
Steffen Grunwald
Steffen Grunwald ist Solutions Architect bei Amazon Web Services EMEA SARL. Er unterstützt dort überwiegend Kunden aus dem Enterprise-Umfeld auf dem Weg in die Cloud.
Kommentare

Hinterlasse einen Kommentar

avatar
4000
  Subscribe  
Benachrichtige mich zu: