TS
Thomas Schmitz

Freiberuflicher IT-Berater, Softwareentwickler & DevOps. Praxisnahe Artikel zu API-Design, Architektur und Cloud-Workflows.

Serie: API-Design · Teil 11 von 22

API-Design Teil 11: Transport & Kryptografie

TLS-Konfiguration, Zertifikatsmanagement, mTLS für interne Services und wie du Secrets sicher verwaltest.

Praxisnah Checkliste

Eine API kann perfekt designed sein – wenn die Transportschicht unsicher ist, ist alles umsonst. Ein abgelaufenes Zertifikat, ein schwacher Cipher, ein Secret im Log: Jeder dieser Fehler kann zum Breach führen.

Dieser Artikel behandelt die oft übersehene Infrastruktur-Ebene: TLS richtig konfigurieren, Zertifikate automatisch rotieren, Secrets sicher verwalten und mTLS für Zero-Trust-Architekturen einsetzen.

Zielbild

Nach diesem Artikel kannst du:

  • Eine sichere TLS-Policy definieren und durchsetzen
  • Zertifikatsmanagement automatisieren
  • mTLS für Service-to-Service-Kommunikation einrichten
  • Secrets sicher speichern und rotieren
  • At-Rest-Encryption für Datenbanken und Backups konfigurieren

Kernfragen

Bevor du weiterliest, versuche diese Fragen für dein Projekt zu beantworten:

  1. Welche TLS-Version ist Minimum? TLS 1.2? TLS 1.3?
  2. Wie rotiert ihr Zertifikate? Manuell? Let's Encrypt? Interne CA?
  3. Braucht ihr mTLS intern? Zero-Trust? Compliance?
  4. Wo liegen eure Secrets? Umgebungsvariablen? Vault? Cloud KMS?
  5. Ist At-Rest-Encryption aktiviert? Datenbank? Backups? Logs?

TLS: Die Grundlage

TLS (Transport Layer Security) verschlüsselt die Kommunikation zwischen Client und Server. Ohne TLS sind alle anderen Sicherheitsmaßnahmen wertlos.

TLS-Versionen

Version Status Empfehlung
TLS 1.0 Deprecated Deaktivieren
TLS 1.1 Deprecated Deaktivieren
TLS 1.2 Aktuell Minimum
TLS 1.3 Aktuell Bevorzugt

Warum TLS 1.3?

  • Schnellerer Handshake (1-RTT statt 2-RTT)
  • Keine unsicheren Cipher Suites mehr möglich
  • Forward Secrecy ist Pflicht

Cipher Suites

Cipher Suites definieren, welche Algorithmen für Verschlüsselung verwendet werden.

TLS 1.3 Cipher Suites (empfohlen):

TLS_AES_256_GCM_SHA384
TLS_AES_128_GCM_SHA256
TLS_CHACHA20_POLY1305_SHA256

TLS 1.2 Cipher Suites (wenn 1.2 nötig):

ECDHE-ECDSA-AES256-GCM-SHA384
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-ECDSA-AES128-GCM-SHA256
ECDHE-RSA-AES128-GCM-SHA256

Verboten:

Cipher Problem
RC4 Gebrochen
DES, 3DES Zu schwach
MD5 Gebrochen
SHA1 Deprecated
CBC-Mode ohne AEAD Padding Oracle
Export Ciphers Absichtlich schwach
NULL Ciphers Keine Verschlüsselung

NGINX-Konfiguration

server {
    listen 443 ssl http2;
    server_name api.example.com;

    # Zertifikate
    ssl_certificate /etc/ssl/certs/api.example.com.crt;
    ssl_certificate_key /etc/ssl/private/api.example.com.key;

    # TLS-Versionen
    ssl_protocols TLSv1.2 TLSv1.3;

    # Cipher Suites (TLS 1.2)
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers on;  # Nur relevant für TLS 1.2

    # TLS 1.3 Cipher Suites (abhängig von NGINX/OpenSSL)
    # ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;

    # Session-Tickets (für Performance)
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;  # Oder mit Rotation
}

Security Headers

Für Browser-Clients sind zusätzliche Header nötig:

# HTTPS erzwingen
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# Weitere Security Headers
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none'" always;

HSTS (HTTP Strict Transport Security)

HSTS zwingt Browser, nur HTTPS zu verwenden:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Direktive Bedeutung
max-age Wie lange HSTS gilt (in Sekunden)
includeSubDomains Gilt auch für Subdomains
preload In Browser-Preload-Listen aufnehmen

