21 PKI und SSH-Authentifizierung in GitLab

Sichere Authentifizierung ist fundamental für jeden GitLab-Workflow. Während HTTPS mit Passwörtern oder Tokens eine Option ist, ist SSH mit Public-Key-Authentifizierung der bevorzugte Mechanismus für Entwickler und Automatisierungen. Dieses Kapitel erklärt die kryptographischen Grundlagen (Public Key Infrastructure), wie SSH-Authentifizierung technisch funktioniert, und wie GitLab sie nutzt.

Das Verständnis dieser Konzepte ist nicht nur akademisch – es ist praktisch essentiell für CI/CD-Pipelines, sichere Deployments, und Troubleshooting von Authentifizierungsproblemen.

21.1 Asymmetrische Kryptographie: Die mathematische Grundlage

21.1.1 Symmetrische vs. Asymmetrische Verschlüsselung

Symmetrische Verschlüsselung nutzt einen einzigen Schlüssel für Ver- und Entschlüsselung:

Alice ──[Key K]──> Encrypt(Message) ──> Ciphertext ──> Decrypt(Ciphertext, Key K) ──> Message

Problem: Wie teilt Alice den Key K sicher mit Bob? Wenn ein Angreifer K abfängt, kann er alle Nachrichten lesen.

Asymmetrische Verschlüsselung löst dieses Problem mit Schlüsselpaaren:

Alice generiert:
- Private Key (geheim, niemals geteilt)
- Public Key (öffentlich, kann frei verteilt werden)

Mathematische Eigenschaft: Was mit dem Public Key verschlüsselt wird, kann nur mit dem Private Key entschlüsselt werden – und umgekehrt.

21.1.2 Die zwei Anwendungsfälle

1. Verschlüsselung (Confidentiality)

Bob will Alice eine geheime Nachricht senden:

2. Digitale Signatur (Authentication + Integrity)

Alice will beweisen, dass eine Nachricht von ihr stammt:

Diese zweite Variante ist die Basis für SSH-Authentifizierung.

21.2 SSH-Authentifizierung: Technical Deep-Dive

21.2.1 Der SSH-Handshake

Wenn du git clone git@gitlab.com:user/project.git ausführst, passiert folgendes:

Phase 1: TCP Connection

Client (You) ──> TCP SYN ──> Server (GitLab)
Client       <── TCP SYN-ACK <── Server
Client       ──> TCP ACK ──> Server

Phase 2: SSH Protocol Negotiation

Client ──> SSH Version (SSH-2.0) ──> Server
Client <── SSH Version (SSH-2.0) <── Server
Client ──> Key Exchange Init ──> Server
Client <── Key Exchange Init <── Server

Negotiated:
- Key Exchange Algorithm: curve25519-sha256
- Host Key Algorithm: ssh-ed25519
- Encryption: chacha20-poly1305@openssh.com
- MAC: (implicit in chacha20-poly1305)
- Compression: none

Phase 3: Key Exchange (Diffie-Hellman)

Client und Server etablieren einen Session Key (symmetrisch) über unsicheren Kanal:

Client ──> Client's DH Public Key ──> Server
Client <── Server's DH Public Key <── Server

Both compute: Session Key = DH(Client_Public, Server_Public, Shared_Secret)

Jetzt haben beide denselben Session Key, ohne dass ein Angreifer ihn kennt. Ab hier ist Kommunikation verschlüsselt.

Phase 4: Server Authentication

Server beweist seine Identität mit Host Key:

Server ──> Host Key (Public) + Signature ──> Client

Client verifies:
- Is this Host Key in ~/.ssh/known_hosts?
- Is Signature valid with this Host Key?

If yes: Server is authenticated
If no: "The authenticity of host ... can't be established"

Phase 5: User Authentication (Public Key Auth)

Client ──> "I want to authenticate with public key" ──> Server
Server ──> "Show me which public key" ──> Client
Client ──> Public Key ──> Server

Server checks:
- Is this Public Key in ~/.ssh/authorized_keys (or GitLab DB)?

