open-how2 – Entdecke. Verstehe. Nutze.
Veröffentlicht am
How2-Tipps

Debian + Nginx + Windows-SubCA: Internes TLS-Zertifikat mit SAN korrekt erstellen

Autor
Debian + Nginx + Windows-SubCA: Internes TLS-Zertifikat mit SAN korrekt erstellen

In vielen internen Netzwerken werden Webserver über eine eigene PKI abgesichert – häufig mit einer Windows-basierten Sub-CA (z. B. Active Directory Certificate Services). Das klingt zunächst einfach: CSR erzeugen, Zertifikat ausstellen, in Nginx einbinden – fertig.

In der Praxis stolpert man jedoch schnell über moderne Browser-Fehler wie:

ERR_CERT_COMMON_NAME_INVALID

oder harte HSTS-Blockaden.

In diesem Artikel zeige ich Schritt für Schritt, wie man auf einem Debian-Server mit Nginx ein korrektes SAN-Zertifikat von einer Windows-SubCA erstellt und sauber ausliefert – inklusive Fullchain.

Beispielumgebung (Dummy):

  • Server: srv-doc01.intern.example.local
  • Website: docs.intern.example.local
  • SubCA: Example-SubCA

Warum der Common Name nicht mehr reicht

Früher genügte es, wenn der Common Name (CN) im Zertifikat dem Hostnamen entsprach:

CN = docs.intern.example.local

Heute akzeptieren Browser das nicht mehr zuverlässig.

Stattdessen wird ausschließlich das Feld:

Subject Alternative Name (SAN)

ausgewertet.

Fehlt dort der Hostname, erscheint sofort:

ERR_CERT_COMMON_NAME_INVALID

Der CN wird praktisch ignoriert.

👉 Jedes Serverzertifikat braucht SAN.

Schritt 1 – Private Key erzeugen (Debian)

Empfehlung: pro Host einen eigenen Key.

sudo mkdir -p /etc/ssl/private /etc/ssl/certs
sudo openssl genrsa -out /etc/ssl/private/docs.intern.example.local.key 4096
sudo chmod 600 /etc/ssl/private/docs.intern.example.local.key

Schritt 2 – CSR mit SAN erstellen (entscheidend!)

Konfigurationsdatei anlegen:

cat > /root/docs.intern.example.local-san.conf <<'EOF'
[req]
default_md = sha256
prompt = no
distinguished_name = dn
req_extensions = req_ext

[dn]
C = DE
ST = NRW
L = ExampleCity
O = ExampleOrg
OU = IT
CN = docs.intern.example.local
emailAddress = admin@example.local

[req_ext]
subjectAltName = @alt_names

[alt_names]
DNS.1 = docs.intern.example.local
EOF

CSR erzeugen:

openssl req -new \
  -key /etc/ssl/private/docs.intern.example.local.key \
  -out /root/docs.intern.example.local.csr \
  -config /root/docs.intern.example.local-san.conf

Kurz prüfen:

openssl req -in /root/docs.intern.example.local.csr -noout -text | grep -A2 "Subject Alternative Name"

Du solltest sehen:

DNS:docs.intern.example.local

Schritt 3 – CSR bei der Windows-SubCA einreichen

Auf der CA (z. B. Microsoft AD CS):

Variante Web Enrollment

  1. Aufrufen:
http://<CA-SERVER>/certsrv
  1. Request a certificate
  2. advanced certificate request
  3. CSR (inkl. BEGIN/END) einfügen
  4. Passendes Template wählen (z. B. „Web Server“)
  5. Zertifikat als Base64 herunterladen

Wichtig:

👉 Das verwendete Template muss SAN aus der CSR übernehmen. Falls nicht, muss es vom CA-Admin angepasst werden.

Schritt 4 – Zertifikat auf Debian installieren

Angenommen, du bekommst docs.cer.

Falls nötig von DER nach PEM:

openssl x509 -inform DER -in docs.cer -out /etc/ssl/certs/docs.intern.example.local.pem

Schritt 5 – SubCA (Intermediate) bereitstellen

Auch das SubCA-Zertifikat wird benötigt:

openssl x509 -inform DER -in Example-SubCA.cer -out /etc/ssl/certs/Example-SubCA.pem

Schritt 6 – Fullchain bauen

cat /etc/ssl/certs/docs.intern.example.local.pem \
    /etc/ssl/certs/Example-SubCA.pem \
> /etc/ssl/certs/docs.intern.example.local-fullchain.pem

Schritt 7 – Nginx konfigurieren

Im passenden server {}-Block von Nginx:

server {
  listen 443 ssl http2;
  server_name docs.intern.example.local;

  ssl_certificate     /etc/ssl/certs/docs.intern.example.local-fullchain.pem;
  ssl_certificate_key /etc/ssl/private/docs.intern.example.local.key;
}

Reload:

nginx -t && systemctl reload nginx

Schritt 8 – Finale Prüfungen

Hat das Zertifikat SAN?

openssl x509 -in /etc/ssl/certs/docs.intern.example.local.pem -noout -ext subjectAltName

Liefert Nginx die komplette Chain?

echo | openssl s_client -connect 127.0.0.1:443 -servername docs.intern.example.local | tail -n 20

Du willst sehen:

Verify return code: 0 (ok)

Typische Fehlerquellen

  • Zertifikat ohne SAN → Browserfehler
  • SubCA nicht im Fullchain → „unable to verify the first certificate“
  • falscher Nginx-vHost → falsches Zertifikat
  • DNS zeigt auf andere IP → du konfigurierst korrekt, Browser landet woanders

Für interne TLS-Zertifikate gilt heute:

  • SAN ist Pflicht
  • Fullchain ist Pflicht
  • systematische OpenSSL-Tests sparen Stunden Fehlersuche

Hat man das einmal sauber umgesetzt, funktionieren auch interne Sites genauso zuverlässig wie öffentliche HTTPS-Dienste.