Wichtig: HSTS ist schwer rückgängig zu machen. Erst mit kurzem max-age testen.

Zertifikatsmanagement

Zertifikate müssen regelmäßig erneuert werden. Manuell ist das fehleranfällig.

Let's Encrypt mit Auto-Renewal

Let's Encrypt bietet kostenlose Zertifikate mit 90-Tagen-Gültigkeit.

# Certbot installieren
apt install certbot python3-certbot-nginx

# Zertifikat erstellen
certbot --nginx -d api.example.com

# Auto-Renewal testen
certbot renew --dry-run

Certbot richtet automatisch einen Cron-Job ein:

# /etc/cron.d/certbot
0 */12 * * * root certbot renew --quiet

Interne CA für Microservices

Für interne Services ist eine eigene CA oft sinnvoller:

Root CA
(offline, lange Gültigkeit)

Intermediate CA
(kürzer, für Signing)

Service A Certificate

Service B Certificate

Service C Certificate

Tools:

  • cfssl: Cloudflare's PKI toolkit
  • step-ca: Smallstep's Certificate Authority
  • Vault PKI: HashiCorp Vault's PKI Secrets Engine

Zertifikats-Rotation

Zertifikatstyp Gültigkeit Rotation
Let's Encrypt 90 Tage Auto (60 Tage)
Interne Services 30-90 Tage Auto
Root CA 10-20 Jahre Manuell, geplant
Intermediate CA 2-5 Jahre Manuell, geplant

Monitoring (Checkliste)

Zertifikate müssen überwacht werden:

# Prometheus Alert
groups:
  - name: ssl
    rules:
      - alert: SSLCertificateExpiringSoon
        expr: ssl_certificate_expiry_seconds < 7 * 24 * 60 * 60
        for: 1h
        labels:
          severity: warning
        annotations:
          summary: "SSL certificate expires in less than 7 days"

mTLS (Mutual TLS)

Bei normalem TLS authentifiziert sich nur der Server. Bei mTLS authentifizieren sich beide Seiten mit Zertifikaten.

Wann mTLS?

Szenario mTLS? Begründung
Public API Nein Clients haben keine Zertifikate
Interne Microservices Ja Zero-Trust, Service Identity
Partner-API Optional Zusätzliche Sicherheit
Hochsichere Umgebungen Ja Compliance, Defense in Depth

mTLS-Handshake

ServerClientServerClientClientHelloServerHello + Server CertificateCertificateRequestClient CertificateCertificateVerifyFinishedFinishedEncrypted Communication (beidseitig)

NGINX mTLS-Konfiguration

server {
    listen 443 ssl http2;
    server_name internal-api.example.com;

    # Server-Zertifikat
    ssl_certificate /etc/ssl/certs/server.crt;
    ssl_certificate_key /etc/ssl/private/server.key;

    # Client-Zertifikat verlangen
    ssl_client_certificate /etc/ssl/certs/ca.crt;
    ssl_verify_client on;
    ssl_verify_depth 2;

    # Client-Zertifikat-Info an Backend weitergeben
    location / {
        proxy_pass http://backend;
        proxy_set_header X-Client-Cert-DN $ssl_client_s_dn;
        proxy_set_header X-Client-Cert-Verify $ssl_client_verify;
    }
}

Service Mesh (Istio, Linkerd)

Service Meshes automatisieren mTLS zwischen Services:

# Istio PeerAuthentication
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: production
spec:
  mtls:
    mode: STRICT

Vorteile:

  • Automatische Zertifikats-Rotation
  • Keine Code-Änderungen nötig
  • Zentrale Policy-Verwaltung

Secrets Management

Secrets (API Keys, DB-Passwörter, Encryption Keys) brauchen besonderen Schutz.

Wo Secrets NICHT hingehören

Ort Problem
Source Code Im Repo für immer
Git History Auch nach Löschen noch da
Logs Oft unverschlüsselt gespeichert
Umgebungsvariablen Potenziell auslesbar (z.B. via Debugging)
Config Files Oft nicht verschlüsselt
Error Messages An Clients gesendet

Secrets Management Tools

Tool Use Case
HashiCorp Vault Enterprise, Multi-Cloud
AWS Secrets Manager AWS-native
GCP Secret Manager GCP-native
Azure Key Vault Azure-native
Kubernetes Secrets Kubernetes-native (+ Sealed Secrets)
1Password/Doppler Team-Secrets, CI/CD

Vault-Beispiel

# Secret speichern
vault kv put secret/api/database \
    username="api_user" \
    password="super-secret-password"

