EAG Proxmox através do túnel SSH Cloudflare
O servidor Proxmox VE 9.2 hospeda VMs de teste descartáveis. Neste ambiente, o host é eric-pve-ssh.eag.tools. Os agentes clonam um template, executam o teste e, em seguida, perguntam antes de excluir qualquer coisa.
Os templates, as etapas de clonagem e os logins convidados correspondem ao ambiente de LAN. O que muda é o caminho: o agente na nuvem alcança o host através do Cloudflare Access e alcança cada convidado saltando por esse host.
Acesso
O script de inicialização do ambiente escreve o par de chaves de PVE_SSH_PRIVATE_B64 e PVE_SSH_PUBLIC_KEY:
| Arquivo | Modo | Uso |
|---|---|---|
~/.ssh/pve_ssh | 600 | Chave privada. Host Proxmox, Windows Administrator, Ubuntu erolleman. |
~/.ssh/pve_ssh.pub | 644 | Chave pública correspondente. |
/etc/ssh/ssh_config.d/eric-pve-ssh.conf já define User root, IdentityFile ~/.ssh/pve_ssh, IdentitiesOnly yes e ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h para eric-pve-ssh.eag.tools. Use esse alias de host. Deixe o arquivo de sistema no lugar.
KEY="$HOME/.ssh/pve_ssh"
test -r "$KEY" || { echo "$KEY ausente; o script de inicialização o cria a partir de PVE_SSH_PRIVATE_B64" >&2; exit 1; }
PVE="ssh -o StrictHostKeyChecking=accept-new eric-pve-ssh.eag.tools"
$PVE 'qm list'
SSH para convidados, tanto para 10.115.64.x (vmbr0) quanto para 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"
Defina USER como Administrator ou erolleman e IP como o endereço do convidado antes de expandir VMSSH.
- Login VM Windows:
Administrator/Change_me, ou~/.ssh/pve_ssh. - Login VM Ubuntu:
erollemancom~/.ssh/pve_ssh.sudonão requer senha.dockerprecisa desudo. - A interface web do Proxmox escuta na LAN em
https://10.115.64.44:8006. Este túnel é apenas SSH. Administre o host comqmepveshatravés de$PVE. - Mantenha o material da chave nos arquivos acima. Não leia
~/.ssh/pve_sshnemPVE_SSH_PRIVATE_B64em um comando, log ou resposta. Não gere chave de substituição.
O PowerShell remoto sobre SSH usa o mesmo salto. Adicione isso a ~/.ssh/config (apenas o bloco Host do convidado; o arquivo de sistema já cobre o host do túnel):
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"
Regras rígidas
- Nunca iniciar, modificar, clonar sobre ou excluir a VM 100 (
ubuntu-2404) ou a VM 101 (ws2025-template). Ambas são templates. - Não alterar a configuração do host (armazenamento, rede, SDN, pacotes) a menos que o usuário peça explicitamente.
- Não executar novamente sysprep,
windows-template/Copy-SysprepFiles.ps1ouubuntu-template/cloud-init-prepare.shem um clone. Esses scripts preparam os templates e permanecem na estação de trabalho. Eles não estão neste ambiente. - Marcar cada VM que você criar com
ai-test. - Quando o teste terminar, perguntar ao usuário se deve destruir as VMs que você criou. Nunca destruir uma VM sem a resposta do usuário.
- Não abrir sessão SSH direta para
10.115.64.44,10.115.64.xou10.20.0.x. Essas redes não são roteadas para o agente na nuvem. Os comandos do host vão através deeric-pve-ssh.eag.tools. Os comandos do convidado usam o saltoProxyCommandacima.
Fatos do host
O host é uma máquina virtual Hyper-V. VT-x aninhado está exposto. Na LAN, seu endereço é 10.115.64.44.
| Item | Valor |
|---|---|
| Hardware | Intel Xeon Gold 6234 (8 núcleos / 16 threads), 94 GB de RAM. Dimensione as VMs de acordo. |
vmbr0 | Ponte LAN, DHCP. Endereço do host 10.115.64.44/24, gateway e DNS 10.115.64.1, domínio de pesquisa eag.lan. As NICs de ambos os templates estão nesta ponte. Os endereços dos convidados são 10.115.64.x. Deste ambiente, o SSH para eles salta através de eric-pve-ssh.eag.tools. |
nat0 | SDN VNet (zona simples nat), 10.20.0.0/24. Gateway 10.20.0.1. DHCP 10.20.0.100–10.20.0.200 (12 h) a partir do dnsmasq no host, DNS 10.20.0.1. SNAT para fora em vmbr0 como 10.115.64.44. O host Proxmox pode alcançar esta sub-rede. Deste ambiente, o SSH para 10.20.0.x usa o mesmo salto. |
local-data | LVM-thin no VG vmdata, ~671 GB. Discos de VM, EFI, TPM e drives cloud-init. |
local-lvm | LVM-thin no pequeno VG do sistema PVE, ~23 GB, vazio. Deixe-o sem uso. |
local | Diretório no sistema de arquivos raiz. Backups, templates de contêiner, importações. |
isos | Diretório /mnt/isos. Apenas ISOs de instalação. |
Qual template
| Necessidade | Clonar |
|---|---|
| Windows, RDP ou Windows PowerShell | 101 ws2025-template |
Linux, Docker, pwsh ou Nushell | 100 ubuntu-2404 |
Se o usuário não disser qual SO, pergunte antes de clonar.
Os clones do Windows habilitam o RDP dentro do convidado. O túnel Cloudflare transporta SSH. Use SSH ou PowerShell remoto para alcançar o convidado.
Template: ws2025-template (VMID 101)
Windows Server 2025 Datacenter Evaluation. 4 vCPU (host), 4 GB RAM, UEFI + Secure Boot + TPM 2.0, 64 GB disco VirtIO SCSI em local-data, NIC VirtIO em vmbr0 (4 filas), drivers VirtIO e agente convidado QEMU instalados.
Na primeira inicialização, cada clone automaticamente:
- Obtém um nome de computador aleatório, fuso horário do Pacífico, localidade en-US e senha do Administrador
Change_me. - Faz login automático uma vez e executa
Initialize-WindowsServer.ps1, que instala o PowerShell 7 mais recente do GitHub, habilita o servidor OpenSSH com um subsistemapowershell(PS remoto sobre SSH), adiciona a chave SSH aadministrators_authorized_keys, habilita RDP, define redes Públicas como Privadas e remove o requisito Ctrl+Alt+Del. - Remove a senha de login automático e o arquivo de resposta, escreve
C:\ProgramData\TemplateSetup\setup-completee então reinicia.
A primeira inicialização leva vários minutos e precisa de internet (download do PowerShell 7). Log: C:\ProgramData\TemplateSetup\Initialize-WindowsServer.log.
Template: ubuntu-2404 (VMID 100)
Ubuntu 24.04.5 LTS. 2 vCPU (x86-64-v2-AES), 4 GB RAM, UEFI (chaves Secure Boot não cadastradas), sem TPM, 32 GB disco VirtIO SCSI em local-data, NIC VirtIO em vmbr0. Agente convidado QEMU, OpenSSH, PowerShell 7 (pwsh), Nushell (nu em /usr/local/bin) e Docker estão instalados. Podman não está instalado. O fuso horário é UTC.
O cloud-init foi limpo e limitado às fontes de dados NoCloud e ConfigDrive. O disco não tem netplan, então um clone não tem rede até que o cloud-init do Proxmox seja executado. A conta erolleman já está no sudo e já possui a chave pública do projeto. O SSH é ativado por socket. O agente convidado inicia a partir do udev quando a porta virtio aparece.
O user-data gerado pelo Proxmox também cria uma conta ubuntu bloqueada, sem chave SSH. Faça login como erolleman.
Fluxo de trabalho: criar uma VM de teste
- [ ] 1. Confirmar que a VM de origem é um template
- [ ] 2. Clonar, configurar, marcar, iniciar
- [ ] 3. Obter o IP do agente convidado
- [ ] 4. Aguardar até que a primeira inicialização termine
- [ ] 5. Executar o teste
- [ ] 6. Perguntar ao usuário se deve destruir a VM
1. Confirmar o template. Se isso não imprimir nada, pare e avise o usuário. Não clone uma VM que não seja um template.
$PVE 'qm config 101 | grep ^template' # Windows
$PVE 'qm config 100 | grep ^template' # Ubuntu
2. Clonar, configurar, marcar, iniciar. Clones vinculados são o padrão. Adicione --full --storage local-data apenas quando a VM precisar sobreviver ao template.
Os clones herdam 4 vCPU / 4 GB (Windows) ou 2 vCPU / 4 GB (Ubuntu). Quando o teste precisar de mais, use qm set no clone antes de iniciá-lo. Deixe os templates inalterados.
Windows:
ID=$($PVE 'pvesh get /cluster/nextid')
$PVE "qm clone 101 $ID --name test-<propósito> && qm set $ID --tags ai-test && qm start $ID"
Ubuntu: anexe o drive cloud-init antes da primeira inicialização. ide2 no template é um CD vazio; substitua-o. --ciupgrade 0 pula a atualização completa padrão de pacotes. Sem --ipconfig0 ip=dhcp o clone nunca obtém um endereço.
ID=$($PVE 'pvesh get /cluster/nextid')
$PVE "qm clone 100 $ID --name test-<propósito> && qm set $ID --tags ai-test --ide2 local-data:cloudinit --citype nocloud --ipconfig0 ip=dhcp --ciupgrade 0 --boot order=scsi0 && qm start $ID"
Rede isolada, para qualquer SO: antes de iniciar, coloque a NIC em nat0. Mantenha isso apenas quando o usuário quiser a VM fora da LAN. O endereço do convidado será 10.20.0.x. O SSH deste ambiente ainda usa o salto em Acesso; o host Proxmox é quem pode alcançar nat0.
$PVE "qm set $ID --net0 virtio,bridge=nat0"
# Apenas Ubuntu. O Windows faz DHCP por conta própria. Aponte o DNS do Ubuntu para o dnsmasq no gateway NAT.
$PVE "qm set $ID --ipconfig0 ip=dhcp --nameserver 10.20.0.1"
3. Obter o IP. O agente convidado responde assim que o SO está ativo. Repita a cada ~15 s. Use o endereço 10.115.64.x para uma NIC vmbr0, ou o endereço 10.20.0.x para 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. Aguardar a primeira inicialização. Os clones obtêm novas chaves de host e os endereços são reutilizados, portanto o SSH do convidado ignora a verificação de chave de host. A chave do host de salto é armazenada com accept-new.
Windows: o SSH surge durante a configuração e o script reinicia a VM quando termina. A VM está pronta assim que setup-complete existe e o Windows foi reiniciado desde que foi escrito.
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) evita aninhamento de aspas 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 significa que a configuração terminou e a VM foi reiniciada. Se imprimir READY failed, leia o log e relate:
$VMSSH 'powershell -NoProfile -Command "Get-Content C:\ProgramData\TemplateSetup\Initialize-WindowsServer.log -Tail 30"'
Ubuntu: aguarde até que o cloud-init relate status: done. status: error significa parar e ler /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. Executar o teste.
Windows: o shell SSH padrão é cmd.exe.
$VMSSH 'pwsh -NoProfile -Command "Get-ComputerInfo | Select-Object OsName, CsName"'
PowerShell remoto sobre SSH (a partir de pwsh no agente na nuvem) usa o bloco Host do convidado em ~/.ssh/config em Acesso:
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. Perguntar antes de limpar. Relate os resultados do teste, liste as VMs que você criou (VMID, nome, IP) e pergunte ao usuário se deseja destruí-las. Use a ferramenta AskQuestion quando disponível, com as opções "Destroy", "Keep running" e "Shut down but keep" (mais escolhas por VM se você criou várias).
Se o usuário escolher destruir:
$PVE "qm stop $ID && qm destroy $ID --purge"
Se o usuário escolher manter mas desligar:
$PVE "qm shutdown $ID --timeout 120 || qm stop $ID"
Quando as VMs forem mantidas, informe ao usuário seus VMIDs para que possam ser encontradas posteriormente (elas mantêm a tag ai-test).
Snapshots
Os discos de ambos os templates estão em LVM-thin, portanto os clones suportam snapshots:
$PVE "qm snapshot $ID before-test"
$PVE "qm rollback $ID before-test"
$PVE "qm delsnapshot $ID before-test"
Limpeza e inventário
$PVE 'pvesh get /cluster/resources --type vm --output-format json' \
| jq -r '.[] | select((.tags // "") | split(";") | index("ai-test")) | "\(.vmid)\t\(.name)\t\(.status)"'
Ofereça-se para destruir apenas VMs ai-test que você criou nesta sessão, a menos que o usuário peça uma limpeza mais ampla. Sempre obtenha a confirmação do usuário primeiro.
Armadilhas
- Windows é uma edição de avaliação com licença de 180 dias. Use-a para VMs de curta duração.
- Um clone Ubuntu que inicializa uma vez sem o drive cloud-init fica sem rede e o cloud-init não tentará novamente de forma limpa. Destrua-o e clone novamente.
- Não execute
sysprepem clones Windows e não converta clones de nenhum dos templates em templates. - O endereço do host é uma concessão DHCP. O SNAT do
nat0está vinculado a10.115.64.44. Se esse endereço mudar, informe; não edite o SDN a menos que o usuário peça. cloudflaredé invocado como/usr/local/bin/cloudflaredpela configuração SSH do sistema. Um arquivo de chave ausente significa que o script de inicialização não foi executado; deixe os segredos intocados e relate isso.- As chaves de host do convidado mudam a cada clone.
UserKnownHostsFile=/dev/nullse aplica à sessão do convidado. A chave do host do túnel permanece em~/.ssh/known_hosts.