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
+4 -4
View File
@@ -53,7 +53,7 @@ The runner host **never executes build tools directly**. Its only role is orches
│ │ ├── Clone_Job_002.vmx │ │
│ │ └── Clone_Job_003.vmx │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ WinRM :5985 (192.168.79.0/24 NAT)
│ │ WinRM :5986 HTTPS (192.168.79.0/24 NAT) │
└──────────────────────────────────┼──────────────────────────────────────┘
┌────────────────────────┼──────────────────────────┐
@@ -105,8 +105,8 @@ The runner host **never executes build tools directly**. Its only role is orches
### WinRM / PowerShell Remoting
- Default transport for remote build execution inside VMs
- Port: **5985** (HTTP, in-lab use); migrate to 5986/HTTPS for hardened setups
- Authentication: **Basic** (unencrypted — acceptable for isolated lab)
- Port: **5986** (HTTPS, self-signed cert, `AllowUnencrypted=false`)
- Authentication: **Basic over HTTPS** (`-SkipCACheck` for lab self-signed cert)
- Used for:
- Transferring source: `Compress-Archive` on host → WinRM copy → `Expand-Archive` in guest
- Running build commands (`Invoke-Command`)
@@ -133,7 +133,7 @@ Build VMs:
...
Clone_Job_N → 192.168.79.1xx
WinRM port 5985 (HTTP) on each VM IP.
WinRM port 5986 (HTTPS, self-signed) on each VM IP.
VMs have internet access via NAT — required for pip/nuget during build.
```
+12 -33
View File
@@ -30,47 +30,26 @@ $cred = Get-StoredCredential -Target 'BuildVMGuest'
---
## 2. WinRM Security
## 2. WinRM Security — HTTPS/5986 (implementato 2026-05-10)
### Current setup (HTTP / port 5985)
### Setup attuale (HTTPS / port 5986)
Acceptable for an **isolated lab network** where:
- Build VMs sono su VMnet8 NAT (192.168.79.0/24) — raggiungibili dall'host, internet via NAT
- No external traffic reaches port 5985
- Credentials are managed via Windows Credential Manager
`Deploy-WinBuild2025.ps1` post-install.ps1 crea un certificato self-signed e configura
il listener HTTPS/5986 **prima** dello snapshot `BaseClean`. `AllowUnencrypted=false`.
### Recommended upgrade: WinRM over HTTPS (port 5986)
- Build VMs su VMnet8 NAT (192.168.79.0/24) — accesso solo dall'host
- Port 5986 firewall rule ristretta a `RemoteAddress '192.168.79.0/24'`
- Credentials via Windows Credential Manager (target `BuildVMGuest`)
Tutti gli script host usano:
```powershell
# Inside the template VM (before taking BaseClean snapshot):
# Create self-signed certificate
$cert = New-SelfSignedCertificate `
-Subject "CN=$(hostname)" `
-CertStoreLocation Cert:\LocalMachine\My `
-KeyUsage DigitalSignature, KeyEncipherment `
-KeyAlgorithm RSA `
-KeyLength 2048
# Create HTTPS WinRM listener
New-WSManInstance WinRM/Config/Listener `
-SelectorSet @{ Transport = 'HTTPS'; Address = '*' } `
-ValueSet @{ Hostname = $(hostname); CertificateThumbprint = $cert.Thumbprint }
# Allow port 5986
New-NetFirewallRule -Name 'WinRM-HTTPS-CI' -DisplayName 'WinRM HTTPS CI' `
-Direction Inbound -Protocol TCP -LocalPort 5986 -Action Allow
```
```powershell
# On the HOST (in scripts), use HTTPS session options:
$sessionOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
$session = New-PSSession -ComputerName $ip -Port 5986 -UseSSL `
$session = New-PSSession -ComputerName $ip -Port 5986 -UseSSL -Authentication Basic `
-Credential $cred -SessionOption $sessionOptions
```
> `-SkipCACheck` is acceptable for a self-signed cert in an isolated lab. Do NOT
> use this against externally accessible machines.
> `-SkipCACheck`/`-SkipCNCheck` sono accettabili per un cert self-signed in lab isolato.
> Non usare contro macchine accessibili dall'esterno — usare una CA trusted in quel caso.
---
@@ -251,7 +230,7 @@ Invoke-Command -Session $session -ScriptBlock {
```
Build VMs can reach:
- The host via VMnet8 gateway (WinRM on port 5985)
- The host via VMnet8 gateway (WinRM HTTPS on port 5986)
- Internet via VMware NAT (for pip, nuget, npm at build time)
- Gitea server if on LAN reachable via NAT gateway
+2 -2
View File
@@ -120,10 +120,10 @@ Allo `Setup-Host.ps1` exit 0:
3. **Configura host WinRM client** (necessario per Prepare-WinBuild2025.ps1):
```powershell
Set-Item WSMan:\localhost\Client\AllowUnencrypted $true -Force
# AllowUnencrypted non serve — Prepare usa HTTPS/5986 (nessun testo in chiaro)
Set-Item WSMan:\localhost\Client\TrustedHosts -Value '192.168.79.*' -Force -Concatenate
```
*Note*: Prepare-WinBuild2025.ps1 imposta queste in modo transitorio e le ripristina nel `finally`.
*Note*: Prepare-WinBuild2025.ps1 aggiunge l'IP specifico della VM in modo transitorio e lo ripristina nel `finally`.
4. **Provisiona il template VM** — vedi [WINDOWS-TEMPLATE-SETUP.md](WINDOWS-TEMPLATE-SETUP.md)
+1 -1
View File
@@ -314,7 +314,7 @@ Equivalente di `Prepare-WinBuild2025.ps1` per Linux. Usa SSH invece di WinRM.
| Aspetto | Windows | Linux |
| ----------------------- | -------------------------------------- | ------------------------------------------- |
| Transport | WinRM HTTP/5985 + Basic | SSH/22 + ed25519 key |
| Transport | WinRM HTTPS/5986 + Basic (-SkipCACheck) | SSH/22 + ed25519 key |
| Auth fluid | `ci_build` admin + UAC off + LATFP=1 | `ci_build` + sudoers NOPASSWD |
| Trasferimento file | `Copy-Item -ToSession` | `scp` o `rsync` |
| Esecuzione remota | `Invoke-Command -Session` | `ssh user@host 'cmd'` |
+9 -8
View File
@@ -65,7 +65,8 @@ winrm quickconfig -q
```powershell
Enable-PSRemoting -Force -SkipNetworkProfileCheck
Set-Item WSMan:\localhost\Service\Auth\Basic $true -Force
Set-Item WSMan:\localhost\Service\AllowUnencrypted $true -Force
# AllowUnencrypted left false — Deploy post-install.ps1 creates HTTPS/5986 listener
# Basic auth is secure over HTTPS; host connects on port 5986 with -SkipCACheck
Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*' -Force
```
@@ -110,12 +111,12 @@ cd N:\Code\Workspace\Local-CI-CD-System\template
Ogni step ha validazione `Assert-Step` (throw on failure, `[OK]` su pass):
1. **Pre-flight**: script dir presente, `Setup-WinBuild2025.ps1` presente, IP ottetti 0-255, TCP/5985 reachable
2. **Configura host WinRM client**: `AllowUnencrypted=true`, aggiunge `$VMIPAddress` ai `TrustedHosts`
- Salva valori precedenti, ripristinati nel `finally` (host posture invariata)
3. **Validazione host WinRM**: `AllowUnencrypted=true`, `TrustedHosts` include IP
4. **Test connettività**: `Test-WSMan -Authentication Basic` con credenziali admin
5. **Apre PSSession** verso la VM
1. **Pre-flight**: script dir presente, `Setup-WinBuild2025.ps1` presente, IP ottetti 0-255, TCP/5986 reachable
2. **Configura host WinRM client**: aggiunge `$VMIPAddress` ai `TrustedHosts` (no `AllowUnencrypted` — HTTPS non lo richiede)
- Salva valore precedente, ripristinato nel `finally` (host posture invariata)
3. **Validazione host WinRM**: `TrustedHosts` include IP
4. **Test connettività**: `Test-WSMan -Port 5986 -UseSSL -Authentication Basic` con credenziali admin
5. **Apre PSSession** `-UseSSL -Port 5986` verso la VM
6. **Crea `C:\CI`** in guest, valida creazione
7. **Copia `Setup-WinBuild2025.ps1`** in `C:\CI\Setup-WinBuild2025.ps1`, valida size match
8. **Esegue `Setup-WinBuild2025.ps1`** dentro la VM (vedi Fase C)
@@ -193,7 +194,7 @@ Final Pre-snapshot gate — 7 check cross-cutting + no installer leftover
| ---- | ---------- | ------------------------------------------------------------------------------ |
| 1 | Assert | `Get-NetFirewallProfile -Profile Domain/Private/Public → Enabled=False` |
| 2 | Assert | GPO DisableAntiSpyware=1 (set da Deploy) |
| 3 | Assert | WinRM Running+Automatic, AllowUnencrypted=true, Auth/Basic=true, MaxMem≥2048 |
| 3 | Assert | WinRM Running+Automatic, AllowUnencrypted=false (HTTPS-only), Auth/Basic=true, MaxMem≥2048 |
| 4 | Operativo | User exists, enabled, PasswordNeverExpires, member of Administrators |
| 4b | Assert | EnableLUA=0, LocalAccountTokenFilterPolicy=1 |
| 5 | Operativo | Ogni dir Test-Path -PathType Container |