EAG Proxmox via le tunnel SSH Cloudflare
Le serveur Proxmox VE 9.2 héberge des machines virtuelles de test jetables. Depuis cet environnement, l'hôte est eric-pve-ssh.eag.tools. Les agents clonent un modèle, exécutent le test, puis demandent avant de supprimer quoi que ce soit.
Les modèles, les étapes de clonage et les connexions aux invités correspondent à l'environnement LAN. Ce qui change, c'est le chemin : l'agent cloud atteint l'hôte via Cloudflare Access, et atteint chaque invité en passant par cet hôte.
Accès
Le script de démarrage de l'environnement écrit la paire de clés à partir de PVE_SSH_PRIVATE_B64 et PVE_SSH_PUBLIC_KEY :
| Fichier | Mode | Utilisation |
|---|---|---|
~/.ssh/pve_ssh | 600 | Clé privée. Hôte Proxmox, Windows Administrator, Ubuntu erolleman. |
~/.ssh/pve_ssh.pub | 644 | Clé publique correspondante. |
/etc/ssh/ssh_config.d/eric-pve-ssh.conf définit déjà User root, IdentityFile ~/.ssh/pve_ssh, IdentitiesOnly yes, et ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h pour eric-pve-ssh.eag.tools. Utilisez cet alias d'hôte. Laissez le fichier système en place.
KEY="$HOME/.ssh/pve_ssh"
test -r "$KEY" || { echo "$KEY manquant ; le script de démarrage le crée à partir de PVE_SSH_PRIVATE_B64" >&2; exit 1; }
PVE="ssh -o StrictHostKeyChecking=accept-new eric-pve-ssh.eag.tools"
$PVE 'qm list'
SSH invité, pour 10.115.64.x (vmbr0) et 10.20.0.x (nat0) :
JUMP='ssh -o StrictHostKeyChecking=accept-new -W %h:%p eric-pve-ssh.eag.tools'
VMSSH="ssh -i $KEY -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 -o ProxyCommand=\"$JUMP\" USER@$IP"
Définissez USER sur Administrator ou erolleman et IP sur l'adresse de l'invité avant de développer VMSSH.
- Connexion VM Windows :
Administrator/Change_me, ou~/.ssh/pve_ssh. - Connexion VM Ubuntu :
erollemanavec~/.ssh/pve_ssh.sudoest sans mot de passe.dockernécessitesudo. - L'interface Web Proxmox écoute sur le LAN à
https://10.115.64.44:8006. Ce tunnel est réservé à SSH. Administrez l'hôte avecqmetpveshvia$PVE. - Gardez le matériel de clé dans les fichiers ci-dessus. Ne lisez ni
~/.ssh/pve_sshniPVE_SSH_PRIVATE_B64dans une commande, un journal ou une réponse. Ne générez pas de clé de remplacement.
PowerShell à distance via SSH utilise le même saut. Ajoutez ceci à ~/.ssh/config (uniquement le bloc Host de l'invité ; le fichier système couvre déjà l'hôte du tunnel) :
Host 10.115.64.* 10.20.0.*
IdentityFile ~/.ssh/pve_ssh
IdentitiesOnly yes
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
ProxyCommand ssh -o StrictHostKeyChecking=accept-new -W %h:%p eric-pve-ssh.eag.tools
Enter-PSSession -HostName <ip> -UserName Administrator -KeyFilePath "$HOME/.ssh/pve_ssh"
Règles strictes
- Ne jamais démarrer, modifier, cloner par-dessus ou supprimer la VM 100 (
ubuntu-2404) ou la VM 101 (ws2025-template). Ce sont des modèles. - Ne pas modifier la configuration de l'hôte (stockage, réseau, SDN, paquets) sauf demande explicite de l'utilisateur.
- Ne pas réexécuter sysprep,
windows-template/Copy-SysprepFiles.ps1ouubuntu-template/cloud-init-prepare.shsur un clone. Ces scripts préparent les modèles et restent sur le poste de travail. Ils ne sont pas dans cet environnement. - Taguez chaque VM que vous créez avec
ai-test. - Lorsque les tests sont terminés, demandez à l'utilisateur s'il faut détruire les VMs que vous avez créées. Ne détruisez jamais une VM sans la réponse de l'utilisateur.
- N'ouvrez pas de session SSH directe vers
10.115.64.44,10.115.64.xou10.20.0.x. Ces réseaux ne sont pas routés vers l'agent cloud. Les commandes hôte passent pareric-pve-ssh.eag.tools. Les commandes invité utilisent le sautProxyCommandci-dessus.
Informations sur l'hôte
L'hôte est une machine virtuelle Hyper-V. La virtualisation imbriquée VT-x est exposée. Sur le LAN, son adresse est 10.115.64.44.
| Élément | Valeur |
|---|---|
| Matériel | Intel Xeon Gold 6234 (8 cœurs / 16 threads), 94 Go de RAM. Dimensionnez les VMs en conséquence. |
vmbr0 | Pont LAN, DHCP. Adresse hôte 10.115.64.44/24, passerelle et DNS 10.115.64.1, domaine de recherche eag.lan. Les cartes réseau des deux modèles sont sur ce pont. Les adresses invitées sont 10.115.64.x. Depuis cet environnement, SSH vers elles passe par eric-pve-ssh.eag.tools. |
nat0 | VNet SDN (zone simple nat), 10.20.0.0/24. Passerelle 10.20.0.1. DHCP 10.20.0.100–10.20.0.200 (12 h) depuis dnsmasq sur l'hôte, DNS 10.20.0.1. SNAT sortie vmbr0 en tant que 10.115.64.44. L'hôte Proxmox peut atteindre ce sous-réseau. Depuis cet environnement, SSH vers 10.20.0.x utilise le même saut. |
local-data | LVM-thin sur VG vmdata, ~671 Go. Disques VM, EFI, TPM et disques cloud-init. |
local-lvm | LVM-thin sur le petit VG système PVE, ~23 Go, vide. Laissez-le inutilisé. |
local | Répertoire sur le système de fichiers racine. Sauvegardes, modèles de conteneurs, importations. |
isos | Répertoire /mnt/isos. ISO d'installation uniquement. |
Quel modèle
| Besoin | Clone |
|---|---|
| Windows, RDP ou Windows PowerShell | 101 ws2025-template |
Linux, Docker, pwsh ou Nushell | 100 ubuntu-2404 |
Si l'utilisateur ne précise pas de système d'exploitation, demandez avant de cloner.
Les clones Windows activent RDP à l'intérieur de l'invité. Le tunnel Cloudflare transporte SSH. Utilisez SSH ou PowerShell à distance pour atteindre l'invité.
Modèle : ws2025-template (VMID 101)
Windows Server 2025 Datacenter Evaluation. 4 vCPU (host), 4 Go de RAM, UEFI + Secure Boot + TPM 2.0, disque SCSI VirtIO de 64 Go sur local-data, carte réseau VirtIO sur vmbr0 (4 files d'attente), pilotes VirtIO et agent invité QEMU installés.
Au premier démarrage, chaque clone automatiquement :
- Obtient un nom d'ordinateur aléatoire, fuseau horaire Pacifique, locale en-US, et mot de passe Administrateur
Change_me. - Se connecte automatiquement une fois et exécute
Initialize-WindowsServer.ps1, qui installe la dernière version de PowerShell 7 depuis GitHub, active le serveur OpenSSH avec un sous-systèmepowershell(PS à distance via SSH), ajoute la clé SSH àadministrators_authorized_keys, active RDP, définit les réseaux Publics sur Privé, et supprime l'exigence Ctrl+Alt+Del. - Supprime le mot de passe de connexion automatique et le fichier de réponses, écrit
C:\ProgramData\TemplateSetup\setup-complete, puis redémarre.
Le premier démarrage prend plusieurs minutes et nécessite internet (téléchargement de PowerShell 7). Journal : C:\ProgramData\TemplateSetup\Initialize-WindowsServer.log.
Modèle : ubuntu-2404 (VMID 100)
Ubuntu 24.04.5 LTS. 2 vCPU (x86-64-v2-AES), 4 Go de RAM, UEFI (clés Secure Boot non inscrites), pas de TPM, disque SCSI VirtIO de 32 Go sur local-data, carte réseau VirtIO sur vmbr0. Agent invité QEMU, OpenSSH, PowerShell 7 (pwsh), Nushell (nu sur /usr/local/bin) et Docker sont installés. Podman n'est pas installé. Le fuseau horaire est UTC.
Cloud-init a été nettoyé et limité aux sources de données NoCloud et ConfigDrive. Le disque n'a pas de netplan, donc un clone n'a pas de réseau tant que Proxmox cloud-init ne s'exécute pas. Le compte erolleman est déjà dans sudo et possède déjà la clé publique du projet. SSH est activé par socket. L'agent invité démarre depuis udev lorsque le port virtio apparaît.
Les user-data générées par Proxmox créent également un compte ubuntu verrouillé sans clé SSH. Connectez-vous en tant que erolleman.
Workflow : créer une VM de test
- [ ] 1. Confirmer que la VM source est un modèle
- [ ] 2. Cloner, configurer, taguer, démarrer
- [ ] 3. Obtenir l'IP depuis l'agent invité
- [ ] 4. Attendre la fin du premier démarrage
- [ ] 5. Exécuter le test
- [ ] 6. Demander à l'utilisateur s'il faut détruire la VM
1. Confirmer le modèle. Si cela n'affiche rien, arrêtez et informez l'utilisateur. Ne clonez pas une VM qui n'est pas un modèle.
$PVE 'qm config 101 | grep ^template' # Windows
$PVE 'qm config 100 | grep ^template' # Ubuntu
2. Cloner, configurer, taguer, démarrer. Les clones liés sont par défaut. Ajoutez --full --storage local-data uniquement lorsque la VM doit survivre au modèle.
Les clones héritent de 4 vCPU / 4 Go (Windows) ou 2 vCPU / 4 Go (Ubuntu). Lorsque le test nécessite plus, utilisez qm set sur le clone avant de le démarrer. Laissez les modèles inchangés.
Windows :
ID=$($PVE 'pvesh get /cluster/nextid')
$PVE "qm clone 101 $ID --name test-<but> && qm set $ID --tags ai-test && qm start $ID"
Ubuntu : attachez le disque cloud-init avant le premier démarrage. ide2 sur le modèle est un CD vide ; remplacez-le. --ciupgrade 0 ignore la mise à jour complète des paquets par défaut. Sans --ipconfig0 ip=dhcp, le clone n'obtient jamais d'adresse.
ID=$($PVE 'pvesh get /cluster/nextid')
$PVE "qm clone 100 $ID --name test-<but> && qm set $ID --tags ai-test --ide2 local-data:cloudinit --citype nocloud --ipconfig0 ip=dhcp --ciupgrade 0 --boot order=scsi0 && qm start $ID"
Réseau isolé, pour les deux OS : avant le démarrage, placez la carte réseau sur nat0. Gardez cela uniquement lorsque l'utilisateur souhaite que la VM soit hors du LAN. L'adresse de l'invité sera 10.20.0.x. SSH depuis cet environnement utilise toujours le saut dans Accès ; l'hôte Proxmox est celui qui peut atteindre nat0.
$PVE "qm set $ID --net0 virtio,bridge=nat0"
# Ubuntu uniquement. Windows obtient un DHCP tout seul. Pointez le DNS Ubuntu vers dnsmasq sur la passerelle NAT.
$PVE "qm set $ID --ipconfig0 ip=dhcp --nameserver 10.20.0.1"
3. Obtenir l'IP. L'agent invité répond une fois que l'OS est opérationnel. Réessayez toutes les ~15 s. Utilisez l'adresse 10.115.64.x pour une carte réseau vmbr0, ou l'adresse 10.20.0.x pour nat0.
$PVE "qm guest cmd $ID network-get-interfaces" \
| jq -r '.[]."ip-addresses"[]? | select(."ip-address-type"=="ipv4") | ."ip-address"' \
| grep -vE '^(127\.|169\.254\.)'
4. Attendre le premier démarrage. Les clones obtiennent de nouvelles clés d'hôte et les adresses sont réutilisées, donc SSH invité ignore la vérification des clés d'hôte. La clé de l'hôte de saut est stockée avec accept-new.
Windows : SSH se met en place pendant l'installation, et le script redémarre la VM à la fin. La VM est prête une fois que setup-complete existe et que Windows a redémarré depuis son écriture.
VMSSH="ssh -i $KEY -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 -o ProxyCommand=\"$JUMP\" Administrator@$IP"
# -EncodedCommand (base64 UTF-16LE) évite les guillemets imbriqués bash/cmd/PowerShell.
PS_CHECK=$(cat <<'EOF'
$m = Get-Item C:\ProgramData\TemplateSetup\setup-complete -ErrorAction SilentlyContinue
if ($m -and (Get-CimInstance Win32_OperatingSystem).LastBootUpTime -gt $m.LastWriteTime) { 'READY ' + (Get-Content $m.FullName) } else { 'WAITING' }
EOF
)
CHECK="powershell -NoProfile -EncodedCommand $(printf %s "$PS_CHECK" | iconv -t UTF-16LE | base64 -w0)"
until STATUS=$($VMSSH "$CHECK" 2>/dev/null | tr -d '\r'); [[ $STATUS == READY* ]]; do sleep 15; done
echo "$STATUS"
READY succeeded signifie que l'installation est terminée et que la VM a redémarré. Si elle affiche READY failed, lisez le journal et signalez-le :
$VMSSH 'powershell -NoProfile -Command "Get-Content C:\ProgramData\TemplateSetup\Initialize-WindowsServer.log -Tail 30"'
Ubuntu : attendez que cloud-init signale status: done. status: error signifie qu'il faut arrêter et lire /var/log/cloud-init-output.log.
VMSSH="ssh -i $KEY -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 -o ProxyCommand=\"$JUMP\" erolleman@$IP"
until STATUS=$($VMSSH 'cloud-init status 2>/dev/null' | tr -d '\r'); [[ $STATUS == status:\ done || $STATUS == status:\ error ]]; do sleep 10; done
echo "$STATUS"
5. Exécuter le test.
Windows : le shell SSH par défaut est cmd.exe.
$VMSSH 'pwsh -NoProfile -Command "Get-ComputerInfo | Select-Object OsName, CsName"'
PowerShell à distance via SSH (depuis pwsh sur l'agent cloud) utilise le bloc invité ~/.ssh/config dans Accès :
Enter-PSSession -HostName <ip> -UserName Administrator -KeyFilePath "$HOME/.ssh/pve_ssh"
Ubuntu :
$VMSSH 'pwsh -NoLogo -Command "$PSVersionTable.PSVersion.ToString()"'
$VMSSH 'sudo docker info --format "{{.ServerVersion}}"'
6. Demander avant de nettoyer. Rapportez les résultats des tests, listez les VMs que vous avez créées (VMID, nom, IP), et demandez à l'utilisateur s'il faut les détruire. Utilisez l'outil AskQuestion lorsque disponible, avec les options "Détruire", "Garder en cours d'exécution" et "Éteindre mais garder" (plus des choix par VM si vous en avez créé plusieurs).
Si l'utilisateur choisit de détruire :
$PVE "qm stop $ID && qm destroy $ID --purge"
Si l'utilisateur choisit de garder mais d'éteindre :
$PVE "qm shutdown $ID --timeout 120 || qm stop $ID"
Lorsque les VMs sont conservées, indiquez à l'utilisateur leurs VMIDs afin qu'elles puissent être retrouvées ultérieurement (elles conservent le tag ai-test).
Instantanés
Les disques des deux modèles sont sur LVM-thin, donc les clones prennent en charge les instantanés :
$PVE "qm snapshot $ID before-test"
$PVE "qm rollback $ID before-test"
$PVE "qm delsnapshot $ID before-test"
Nettoyage et inventaire
$PVE 'pvesh get /cluster/resources --type vm --output-format json' \
| jq -r '.[] | select((.tags // "") | split(";") | index("ai-test")) | "\(.vmid)\t\(.name)\t\(.status)"'
Proposez de détruire uniquement les VMs ai-test que vous avez créées dans cette session, sauf si l'utilisateur demande un nettoyage plus large. Obtenez toujours la confirmation de l'utilisateur au préalable.
Pièges
- Windows est une édition d'évaluation avec une licence de 180 jours. Utilisez-la pour des VMs éphémères.
- Un clone Ubuntu qui démarre une fois sans le disque cloud-init se retrouve sans réseau, et cloud-init ne réessaiera pas proprement. Détruisez-le et clonez à nouveau.
- N'exécutez pas
sysprepsur les clones Windows et ne convertissez pas les clones de l'un ou l'autre modèle en modèles. - L'adresse de l'hôte est un bail DHCP. Le SNAT de
nat0est épinglé à10.115.64.44. Si cette adresse change, dites-le ; ne modifiez pas le SDN sauf demande de l'utilisateur. cloudflaredest invoqué en tant que/usr/local/bin/cloudflaredpar la configuration SSH système. Un fichier de clé manquant signifie que le script de démarrage ne s'est pas exécuté ; ne touchez pas aux secrets et signalez-le.- Les clés d'hôte des invités changent à chaque clone.
UserKnownHostsFile=/dev/nulls'applique à la session invitée. La clé d'hôte du tunnel reste dans~/.ssh/known_hosts.