# Secret lesen
vault kv get secret/api/database

In der Anwendung:

import hvac

client = hvac.Client(url='https://vault.example.com')
client.token = os.environ['VAULT_TOKEN']

secret = client.secrets.kv.read_secret_version(path='api/database')
db_password = secret['data']['data']['password']

Secret Rotation

Secrets sollten regelmäßig rotiert werden:

Secret-Typ Rotation
DB-Passwörter 90 Tage
API Keys Bei Kompromittierung
Encryption Keys 1 Jahr
JWT Signing Keys 90 Tage
Service Account Tokens 24 Stunden

Rotation ohne Downtime:

  1. Neues Secret erstellen
  2. Beide Secrets akzeptieren (Grace Period)
  3. Anwendungen auf neues Secret umstellen
  4. Altes Secret deaktivieren

At-Rest Encryption

Daten müssen auch im Ruhezustand verschlüsselt sein.

Datenbank-Encryption

Managed Database mit Encryption (empfohlen):

# Terraform: AWS RDS
resource "aws_db_instance" "api" {
  storage_encrypted = true
  kms_key_id        = aws_kms_key.database.arn
}

Alternative (Self-Hosted): Disk-/Volume-Encryption (z.B. LUKS/BitLocker) oder spaltenweise Verschlüsselung via pgcrypto.

Backup-Encryption

# PostgreSQL Backup mit Encryption
pg_dump dbname | gpg --symmetric --cipher-algo AES256 > backup.sql.gpg

# Restore
gpg --decrypt backup.sql.gpg | psql dbname

Encryption-Hierarchie

Master Key (KMS)
(nie exportiert, HSM-backed)

Data Encryption Keys
(pro Datenbank, Backup, Service)

Encrypted Data
(DB, Backups, Logs, Files)

Key Management

Prinzip Umsetzung
Separation of Duties Wer Keys verwaltet ≠ Wer Daten verwaltet
Least Privilege Keys nur für nötige Operationen
Audit Jeder Key-Zugriff wird geloggt
Rotation Keys regelmäßig rotieren
Backup Keys sicher und getrennt backuppen

TLS für Datenbank-Verbindungen

Auch interne Verbindungen sollten verschlüsselt sein.

PostgreSQL mit TLS

Server-Konfiguration (postgresql.conf):

ssl = on
ssl_cert_file = '/etc/ssl/certs/server.crt'
ssl_key_file = '/etc/ssl/private/server.key'
ssl_ca_file = '/etc/ssl/certs/ca.crt'

Client-Konfiguration (pg_hba.conf):

# Nur SSL-Verbindungen erlauben
hostssl all all 0.0.0.0/0 scram-sha-256

Connection String:

postgresql://user:pass@db.example.com:5432/dbname?sslmode=verify-full&sslrootcert=/path/to/ca.crt

SSL-Modi

Modus Beschreibung Empfehlung
disable Kein SSL Nie
allow SSL wenn Server will Nein
prefer SSL bevorzugt Nein
require SSL erforderlich Minimum
verify-ca + CA prüfen Besser
verify-full + Hostname prüfen Empfohlen

Regeln & Anti-Patterns

