WinRM et Sysprep¶
Configuration de WinRM over HTTPS pour le provisioning Ansible et préparation de Sysprep pour la generalisation de l'image.
WinRM : le protocole de gestion Windows¶
WinRM (Windows Remote Management) est le protocole standard de Microsoft pour l'administration distante. Contrairement a SSH sur Linux, WinRM utilisé SOAP over HTTP/HTTPS.
| Aspect | SSH (Linux) | WinRM (Windows) |
|---|---|---|
| Protocole | SSH | SOAP/HTTP(S) |
| Port par défaut | 22 | 5985 (HTTP) / 5986 (HTTPS) |
| Authentification | Clés SSH | NTLM, Kerberos, certificats |
| Chiffrement | Natif | Via HTTPS (TLS) |
Sécurité
N'utilisez jamais WinRM over HTTP en production. Toujours WinRM over HTTPS avec un certificat (même auto-signe pour le build Packer).
Script de bootstrap WinRM¶
Ce script PowerShell active WinRM/HTTPS avec un certificat auto-signe. Packer l'exécuté au démarrage de la VM via les metadata GCP.
Créez scripts/setup-winrm.ps1 :
# Configurer WinRM HTTPS avec certificat auto-signe
$ErrorActionPreference = "Stop"
# Creer un certificat auto-signe
$cert = New-SelfSignedCertificate `
-DnsName $env:COMPUTERNAME `
-CertStoreLocation Cert:\LocalMachine\My `
-NotAfter (Get-Date).AddYears(1)
# Activer WinRM
Enable-PSRemoting -Force -SkipNetworkProfileCheck
# Supprimer les listeners existants
Get-ChildItem WSMan:\localhost\Listener | Remove-Item -Recurse -Force
# Creer le listener HTTPS
New-Item -Path WSMan:\localhost\Listener -Transport HTTPS `
-Address * -CertificateThumbPrint $cert.Thumbprint -Force
# Configurer les limites WinRM
Set-Item WSMan:\localhost\MaxTimeoutms 1800000
Set-Item WSMan:\localhost\Service\AllowUnencrypted $false
Set-Item WSMan:\localhost\Service\Auth\Basic $true
Set-Item WSMan:\localhost\Service\Auth\Negotiate $true
# Ouvrir le firewall pour WinRM HTTPS
New-NetFirewallRule -Name "WinRM-HTTPS" `
-DisplayName "WinRM HTTPS (5986)" `
-Protocol TCP -LocalPort 5986 `
-Action Allow -Direction Inbound
# Redemarrer le service
Restart-Service WinRM
Configuration du communicator Packer¶
Le communicator Packer pour Windows utilisé WinRM. Voici le bloc source pour GCP :
source "googlecompute" "windows-vdi" {
project_id = var.project_id
zone = var.zone
source_image_family = "windows-2022"
source_image_project_id = "windows-cloud"
machine_type = var.machine_type
disk_size = var.disk_size
disk_type = "pd-ssd"
image_name = "vdi-windows-${var.profile}-{{timestamp}}"
image_family = "vdi-windows-${var.profile}"
image_description = "VDI Windows Server 2022 - profil ${var.profile}"
universe_domain = var.universe_domain
communicator = "winrm"
winrm_username = "packer_user"
winrm_insecure = true
winrm_use_ssl = true
winrm_timeout = "10m"
tags = ["packer-build"]
metadata = {
sysprep-specialize-script-ps1 = file("../scripts/setup-winrm.ps1")
}
}
Metadata GCP
GCP exécuté automatiquement le script passe dans sysprep-specialize-script-ps1 au premier démarrage de la VM. C'est le mécanisme idéal pour activer WinRM avant que Packer tente de se connecter.
Provisioner Ansible¶
Le bloc build utilise le provisioner Ansible :
build {
sources = ["source.googlecompute.windows-vdi"]
provisioner "ansible" {
playbook_file = "../ansible/playbook.yml"
user = "packer_user"
use_proxy = false
extra_arguments = [
"--extra-vars", "ansible_winrm_server_cert_validation=ignore profile=${var.profile}"
]
}
}
Sysprep : generaliser l'image¶
Sysprep supprimé les identifiants uniques (SID, nom machine) pour que chaque VM créée depuis l'image soit unique.
Fichier unattend.xml¶
Créez scripts/unattend.xml :
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="generalize">
<component name="Microsoft-Windows-PnpSysprep"
processorArchitecture="amd64"
publicKeyToken="31bf3856ad364e35"
language="neutral" versionScope="nonSxS">
<PersistAllDeviceInstalls>true</PersistAllDeviceInstalls>
</component>
</settings>
<settings pass="oobeSystem">
<component name="Microsoft-Windows-Shell-Setup"
processorArchitecture="amd64"
publicKeyToken="31bf3856ad364e35"
language="neutral" versionScope="nonSxS">
<OOBE>
<HideEULAPage>true</HideEULAPage>
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
<NetworkLocation>Work</NetworkLocation>
<ProtectYourPC>3</ProtectYourPC>
</OOBE>
<TimeZone>Romance Standard Time</TimeZone>
</component>
</settings>
</unattend>
Script Sysprep¶
Créez scripts/sysprep.ps1 :
# Nettoyer avant Sysprep
Remove-Item -Path "C:\Windows\Temp\*" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "$env:TEMP\*" -Recurse -Force -ErrorAction SilentlyContinue
# Copier unattend.xml
Copy-Item -Path "C:\scripts\unattend.xml" -Destination "C:\Windows\System32\Sysprep\unattend.xml"
# Lancer Sysprep
& "$env:SystemRoot\System32\Sysprep\sysprep.exe" `
/generalize /oobe /shutdown /quiet `
/unattend:"C:\Windows\System32\Sysprep\unattend.xml"
Ordre d'exécution
Sysprep doit être la dernière étape du build Packer. Ajoutez-le comme dernier provisioner dans le bloc build, après Ansible.
Provisioner Sysprep dans Packer¶
Ajoutez ce bloc à la fin du build :
provisioner "file" {
source = "../scripts/unattend.xml"
destination = "C:\\scripts\\unattend.xml"
}
provisioner "powershell" {
script = "../scripts/sysprep.ps1"
}
Note sur OpenSSH natif¶
Depuis Windows Server 2019, Microsoft fournit un serveur OpenSSH natif. Ansible peut l'utiliser comme sur Linux :
# Installer OpenSSH Server (optionnel)
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic
Cette approche est emergente et moins documentee dans l'écosystème Ansible/Windows. WinRM reste le standard recommande pour le provisioning Packer.