security(sprint1): §1.1/1.3/1.4 — WinRM HTTPS/5986, SHA256 pinning infra, IP regex per-octet

§1.4 — Replace loose IP ValidatePattern with per-octet regex in 4 scripts
  (Invoke-CIJob, Invoke-RemoteBuild, Get-BuildArtifacts, Wait-VMReady)

§1.1 — Migrate all WinRM connections from HTTP/5985 to HTTPS/5986
  - Deploy post-install.ps1: remove AllowUnencrypted=true; self-signed cert + HTTPS listener
    already present; firewall rule restricted to 192.168.79.0/24
  - Setup-WinBuild2025.ps1: assert AllowUnencrypted=false
  - Prepare-WinBuild2025.ps1: preflight uses TCP/5986; Test-WSMan -UseSSL -Port 5986;
    New-PSSession -UseSSL -Port 5986; host AllowUnencrypted save/restore removed (not needed for HTTPS)
  - Invoke-RemoteBuild, Get-BuildArtifacts: New-PSSession -UseSSL -Port 5986 -Authentication Basic
  - Wait-VMReady: New-WSManSessionOption + Test-WSMan -Port 5986 -UseSSL
  - Validate-DeployState, Validate-SetupState: Invoke-Command -UseSSL -Port 5986,
    AllowUnencrypted check → false; AllowUnencrypted host-side removed from both
  - Docs: PLAN, README, ARCHITECTURE, BEST-PRACTICES, HOST-SETUP, WINDOWS-TEMPLATE-SETUP,
    LINUX-TEMPLATE-SETUP, TODO updated

§1.3 — SHA256 hash pinning infrastructure
  - Assert-Hash function + $script:Hashes hashtable added to Setup-WinBuild2025.ps1
  - Assert-Hash called after dotnet-install.ps1, python installer, vs_buildtools.exe downloads
  - Hashes initialized to '' (warn-skip); must be filled before next snapshot refresh

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Simone
2026-05-10 14:46:41 +02:00
parent 41611d46a7
commit 68cde01c9d
17 changed files with 193 additions and 183 deletions
+7 -10
View File
@@ -63,11 +63,9 @@ $cred = New-Object System.Management.Automation.PSCredential(
)
$so = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
$prevAllowUnenc = (Get-Item WSMan:\localhost\Client\AllowUnencrypted).Value
$prevTrustedHosts = (Get-Item WSMan:\localhost\Client\TrustedHosts).Value
try {
Set-Item WSMan:\localhost\Client\AllowUnencrypted $true -Force
$cur = (Get-Item WSMan:\localhost\Client\TrustedHosts).Value
if ($cur -ne '*' -and $cur -notmatch [regex]::Escape($VMIPAddress)) {
$newHosts = if ($cur) { "$cur,$VMIPAddress" } else { $VMIPAddress }
@@ -77,7 +75,7 @@ try {
Write-Host "`nValidating full Setup state on $VMIPAddress..." -ForegroundColor Cyan
$checks = Invoke-Command -ComputerName $VMIPAddress -Credential $cred `
-Authentication Basic -SessionOption $so -ScriptBlock {
-Authentication Basic -UseSSL -Port 5986 -SessionOption $so -ScriptBlock {
param($BuildUsername, $DotNetChannel, $PythonVersion)
@@ -109,8 +107,8 @@ try {
# WinRM
Chk 'WinRM service Running' { (Get-Service WinRM -EA Stop).Status -eq 'Running' }
Chk 'WinRM service Automatic' { (Get-Service WinRM -EA Stop).StartType -eq 'Automatic' }
Chk 'WinRM AllowUnencrypted=true' {
(Get-Item WSMan:\localhost\Service\AllowUnencrypted -EA Stop).Value -eq 'true'
Chk 'WinRM AllowUnencrypted=false (HTTPS-only)' {
(Get-Item WSMan:\localhost\Service\AllowUnencrypted -EA Stop).Value -eq 'false'
}
Chk 'WinRM Auth/Basic=true' {
(Get-Item WSMan:\localhost\Service\Auth\Basic -EA Stop).Value -eq 'true'
@@ -270,7 +268,7 @@ try {
Write-Host "Applying remediation for $($failedNames.Count) failed check(s)..." -ForegroundColor Yellow
Invoke-Command -ComputerName $VMIPAddress -Credential $cred `
-Authentication Basic -SessionOption $so -ScriptBlock {
-Authentication Basic -UseSSL -Port 5986 -SessionOption $so -ScriptBlock {
param([string[]] $FailedNames, [string] $AdminPassword)
@@ -296,7 +294,7 @@ try {
# ── Re-run checks ─────────────────────────────────────────────────────────
Write-Host "`nRe-validating after remediation..." -ForegroundColor Cyan
$checks = Invoke-Command -ComputerName $VMIPAddress -Credential $cred `
-Authentication Basic -SessionOption $so -ScriptBlock {
-Authentication Basic -UseSSL -Port 5986 -SessionOption $so -ScriptBlock {
param($BuildUsername, $DotNetChannel, $PythonVersion)
$results = [System.Collections.Generic.List[PSCustomObject]]::new()
@@ -310,7 +308,7 @@ try {
Chk 'Defender GPO DisableAntiSpyware=1' { (Get-ItemProperty 'HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender' -Name DisableAntiSpyware -EA Stop).DisableAntiSpyware -eq 1 }
Chk 'WinRM service Running' { (Get-Service WinRM -EA Stop).Status -eq 'Running' }
Chk 'WinRM service Automatic' { (Get-Service WinRM -EA Stop).StartType -eq 'Automatic' }
Chk 'WinRM AllowUnencrypted=true' { (Get-Item WSMan:\localhost\Service\AllowUnencrypted -EA Stop).Value -eq 'true' }
Chk 'WinRM AllowUnencrypted=false (HTTPS-only)' { (Get-Item WSMan:\localhost\Service\AllowUnencrypted -EA Stop).Value -eq 'false' }
Chk 'WinRM Auth/Basic=true' { (Get-Item WSMan:\localhost\Service\Auth\Basic -EA Stop).Value -eq 'true' }
Chk 'WinRM MaxMemoryPerShellMB >= 2048' { [int](Get-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB -EA Stop).Value -ge 2048 }
$polSys = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
@@ -369,6 +367,5 @@ try {
}
} finally {
Set-Item WSMan:\localhost\Client\AllowUnencrypted $prevAllowUnenc -Force -EA SilentlyContinue
Set-Item WSMan:\localhost\Client\TrustedHosts $prevTrustedHosts -Force -EA SilentlyContinue
Set-Item WSMan:\localhost\Client\TrustedHosts $prevTrustedHosts -Force -EA SilentlyContinue
}