Do

  • TLS 1.2 als Minimum, TLS 1.3 bevorzugt
  • Nur sichere Cipher Suites (AEAD, Forward Secrecy)
  • Automatische Zertifikats-Rotation (Let's Encrypt, Vault)
  • Zertifikats-Expiry überwachen
  • mTLS für interne Service-Kommunikation
  • Secrets in Vault/Secrets Manager, nicht in Code
  • Secret Rotation mit Grace Period
  • At-Rest Encryption für Datenbanken und Backups
  • TLS auch für interne DB-Verbindungen

Don't

  • TLS 1.0/1.1 erlauben
  • Schwache Ciphers (RC4, DES, MD5, SHA1)
  • Selbstsignierte Zertifikate in Production (außer mit eigener CA)
  • Zertifikate manuell rotieren
  • Secrets in Git, Logs oder Umgebungsvariablen
  • Secrets hardcoden
  • Unverschlüsselte Backups
  • sslmode=disable für Datenbanken

Artefakt: Security-Transport-Check

# Security-Transport-Check

## TLS-Konfiguration

### Protokolle

- [ ] TLS 1.0 deaktiviert
- [ ] TLS 1.1 deaktiviert
- [ ] TLS 1.2 aktiviert (Minimum)
- [ ] TLS 1.3 aktiviert (bevorzugt)

### Cipher Suites

- [ ] Nur AEAD-Ciphers (GCM, ChaCha20-Poly1305)
- [ ] Forward Secrecy (ECDHE)
- [ ] Keine RC4, DES, 3DES
- [ ] Keine MD5, SHA1
- [ ] Keine Export/NULL Ciphers

### Validierung

```bash
# TLS-Konfiguration testen
nmap --script ssl-enum-ciphers -p 443 api.example.com

# Oder mit testssl.sh
./testssl.sh api.example.com
```

## Zertifikate

### Public API

- [ ] Zertifikat von vertrauenswürdiger CA
- [ ] Auto-Renewal konfiguriert (Certbot/ACME)
- [ ] Expiry-Monitoring aktiv
- [ ] OCSP Stapling aktiviert

### Interne Services

- [ ] Interne CA eingerichtet
- [ ] Zertifikats-Rotation automatisiert
- [ ] mTLS zwischen Services aktiviert

### Monitoring

- [ ] Alert bei Expiry < 14 Tage (Warning)
- [ ] Alert bei Expiry < 7 Tage (Critical)
- [ ] Alert bei Zertifikatsfehler

## Security Headers (Checkliste)

- [ ] `Strict-Transport-Security` (HSTS)
- [ ] `X-Content-Type-Options: nosniff`
- [ ] `X-Frame-Options: DENY`
- [ ] `Referrer-Policy`
- [ ] `Content-Security-Policy` (wenn Browser-Clients)

## Secrets Management (Checkliste)

### Speicherung

- [ ] Secrets in Vault/Secrets Manager
- [ ] Keine Secrets in Git
- [ ] Keine Secrets in Logs
- [ ] Keine Secrets in Error Messages

### Rotation

| Secret          | Rotation   | Letzte Rotation |
|-----------------|------------|-----------------|
| DB-Passwort     | 90 Tage    | YYYY-MM-DD      |
| JWT Signing Key | 90 Tage    | YYYY-MM-DD      |
| API Keys        | Bei Bedarf | YYYY-MM-DD      |
| Encryption Keys | 1 Jahr     | YYYY-MM-DD      |

### Zugriff

- [ ] Least Privilege für Secret-Zugriff
- [ ] Audit-Log für Secret-Zugriffe
- [ ] Separate Secrets pro Umgebung

## At-Rest Encryption (Checkliste)

### Datenbank

- [ ] Encryption aktiviert
- [ ] KMS-managed Keys
- [ ] Key Rotation konfiguriert

### Backups

- [ ] Backups verschlüsselt
- [ ] Backup-Keys getrennt von Daten-Keys
- [ ] Backup-Restore getestet

### Logs

- [ ] Sensitive Daten nicht in Logs
- [ ] Logs verschlüsselt (wenn persistent)

## Datenbank-Verbindungen

- [ ] TLS aktiviert (`sslmode=verify-full`)
- [ ] Server-Zertifikat von interner CA
- [ ] Client-Zertifikat (wenn mTLS)

## Test-Befehle

```bash
# TLS-Version und Ciphers prüfen
openssl s_client -connect api.example.com:443 -tls1_3

# Zertifikat anzeigen
openssl s_client -connect api.example.com:443 </dev/null 2>/dev/null | openssl x509 -text

# Expiry-Datum
echo | openssl s_client -connect api.example.com:443 2>/dev/null | openssl x509 -noout -enddate

# Headers prüfen
curl -I https://api.example.com

# SSL Labs Test
# https://www.ssllabs.com/ssltest/
```

Checkliste

Bevor du zum nächsten Artikel gehst, prüfe:

  • [ ] TLS 1.2+ ist Minimum, TLS 1.3 bevorzugt
  • [ ] Nur sichere Cipher Suites sind aktiviert
  • [ ] HSTS ist konfiguriert (für Browser-Clients)
  • [ ] Zertifikate rotieren automatisch
  • [ ] Zertifikats-Expiry wird überwacht
  • [ ] mTLS ist für interne Services aktiv (oder geplant)
  • [ ] Secrets liegen in Vault/Secrets Manager
  • [ ] Secret Rotation ist definiert
  • [ ] At-Rest Encryption ist aktiv (DB, Backups)
  • [ ] DB-Verbindungen nutzen TLS
  • [ ] Security-Transport-Check ist dokumentiert

Wie es weitergeht

Im nächsten Teil geht es um OWASP API Security: Die Top-10-Risiken für APIs und wie du sie in deinem Design von Anfang an verhinderst.

Alle Teile der Serie: Serie: API-Design

Mehr Beiträge aus dem Blog.