Outils pour utilisateurs

Outils du site


linux:ca-ssh

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
linux:ca-ssh [2026/06/03 13:16] rootlinux:ca-ssh [2026/06/03 18:23] (Version actuelle) – [Étape 4.2 : Signature par la CA Yubikey] root
Ligne 2: Ligne 2:
  
 Guide complet pour mettre en place une autorité de certification SSH dans un contexte MSP, avec support multi-Yubikey et intégration dans l'infrastructure MIS. Guide complet pour mettre en place une autorité de certification SSH dans un contexte MSP, avec support multi-Yubikey et intégration dans l'infrastructure MIS.
 +
 +**Architecture allégée** : la clé privée de la CA est stockée sur une Yubikey 5 NFC dédiée (slot PIV), pas sur disque. Un backup d'urgence (fichier classique chiffré) est conservé dans Bitwarden pour les cas de perte matérielle.
  
 ---- ----
Ligne 10: Ligne 12:
  
 ^ Rôle ^ Système ^ Notes ^ ^ Rôle ^ Système ^ Notes ^
-| **Machine CA** (signature des certifs) | Linux (LXC Proxmox) | OpenSSH côté Linux uniquement pour ce setup +| **Poste de signature** (utilisation Yubikey CA) | Windows / Linux / macOS | OpenSSH + OpenSC ou ykcs11 
-| **Poste technicien** (utilisation Yubikey) | Windows / Linux / macOS | OpenSSH inclus dans Windows 10/11 (1809+) |+| **Poste technicien** (utilisation Yubikey perso) | Windows / Linux / macOS | OpenSSH inclus dans Windows 10/11 (1809+) |
 | **Serveurs clients** (qui acceptent les certifs) | Linux principalement | Windows Server avec OpenSSH for Windows fonctionne aussi | | **Serveurs clients** (qui acceptent les certifs) | Linux principalement | Windows Server avec OpenSSH for Windows fonctionne aussi |
  
Ligne 22: Ligne 24:
   * L'utilisation des certificats SSH est transparente : il suffit de placer le ''-cert.pub'' à côté de la clé privée   * L'utilisation des certificats SSH est transparente : il suffit de placer le ''-cert.pub'' à côté de la clé privée
  
