Loading...
SSL/TLS für PostgreSQL mit Docker einrichten

SSL/TLS für PostgreSQL mit Docker einrichten

Lukas Mauser - Co-Founder von sliplane.ioLukas Mauser
8 min

Ziel

Wenn du PostgreSQL produktiv betreiben möchtest, ist die Einrichtung von Transport Layer Security (TLS) ein Muss, um Man-in-the-Middle-Angriffe zu verhindern. In dieser Schritt-für-Schritt-Anleitung zeige ich dir, wie du dich mit deiner eigenen lokalen Zertifizierungsstelle sicher mit deiner Datenbank verbindest. Wenn du eine ausführliche Erklärung aller Einstellungen benötigst, schau dir die offizielle Dokumentation zur TLS-Einrichtung in PostgreSQL an.

In diesem Beispiel erlauben wir NUR verschlüsselte Verbindungen und setzen sslmode auf verify-full, was die strengste Verbindungseinstellung in PostgreSQL ist.

Voraussetzungen

Du benötigst Docker auf deinem Rechner. Wenn du einen Mac oder Windows verwendest, installiere Docker Desktop und stelle sicher, dass es im Hintergrund läuft. Überprüfe, ob Docker läuft, indem du docker ps im Terminal eingibst. Du solltest eine Liste laufender Container sehen oder zumindest keine Fehlermeldung erhalten, wenn Docker läuft.

PostgreSQL mit TLS via OpenSSL und Docker einrichten

Schritt 1: Zertifizierungsstelle (CA) generieren

Hinweis: Alle im Folgenden generierten Zertifikatsdateien (CA, Server und Client) sollten als Geheimnisse behandelt werden. Füge sie nicht zu deinem Git-Repository hinzu, logge sie nicht und baue sie nicht in dein Docker-Image ein (nur zur Laufzeit als Umgebungsvariablen verwenden). Füge sie ggf. deiner .gitignore hinzu.

Zuerst erstellen wir einen Root-CA-Schlüssel und ein Zertifikat, das unsere Server- und Client-Zertifikate signiert. Du kannst den Namen ändern, wenn du möchtest. Unsere CA ist 365 Tage gültig und muss danach erneuert werden.

openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 365 -out rootCA.crt -subj "/CN=MyLocalCA"

Schritt 2: Server-Zertifikate erstellen

Erzeuge einen Schlüssel und eine CSR (Certificate Signing Request) und signiere sie mit der CA:

Wichtig: Hier musst du den Domainnamen angeben, auf dem deine PostgreSQL-Instanz läuft. Im Beispiel verwende ich localhost, aber passe den Hostnamen an, falls du einen anderen verwendest.

openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/CN=localhost"
openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out server.crt -days 365 -sha256

Schritt 3: Client-Zertifikate erstellen

Dieses Zertifikat wird vom Client zur Authentifizierung verwendet. Nur Zertifikate, die von derselben CA wie das Server-Zertifikat signiert wurden, funktionieren.

Die Erstellung erfolgt analog zum Server. Als Common Name habe ich den Postgres-User gewählt:

openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr -subj "/CN=postgres"
openssl x509 -req -in client.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out client.crt -days 365 -sha256

Schritt 4: Init-Skript zur Aktivierung von TLS in PostgreSQL

Lege eine neue Datei im Projekt-Root an und nenne sie ssl-config.sh. Das Skript ist für die Verwendung in einem Docker-Container auf Basis eines PostgreSQL-Images gedacht.

Es kopiert die Server-Zertifikate in den Container und nimmt alle nötigen Einstellungen vor, um TLS mit sslmode verify-full zu erzwingen.

Wenn du unsichere Verbindungen erlauben willst, kannst du den Abschnitt "Force SSL" im Skript weglassen oder sslmode anpassen.

#!/bin/bash

# Zertifikatsdateien hinzufügen
echo "$SERVER_CRT" > /var/lib/postgresql/server.crt
echo "$SERVER_KEY" > /var/lib/postgresql/server.key
echo "$ROOT_CA_CRT" > /var/lib/postgresql/rootCA.crt

# Berechtigungen setzen
chmod 600 /var/lib/postgresql/server.* /var/lib/postgresql/rootCA.crt
chown postgres:postgres /var/lib/postgresql/server.* /var/lib/postgresql/rootCA.crt

# PostgreSQL für SSL konfigurieren
echo "ssl = on" >> /var/lib/postgresql/data/postgresql.conf
echo "ssl_cert_file = '/var/lib/postgresql/server.crt'" >> /var/lib/postgresql/data/postgresql.conf
echo "ssl_key_file = '/var/lib/postgresql/server.key'" >> /var/lib/postgresql/data/postgresql.conf
echo "ssl_ca_file = '/var/lib/postgresql/rootCA.crt'" >> /var/lib/postgresql/data/postgresql.conf

# SSL erzwingen
echo "hostssl all all all cert clientcert=verify-full" > /var/lib/postgresql/data/pg_hba.conf

Das Skript benötigt 3 Umgebungsvariablen:

  • SERVER_CRT
  • SERVER_KEY
  • ROOT_CA_CRT

