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.
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.
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.
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.
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
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.
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.
1. Public Key kopieren:
cat ~/.ssh/id_ed25519.pub2. In GitLab UI einfügen: - User Settings → SSH 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!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.gitProblem: 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
fimacOS Keychain Integration:
# Zu ~/.ssh/config hinzufügen
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519macOS speichert Passphrase in Keychain, Agent lädt Schlüssel automatisch.
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.gitCI/CD Variable SSH_DEPLOY_KEY enthält
Private Key (Type: File, Protected, Masked).
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| 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.
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).
ssh -vvv -T git@gitlab.com
# Output zeigt jeden Schritt:
# - Key Exchange Algorithms
# - Host Key Verification
# - Public Key Authentication Attempts
# - Success/Failure ReasonsHä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.com2. “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.com3. “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 ~/.ssh4. 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.comWarum: 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).
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*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).
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.
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.
Für die Interessierten: Wie funktioniert Ed25519 mathematisch?
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”).
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)
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)
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).
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.