-**Côté machine CA** : on reste sur Linux (LXC Debian sur Proxmox). C'est plus simple, plus auditable, et compatible avec l'écosystème MIS existant.+**Pour signer avec la Yubikey CA depuis Windows** : Yubico fournit ''ykcs11.dll'' (inclus dans ''yubico-piv-tool''qui peut être utilisé comme provider PKCS#11 pour ''ssh-keygen -D''. Marche aussi.
  
 ---- ----
Ligne 41: Ligne 43:
  
 **OpenSSH 10.0** : meilleurs algos par défaut, mais surtout : **OpenSSH 10.0** : meilleurs algos par défaut, mais surtout :
-  * Les **clés DSA ne sont plus supportées du tout**, même avec les options de compat (''HostKeyAlgorithms'', ''PubkeyAcceptedAlgorithms''). Aucun impact pour nous (on n'utilise que Ed25519/Ed25519-sk), mais à savoir si tu te connectes à de très vieux équipements (un ''apt install openssh-client-ssh1'' peut servir pour ces cas-là).+  * Les **clés DSA ne sont plus supportées du tout**, même avec les options de compat (''HostKeyAlgorithms'', ''PubkeyAcceptedAlgorithms''). Aucun impact pour nous (on n'utilise que Ed25519/ECCP384), mais à savoir si tu te connectes à de très vieux équipements.
   * Le support FIDO2 (libfido2) est plus mature qu'en Bookworm.   * Le support FIDO2 (libfido2) est plus mature qu'en Bookworm.
   * Les algorithmes post-quantum (mlkem768x25519-sha256) sont disponibles par défaut pour le key exchange.   * Les algorithmes post-quantum (mlkem768x25519-sha256) sont disponibles par défaut pour le key exchange.
- 
-**''/tmp'' est maintenant un tmpfs** en Trixie (RAM). Aucun impact sur nos workflows (les ''.pub'' font quelques centaines d'octets), mais à garder en tête pour des scripts qui manipuleraient de gros fichiers temporaires. 
- 
-**''/etc/sysctl.conf'' n'est plus lu** : utiliser ''/etc/sysctl.d/99-mis.conf'' à la place pour tes éventuelles personnalisations kernel. Sans impact direct sur le SSH CA, mais bon à savoir pour tes playbooks Ansible. 
- 
-**openssh-server ne lit plus ''~/.pam_environment''** : si jamais tu avais des configs spécifiques pour des sessions SSH, à migrer vers ''~/.bash_profile'' ou la conf PAM système. Non pertinent pour notre workflow MIS. 
  
 ==== Support à long terme ==== ==== Support à long terme ====
Ligne 57: Ligne 53:
  
 C'est donc une base saine pour démarrer une infra MSP qui doit vivre 4-5 ans sans upgrade majeur. C'est donc une base saine pour démarrer une infra MSP qui doit vivre 4-5 ans sans upgrade majeur.
- 
-==== Images officielles ==== 
- 
-  * Cloud image : https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2 
-  * Template LXC Proxmox : ''debian-13-standard_13.X-Y_amd64.tar.zst'' (récupérable via ''pveam'') 
  
 ---- ----
Ligne 68: Ligne 59:
  
 <code> <code>
-┌──────────────────┐ +──────────────────────────┐ 
-│   Yubikey x2     │  Techniciens MIS (Vincent, futur tech...+│  Poste de signature      │ 
-│   par tech       │  → génèrent leurs clés ed25519-sk localement +│  (laptop MIS Vincent)    │ 
-─────────────────┘ +│                          │ 
-         │ .pub envoyée à Odoo +│  ┌────────────────────┐  │     ┌─────────────────────────┐ 
-         ▼ +│  │ Yubikey CA dédiée  │──┼────►│ ssh-keygen -s           │ 
-──────────────────┐         ┌──────────────────────┐ +│  │ (slot PIV 9c)      │  │     │ via PKCS#11             │ 
-│      Odoo        │ ──API──►│  Proxmox MIS         │ +│  │ ECCP384            │  │     │ → certificat signé      │ 
-│ makeitsimple_    │         │  └─ LXC mis-ssh-ca    +│  │ touch CACHED       │  │     └─────────────────────────┘ 
-│   ssh_ca         │  démarre│     (éteinte 99%     │ +│  └────────────────────┘  │ 
-│                  │  à la   │      du temps)       │ +│                          │ 
-│                  │  demande│                       +│  ┌────────────────────┐  │ 
-└─────────────────┘         └──────────┬───────────┘ +│  │ Fichier emergency  │  │  (utilisé uniquement si 
-         │                              │ ssh-keygen -s +│  │ chiffré age        │  │   Yubikey CA perdue) 
-         │                              ▼ +│  │ dans Bitwarden     │  │ 
-         │                   ──────────────────────┐ +│  └────────────────────┘  │ 
-         │                   │  Certificat SSH      │ +──────────────────────────┘ 
-         ──────────────────│  signé (-cert.pub)   │ +              │ 
-         │                   └──────────────────────┘ +              │ déploiement via Ansible 
-         │ +              ▼ 
-         │ déploiement +──────────────────────────────────┐ 
-         ▼ +│  Serveurs clients                │ 
-┌──────────────────┐ +│  /etc/ssh/mis-users-ca.pub       │ ← contient 2 lignes : 
-│  Serveurs        │ +│  (200+ VMs)                      │   1. Yubikey CA pub 
-│  clients         │  /etc/ssh/mis-users-ca.pub +│                                  │   2. Emergency CA pub 
-│  (200+ VMs)      │  /etc/ssh/mis-revoked-keys +│  /etc/ssh/mis-revoked-keys       │ ← KRL pour révocations 
-└──────────────────┘+──────────────────────────────────┘
 </code> </code>
 +
 +**Le principe** :
 +  * La CA quotidienne vit sur Yubikey PIV → clé privée non-extractible, touch + PIN obligatoires
 +  * La CA emergency est un fichier classique chiffré avec ''age'', stocké dans Bitwarden
 +  * Les **deux** clés publiques sont déployées sur les serveurs comme CAs valides
 +  * En cas de perte de la Yubikey CA, on déchiffre l'emergency, on s'en sert pour signer en attendant la nouvelle Yubikey, puis on révoque (rolling rotation)
  
 ---- ----
  
-===== Phase 1 : Préparation de la LXC CA =====+===== Phase 1 : Préparation du poste de signature =====
  
-==== Étape 1.1 : Création du conteneur ====+==== Étape 1.1 : Matériel requis ====
  
-Sur le Proxmox MIS (pas un hyperviseur client) :+  * **1x Yubikey 5 NFC dédiée à la CA** (~50 €). À **séparer** de tes Yubikeys SSH d'authentification quotidienne. Cette Yubikey reste rangée la plupart du temps, branchée uniquement pour signer. 
 +  * Ton laptop MIS comme poste de signature (Linux, macOS ou Windows) 
 + 
 +==== Étape 1.2 : Installation des outils ==== 
 + 
 +**Sur Debian / Ubuntu / WSL2** :
  
 <code bash> <code bash>
-# Variables +sudo apt update 
-CTID=200 +sudo apt install -y \ 
-HOSTNAME="mis-ssh-ca" +    openssh-client \ 
-STORAGE="local-zfs" +    yubikey-manager \ 
-BRIDGE="vmbr10"          # VLAN management isolé +    opensc \ 
-TEMPLATE="debian-13-standard_13.5-1_amd64.tar.zst" +    age 
-# Vérifier le nom exact disponible avec : +</code>
-#   pveam update && pveam available | grep debian-13 +
-# Et télécharger si pas encore présent : +
-#   pveam download local debian-13-standard_13.5-1_amd64.tar.zst+
  
-# Création LXC +**Sur macOS** (Homebrew) :
-pct create $CTID local:vztmpl/$TEMPLATE \ +
-  --hostname $HOSTNAME \ +
-  --cores 1 --memory 512 --swap 256 \ +
-  --rootfs $STORAGE:8 \ +
-  --net0 name=eth0,bridge=$BRIDGE,ip=10.10.10.50/24,gw=10.10.10.1 \ +
-  --nameserver 10.10.10.1 \ +
-  --onboot 0 \ +
-  --start 0 \ +
-  --unprivileged 1 \ +
-  --features nesting=0,keyctl=0 \ +
-  --password "TEMP_PASSWORD_CHANGE_IMMEDIATELY"+
  
-# Démarrage +<code bash> 
-pct start $CTID+brew install yubikey-manager opensc age openssh
 </code> </code>
  
-==== Étape 1.Durcissement initial ====+**Sur Windows** : 
 + 
 +<code powershell> 
 +# Yubikey Manager : https://www.yubico.com/support/download/yubikey-manager/ 
 +# Installer aussi yubico-piv-tool qui contient ykcs11.dll 
 +# OpenSSH inclus avec Windows 10/11 (sinon : Add-WindowsCapability) 
 +# age : winget install FiloSottile.age 
 +</code> 
 + 
 +==== Étape 1.Localisation du provider PKCS#11 ==== 
 + 
 +Cette information est cruciale pour les commandes de signature. Note le chemin selon ton OS : 
 + 
 +^ OS ^ Chemin PKCS#11 (OpenSC) ^ 
 +| Debian/Ubuntu (amd64) | ''/usr/lib/x86_64-linux-gnu/opensc-pkcs11.so''
 +| Debian/Ubuntu (arm64) | ''/usr/lib/aarch64-linux-gnu/opensc-pkcs11.so''
 +| macOS (Intel) | ''/usr/local/lib/opensc-pkcs11.so''
 +| macOS (Apple Silicon) | ''/opt/homebrew/lib/opensc-pkcs11.so''
 +| Windows | ''C:\Program Files\OpenSC Project\OpenSC\pkcs11\opensc-pkcs11.dll''
 + 
 +Vérification rapide qu'il existe :
  
 <code bash> <code bash>
-Entrer dans la LXC +Linux/macOS 
-pct enter $CTID+ls -la $PKCS11_PATH 
 +</code>
  
-# Hardening de base +Pour la suite du document, on utilisera la variable ''$PKCS11'' à adapter à ton chemin :
-apt update && apt upgrade -y +
-apt install -y openssh-server fail2ban ufw vim+
  
-# Firewall : SSH uniquement depuis le subnet de management +<code bash> 
-ufw default deny incoming +export PKCS11=/usr/lib/x86_64-linux-gnu/opensc-pkcs11.so 
-ufw default deny outgoing +</code>
-ufw allow from 10.10.10.0/24 to any port 22 proto tcp +
-ufw allow out 53/udp                                   # DNS pour apt +
-ufw allow out 80,443/tcp                               # apt updates +
-ufw enable+
  
-# Utilisateur dédié pour la signature +==== Étape 1.4 : Initialisation des PINs de la Yubikey CA ====
-useradd -m -s /bin/bash ca-signer +
-mkdir -p /home/ca-signer/.ssh +
-chmod 700 /home/ca-signer/.ssh+
  
-# Désactivation auth password sur SSH +⚠️ **Yubikey CA branchée**Vérifie que c'est la bonne (pas une Yubikey SSH du quotidien) : 
-sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no//etc/ssh/sshd_config + 
-sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config +<code bash> 
-systemctl restart ssh+ykman info 
 +Doit afficher le serial number de la Yubikey CA
 </code> </code>
  
-==== Étape 1.3 : Stockage chiffré (optionnel mais recommandé====+**PIN PIV** (8 caractères minimum, sera demandé à chaque session de signature:
  
-Pour aller plus loinla rootfs de la LXC peut être stockée sur un dataset ZFS chiffré côté hôte Proxmox :+<code bash> 
 +ykman piv access change-pin 
 +# Default PIN: 123456 
 +# New PIN: [choisir 8+ chars] 
 +</code> 
 + 
 +**PUK** (utilisé pour débloquer si trop d'échecs PINà conserver précieusement) :
  
 <code bash> <code bash>
-Sur l'hôte Proxmox (à faire AVANT la création de la LXC) +ykman piv access change-puk 
-zfs create -o encryption=aes-256-gcm -o keyformat=passphrase rpool/encrypted-vault +Default PUK: 12345678 
-La passphrase sera demandée à chaque démarrage de l'hôte+New PUK: [générer 8 chars aléatoires]
 </code> </code>
 +
 +**Management Key** (utilisée pour les opérations admin PIV, on la protège avec le PIN) :
 +
 +<code bash>
 +ykman piv access change-management-key --algorithm AES256 --generate --protect
 +# --protect = stocke la management key chiffrée par le PIN
 +</code>
 +
 +📋 **Notes à conserver dans Bitwarden, entrée "MIS Yubikey CA"** :
 +  * Serial number de la Yubikey
 +  * PIN PIV
 +  * PUK
 +  * (la management key est protégée par le PIN, pas besoin de la stocker à part)
  
 ---- ----
Ligne 177: Ligne 197:
 ===== Phase 2 : Génération des CAs ===== ===== Phase 2 : Génération des CAs =====
  
-==== Étape 2.1 : CA pour les utilisateurs (techniciens) ====+==== Étape 2.1 : CA principale sur Yubikey (users) ====
  
 <code bash> <code bash>
-Connecté en tant que ca-signer dans la LXC +Yubikey CA branchée 
-mkdir -p ~/mis-ca && cd ~/mis-ca+mkdir -p ~/mis-ssh-ca && cd ~/mis-ssh-ca
 chmod 700 . chmod 700 .
  
-ssh-keygen -t ed25519 -a 200 +# Génération de la paire ECCP384 dans le slot 9c (Digital Signature) 
-  -f mis-users-ca +ykman piv keys generate \ 
-  -C "MIS Users CA Make IT Simple" +  --algorithm ECCP384 
-  -N 'PASSPHRASE_TRES_ROBUSTE_ICI'+  --pin-policy ONCE 
 +  --touch-policy CACHED 
 +  9c \ 
 +  mis-users-ca-yubi-cert.pub 
 +# → demande le PIN 
 +# → demande le touch
 </code> </code>
  
-==== Étape 2.2 : CA pour les hôtes (serveurs) ====+Décortiquons les options : 
 + 
 +^ Option ^ Valeur ^ Sens ^ 
 +| ''--algorithm'' | ''ECCP384'' | Courbe elliptique NIST P-384 (compromis sécurité/perf) | 
 +| ''--pin-policy'' | ''ONCE'' | PIN demandé 1x par session (après débranchement = re-demandé) | 
 +| ''--touch-policy'' | ''CACHED'' | Touch valide 15s après un précédent touch | 
 +| ''9c'' | slot | Slot "Digital Signature" - sémantique appropriée | 
 + 
 +**Alternative plus stricte** : ''--touch-policy ALWAYS'' exige un touch à **chaque** signature. Plus sûr mais pénible pour signer plusieurs certifs d'affilée (enrôlement de plusieurs Yubikeys d'un nouveau tech). ''CACHED'' est un bon compromis. 
 + 
 +==== Étape 2.2 : Certificat self-signed PIV ==== 
 + 
 +PIV exige qu'un certificat X.509 soit présent dans le slot, même s'il ne sert à rien dans notre usage SSH :
  
 <code bash> <code bash>
-ssh-keygen -t ed25519 -a 200 +ykman piv certificates generate 
-  -f mis-hosts-ca \ +  --subject "CN=MIS Users CA,O=Make IT Simple,C=BE" \ 
-  -C "MIS Hosts CA Make IT Simple"+  --valid-days 3650 \ 
-  -N 'AUTRE_PASSPHRASE_TRES_ROBUSTE'+  9c \ 
 +  mis-users-ca-yubi-cert.pub 
 +# → demande le PIN
 </code> </code>
  
-==== Étape 2.3 : Backup chiffré des clés privées ====+==== Étape 2.3 : Export de la clé publique au format SSH ====
  
-⚠️ **Étape critique**. Sans backup, perdre la LXC = perdre tout le contrôle d'accès.+C'est cette clé publique qui sera déployée sur tous les serveurs comme **CA principale acceptée** :
  
 <code bash> <code bash>
-# Création d'une archive chiffrée +ssh-keygen -D $PKCS11 -e > mis-users-ca-yubi.pub
-cd ~/mis-ca +
-tar czf - mis-users-ca mis-hosts-ca | \ +
-  age -p > mis-ca-backup-$(date +%Y%m%d).tar.gz.age +
-# Demande une passphrase distincte des passphrases des CAs+
  
-À conserver dans : +Inspection 
-# 1. Bitwarden (attachment de l'entrée "MIS SSH CA Master Backup") +cat mis-users-ca-yubi.pub 
-2Clé USB chiffrée dans coffre physique +Doit afficher : ecdsa-sha2-nistp384 AAAA... 
-3. (optionnelCoffre bancaire pour archive papier-QR de la passphrase+ 
 +Renommer avec un commentaire explicite (facultatif) 
 +sed -i 's|$| MIS Users CA - Yubikey|' mis-users-ca-yubi.pub
 </code> </code>
  
-----+==== Étape 2.4 : Génération de la CA emergency (container éphémère) ====
  
-===== Phase 3 Bootstrap d'un serveur client =====+La CA emergency est une clé privée Ed25519 classique, mais qui ne doit **jamais exister en clair sur ton laptop** après génération. La meilleure approche : un container Docker éphémère sans réseau, qui ne laisse aucune trace après destruction.
  
-==== Étape 3.1 : Déploiement de la CA users sur le serveur ====+**Pourquoi pas juste sur ton laptop ?** Parce qu'entre la génération en clair et le chiffrement age, la clé existe en clair sur ton disque. Avec un container sans réseau, aucun process tiers (même un éventuel malware) ne peut exfiltrer pendant cette fenêtre.
  
-Sur un serveur client (Debian provisionné via cloud-init) :+**Génération via Docker** :
  
 <code bash> <code bash>
-Copie de la clé publique de la CA users +Lancement d'un container Debian 13 minimal, SANS RÉSEAU 
-scp ca-signer@10.10.10.50:~/mis-ca/mis-users-ca.pub /etc/ssh/mis-users-ca.pub +docker run --rm -it \ 
-chmod 644 /etc/ssh/mis-users-ca.pub+  --network none \ 
 +  --hostname offline-ca-gen \ 
 +  -v ~/mis-ssh-ca:/output \ 
 +  debian:trixie-slim bash 
 +</code>
  
-# Création d'un KRL vide initial +**Dans le container** (aucun accès Internet possible) :
-ssh-keygen -k -f /etc/ssh/mis-revoked-keys +
-chmod 644 /etc/ssh/mis-revoked-keys+
  
-Configuration sshd +<code bash> 
-cat >> /etc/ssh/sshd_config <<'EOF'+Installation des outils (depuis le cache APT du container, pas Internet) 
 +# Si l'image n'a pas les paquets, faire docker build préalable (voir note ci-dessous) 
 +apt-get install -y openssh-client age coreutils 2>/dev/null || echo "Image sans cache, voir note"
  
-===== MIS SSH CA ===== +cd /tmp 
-TrustedUserCAKeys /etc/ssh/mis-users-ca.pub + 
-RevokedKeys /etc/ssh/mis-revoked-keys +Génération Ed25519 classique 
-PasswordAuthentication no +ssh-keygen -t ed25519 -a 200 \ 
-KbdInteractiveAuthentication no +  -f mis-users-ca-emergency \ 
-PubkeyAuthentication yes +  -C "MIS Users CA - EMERGENCY USE ONLY" \ 
-# ======================+  -N '' 
 + 
 +# Chiffrement avec age - passphrase en interactif (PAS en argument !) 
 +age --passphrase \ 
 +  -o mis-users-ca-emergency.age \ 
 +  mis-users-ca-emergency 
 +# → entrer une passphrase TRÈS robuste (Diceware 6-8 mots recommandé) 
 + 
 +# Effacement sécurisé de la version en clair 
 +shred -u mis-users-ca-emergency 
 + 
 +# Copie des fichiers finaux vers l'hôte via le volume monté 
 +cp mis-users-ca-emergency.age /output/ 
 +cp mis-users-ca-emergency.pub /output/ 
 + 
 +# Sortie du container → destruction automatique (--rm) 
 +exit 
 +</code> 
 + 
 +**Note** : si ''debian:trixie-slim'' n'a pas les paquets en cache, prépare une image avec les outils inclus une fois pour toutes : 
 + 
 +<code bash> 
 +# À faire une seule fois, sur ton hôte 
 +cat > /tmp/Dockerfile <<'EOF' 
 +FROM debian:trixie-slim 
 +RUN apt-get update && \ 
 +    apt-get install -y --no-install-recommends \ 
 +        openssh-client age coreutils && \ 
 +    rm -rf /var/lib/apt/lists/*
 EOF EOF
  
-Test et reload +docker build -t mis-ca-gen:latest -f /tmp/Dockerfile /tmp/ 
-sshd -t && systemctl reload ssh+ 
 +Puis utiliser cette image (en remplaçant debian:trixie-slim) : 
 +docker run --rm -it --network none -v ~/mis-ssh-ca:/output mis-ca-gen:latest bash
 </code> </code>
  
-À industrialiser via Ansible (voir Phase 7).+**Variante Podman rootless** (si tu préfères ne pas dépendre d'un daemon Docker root:
  
-==== Étape 3.2 Certificat d'hôte pour le serveur (recommandé) ====+<code bash> 
 +podman run --rm -it --network none -v ~/mis-ssh-ca:/output:Z mis-ca-gen:latest bash 
 +</code>
  
-Sur la CA :+**Résultat sur ton hôte** :
  
 <code bash> <code bash>
-# Récupération de la clé publique du serveur +ls -la ~/mis-ssh-ca/ 
-scp mis-admin@srv01.acme.lan:/etc/ssh/ssh_host_ed25519_key.pub /tmp/srv01.pub+# mis-users-ca-emergency.age       ← clé privée DOUBLEMENT chiffrable (age + Bitwarden) 
 +# mis-users-ca-emergency.pub       ← clé publique (pas un secret) 
 +mis-users-ca-yubi.pub            ← clé publique de la Yubikey CA 
 +# mis-users-ca-yubi-cert.pub       ← cert X.509 PIV (inutile pour SSH) 
 +</code>
  
-# Signature comme hôte +==== Étape 2.5 : CA pour les hôtes (optionnelle pour démarrer====
-ssh-keygen -s ~/mis-ca/mis-hosts-ca \ +
-  -I "srv01.acme.lan-$(date +%Y)" \ +
-  -h \ +
-  -n "srv01.acme.lan,srv01,192.168.1.50"+
-  -V "+104w"+
-  /tmp/srv01.pub+
  
-# Envoi sur le serveur +Même approche pour la CA d'hôtes, si tu décides de la mettre en place : 
-scp /tmp/srv01-cert.pub mis-admin@srv01.acme.lan:/tmp/ +  * Soit sur la **même Yubikey** dans le slot 9a (Authentication) ou 9d (Key Management) 
-ssh mis-admin@srv01.acme.lan "sudo mv /tmp/srv01-cert.pub /etc/ssh/ssh_host_ed25519_key-cert.pub"+  * Soit avec un fichier classique chiffré, plus simple pour démarrer
  
-# Activation côté serveur +Comme tu as décidé de ne pas faire les certifs machines tout de suite, on saute cette étape pour le momentÀ reprendre quand tu te lanceras dans les certifs d'hôtes. 
-ssh mis-admin@srv01.acme.lan "sudo sed -i '/^HostCertificate/d' /etc/ssh/sshd_config && \ + 
-  echo 'HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub' | sudo tee -a /etc/ssh/sshd_config && \ +==== Étape 2.6 : Stratégie de stockage des secrets (double chiffrement) ==== 
-  sudo systemctl reload ssh"+ 
 +**Principe** : la clé emergency est protégée par **deux couches** indépendantes : 
 + 
 +<code> 
 +Clé privée Ed25519 (claire) 
 +        ↓ couche 1 : chiffrement age (passphrase forte) 
 +Fichier .age (illisible sans passphrase age) 
 +        ↓ couche 2 : attachment dans Bitwarden (chiffré par master password) 
 +Coffre Bitwarden (illisible sans master password)
 </code> </code>
  
-==== Étape 3.3 Configuration côté postes techniciens ====+Pour que cette défense en profondeur fonctionne, **les deux secrets doivent être stockés à des endroits différents** sinon une seule compromission donne accès à tout.
  
-Sur **chaque** poste tech (Windows ou Linux), dans ''~/.ssh/known_hosts'' :+=== Ce qui va dans Bitwarden === 
 + 
 +Entrée **"MIS SSH CA - Master Backup"** 
 + 
 +**Notes (champ texte de l'entrée)** :
  
 <code> <code>
-@cert-authority *.acme.lan,*.mis.lan,10.10.ssh-ed25519 AAAAC3... MIS Hosts CA+═══════════════════════════════════════════════ 
 +PROCÉDURE DE RÉCUPÉRATION D'URGENCE 
 + 
 +1Récupérer la passphrase age : 
 +   - Coffre bureau MISenveloppe scellée "CA Emergency" 
 +   - OU coffre backup (maison Vincent / coffre bancaire) 
 + 
 +2Télécharger mis-users-ca-emergency.age depuis cette entrée 
 + 
 +3Sur container éphémère : 
 +     docker run --rm -it --network none -v $PWD:/work mis-ca-gen bash 
 +     cd /work 
 +     age --decrypt mis-users-ca-emergency.age > recovery-key 
 +     chmod 600 recovery-key 
 +     # utiliser pour signer (voir Phase 9 du runbook) 
 +     shred -u recovery-key 
 +     exit 
 + 
 +═══════════════════════════════════════════════ 
 +INFOS YUBIKEY CA 
 + 
 +Serial number    : [serial à compléter] 
 +PIN PIV          : [PIN à compléter] 
 +PUK              : [PUK à compléter] 
 +Algorithme       : ECCP384 
 +Slot             : 9c 
 +Touch policy     : CACHED 
 +PIN policy       : ONCE 
 + 
 +═══════════════════════════════════════════════ 
 +FINGERPRINTS (vérification d'intégrité) 
 + 
 +Yubikey CA pub   : [ssh-keygen -l -f mis-users-ca-yubi.pub] 
 +Emergency CA pub : [ssh-keygen -l -f mis-users-ca-emergency.pub] 
 + 
 +═══════════════════════════════════════════════
 </code> </code>
  
-(la clé publique correspond au contenu de ''mis-hosts-ca.pub'')+**Attachments (fichiers attachés à l'entrée)** :
  
-À partir de ce moment, plus aucun warning de host key à la première connexion sur un serveur MIS.+^ Fichier ^ Sensibilité ^ Pourquoi dans Bitwarden ^ 
 +| ''mis-users-ca-emergency.age'' | DOUBLEMENT chiffré | Clé privée emergency, inutilisable sans la passphrase age | 
 +| ''mis-users-ca-emergency.pub'' | Publique (pas un secret) | Pratique pour la déployer et la vérifier | 
 +| ''mis-users-ca-yubi.pub'' | Publique (pas un secret) | Pratique pour le déploiement | 
 +| ''mis-users-ca-deploy.pub'' | Publique | Concaténation des 2 pubs prête à déployer | 
 + 
 +**Ce qui ne doit JAMAIS aller dans Bitwarden** : 
 +  * ❌ La passphrase age (sinon couche 1 + couche 2 = même point de défaillance) 
 +  * ❌ La clé privée emergency en clair 
 +  * ❌ Un export PKCS#12 de la Yubikey (impossible techniquement, mais à ne pas chercher à faire) 
 + 
 +=== Ce qui va sur papier (hors numérique) === 
 + 
 +La **passphrase age** uniquement. À écrire à la main sur papier : 
 + 
 +  * **Localisation principale** : coffre physique au bureau MIS, dans une enveloppe scellée "CA Emergency - Vincent uniquement" 
 +  * **Localisation backup** : coffre physique à la maison de Vincent (ou coffre bancaire), même enveloppe 
 + 
 +**Format recommandé** : passphrase Diceware 6-8 mots, plus facile à recopier sans erreur qu'une chaîne aléatoire. 
 + 
 +Exemple : ''correct horse battery staple winter coffee'' (à remplacer évidemment). 
 + 
 +**Approche avancée (optionnelle)** : Shamir Secret Sharing avec ''ssss-split'' pour découper la passphrase en N parts dont K nécessaires. Exemple : 3 parts, 2 nécessaires, distribuées entre Vincent + associé + avocat de confiance. Sécurité maximale, mais à mettre en place quand tout le reste est rodé. 
 + 
 +=== Backup hors-Bitwarden additionnel === 
 + 
 +En complément (ceinture-bretelles) : 
 +  * Clé USB chiffrée LUKS dans coffre physique avec une copie de tout ''~/mis-ssh-ca/'' 
 +  * À refaire à chaque rotation/renouvellement de CA 
 +  * La passphrase LUKS est encore un secret différent (toujours pas dans Bitwarden) 
 + 
 +==== Étape 2.7 : Test de récupération (CRITIQUE) ==== 
 + 
 +⚠️ **Avant de tout ranger dans le coffre et de considérer le setup terminé**, tu dois faire un test de récupération complet. C'est l'étape qui te garantit que le jour J, la procédure fonctionnera vraiment. 
 + 
 +<code bash> 
 +# 1. Dans un dossier temporaire de test 
 +mkdir /tmp/test-recovery && cd /tmp/test-recovery 
 + 
 +# 2. Copier le .age depuis Bitwarden (téléchargement de l'attachment) 
 +# OU depuis ~/mis-ssh-ca/ si encore dispo 
 +cp ~/mis-ssh-ca/mis-users-ca-emergency.age . 
 + 
 +# 3. Aller récupérer le papier dans le coffre, lire la passphrase 
 +#    (Geste réel, pas une simulation : tu dois vérifier que la passphrase 
 +#     est bien lisible et que tu peux la recopier sans erreur) 
 + 
 +# 4. Déchiffrer en utilisant la passphrase du papier 
 +age --decrypt mis-users-ca-emergency.age > recovery-key 
 +# → entrer la passphrase telle qu'écrite sur papier 
 + 
 +# 5. Vérifier que la clé déchiffrée est bien la bonne 
 +ssh-keygen -y -f recovery-key > recovered.pub 
 +diff recovered.pub ~/mis-ssh-ca/mis-users-ca-emergency.pub 
 +# Sortie attendue : VIDE (les deux fichiers sont identiques) 
 +# Si différents → la passphrase a été mal recopiée OU le .age est corrompu 
 + 
 +# 6. Nettoyage immédiat 
 +shred -u recovery-key recovered.pub 
 +cd .. && rm -rf /tmp/test-recovery 
 +</code> 
 + 
 +**Si le test réussit, tu as validé** : 
 +  * ✅ La passphrase est correctement écrite sur papier (lisible, sans erreur) 
 +  * ✅ Le fichier ''.age'' dans Bitwarden n'est pas corrompu 
 +  * ✅ Tu sais exécuter la procédure (le geste compte autant que le savoir) 
 +  * ✅ Les fingerprints correspondent 
 + 
 +**Si le test échoue**, NE PAS continuer. Identifier le problème (passphrase mal recopiée ? mauvais fichier ''.age'' ?) et regénérer si nécessaire. 
 + 
 +**À refaire annuellement** dans le cadre du drill de récupération (voir checklist en fin de doc). 
 + 
 +---- 
 + 
 +===== Phase 3 : Bootstrap d'un serveur client ===== 
 + 
 +==== Étape 3.1 : Préparation du fichier de CAs publiques ==== 
 + 
 +Sur ton poste de signature, prépare un fichier qui contient les **deux** clés publiques (Yubikey + emergency) que tu vas déployer sur tous les serveurs : 
 + 
 +<code bash> 
 +cd ~/mis-ssh-ca 
 +cat mis-users-ca-yubi.pub mis-users-ca-emergency.pub > mis-users-ca-deploy.pub 
 + 
 +cat mis-users-ca-deploy.pub 
 +# Doit contenir 2 lignes : 
 +# ecdsa-sha2-nistp384 AAAA... MIS Users CA - Yubikey 
 +# ssh-ed25519 AAAA... MIS Users CA - EMERGENCY USE ONLY 
 +</code> 
 + 
 +C'est ce fichier ''mis-users-ca-deploy.pub'' qui sera distribué sur tout le parc. OpenSSH accepte plusieurs CAs dans un même ''TrustedUserCAKeys'', une par ligne. 
 + 
 +==== Étape 3.2 : Déploiement sur un serveur client ==== 
 + 
 +Sur un serveur client (Debian 13 provisionné via cloud-init) : 
 + 
 +<code bash> 
 +# Copie du fichier de CAs 
 +scp ~/mis-ssh-ca/mis-users-ca-deploy.pub mis-admin@srv01.acme.lan:/tmp/ 
 + 
 +# Côté serveur, déploiement 
 +ssh mis-admin@srv01.acme.lan 
 +sudo install -o root -g root -m 0644 /tmp/mis-users-ca-deploy.pub /etc/ssh/mis-users-ca.pub 
 + 
 +# Création d'un KRL vide initial 
 +sudo ssh-keygen -k -f /etc/ssh/mis-revoked-keys 
 +sudo chmod 644 /etc/ssh/mis-revoked-keys 
 + 
 +# Configuration sshd 
 +sudo tee -a /etc/ssh/sshd_config <<'EOF' 
 + 
 +# ===== MIS SSH CA ===== 
 +TrustedUserCAKeys /etc/ssh/mis-users-ca.pub 
 +RevokedKeys /etc/ssh/mis-revoked-keys 
 +PasswordAuthentication no 
 +KbdInteractiveAuthentication no 
 +PubkeyAuthentication yes 
 +# ====================== 
 +EOF 
 + 
 +# Test et reload 
 +sudo sshd -t && sudo systemctl reload ssh 
 +</code> 
 + 
 +À industrialiser via Ansible (voir Phase 7).
  
 ---- ----
Ligne 295: Ligne 537:
 ==== Étape 4.1 : Génération sur le poste du technicien ==== ==== Étape 4.1 : Génération sur le poste du technicien ====
  
-**Sur Windows** :+**Sur Windows** (PowerShell, Yubikey du tech branchée) :
  
 <code powershell> <code powershell>
-# PowerShell, Yubikey branchée 
 # Définition d'un PIN FIDO2 si pas déjà fait (via Yubikey Manager GUI) # Définition d'un PIN FIDO2 si pas déjà fait (via Yubikey Manager GUI)
  
Ligne 316: Ligne 557:
 Résultat : ''id_ed25519_sk_yubi1'' (stub) et ''id_ed25519_sk_yubi1.pub'' (clé publique). Résultat : ''id_ed25519_sk_yubi1'' (stub) et ''id_ed25519_sk_yubi1.pub'' (clé publique).
  
-==== Étape 4.2 : Signature par la CA ====+==== Étape 4.2 : Signature par la CA Yubikey ====
  
-Le technicien envoie sa ''.pub'' à l'admin MIS (via Odoo, mail, ou git interne)Sur la CA :+Le tech envoie sa ''.pub'' au poste de signature**Yubikey CA branchée** :
  
 <code bash> <code bash>
-# Sur la LXC, en tant que ca-signer +cd ~/mis-ssh-ca 
-cd ~/mis-ca+export PKCS11=/usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
  
 # Variables # Variables
-PUBKEY_PATH=/tmp/vincent-yubi-primary.pub+PUBKEY=/tmp/vincent-yubi-primary.pub
 CERT_ID="vincent-yubi-primary-$(date +%Y)" CERT_ID="vincent-yubi-primary-$(date +%Y)"
 PRINCIPALS="mis-admin,vincent" PRINCIPALS="mis-admin,vincent"
 VALIDITY="+52w" VALIDITY="+52w"
-SERIAL=1001            # incrémenté à chaque signature+SERIAL=1001
  
-ssh-keygen -s mis-users-ca \+ssh-keygen -s mis-users-ca-yubi.pub \ 
 +  -D $PKCS11 \
   -I "$CERT_ID" \   -I "$CERT_ID" \
   -n "$PRINCIPALS" \   -n "$PRINCIPALS" \
Ligne 340: Ligne 582:
   -O no-agent-forwarding \   -O no-agent-forwarding \
   -O permit-pty \   -O permit-pty \
-  "$PUBKEY_PATH"+  "$PUBKEY"
  
-Le fichier vincent-yubi-primary-cert.pub est généré à côté de la .pub+Appuyer sur la yubikey dès que le pin est introduit 
 +# → demande le PIN PIV (1x par session grâce à --pin-policy ONCE) 
 +# → demande le touch sur la Yubikey CA 
 +# → fichier vincent-yubi-primary-cert.pub généré à côté de la .pub
 </code> </code>
 +
 +**Note importante** : avec ''-D $PKCS11'', l'argument ''-s'' n'est **pas** la clé privée (qui est sur la Yubikey) mais la clé **publique** de la CA. C'est elle qui permet à ''ssh-keygen'' d'identifier laquelle utiliser sur le token.
  
 Renvoyer le ''-cert.pub'' au technicien. Renvoyer le ''-cert.pub'' au technicien.
Ligne 364: Ligne 611:
 </code> </code>
  
-Doit afficher : Principals, Valid from/to, Critical Options, Extensions.+Doit afficher : Signing CA (''ECDSA SHA256:...'' = ta Yubikey CA), Principals, Valid from/to.
  
 ==== Étape 4.4 : Test de connexion ==== ==== Étape 4.4 : Test de connexion ====
Ligne 370: Ligne 617:
 <code bash> <code bash>
 ssh -i ~/.ssh/id_ed25519_sk_yubi1 mis-admin@srv01.acme.lan ssh -i ~/.ssh/id_ed25519_sk_yubi1 mis-admin@srv01.acme.lan
-# → PIN FIDO2 demandé +# → PIN FIDO2 demandé (côté Yubikey du tech) 
-# → touch Yubikey+# → touch Yubikey du tech
 # → connecté # → connecté
 </code> </code>
- 
-**Indicateur clé** : aucune modification d'''authorized_keys'' sur le serveur. Tout passe par le certificat. 
  
 ==== Étape 4.5 : Enrôlement de la Yubikey de backup ==== ==== Étape 4.5 : Enrôlement de la Yubikey de backup ====
  
-**Répéter Étape 4.1 à 4.4 avec la deuxième Yubikey**. Important utiliser un serial différent (''-z 1002''et un identifiant unique (''vincent-yubi-backup-2026'')+**Répéter Étape 4.1 à 4.4 avec la deuxième Yubikey du tech**. Utiliser : 
- +  * Serial différent (''-z 1002'') 
-À la fin, le technicien a 6 fichiers dans ''~/.ssh/''+  * Identifiant unique (''vincent-yubi-backup-2026'')
- +
-<code> +
-id_ed25519_sk_yubi1 +
-id_ed25519_sk_yubi1.pub +
-id_ed25519_sk_yubi1-cert.pub +
-id_ed25519_sk_yubi2 +
-id_ed25519_sk_yubi2.pub +
-id_ed25519_sk_yubi2-cert.pub +
-</code>+
  
 ==== Étape 4.6 : Configuration `~/.ssh/config` côté tech ==== ==== Étape 4.6 : Configuration `~/.ssh/config` côté tech ====
  
 <code> <code>
-Host *.acme.lan acme-* +Host *.acme.lan acme-* *.mis.lan
-    User mis-admin +
-    IdentityFile ~/.ssh/id_ed25519_sk_yubi1 +
-    IdentityFile ~/.ssh/id_ed25519_sk_yubi2 +
-    IdentitiesOnly yes +
-    CertificateFile ~/.ssh/id_ed25519_sk_yubi1-cert.pub +
-    CertificateFile ~/.ssh/id_ed25519_sk_yubi2-cert.pub +
- +
-Host *.mis.lan+
     User mis-admin     User mis-admin
     IdentityFile ~/.ssh/id_ed25519_sk_yubi1     IdentityFile ~/.ssh/id_ed25519_sk_yubi1
Ligne 411: Ligne 639:
     CertificateFile ~/.ssh/id_ed25519_sk_yubi2-cert.pub     CertificateFile ~/.ssh/id_ed25519_sk_yubi2-cert.pub
 </code> </code>
- 
-SSH essaiera Yubi1 d'abord, puis Yubi2 si la première n'est pas branchée. Aucune intervention nécessaire pour basculer. 
  
 ---- ----
Ligne 420: Ligne 646:
 ==== Étape 5.1 : Mise à jour de la KRL ==== ==== Étape 5.1 : Mise à jour de la KRL ====
  
-Sur la CA, si on perd la Yubikey backup de Vincent :+Yubikey CA branchée sur le poste de signature :
  
 <code bash> <code bash>
-cd ~/mis-ca+cd ~/mis-ssh-ca
  
-Création du spec de révocation+Spec de révocation
 cat > /tmp/krl-spec.txt <<'EOF' cat > /tmp/krl-spec.txt <<'EOF'
 # Révocation par serial # Révocation par serial
Ligne 437: Ligne 663:
 EOF EOF
  
-# Génération/mise à jour de la KRL +# Génération/mise à jour de la KRL via Yubikey 
-ssh-keygen -k -f mis-revoked-keys -s mis-users-ca -u /tmp/krl-spec.txt+ssh-keygen -k -f mis-revoked-keys 
 +  -s mis-users-ca-yubi.pub \ 
 +  -D $PKCS11 \ 
 +  -u /tmp/krl-spec.txt
 # -u = update (ajoute au KRL existant) # -u = update (ajoute au KRL existant)
-Sans -u, le KRL est remplacé +→ demande PIN + touch
- +
-# Vérification du contenu +
-ssh-keygen -Q -f mis-revoked-keys -t krl+
 </code> </code>
  
-==== Étape 5.2 : Déploiement de la KRL ==== +==== Étape 5.2 : Déploiement de la KRL via Ansible ====
- +
-Via Ansible sur tout le parc (voir Phase 7) :+
  
 <code bash> <code bash>
-ansible-playbook -i inventory.yml mis-deploy-krl.yml+ansible-playbook -i inventory.yml mis-update-krl.yml
 </code> </code>
  
Ligne 459: Ligne 683:
  
 ===== Phase 6 : Renouvellement des certificats ===== ===== Phase 6 : Renouvellement des certificats =====
- 
-Les certificats ayant une durée de vie de 1 an, prévoir un workflow de renouvellement : 
  
 ==== Option A : Manuel ==== ==== Option A : Manuel ====
  
-Refaire les étapes 4.2 (signature) avec un nouvel identifiant ''vincent-yubi-primary-2027'' et envoyer le nouveau ''-cert.pub'' au tech. Le tech remplace son ancien ''-cert.pub''.+Refaire l'étape 4.2 (signature) avec un nouvel identifiant ''vincent-yubi-primary-2027'' et envoyer le nouveau ''-cert.pub'' au tech. Le tech remplace son ancien ''-cert.pub''.
  
 ==== Option B : Automatisé via Odoo ==== ==== Option B : Automatisé via Odoo ====
Ligne 471: Ligne 693:
   - Notifie le tech par mail   - Notifie le tech par mail
   - Propose un wizard de renouvellement   - Propose un wizard de renouvellement
-  - Si le tech accepte, regénère un certif via l'API de la CA +  - Si le tech accepte, déclenche une demande de signature (qui attend que tu branches la Yubikey CA + valides physiquement) 
-  - Envoie le nouveau ''-cert.pub'' au tech (par mail chiffré ou portail download)+  - Envoie le nouveau ''-cert.pub'' au tech
  
 ---- ----
Ligne 488: Ligne 710:
   become: true   become: true
   vars:   vars:
-    ca_pub_path: files/mis-users-ca.pub+    ca_pub_path: files/mis-users-ca-deploy.pub   # contient les 2 CAs (Yubikey + emergency)
     krl_path: files/mis-revoked-keys     krl_path: files/mis-revoked-keys
      
   tasks:   tasks:
-    - name: Deploy MIS users CA public key+    - name: Deploy MIS users CA public keys
       copy:       copy:
         src: "{{ ca_pub_path }}"         src: "{{ ca_pub_path }}"
Ligne 544: Ligne 766:
 </code> </code>
  
-==== Playbook de mise à jour KRL uniquement (rapide) ====+==== Playbook de mise à jour KRL uniquement ====
  
 ''playbooks/mis-update-krl.yml'' : ''playbooks/mis-update-krl.yml'' :
Ligne 575: Ligne 797:
 ⚠️ **Ne JAMAIS sauter cette étape.** ⚠️ **Ne JAMAIS sauter cette étape.**
  
-Indépendamment de la CA, chaque serveur doit avoir au moins un accès de secours :+C'est un parachute **indépendant** de la CA SSH (ni Yubikeyni emergency CA). Le compte break-glass utilise une clé SSH classique, pour le cas où **toute** la PKI CA serait inaccessible (perte Yubikey + Bitwarden corrompu + papier coffre perdu, scénario apocalypse).
  
 <code bash> <code bash>
Ligne 583: Ligne 805:
  
 # Stocker mis-breakglass (privé) : # Stocker mis-breakglass (privé) :
-#   - Chiffré dans Bitwarden (attachment)+#   - Chiffré dans Bitwarden (attachment) - entrée distincte de la CA
 #   - Sur clé USB chiffrée dans coffre physique #   - Sur clé USB chiffrée dans coffre physique
 #   - Supprimer du disque local après stockage sécurisé #   - Supprimer du disque local après stockage sécurisé
Ligne 593: Ligne 815:
  
 <code bash> <code bash>
-# Dans virt-customize de la golden image 
 virt-customize -a debian-13-genericcloud-amd64.qcow2 \ virt-customize -a debian-13-genericcloud-amd64.qcow2 \
   --run-command 'useradd -m -s /bin/bash mis-breakglass' \   --run-command 'useradd -m -s /bin/bash mis-breakglass' \
Ligne 600: Ligne 821:
   ...   ...
 </code> </code>
- 
-Le jour où la CA est inaccessible (perte de toutes les Yubikeys, corruption de la LXC, etc.), tu sors la clé du coffre Bitwarden, tu te connectes avec, tu reconstruis la situation. 
  
 ---- ----
  
-===== Phase 9 : Migration future vers Yubikey PIV pour la CA =====+===== Phase 9 : Procédure de récupération d'urgence =====
  
-Quand le workflow sera rodé (6-12 mois), migration de la clé privée de la CA depuis disque vers Yubikey PIV :+==== Cas 1 Yubikey CA perdue / cassée, emergency disponible ====
  
-<code bash> +**Workflow** :
-# Sur un poste sûr, Yubikey dédiée "CA Master" branchée +
-apt install yubikey-manager opensc+
  
-# Génération d'une nouvelle paire ECCP384 dans slot 9c +  - Acheter une nouvelle Yubikey 5 NFC dédiée à la CA 
-ykman piv keys generate --algorithm ECCP384 --pin-policy ONCE --touch-policy CACHED \ +  - Déchiffrer temporairement l'emergency : 
-  9c /tmp/mis-ca-piv.pub+   ```bash 
 +   cd ~/mis-ssh-ca 
 +   age --decrypt mis-users-ca-emergency.age > /tmp/emergency-key 
 +   chmod 600 /tmp/emergency-key 
 +   ``` 
 +  - **Utiliser l'emergency CA pour signer une nouvelle CA Yubikey** (chaîne de confiance temporaire) : 
 +   ```bash 
 +   # Préparer la nouvelle Yubikey (Étapes 1.4 + 2.1 à 2.3) 
 +   # Tu obtiens mis-users-ca-yubi-NEW.pub 
 +   ``` 
 +  Mettre à jour ''mis-users-ca-deploy.pub'' pour inclure la **nouvelle** Yubikey CA + l'emergency (toujours) : 
 +   ```bash 
 +   cat mis-users-ca-yubi-NEW.pub mis-users-ca-emergency.pub > mis-users-ca-deploy.pub 
 +   ``` 
 +  - Déployer via Ansible sur tout le parc 
 +  - Révoquer l'ancienne Yubikey CA via KRL (signature avec la NEW Yubikey) : 
 +   ```bash 
 +   cat > /tmp/krl-revoke-old-ca.txt <<'EOF' 
 +   # Révocation de l'ancienne CA Yubikey perdue 
 +   sha256: SHA256:<fingerprint de mis-users-ca-yubi-OLD.pub
 +   EOF 
 +    
 +   ssh-keygen -k -f mis-revoked-keys \ 
 +     -s mis-users-ca-yubi-NEW.pub \ 
 +     -D $PKCS11 \ 
 +     -u /tmp/krl-revoke-old-ca.txt 
 +   ``` 
 +  - **Effacement sécurisé** du fichier emergency en clair : 
 +   ```bash 
 +   shred -u /tmp/emergency-key 
 +   ``` 
 +  - Mise à jour de l'entrée Bitwarden avec le nouveau serial Yubikey
  
-# Certificat self-signed pour PIV +**Important** : tous les certificats utilisateurs signés par l'ancienne Yubikey CA sont **toujours valides** (puisque l'ancienne CA est encore dans le déploiement jusqu'à révocation, et que la révocation cible le pub de la CA, pas les certifs signés). Pour invalider tous les certifs émis par l'ancienne CA, supprimer son ''.pub'' du déploiement et redéployer.
-ykman piv certificates generate --subject "CN=MIS Users CA" 9c /tmp/mis-ca-piv.pub+
  
-# Export au format SSH +==== Cas 2 : Tout est perdu sauf break-glass ====
-ssh-keygen -D /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so -e > mis-users-ca-yubi.pub +
-</code>+
  
-Pour signer ensuite :+Scénario apocalypse Yubikey CA perdue + Bitwarden inaccessible + papier coffre détruit.
  
-<code bash> +  - Connexion sur chaque serveur via SSH avec ''mis-breakglass''
-ssh-keygen -mis-users-ca-yubi.pub \ +   ```bash 
-  -D /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so \ +   ssh -i ~/.bitwarden-recovered/mis-breakglass mis-breakglass@srv01.acme.lan 
-  -I "vincent-yubi-primary-2027" \ +   ``` 
-  -n "mis-admin,vincent" \ +  - Régénération complète d'une nouvelle CA (depuis zéro, Phase 2) 
-  -V "+52w"+  - Déploiement manuel du nouveau ''mis-users-ca.pub'' sur chaque serveur via ''mis-breakglass'' 
-  vincent-yubi-primary.pub +  - Re-signature de toutes les Yubikeys techniciens 
-# → PIN PIV demandé +  - Rotation du break-glass aussi (puisqu'il a servi)
-# → touch Yubikey +
-# → certificat signé +
-</code>+
  
-La clé privée de la CA n'existe plus sur disque, elle est uniquement dans la Yubikey "CA Master" (qui doit avoir une jumelle de backup stockée en coffre).+**À tester** : faire un drill annuel de récupération sur un environnement de staging pour valider que la procédure marche **avant** d'en avoir vraiment besoin.
  
 ---- ----
Ligne 649: Ligne 891:
 # Inspecter un certificat utilisateur # Inspecter un certificat utilisateur
 ssh-keygen -L -f id_ed25519_sk_yubi1-cert.pub ssh-keygen -L -f id_ed25519_sk_yubi1-cert.pub
 +
 +# Voir l'état PIV de la Yubikey CA
 +ykman piv info
 +
 +# Voir le slot 9c (où vit la CA)
 +ykman piv keys metadata 9c
  
 # Voir la KRL active sur un serveur # Voir la KRL active sur un serveur
Ligne 657: Ligne 905:
 # Output: "id_ed25519_sk_yubi1-cert.pub: ok" ou "REVOKED" # Output: "id_ed25519_sk_yubi1-cert.pub: ok" ou "REVOKED"
  
-# Côté serveur, voir quelles connexions par certificat+# Côté serveur, voir les connexions par certificat
 journalctl -u ssh | grep "Accepted publickey.*ID" journalctl -u ssh | grep "Accepted publickey.*ID"
  
-# Lister les clés résidentes sur une Yubikey +# Lister les clés publiques visibles via PKCS#11 (avec Yubikey CA branchée) 
-ssh-keygen -K +ssh-keygen -D $PKCS11 -e 
-Récupère les stubs sur le poste courant depuis la Yubikey+ 
 +Tester une signature sans toucher à un fichier 
 +echo "test" | ssh-keygen -Y sign -n test -f mis-users-ca-yubi.pub -D $PKCS11
 </code> </code>
  
-==== B. Format complet d'une signature ssh-keygen ====+==== B. Format complet d'une signature ssh-keygen avec Yubikey ====
  
 <code bash> <code bash>
-ssh-keygen -s CA_PRIVATE_KEY \+ssh-keygen -s CA_PUBLIC_KEY \ 
 +  -D PKCS11_PROVIDER \
   -I CERT_IDENTIFIER \   -I CERT_IDENTIFIER \
   -n PRINCIPAL1,PRINCIPAL2 \   -n PRINCIPAL1,PRINCIPAL2 \
Ligne 679: Ligne 930:
  
 ^ Option ^ Description ^ ^ Option ^ Description ^
-| ''-s'' | Chemin vers la clé privée de la CA |+| ''-s'' | Chemin vers la clé **publique** de la CA (quand ''-D'' est utilisé) | 
 +| ''-D'' | Path vers le module PKCS#11 (''opensc-pkcs11.so''|
 | ''-I'' | Identifiant lisible du certificat (visible dans logs sshd) | | ''-I'' | Identifiant lisible du certificat (visible dans logs sshd) |
 | ''-n'' | Principals (noms d'utilisateurs autorisés), séparés par virgule | | ''-n'' | Principals (noms d'utilisateurs autorisés), séparés par virgule |
Ligne 688: Ligne 940:
 | ''-O no-port-forwarding'' | Désactive le port forwarding | | ''-O no-port-forwarding'' | Désactive le port forwarding |
 | ''-O no-agent-forwarding'' | Désactive l'agent forwarding | | ''-O no-agent-forwarding'' | Désactive l'agent forwarding |
-| ''-O no-X11-forwarding'' | Désactive X11 | 
 | ''-O permit-pty'' | Autorise l'allocation PTY (interactif) | | ''-O permit-pty'' | Autorise l'allocation PTY (interactif) |
 | ''-O force-command="..."'' | Force l'exécution d'une commande spécifique | | ''-O force-command="..."'' | Force l'exécution d'une commande spécifique |
Ligne 695: Ligne 946:
 ==== C. Liens utiles ==== ==== C. Liens utiles ====
  
-  * OpenSSH manual ''ssh-keygen(1)'' : ''man ssh-keygen''+  * OpenSSH manual ''ssh-keygen(1)'' : ''man ssh-keygen'' (sections CERTIFICATES et KEY REVOCATION LISTS)
   * Documentation officielle Yubico FIDO2 SSH : https://developers.yubico.com/SSH/   * Documentation officielle Yubico FIDO2 SSH : https://developers.yubico.com/SSH/
-  * Cloud-init reference : https://cloudinit.readthedocs.io/+  * Documentation Yubico PIV : https://developers.yubico.com/PIV/Guides/SSH//with//PIV//and//PKCS11.html 
 +  * Documentation ''age'' : https://age-encryption.org/
   * Format des certificats SSH (technique) : ''PROTOCOL.certkeys'' dans le code OpenSSH   * Format des certificats SSH (technique) : ''PROTOCOL.certkeys'' dans le code OpenSSH
  
Ligne 704: Ligne 956:
 ===== Checklist de mise en place ===== ===== Checklist de mise en place =====
  
-==== Phase 0 - Préparation ==== +==== Phase 0 - Matériel et logiciels ==== 
-  * [ ] Yubikeys commandées (minimum 2 par technicien + 1 vault+  * [ ] Yubikey 5 NFC dédiée à la CA commandée 
-  * [ ] PINs FIDO2 définis sur chaque Yubikey (via Yubikey Manager) +  * [ ] Yubikeys 5 NFC techniciens commandées (2 par tech minimum
-  * [ ] Bitwarden ready pour stockage des secrets+  * [ ] Bitwarden ready avec entrée "MIS SSH CA - Master Backup" 
 +  * [ ] Coffre physique identifié pour passphrase + clé USB de backup 
 +  * [ ] OpenSSH + yubikey-manager + opensc + age installés sur le poste de signature
  
 ==== Phase 1-2 - CA ==== ==== Phase 1-2 - CA ====
-  * [ ] LXC ''mis-ssh-ca'' créée et durcie +  * [ ] PINs PIV de la Yubikey CA configurés (PIN + PUK + management key) 
-  * [ ] CA users générée + passphrase robuste +  * [ ] CA principale générée sur Yubikey (slot 9c, ECCP384) 
-  * [ ] CA hosts générée + passphrase robuste +  * [ ] Clé publique Yubikey CA exportée (''mis-users-ca-yubi.pub'') 
-  * [ ] Backup chiffré des CAs dans Bitwarden + offline +  * [ ] Image Docker ''mis-ca-gen'' préparée 
-  * [ ] LXC éteinte par défaut, allumage à la demande+  * [ ] Emergency CA générée dans container éphémère chiffrée avec age 
 +  * [ ] Bitwarden : entrée "MIS SSH CA - Master Backup" avec attachments 
 +  * [ ] Passphrase age écrite sur papier dans coffre bureau MIS 
 +  * [ ] Passphrase age (copie) dans coffre backup (maison ou bancaire) 
 +  * [ ] Backup additionnel sur clé USB LUKS dans coffre 
 +  * [ ] **Test de récupération validé** (Étape 2.7) avant rangement définitif
  
 ==== Phase 3 - Bootstrap parc ==== ==== Phase 3 - Bootstrap parc ====
-  * [ ] Compte break-glass ''mis-breakglass'' créé et clé déployée partout+  * [ ] Compte break-glass ''mis-breakglass'' créé et clé déployée partout (indépendant CA)
   * [ ] Playbook Ansible ''mis-ssh-ca-deploy.yml'' testé sur 1-2 serveurs   * [ ] Playbook Ansible ''mis-ssh-ca-deploy.yml'' testé sur 1-2 serveurs
 +  * [ ] Fichier ''mis-users-ca-deploy.pub'' contient les 2 CAs (Yubikey + emergency)
   * [ ] Déploiement progressif sur le parc complet   * [ ] Déploiement progressif sur le parc complet
-  * [ ] Certificats d'hôtes générés pour les serveurs critiques 
  
 ==== Phase 4 - Techniciens ==== ==== Phase 4 - Techniciens ====
Ligne 730: Ligne 989:
   * [ ] Module Odoo ''makeitsimple_ssh_ca'' (modèles + wizards)   * [ ] Module Odoo ''makeitsimple_ssh_ca'' (modèles + wizards)
   * [ ] Intégration Semaphore pour déploiement KRL   * [ ] Intégration Semaphore pour déploiement KRL
-  * [ ] Cron de notification d'expiration +  * [ ] Cron de notification d'expiration des certifs 
-  * [ ] Migration CA vers Yubikey PIV (à 6-12 mois)+  * [ ] **Drill de récupération annuel** (cas 1 emergencytesté en staging
  
 ---- ----
  
 //Document maintenu par Make IT Simple - dernière révision : 2026// //Document maintenu par Make IT Simple - dernière révision : 2026//
linux/ca-ssh.1780492595.txt.gz · Dernière modification : de root