Der Inhalt dieser Variablen ist der Klartext der drei Zertifikatsdateien server.crt, server.key und rootCA.crt.

Schritt 5: Docker-Image mit aktiviertem TLS bauen

Wir erstellen ein einfaches Dockerfile auf Basis von postgres:17.5 und kopieren unser Init-Skript in das Verzeichnis docker-entrypoint-initdb.d:

FROM postgres:17.5

COPY ssl-config.sh /docker-entrypoint-initdb.d/ssl-config.sh

Schritt 6: Verbindung zur Instanz herstellen

Um zu prüfen, ob alles funktioniert, bauen und starten wir das Image lokal und versuchen, uns zu verbinden. Wir nutzen den psql-Client. Falls nicht installiert, installiere ihn z.B. mit brew install libpq auf MacOS.

Hinweis: Dieser lokale Test funktioniert nur, wenn du zuvor den Common Name deines Server-Zertifikats auf localhost gesetzt hast. Andernfalls musst du ein neues Server-Zertifikat mit localhost als Common Name erstellen.

Image bauen:

docker build -t postgres-tls .

Image starten:

docker run \
 -e POSTGRES_PASSWORD=secret \
 -e SERVER_CRT="$(cat server.crt)" \
 -e SERVER_KEY="$(cat server.key)" \
 -e ROOT_CA_CRT="$(cat rootCA.crt)" \
 -p 5432:5432 --name postgres-tls postgres-tls

Achte darauf, die korrekten Pfade zu deinen Zertifikatsdateien anzugeben, falls du sie verschoben hast.

Verbindung testen:

# Damit solltest du in die PostgreSQL-Shell gelangen:
psql "host=localhost dbname=postgres user=postgres sslmode=verify-full sslrootcert=rootCA.crt sslcert=client.crt sslkey=client.key"

# Das sollte fehlschlagen, da wir TLS erzwingen:
psql "host=localhost dbname=postgres user=postgres sslmode=disable"

Wichtig: Führe dies im selben Verzeichnis aus, in dem deine Zertifikate liegen, oder passe die Pfade an.

Deployment

Um die Datenbank über das Internet verfügbar zu machen, deployen wir sie auf Sliplane.

  1. Erstelle ein GitHub-Repository mit den beiden oben beschriebenen Dateien: ssl-config.sh aus Schritt 4 und Dockerfile aus Schritt 5. Ein Beispiel-Repo zum Forken findest du hier: PostgreSQL mit TLS Repository
  2. Melde dich bei Sliplane mit deinem GitHub-Account an
  3. Erstelle ein neues Projekt und klicke auf "Deploy Service"
  4. Erstelle einen neuen Server, auf dem deine PostgreSQL-Instanz laufen soll – du kannst mit dem Basis-Server starten und später skalieren
  5. Wähle "Repository" als Deploy-Quelle
  6. Wähle dein PostgreSQL-Repository aus der Liste

Falls das Repository nicht angezeigt wird, klicke zuerst auf "Configure Repository Access", um Sliplane Zugriff zu gewähren

  1. Stelle das Protokoll auf TCP und klicke auf "Deploy". So sollten die Einstellungen aussehen:

Image description

Hinweis: Dieser Deploy wird absichtlich fehlschlagen! Wir haben die Umgebungsvariablen noch nicht gesetzt. Wir müssen zuerst deployen, um eine sliplane.app-Domain zu erhalten, die wir für das Zertifikat benötigen. Alternativ kannst du die Umgebungsvariablen schon ausfüllen, wenn du eine eigene Domain im Zertifikat verwendest und diese später an den Service anhängst.

  1. Erstelle die Zertifikate gemäß Schritt 1-3. Verwende dabei die sliplane.app-Domain deines Services als Common Name für das Server-Zertifikat. Du findest sie in den Service-Einstellungen unter "Public Domain".

Hinweis: Dein Service muss öffentlich sein, damit er eine Domain erhält (siehe Screenshot oben).

  1. Nachdem du die Zertifikate für deine öffentliche Postgres-Instanz erstellt hast, füge sie als Umgebungsvariablen hinzu, zusammen mit einem POSTGRES_PASSWORD deiner Wahl.

Deine Umgebungsvariablen sollten enthalten:

  • POSTGRES_PASSWORD
  • SERVER_CRT
  • SERVER_KEY
  • ROOT_CA_CRT

Image description

Nach dem Speichern der Umgebungsvariablen wird ein neuer Deploy ausgelöst, der nun erfolgreich sein sollte.

Das war's! Du hast jetzt Zugriff auf eine PostgreSQL-Instanz über eine sichere Verbindung. Teste sie mit:

psql "host=YOUR_APP.sliplane.app dbname=postgres user=postgres sslmode=verify-full sslrootcert=rootCA.crt sslcert=client.crt sslkey=client.key"

Hinweis: Ersetze die sliplane.app-Domain durch die, die dir zugewiesen wurde und die im Zertifikat verwendet wird.

Wenn dir dieses Tutorial gefallen hat, freue ich mich über Kommentare, Likes und Shares.

Danke!

Lukas

Willkommen in der Container-Cloud

Sliplane macht es einfach, Container in der Cloud zu deployen und bei Bedarf zu skalieren. Probier es jetzt aus!