If yes:
  Server ──> Random Challenge (encrypted with Public Key) ──> Client
  Client ──> Signature (signed with Private Key) ──> Server
  
  Server verifies:
  - Is Signature valid with Public Key?
  - Does Signature prove possession of Private Key?
  
  If yes: User is authenticated

Phase 6: Session Established

Client <──> Encrypted Channel <──> Server

Now: Git commands can be executed

Dieser gesamte Flow passiert in Millisekunden bei jedem git push, git pull, git clone.

21.3 SSH-Schlüssel-Algorithmen

21.3.1 Ed25519: Der moderne Standard

Ed25519 ist ein Elliptic Curve-Algorithmus, basierend auf der Edwards-Kurve Curve25519.

Eigenschaften: - Kleine Schlüssel: 256 Bit Private Key, 256 Bit Public Key - Schnell: Sehr performant für Sign/Verify-Operationen - Sicher: Resistent gegen bekannte Angriffe, keine bekannten Backdoors - Deterministisch: Keine Zufallszahlen bei Signatur-Erstellung nötig

Generierung:

ssh-keygen -t ed25519 -C "your.email@example.com"

Output:

Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 

Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub

Dateien:

~/.ssh/id_ed25519      # Private Key (keep secret!)
~/.ssh/id_ed25519.pub  # Public Key (can be shared)

Public Key Format:

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJOMx+8zkuyMsGqceXr8j8kAMgLsH8U7yz3kVRydD5sQ your.email@example.com
│           │                                                                    │
│           └─ Base64-encoded Public Key (256 bits)                             └─ Comment
└─ Algorithm identifier

21.3.2 RSA: Der klassische Algorithmus

RSA basiert auf der Schwierigkeit der Primfaktorzerlegung großer Zahlen.

Eigenschaften: - Große Schlüssel: Minimum 2048 Bit (besser 4096 Bit) für moderne Sicherheit - Langsamer: Deutlich langsamer als Ed25519 - Bewährt: Seit Jahrzehnten im Einsatz, gut verstanden - Kompatibel: Funktioniert überall (auch sehr alte Systeme)

Generierung:

ssh-keygen -t rsa -b 4096 -C "your.email@example.com"

Größenvergleich:

Ed25519 Public Key:  ~80 Zeichen (Base64)
RSA 4096 Public Key: ~600 Zeichen (Base64)

Empfehlung: Ed25519, außer wenn Kompatibilität mit sehr alten Systemen nötig.

21.3.3 ECDSA: Der Kompromiss

ECDSA (Elliptic Curve Digital Signature Algorithm) nutzt Elliptic Curves wie Ed25519, aber mit anderen Kurven.

Eigenschaften: - Mittelgroße Schlüssel: 256, 384, oder 521 Bit - Schneller als RSA, langsamer als Ed25519 - Kontroverse: NIST-Kurven (P-256, P-384, P-521) stehen unter Verdacht, NSA-Backdoors zu haben

Generierung:

ssh-keygen -t ecdsa -b 521 -C "your.email@example.com"

Empfehlung: Vermeiden. Ed25519 ist besser.

21.4 SSH-Schlüssel in GitLab: Praktische Nutzung

21.4.1 Schlüssel zu GitLab hinzufügen

1. Public Key kopieren:

cat ~/.ssh/id_ed25519.pub

2. In GitLab UI einfügen: - User SettingsSSH Keys - Public Key einfügen - Title vergeben (z.B. “Laptop - Work”, “CI Runner”) - Optional: Expiration Date setzen (Best Practice für Rotation)

3. Verbindung testen:

ssh -T git@gitlab.com

# Output:
Welcome to GitLab, @username!

21.4.2 Mehrere Schlüssel verwalten

Szenario: Verschiedene Schlüssel für verschiedene GitLab-Instanzen oder Identitäten.

SSH Config (~/.ssh/config):

# Personal GitLab.com
Host gitlab.com
  HostName gitlab.com
  User git
  IdentityFile ~/.ssh/id_ed25519_personal
  IdentitiesOnly yes

# Work GitLab (Self-Hosted)
Host gitlab.company.com
  HostName gitlab.company.com
  User git
  IdentityFile ~/.ssh/id_ed25519_work
  IdentitiesOnly yes

