Compare commits

...
1 Commits
Author SHA1 Message Date
alexrg 1332f546fa Wait for Windows enrollment network readiness 2026-09-09 10:19:36 -06:00
3 changed files with 42 additions and 4 deletions
+33 -2
View File
@@ -178,6 +178,7 @@ function Set-ClientDomainAddress {
$matchingAddress = Get-NetIPAddress -InterfaceIndex $adapter.ifIndex -AddressFamily IPv4 `
-ErrorAction SilentlyContinue |
Where-Object {
$_.AddressState -eq 'Preferred' -and
$_.IPAddress -notmatch '^(127\.|169\.254\.)' -and
(Test-IPv4AddressesSharePrefix -FirstAddress ([ipaddress]$_.IPAddress) `
-SecondAddress $DomainControllerAddress -PrefixLength $PrefixLength)
@@ -207,8 +208,21 @@ function Set-ClientDomainAddress {
New-NetIPAddress -InterfaceIndex $adapter.ifIndex -AddressFamily IPv4 `
-IPAddress $RequestedAddress.IPAddressToString -PrefixLength $PrefixLength | Out-Null
}
$addressReadyDeadline = (Get-Date).AddSeconds(20)
do {
$configuredAddress = Get-NetIPAddress -InterfaceIndex $adapter.ifIndex `
-AddressFamily IPv4 -IPAddress $RequestedAddress.IPAddressToString `
-ErrorAction SilentlyContinue
if ($configuredAddress -and $configuredAddress.AddressState -eq 'Preferred') {
return $RequestedAddress
}
Start-Sleep -Milliseconds 500
} while ((Get-Date) -lt $addressReadyDeadline)
$observedState = if ($configuredAddress) { $configuredAddress.AddressState } else { 'Missing' }
throw "The SGU client address '$RequestedAddress' did not become ready on '$InterfaceAlias' within 20 seconds. Observed state: $observedState."
}
function Test-TcpPort {
param(
@@ -234,6 +248,23 @@ function Test-TcpPort {
}
}
function Wait-TcpPort {
param(
[Parameter(Mandatory)][ipaddress]$Address,
[Parameter(Mandatory)][int]$Port,
[int]$TimeoutSeconds = 20
)
$deadline = (Get-Date).AddSeconds($TimeoutSeconds)
do {
if (Test-TcpPort -Address $Address -Port $Port -TimeoutMilliseconds 2000) {
return $true
}
Start-Sleep -Milliseconds 750
} while ((Get-Date) -lt $deadline)
return $false
}
function Connect-SguAzureP2s {
param([Parameter(Mandatory)][string]$ConnectionName)
@@ -348,8 +379,8 @@ else {
-ServerAddresses $DomainControllerIPv4Address.IPAddressToString
}
if (-not (Test-TcpPort -Address $DomainControllerIPv4Address -Port 5985)) {
throw "The domain controller at $DomainControllerIPv4Address is not accepting WinRM on TCP 5985. Run the server bootstrap first and verify the selected IP."
if (-not (Wait-TcpPort -Address $DomainControllerIPv4Address -Port 5985 -TimeoutSeconds 20)) {
throw "The domain controller at $DomainControllerIPv4Address did not accept WinRM on TCP 5985 after 20 seconds. Run the server bootstrap first and verify the selected IP."
}
if (-not $DomainCredential) {
+1 -1
View File
@@ -112,7 +112,7 @@ Bootstrap reproducible para el laboratorio SGU.
- **Advertencia:** el bootstrap de servidor crea un bosque nuevo. No restaura los SID, contraseñas ni relaciones de confianza del bosque anterior; para conservarlos se requiere una recuperación de bosque desde una copia de estado del sistema.
- `sgu-server-bootstrap-$Version.zip`: crea el bosque AD/DNS, OUs, grupo RDP, GPO, recurso `Packages`, broker mTLS y administración remota; se reanuda solo después del reinicio.
- `sgu-client-bootstrap-$Version.zip`: registra un certificado mTLS único, instala y valida el Credential Provider antes de unir el equipo al dominio, habilita RDP/WinRM y se repara al arranque.
- En clientes Hyper-V con dos NIC, el bootstrap selecciona la red privada sin puerta de enlace, solicita o acepta la IP fija del cliente y conserva en pantalla y archivo cualquier error de enrolamiento.
- En clientes Hyper-V con dos NIC, el bootstrap selecciona la red privada sin puerta de enlace, solicita o acepta la IP fija del cliente, espera a que la dirección y WinRM estén disponibles y conserva en pantalla y archivo cualquier error de enrolamiento.
- `sgu-linux-client-bootstrap-$Version.zip`: une clientes Debian/Ubuntu o RHEL/Fedora/Rocky/AlmaLinux con realmd, Kerberos y SSSD. Solicita interactivamente la contraseña de unión y no instala el Credential Provider de Windows.
- `sgu-azure-infrastructure-$Version.zip`: despliega mediante Bicep una VM Windows Server 2025, red privada, IP pública protegida por NSG y Azure VPN Gateway P2S; también genera certificados por equipo y descarga el perfil de cliente.
- El bootstrap Azure conserva la IP privada administrada por la NIC de Azure, autoriza el pool P2S en los firewalls SGU y nunca publica LDAP, Kerberos, SMB, RPC, WinRM ni el Auth Broker directamente a Internet.
+7
View File
@@ -99,6 +99,13 @@ Describe 'SGU public-cloud network safety' {
$source | Should Not Match "Get-NetRoute -AddressFamily IPv4 -DestinationPrefix '0\.0\.0\.0/0'"
}
It 'waits for the new address and WinRM route to stabilize' {
$source = Get-Content -LiteralPath $clientBootstrapPath -Raw
$source | Should Match "AddressState -eq 'Preferred'"
$source | Should Match 'function Wait-TcpPort'
$source | Should Match 'Wait-TcpPort -Address \$DomainControllerIPv4Address -Port 5985'
}
It 'uses an all-user machine-certificate VPN profile' {
$source = Get-Content -LiteralPath $azureClientPath -Raw
$source | Should Match '-AuthenticationMethod MachineCertificate'