# GitLab.com with different identity
Host gitlab-work
  HostName gitlab.com
  User git
  IdentityFile ~/.ssh/id_ed25519_work_gitlab
  IdentitiesOnly yes

Nutzung:

# Personal GitLab.com
git clone git@gitlab.com:personal/project.git

# Work GitLab
git clone git@gitlab.company.com:company/project.git

# Work identity on GitLab.com
git clone git@gitlab-work:work-org/project.git

21.4.3 SSH-Agent: Passphrase-Management

Problem: Passphrase bei jedem git push eingeben ist nervig.

Lösung: SSH-Agent speichert entschlüsselten Private Key im RAM.

Setup:

# Agent starten (meist schon aktiv)
eval "$(ssh-agent -s)"

# Schlüssel hinzufügen
ssh-add ~/.ssh/id_ed25519

# Passphrase eingeben (einmalig)
Enter passphrase for /home/user/.ssh/id_ed25519: 

# Schlüssel im Agent verifizieren
ssh-add -l
256 SHA256:ABC...XYZ your.email@example.com (ED25519)

Permanenz (Linux):

# In ~/.bashrc oder ~/.zshrc
if [ -z "$SSH_AUTH_SOCK" ]; then
   eval "$(ssh-agent -s)"
   ssh-add ~/.ssh/id_ed25519 2>/dev/null
fi

macOS Keychain Integration:

# Zu ~/.ssh/config hinzufügen
Host *
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/id_ed25519

macOS speichert Passphrase in Keychain, Agent lädt Schlüssel automatisch.

21.5 Deploy Keys und Deploy Tokens

21.5.1 Deploy Keys: SSH für spezifische Repositories

Deploy Keys sind SSH-Schlüssel, die auf Repository-Ebene registriert sind (nicht User-Ebene).

Use Case: CI/CD Runner soll nur auf ein spezifisches Repository zugreifen (nicht alle User-Repositories).

Setup:

# 1. Schlüssel generieren (ohne Passphrase für Automation)
ssh-keygen -t ed25519 -C "deploy-key-project-x" -f ~/.ssh/deploy_key_project_x

# 2. Public Key kopieren
cat ~/.ssh/deploy_key_project_x.pub

# 3. In GitLab: Repository → Settings → Repository → Deploy Keys
#    - Key einfügen
#    - Title: "CI Runner"
#    - ☐ Grant write permissions (optional, meist read-only)

Nutzung in CI/CD:

# .gitlab-ci.yml
before_script:
  - eval "$(ssh-agent -s)"
  - echo "$SSH_DEPLOY_KEY" | ssh-add -
  - mkdir -p ~/.ssh
  - chmod 700 ~/.ssh
  - ssh-keyscan gitlab.com >> ~/.ssh/known_hosts

job:
  script:
    - git clone git@gitlab.com:user/project.git

CI/CD Variable SSH_DEPLOY_KEY enthält Private Key (Type: File, Protected, Masked).

21.5.2 Deploy Tokens: HTTPS-basierte Alternative

Deploy Tokens sind HTTPS-Tokens für Repository-Zugriff ohne SSH.

Vorteile: - Kein SSH-Setup nötig - Funktioniert überall (auch wo SSH blockiert ist) - Kann für Container Registry, Package Registry genutzt werden

Setup:

Repository → Settings → Repository → Deploy Tokens
- Name: "CI Token"
- Expires at: (optional)
- Scopes: ☑ read_repository, ☑ read_registry

Output: Username + Token (einmalig angezeigt, notieren!)

Nutzung:

# Clone via HTTPS mit Deploy Token
git clone https://gitlab-token:<token>@gitlab.com/user/project.git

# Docker Registry Login
docker login registry.gitlab.com -u gitlab-token -p <token>

In CI/CD:

variables:
  GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_PATH

job:
  script:
    - git clone https://gitlab-token:${DEPLOY_TOKEN}@gitlab.com/user/project.git

21.5.3 Deploy Keys vs. Deploy Tokens

Aspekt Deploy Keys (SSH) Deploy Tokens (HTTPS)
Protokoll SSH HTTPS
Scope Single Repository Single Repository (or group)
Permissions Read or Read/Write Read Repository, Read Registry, Write Registry
Setup SSH-Keygen, Key-Management Token generieren
CI/CD SSH-Agent nötig Direkt in URL
Use Case Git-Operations Git + Docker Registry + Packages

Empfehlung: Deploy Tokens für CI/CD (einfacher), Deploy Keys für erweiterte Git-Workflows.

21.6 Project Access Tokens: User-like Tokens

Project Access Tokens (GitLab 13.0+) sind wie Bot-User mit spezifischen Permissions.

Setup:

Project → Settings → Access Tokens
- Token name: "CI Bot"
- Expiration date: (empfohlen)
- Role: Developer, Maintainer, etc.
- Scopes: api, read_repository, write_repository

Nutzung:

# HTTPS Clone mit Access Token
git clone https://oauth2:<token>@gitlab.com/user/project.git

# API Calls
curl --header "PRIVATE-TOKEN: <token>" \
  "https://gitlab.com/api/v4/projects/:id"

Vorteil: Granulare Permissions (Role-based), kann API nutzen (Deploy Token kann das nicht).

21.7 Troubleshooting SSH-Probleme

21.7.1 Verbose SSH-Modus

ssh -vvv -T git@gitlab.com

# Output zeigt jeden Schritt:
# - Key Exchange Algorithms
# - Host Key Verification
# - Public Key Authentication Attempts
# - Success/Failure Reasons

Häufige Probleme:

1. “Permission denied (publickey)”

debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
debug1: Offering public key: /home/user/.ssh/id_ed25519 ED25519
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
git@gitlab.com: Permission denied (publickey).

Ursachen: - Public Key nicht in GitLab hochgeladen - Falscher Private Key verwendet (SSH-Agent hat falschen Key geladen) - Falscher Username (git@gitlab.com, nicht user@gitlab.com!)

Fix:

# Public Key in GitLab UI überprüfen
cat ~/.ssh/id_ed25519.pub

# SSH-Agent Keys überprüfen
ssh-add -l

# Spezifischen Key testen
ssh -i ~/.ssh/id_ed25519 -T git@gitlab.com

2. “Host key verification failed”

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Ursache: Host Key in ~/.ssh/known_hosts stimmt nicht mit Server-Key überein.

Szenarien: - GitLab-Server neu installiert (legitim) - Man-in-the-Middle-Angriff (!!!)

Fix (nur wenn legitim):

# Host Key entfernen
ssh-keygen -R gitlab.com

# Neu verbinden
ssh -T git@gitlab.com

3. “Bad owner or permissions on ~/.ssh/config”

# SSH Config muss restriktiv sein
chmod 600 ~/.ssh/config

# Private Keys auch
chmod 600 ~/.ssh/id_ed25519

# Public Keys können permissiver sein
chmod 644 ~/.ssh/id_ed25519.pub

# ~/.ssh Verzeichnis selbst
chmod 700 ~/.ssh

4. SSH-Agent lädt falschen Key

# Alle Keys aus Agent entfernen
ssh-add -D

# Spezifischen Key hinzufügen
ssh-add ~/.ssh/id_ed25519

# Test
ssh -T git@gitlab.com

21.8 Best Practices

21.8.1 Passphrase verwenden

Warum: Private Key ist eine Datei auf Disk. Wenn Laptop gestohlen wird, ist Key kompromittiert – außer er ist mit Passphrase geschützt.

Passphrase-Anforderungen: - Minimum 20 Zeichen - Mix aus Groß-/Kleinbuchstaben, Zahlen, Symbolen - Nicht Passwort (wiederverwendet), sondern einzigartige Phrase

Mit SSH-Agent ist Passphrase kein Usability-Problem (einmalig pro Session).

21.8.2 Schlüssel rotieren

Empfehlung: Alle 1-2 Jahre neue Schlüssel generieren.

Prozess:

# 1. Neuen Key generieren
ssh-keygen -t ed25519 -C "email@example.com"

# 2. Zu GitLab hinzufügen (parallel zum alten)

# 3. Testen
ssh -T git@gitlab.com

# 4. Alten Key aus GitLab entfernen

# 5. Alte Key-Dateien löschen
rm ~/.ssh/id_ed25519_old*

21.8.3 Expiration Dates setzen

GitLab ermöglicht Expiration Date für SSH-Keys.

Nutzen: Erzwingt Rotation, verhindert vergessene alte Keys.

Setup: Bei Key-Upload in GitLab UI “Expiration Date” setzen (z.B. +1 Jahr).

21.8.4 Separate Keys für verschiedene Kontexte

Empfehlung: - Personal Projects: ~/.ssh/id_ed25519_personal - Work Projects: ~/.ssh/id_ed25519_work - CI/CD (Deploy Keys): ~/.ssh/deploy_key_project_x

Vorteil: Compromise eines Keys betrifft nicht alle Kontexte.

21.8.5 Backup (nur Public Keys!)

Private Keys: NIEMALS in Cloud-Backup (Dropbox, Google Drive, etc.). Wenn Backup, dann verschlüsselt (z.B. mit GPG).

Public Keys: Können gebackupt werden (sind eh öffentlich). Praktisch, um Keys schnell auf neuen Maschinen zu deployen.

21.9 Kryptographische Details: Ed25519 Deep-Dive

Für die Interessierten: Wie funktioniert Ed25519 mathematisch?

21.9.1 Elliptic Curve Cryptography (ECC)

Idee: Statt Primfaktorzerlegung (RSA) nutzen wir Punkt-Multiplikation auf Elliptic Curves.

Kurve: Edwards-Kurve über 𝔽p (Finite Field)

x2 + y2 = 1 + dx2y2

wobei p = 2255 − 19 (Primzahl, daher “25519”).

Punkt-Multiplikation:

P = Punkt auf Kurve
k = Scalar (Zahl)
Q = k * P  (Punkt-Multiplikation)

Eigenschaft: Gegeben Q und P, ist es extrem schwer, k zu finden (“Discrete Logarithm Problem”).

21.9.2 Schlüssel-Generierung

Private Key: Zufällige 256-Bit Zahl (Scalar)

private_key = random(256 bits)

Public Key: Punkt auf Kurve

public_key = private_key * G  (G = Generator-Punkt)

21.9.3 Signatur-Erstellung

Message M signieren:

1. Hash: r = Hash(nonce || M)
2. Commit: R = r * G (Punkt auf Kurve)
3. Challenge: h = Hash(R || public_key || M)
4. Response: s = r + h * private_key (modulo Gruppenordnung)

Signature = (R, s)

21.9.4 Signatur-Verifikation

Signatur (R, s) für Message M verifizieren:

1. Challenge: h = Hash(R || public_key || M)
2. Check: s * G == R + h * public_key

If yes: Signature valid (only owner of private_key could create it)

Warum sicher: Ohne private_key kann man s nicht berechnen (Discrete Log Problem).

21.10 Zusammenfassung: SSH als GitLab-Fundament

SSH mit Public-Key-Authentifizierung ist mehr als Convenience – es ist Security-Best-Practice:

Vorteile: - Passwortlos: Keine Passwörter über Netzwerk, kein Phishing - Key-basiert: Stärkere Kryptographie als Passwörter - Automatisierbar: CI/CD kann ohne menschliche Interaktion arbeiten - Granular: Deploy Keys, Deploy Tokens, Access Tokens für unterschiedliche Szenarien

Kryptographische Basis: - Asymmetrische Kryptographie: Public/Private Key Pairs - Ed25519: Moderne, schnelle, sichere Elliptic Curve - SSH Protocol: Etablierter, geprüfter Standard

GitLab-Integration: - User SSH Keys: Für Entwickler - Deploy Keys: Für CI/CD (repository-spezifisch) - Deploy Tokens: HTTPS-basierte Alternative - Project Access Tokens: Bot-User mit granularen Permissions

Master SSH, und GitLab-Authentifizierung wird von Hürde zu Selbstverständlichkeit. Verstehe die Kryptographie, und Troubleshooting wird von Trial-and-Error zu informierter Diagnose.

SSH ist nicht nur “git clone funktioniert” – es ist das Fundament sicherer, automatisierter DevOps-Workflows.