docs(windows): add ISO-builder design + scaffold the windows/ tree
Add windows/iso-builder.md: reproducible custom-packed-ISO pipeline design for
SilverMetal Enhanced - Windows on IoT Enterprise LTSC. Covers the licensing
frame (IoT = blessed channel for preinstalled custom images; self-apply stays a
builder), 7 build stages (verify/extract/DISM-service/inject-unattend/brand/
oscdimg-repack/attest), the offline-vs-first-boot-vs-firmware control split, an
honest reproducibility scope (pinned inputs + SBOM + attestation, NOT bit-
identical on Windows), and M0-M4 milestones.
Scaffold windows/ per the planned layout:
- installer/ build.ps1 (7-stage orchestrator, stages stubbed to M2),
inputs.manifest.json (pinned-input schema), autounattend.xml
(local-account OOBE), oem/SetupComplete.cmd (first-boot runner)
- hardening/ shared §A-H PowerShell modules + Verify-SilverMetalWindows.ps1
(used by BOTH the ISO first-boot path and the self-apply track).
BitLocker module enforces TPM+PIN and blocks TPM-only.
- policies/ wdac/ debloat/ stack-installer/ drivers/ tests/ scaffolded with
READMEs; wdac/ documents audit->enforce; debloat/ flags Tiny11/NTLite as an
anti-pattern; rename applocker/ -> wdac/ realised.
All 11 PowerShell scripts parse clean; manifest JSON + autounattend XML valid.
Module bodies are M1 scaffold (safe: log + policy-set; interactive/firmware
steps documented, not faked).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
10
windows/debloat/README.md
Normal file
10
windows/debloat/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# windows/debloat
|
||||
|
||||
Residue removal for the lean IoT Enterprise LTSC base.
|
||||
|
||||
- `appx-remove.txt` — provisioned-package removal list (short by design; LTSC is already minimal).
|
||||
- Service-disable lists are applied by [`../hardening/00-provisioning.ps1`](../hardening/00-provisioning.ps1) and [`07-privacy-update.ps1`](../hardening/07-privacy-update.ps1) (telemetry/feedback services only — never update/security services).
|
||||
|
||||
**Anti-pattern (do not do):** Tiny11/NTLite-style component amputation. It breaks
|
||||
servicing and genuineness, violating design-principles #2 and #13. LTSC gives the
|
||||
lean base without the breakage.
|
||||
17
windows/debloat/appx-remove.txt
Normal file
17
windows/debloat/appx-remove.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
# SilverMetal Enhanced - Windows : provisioned appx removal list.
|
||||
# One package family name (or prefix) per line; '#' comments ignored.
|
||||
# IoT Enterprise LTSC is already lean, so this list is intentionally SHORT and
|
||||
# only targets residue. Do NOT remove servicing/Store-for-Business components
|
||||
# that LTSC relies on. Verify per-build (TODO-M2).
|
||||
#
|
||||
# Removed offline in the WIM by build.ps1 (DISM /Remove-ProvisionedAppxPackage)
|
||||
# and at first boot for the provisioned user where applicable.
|
||||
|
||||
Microsoft.Windows.Copilot
|
||||
Microsoft.549981C3F5F10 # Cortana
|
||||
Microsoft.BingWeather
|
||||
Microsoft.BingNews
|
||||
Microsoft.GamingApp
|
||||
Microsoft.XboxGamingOverlay
|
||||
Microsoft.MicrosoftSolitaireCollection
|
||||
# TODO-M2: confirm against the actual LTSC media manifest before enabling removal.
|
||||
15
windows/drivers/README.md
Normal file
15
windows/drivers/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# windows/drivers
|
||||
|
||||
GPD Pocket 4 driver pack, injected offline into the WIM (`DISM /Add-Driver`) by
|
||||
`../installer/build.ps1` stage 3.
|
||||
|
||||
Targets the Pocket 4 hardware a vanilla LTSC install may lack: Strix Point GPU,
|
||||
sensors / auto-rotate, Wi-Fi, fingerprint, modular-port controllers, fan/EC.
|
||||
|
||||
**Sourcing (M2):** confirm redistribution terms for the GPD driver pack. If
|
||||
redistribution is not permitted, store a **sourced manifest** (URL + SHA-256 +
|
||||
version, pinned in `../installer/inputs.manifest.json`) and fetch at build time
|
||||
rather than committing the binaries.
|
||||
|
||||
Open question (hardening-spec §8): which drivers are actually absent from a
|
||||
vanilla LTSC install — determine on the physical unit.
|
||||
27
windows/hardening/00-provisioning.ps1
Normal file
27
windows/hardening/00-provisioning.ps1
Normal file
@@ -0,0 +1,27 @@
|
||||
#Requires -Version 5.1
|
||||
<# SilverMetal Enhanced - Windows | Domain A: Provisioning baseline
|
||||
De-cloud, debloat, telemetry -> Security floor. Idempotent.
|
||||
Spec: ../hardening-spec.md (A) | SCAFFOLD (M1): verify on the unit.
|
||||
#>
|
||||
[CmdletBinding()] param()
|
||||
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||
Write-Host '[A] Provisioning baseline'
|
||||
|
||||
# Telemetry floor (level 0 'Security' is honoured only on Enterprise/Education/LTSC).
|
||||
$dc = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection'
|
||||
New-Item -Path $dc -Force | Out-Null
|
||||
Set-ItemProperty $dc -Name AllowTelemetry -Type DWord -Value 0
|
||||
Set-ItemProperty $dc -Name DoNotShowFeedbackNotifications -Type DWord -Value 1
|
||||
|
||||
# Kill connected-experience / advertising / activity surfaces.
|
||||
$svc = 'DiagTrack','dmwappushservice'
|
||||
foreach ($s in $svc) { Get-Service $s -EA SilentlyContinue | Set-Service -StartupType Disabled -PassThru | Stop-Service -Force -EA SilentlyContinue }
|
||||
|
||||
# Advertising ID, Tailored experiences, Activity feed (machine policies).
|
||||
$adv = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\AdvertisingInfo'
|
||||
New-Item $adv -Force | Out-Null; Set-ItemProperty $adv -Name DisabledByGroupPolicy -Type DWord -Value 1
|
||||
|
||||
# TODO-M1: Recall/Copilot/Cortana off; remove residual provisioned appx (Enterprise prototype);
|
||||
# confirm no MSA bound (OOBE handled this via autounattend).
|
||||
|
||||
Write-Host ' [A] applied (telemetry=0, DiagTrack disabled, ad-ID off)'
|
||||
23
windows/hardening/01-boot-firmware.ps1
Normal file
23
windows/hardening/01-boot-firmware.ps1
Normal file
@@ -0,0 +1,23 @@
|
||||
#Requires -Version 5.1
|
||||
<# SilverMetal Enhanced - Windows | Domain B: Boot & firmware trust
|
||||
Most of B is a FIRMWARE step (Secure Boot custom-key enrollment, BIOS admin
|
||||
password) that an OS image cannot perform. This module STAGES our keys and
|
||||
reports Secure Boot state; the enrollment itself is done in UEFI setup at
|
||||
provisioning (SKU) or as a documented user step (self-apply).
|
||||
Spec: ../hardening-spec.md (B) | SCAFFOLD (M1).
|
||||
#>
|
||||
[CmdletBinding()] param()
|
||||
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||
Write-Host '[B] Boot & firmware trust'
|
||||
|
||||
try {
|
||||
if (Confirm-SecureBootUEFI) { Write-Host ' Secure Boot: ENABLED' }
|
||||
else { Write-Warning ' Secure Boot is DISABLED - enable + enrol custom keys in UEFI setup.' }
|
||||
} catch { Write-Warning " Secure Boot state unavailable (legacy/CSM?): $_" }
|
||||
|
||||
# TODO-M1: stage SilverMetal PK/KEK/db (retain Microsoft UEFI CA for option ROMs) to a known path
|
||||
# for KeyTool/manual enrollment; document the firmware-side procedure.
|
||||
# REMINDER (manual, NOT scriptable here): set a BIOS admin password; disable PXE/legacy/CSM;
|
||||
# verify enrolled keys survive a GPD BIOS update (open question, hardening-spec.md §8).
|
||||
|
||||
Write-Host ' [B] staged (firmware enrollment is a documented manual step)'
|
||||
28
windows/hardening/02-data-at-rest.ps1
Normal file
28
windows/hardening/02-data-at-rest.ps1
Normal file
@@ -0,0 +1,28 @@
|
||||
#Requires -Version 5.1
|
||||
<# SilverMetal Enhanced - Windows | Domain C: Data at rest (crown jewel)
|
||||
BitLocker XTS-AES-256 with TPM + PIN. NEVER TPM-only: the faulTPM class
|
||||
extracts the VMK from the AMD fTPM; a PIN forces an offline brute-force.
|
||||
The PIN is set INTERACTIVELY by the user (cannot be shipped in an image).
|
||||
Spec: ../hardening-spec.md (C) | SCAFFOLD (M1): run on the unit.
|
||||
#>
|
||||
[CmdletBinding()] param([string]$MountPoint = $env:SystemDrive)
|
||||
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||
Write-Host '[C] Data at rest (BitLocker TPM+PIN)'
|
||||
|
||||
# Enforce TPM+PIN at startup and forbid cloud recovery escrow via policy.
|
||||
$fve = 'HKLM:\SOFTWARE\Policies\Microsoft\FVE'
|
||||
New-Item $fve -Force | Out-Null
|
||||
Set-ItemProperty $fve -Name UseAdvancedStartup -Type DWord -Value 1 # require startup auth
|
||||
Set-ItemProperty $fve -Name UseTPMPIN -Type DWord -Value 1 # TPM+PIN required
|
||||
Set-ItemProperty $fve -Name UseTPM -Type DWord -Value 2 # TPM-only NOT allowed
|
||||
Set-ItemProperty $fve -Name EnableNonTPM -Type DWord -Value 0
|
||||
Set-ItemProperty $fve -Name MinimumPIN -Type DWord -Value 8 # enhanced PIN length
|
||||
Set-ItemProperty $fve -Name OSEncryptionType -Type DWord -Value 1 # full (not used-space-only)
|
||||
# No Microsoft-account / AD escrow of recovery key:
|
||||
Set-ItemProperty $fve -Name OSManageDRA -Type DWord -Value 0
|
||||
|
||||
# TODO-M1 (interactive on the unit): prompt the user for a >=8-char enhanced PIN, then:
|
||||
# Enable-BitLocker -MountPoint $MountPoint -EncryptionMethod XtsAes256 -TpmAndPinProtector -Pin $securePin
|
||||
# Add a recovery password and store it OFFLINE (SilverKeys), never cloud-escrowed.
|
||||
|
||||
Write-Host " [C] policy set (TPM+PIN required, TPM-only blocked). PIN enrollment = interactive."
|
||||
38
windows/hardening/03-kernel-credential.ps1
Normal file
38
windows/hardening/03-kernel-credential.ps1
Normal file
@@ -0,0 +1,38 @@
|
||||
#Requires -Version 5.1
|
||||
<# SilverMetal Enhanced - Windows | Domain D: Kernel & credential isolation
|
||||
VBS + HVCI + Credential Guard + LSA protection + Kernel DMA Protection.
|
||||
The genuinely strong, hardware-backed part of hardened Windows.
|
||||
Spec: ../hardening-spec.md (D) | SCAFFOLD (M1).
|
||||
#>
|
||||
[CmdletBinding()] param()
|
||||
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||
Write-Host '[D] Kernel & credential isolation'
|
||||
|
||||
# VBS + HVCI (Memory Integrity)
|
||||
$dg = 'HKLM:\SYSTEM\CurrentControlSet\Control\DeviceGuard'
|
||||
New-Item $dg -Force | Out-Null
|
||||
Set-ItemProperty $dg -Name EnableVirtualizationBasedSecurity -Type DWord -Value 1
|
||||
Set-ItemProperty $dg -Name RequirePlatformSecurityFeatures -Type DWord -Value 1 # Secure Boot
|
||||
$hvci = "$dg\Scenarios\HypervisorEnforcedCodeIntegrity"
|
||||
New-Item $hvci -Force | Out-Null
|
||||
Set-ItemProperty $hvci -Name Enabled -Type DWord -Value 1
|
||||
|
||||
# Credential Guard
|
||||
$lsacfg = "$dg\Scenarios\CredentialGuard"
|
||||
New-Item $lsacfg -Force | Out-Null
|
||||
Set-ItemProperty $lsacfg -Name Enabled -Type DWord -Value 1
|
||||
|
||||
# LSA protection (RunAsPPL)
|
||||
$lsa = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa'
|
||||
Set-ItemProperty $lsa -Name RunAsPPL -Type DWord -Value 1
|
||||
|
||||
# Kernel DMA Protection: on AMD this is firmware-gated (ACPI IVRS DMA_REMAP bit).
|
||||
# Block new DMA devices while locked as the compensating control (see Domain G).
|
||||
$ki = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Kernel DMA Protection'
|
||||
New-Item $ki -Force | Out-Null
|
||||
Set-ItemProperty $ki -Name DeviceEnumerationPolicy -Type DWord -Value 0 # block until authorized
|
||||
|
||||
# TODO-M1: confirm msinfo32 reports VBS=Running + Credential Guard + HVCI after reboot;
|
||||
# confirm whether Kernel DMA Protection shows On (IVRS bit) — open question §8.
|
||||
|
||||
Write-Host ' [D] policy set (VBS/HVCI/CredGuard/LSA-PPL/DMA). Effective after reboot.'
|
||||
36
windows/hardening/04-app-control.ps1
Normal file
36
windows/hardening/04-app-control.ps1
Normal file
@@ -0,0 +1,36 @@
|
||||
#Requires -Version 5.1
|
||||
<# SilverMetal Enhanced - Windows | Domain E: Application control
|
||||
WDAC (App Control) AUDIT-first then enforce; Defender ASR at max; Defender
|
||||
on for detection but sample submission OFF (privacy); SmartScreen; CFA.
|
||||
Balanced posture = audit before enforce (don't brick the dev workflow).
|
||||
Spec: ../hardening-spec.md (E) | SCAFFOLD (M1).
|
||||
#>
|
||||
[CmdletBinding()] param()
|
||||
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||
Write-Host '[E] Application control'
|
||||
|
||||
# --- Defender: detection on, but do NOT exfiltrate user files ---
|
||||
Set-MpPreference -MAPSReporting Advanced
|
||||
Set-MpPreference -SubmitSamplesConsent 2 # 2 = never send samples
|
||||
Set-MpPreference -PUAProtection Enabled
|
||||
Set-MpPreference -EnableControlledFolderAccess Enabled
|
||||
|
||||
# --- ASR rules at max (Block) ---
|
||||
$asr = @{
|
||||
'BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550'=1 # block executable content from email/webmail
|
||||
'9E6C4E1F-7D60-472F-BA1A-A39EF669E4B2'=1 # block credential stealing from lsass
|
||||
'D4F940AB-401B-4EFC-AADC-AD5F3C50688A'=1 # block Office child processes
|
||||
'3B576869-A4EC-4529-8536-B80A7769E899'=1 # block Office executable content creation
|
||||
'5BEB7EFE-FD9A-4556-801D-275E5FFC04CC'=1 # block obfuscated scripts
|
||||
'D3E037E1-3EB8-44C8-A917-57927947596D'=1 # block JS/VBS launching downloaded content
|
||||
'B2B3F03D-6A65-4F7B-A9C7-1C7EF74A9BA4'=1 # block untrusted/unsigned from USB
|
||||
}
|
||||
foreach ($id in $asr.Keys) { Add-MpPreference -AttackSurfaceReductionRules_Ids $id -AttackSurfaceReductionRules_Actions $asr[$id] }
|
||||
|
||||
# --- WDAC: deploy base policy in AUDIT first ---
|
||||
# TODO-M1: compile ..\wdac\silvermetal-base.xml -> .cip in AUDIT mode (option 3 'Audit Mode' set),
|
||||
# stage to C:\Windows\System32\CodeIntegrity\CiPolicies\Active, CiTool --refresh.
|
||||
# After a real-usage shakedown, regenerate from audit events and PROMOTE to enforce.
|
||||
Write-Warning ' WDAC base policy authoring is M1 (audit) -> M2 (enforce). Not yet deployed.'
|
||||
|
||||
Write-Host ' [E] Defender+ASR applied; WDAC pending policy authoring.'
|
||||
31
windows/hardening/05-network-radios.ps1
Normal file
31
windows/hardening/05-network-radios.ps1
Normal file
@@ -0,0 +1,31 @@
|
||||
#Requires -Version 5.1
|
||||
<# SilverMetal Enhanced - Windows | Domain F: Network & radios
|
||||
Distrust the network: firewall default-deny inbound, encrypted DNS, kill
|
||||
LAN name-resolution leak vectors, WiFi-only (no baseband module). SilverVPN
|
||||
always-on kill-switch is installed by 08-stack-install.ps1.
|
||||
Spec: ../hardening-spec.md (F) | SCAFFOLD (M1).
|
||||
#>
|
||||
[CmdletBinding()] param()
|
||||
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||
Write-Host '[F] Network & radios'
|
||||
|
||||
# Firewall: default-deny inbound on all profiles.
|
||||
Set-NetFirewallProfile -Profile Domain,Public,Private -DefaultInboundAction Block -DefaultOutboundAction Allow -Enabled True
|
||||
|
||||
# Disable SMBv1 + LAN name-resolution leak vectors.
|
||||
Disable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol -NoRestart -EA SilentlyContinue | Out-Null
|
||||
$dns = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient'
|
||||
New-Item $dns -Force | Out-Null
|
||||
Set-ItemProperty $dns -Name EnableMulticast -Type DWord -Value 0 # LLMNR off
|
||||
$nbt = 'HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters'
|
||||
Set-ItemProperty $nbt -Name NodeType -Type DWord -Value 2 # NetBIOS: P-node (no broadcast)
|
||||
|
||||
# Encrypted DNS (DoH) auto + WPAD off.
|
||||
$doh = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient'
|
||||
Set-ItemProperty $doh -Name DoHPolicy -Type DWord -Value 3 # require DoH
|
||||
Set-Service WinHttpAutoProxySvc -StartupType Disabled -EA SilentlyContinue
|
||||
|
||||
# TODO-M1: configure DoH server template; verify NO WWAN adapter present (we do not fit the
|
||||
# 4G/5G baseband module); disable Bluetooth radio unless in use.
|
||||
|
||||
Write-Host ' [F] firewall default-deny, SMB1 off, LLMNR/NetBIOS/WPAD off, DoH required.'
|
||||
32
windows/hardening/06-physical-lock.ps1
Normal file
32
windows/hardening/06-physical-lock.ps1
Normal file
@@ -0,0 +1,32 @@
|
||||
#Requires -Version 5.1
|
||||
<# SilverMetal Enhanced - Windows | Domain G: Physical & lock-screen hygiene
|
||||
Theft is threat #1 for a pocket device. Short auto-lock, PIN on wake, block
|
||||
DMA while locked, prefer hibernate, no HW kill switch (software cam/mic).
|
||||
Spec: ../hardening-spec.md (G) | SCAFFOLD (M1).
|
||||
#>
|
||||
[CmdletBinding()] param()
|
||||
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||
Write-Host '[G] Physical & lock-screen hygiene'
|
||||
|
||||
# Auto-lock: machine inactivity limit (seconds) + require password on wake.
|
||||
$sys = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
|
||||
New-Item $sys -Force | Out-Null
|
||||
Set-ItemProperty $sys -Name InactivityTimeoutSecs -Type DWord -Value 120 # lock after 2 min idle
|
||||
$pol = 'HKLM:\SOFTWARE\Policies\Microsoft\Power\PowerSettings\0e796bdb-100d-47d6-a2d5-f7d2daa51f51'
|
||||
New-Item $pol -Force | Out-Null
|
||||
Set-ItemProperty $pol -Name ACSettingIndex -Type DWord -Value 1 # require password on wake (AC)
|
||||
Set-ItemProperty $pol -Name DCSettingIndex -Type DWord -Value 1 # ... and on battery
|
||||
|
||||
# Block new DMA-capable devices while the screen is locked (compensates if firmware
|
||||
# Kernel DMA Protection is absent - see Domain D / open question §8).
|
||||
$fve = 'HKLM:\SOFTWARE\Policies\Microsoft\FVE'
|
||||
New-Item $fve -Force | Out-Null
|
||||
Set-ItemProperty $fve -Name DisableExternalDMAUnderLock -Type DWord -Value 1
|
||||
|
||||
# Prefer hibernate over sleep (keys not left resident in RAM as long).
|
||||
powercfg /hibernate on 2>$null
|
||||
# TODO-M1: set lid-close + idle -> hibernate via powercfg; deny camera/mic per-app
|
||||
# (Device Manager disable is the stopgap; the Pocket 4 has NO hardware kill switch).
|
||||
# NOTE: SilverDuress (Stack, v1.1) provides duress-PIN / panic-wipe - installed by module 08.
|
||||
|
||||
Write-Host ' [G] auto-lock=120s, password-on-wake, DMA-blocked-while-locked, hibernate on.'
|
||||
36
windows/hardening/07-privacy-update.ps1
Normal file
36
windows/hardening/07-privacy-update.ps1
Normal file
@@ -0,0 +1,36 @@
|
||||
#Requires -Version 5.1
|
||||
<# SilverMetal Enhanced - Windows | Domain H: Privacy minimisation & update integrity
|
||||
Trim telemetry tasks/services at GP+service+firewall layers. Do NOT block
|
||||
Microsoft domains in the hosts file (breaks Windows Update; violates
|
||||
design-principle #13). Keep Windows Update ON. Publish residual telemetry.
|
||||
Spec: ../hardening-spec.md (H) | SCAFFOLD (M1).
|
||||
#>
|
||||
[CmdletBinding()] param()
|
||||
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||
Write-Host '[H] Privacy minimisation & update integrity'
|
||||
|
||||
# Disable telemetry/feedback scheduled tasks (keep update/time/security tasks).
|
||||
$tasks = @(
|
||||
'\Microsoft\Windows\Application Experience\Microsoft Compatibility Appraiser'
|
||||
'\Microsoft\Windows\Application Experience\ProgramDataUpdater'
|
||||
'\Microsoft\Windows\Customer Experience Improvement Program\Consolidator'
|
||||
'\Microsoft\Windows\Customer Experience Improvement Program\UsbCeip'
|
||||
'\Microsoft\Windows\Feedback\Siuf\DmClient'
|
||||
)
|
||||
foreach ($t in $tasks) { Disable-ScheduledTask -TaskPath (Split-Path $t) -TaskName (Split-Path $t -Leaf) -EA SilentlyContinue | Out-Null }
|
||||
|
||||
# CEIP off.
|
||||
$sqm = 'HKLM:\SOFTWARE\Policies\Microsoft\SQMClient\Windows'
|
||||
New-Item $sqm -Force | Out-Null; Set-ItemProperty $sqm -Name CEIPEnable -Type DWord -Value 0
|
||||
|
||||
# Windows Update STAYS ON (update-or-die). We minimise telemetry, never patching.
|
||||
Get-Service wuauserv | Set-Service -StartupType Automatic
|
||||
# Guard: assert the hosts file contains no Microsoft update/licensing domains (anti-footgun).
|
||||
$hosts = Get-Content "$env:windir\System32\drivers\etc\hosts" -EA SilentlyContinue
|
||||
if ($hosts -match 'microsoft\.com|windowsupdate|msftncsi|login\.live') {
|
||||
Write-Warning ' hosts file blocks Microsoft domains - REMOVE (breaks Windows Update).'
|
||||
}
|
||||
|
||||
# TODO-M1: run tests\telemetry-leak test; document the irreducible residual (we publish, not claim zero).
|
||||
|
||||
Write-Host ' [H] telemetry tasks/CEIP off; Windows Update preserved.'
|
||||
27
windows/hardening/08-stack-install.ps1
Normal file
27
windows/hardening/08-stack-install.ps1
Normal file
@@ -0,0 +1,27 @@
|
||||
#Requires -Version 5.1
|
||||
<# SilverMetal Enhanced - Windows | SilverLABS Application Stack
|
||||
The Stack is the spine (design-principle #7). Install native Windows builds
|
||||
and set SilverBrowser default + SilverVPN always-on kill-switch.
|
||||
Spec: ../hardening-spec.md (#4) | SCAFFOLD (M4): some components are
|
||||
Linux-MVP today (windows/README.md) - their Windows builds may lag.
|
||||
#>
|
||||
[CmdletBinding()] param([string]$StackDir = "$PSScriptRoot\..\stack-installer")
|
||||
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||
Write-Host '[Stack] SilverLABS Application Stack'
|
||||
|
||||
# Component -> hardening-spec mapping:
|
||||
# SilverBrowser (A,H) default browser | SilverVPN (F) always-on kill-switch
|
||||
# SilverSync (A) replaces OneDrive | SilverChat (F) E2EE over VPN
|
||||
# SilverDuress (G) duress/panic-wipe | SilverKeys (C,A) pwd/2FA + offline BL recovery key
|
||||
$components = 'SilverBrowser','SilverVPN','SilverSync','SilverChat','SilverDuress','SilverKeys'
|
||||
|
||||
foreach ($c in $components) {
|
||||
# TODO-M4: install $StackDir\$c\*.msi/.exe silently; verify signature against the
|
||||
# SilverLABS signing key (trust-model.md) before install.
|
||||
Write-Warning " $c install pending native Windows build (M4)."
|
||||
}
|
||||
|
||||
# TODO-M4: set SilverBrowser as default http/https handler; enable SilverVPN kill-switch
|
||||
# (no plaintext fallback); register SilverDuress.
|
||||
|
||||
Write-Host ' [Stack] mapping staged; installs land at M4.'
|
||||
59
windows/hardening/Verify-SilverMetalWindows.ps1
Normal file
59
windows/hardening/Verify-SilverMetalWindows.ps1
Normal file
@@ -0,0 +1,59 @@
|
||||
#Requires -Version 5.1
|
||||
<# SilverMetal Enhanced - Windows | Verification
|
||||
Asserts the hardening-spec.md verification gates and emits a report. Evidence
|
||||
before assertions: each check reports the observed value, not a claim.
|
||||
Spec: ../hardening-spec.md (§6) | SCAFFOLD (M1): fill remaining gates.
|
||||
Exit code 0 = all pass; non-zero = count of failed gates.
|
||||
#>
|
||||
[CmdletBinding()] param([string]$ReportPath = "$env:ProgramData\SilverMetal\verify-report.json")
|
||||
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Continue'
|
||||
|
||||
$results = [ordered]@{}
|
||||
function Test-Gate { param([string]$Name,[scriptblock]$Check)
|
||||
try { $v = & $Check; $results[$Name] = @{ pass = [bool]$v.pass; detail = $v.detail } }
|
||||
catch { $results[$Name] = @{ pass = $false; detail = "error: $_" } }
|
||||
}
|
||||
|
||||
Test-Gate 'Telemetry=Security(0)' {
|
||||
$v = (Get-ItemProperty 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection' -Name AllowTelemetry -EA Stop).AllowTelemetry
|
||||
@{ pass = ($v -eq 0); detail = "AllowTelemetry=$v" }
|
||||
}
|
||||
Test-Gate 'BitLocker XtsAes256 + TpmPin' {
|
||||
$bl = Get-BitLockerVolume -MountPoint $env:SystemDrive -EA Stop
|
||||
$hasPin = ($bl.KeyProtector.KeyProtectorType -contains 'TpmPin')
|
||||
@{ pass = ($bl.ProtectionStatus -eq 'On' -and $bl.EncryptionMethod -eq 'XtsAes256' -and $hasPin)
|
||||
detail = "$($bl.ProtectionStatus)/$($bl.EncryptionMethod)/TpmPin=$hasPin" }
|
||||
}
|
||||
Test-Gate 'VBS + HVCI + CredentialGuard running' {
|
||||
$dg = Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard -EA Stop
|
||||
$svc = $dg.SecurityServicesRunning
|
||||
@{ pass = (($svc -contains 1) -and ($svc -contains 2)); detail = "running=$($svc -join ',')" }
|
||||
}
|
||||
Test-Gate 'WDAC enforced' {
|
||||
$dg = Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard -EA Stop
|
||||
@{ pass = ($dg.CodeIntegrityPolicyEnforcementStatus -eq 2)
|
||||
detail = "enforcement=$($dg.CodeIntegrityPolicyEnforcementStatus) (2=enforced,1=audit)" }
|
||||
}
|
||||
Test-Gate 'Secure Boot enabled' {
|
||||
@{ pass = (Confirm-SecureBootUEFI); detail = 'Confirm-SecureBootUEFI' }
|
||||
}
|
||||
Test-Gate 'Firewall default-deny inbound' {
|
||||
$p = Get-NetFirewallProfile -EA Stop
|
||||
@{ pass = -not ($p.DefaultInboundAction -contains 'Allow'); detail = ($p.DefaultInboundAction -join ',') }
|
||||
}
|
||||
Test-Gate 'Windows Update healthy' {
|
||||
$s = Get-Service wuauserv -EA Stop
|
||||
@{ pass = ($s.StartType -ne 'Disabled'); detail = "$($s.Status)/$($s.StartType)" }
|
||||
}
|
||||
# TODO-M1: VPN kill-switch egress test; telemetry-leak capture; Stack functional check.
|
||||
|
||||
$pass = ($results.Values | Where-Object { $_.pass }).Count
|
||||
$fail = ($results.Values | Where-Object { -not $_.pass }).Count
|
||||
New-Item (Split-Path $ReportPath) -ItemType Directory -Force -EA SilentlyContinue | Out-Null
|
||||
$results | ConvertTo-Json -Depth 4 | Set-Content $ReportPath
|
||||
$results.GetEnumerator() | ForEach-Object {
|
||||
$c = if ($_.Value.pass) { 'Green' } else { 'Red' }
|
||||
Write-Host ("[{0}] {1} - {2}" -f ($(if($_.Value.pass){'PASS'}else{'FAIL'}), $_.Key, $_.Value.detail)) -ForegroundColor $c
|
||||
}
|
||||
Write-Host "`n$pass passed, $fail failed. Report: $ReportPath"
|
||||
exit $fail
|
||||
17
windows/installer/README.md
Normal file
17
windows/installer/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# windows/installer
|
||||
|
||||
The custom packed-ISO build pipeline. See [`../iso-builder.md`](../iso-builder.md) for the design.
|
||||
|
||||
| File | Role |
|
||||
|---|---|
|
||||
| `build.ps1` | Pipeline orchestrator (7 stages). Run on Windows + Windows ADK. |
|
||||
| `inputs.manifest.json` | Pinned inputs — base ISO SHA-256, driver-pack/Stack/tool versions. The Microsoft ISO is an **input, never committed**. |
|
||||
| `autounattend/autounattend.xml` | OOBE automation — local account (no MSA), regional, BitLocker-ready disk layout, hands off to first-boot. |
|
||||
| `oem/SetupComplete.cmd` | First-boot entry point — runs the shared `../hardening/` modules, then schedules `Verify`. |
|
||||
|
||||
**Usage (M2+):**
|
||||
```powershell
|
||||
.\build.ps1 -SourceIso 'D:\Win11_IoT_Enterprise_LTSC_x64.iso'
|
||||
```
|
||||
|
||||
Current status: **M0 scaffold** — stages 2–7 throw `NotImplemented` until M2/M3.
|
||||
65
windows/installer/autounattend/autounattend.xml
Normal file
65
windows/installer/autounattend/autounattend.xml
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SilverMetal Enhanced - Windows : Windows 11 IoT Enterprise LTSC answer file.
|
||||
|
||||
Purpose: automate OOBE, force a LOCAL account (no Microsoft Account / no cloud
|
||||
key escrow), set regional defaults, prepare a BitLocker-ready disk layout, and
|
||||
hand off to $OEM$\SetupComplete.cmd for first-boot hardening.
|
||||
|
||||
SCAFFOLD (M0). Disk layout + image selectors are filled at M2 against the
|
||||
licensed media. Do NOT embed product keys, PINs, or secrets here.
|
||||
|
||||
Design: ../../iso-builder.md Controls: ../../hardening-spec.md (domains A, C)
|
||||
-->
|
||||
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
||||
|
||||
<settings pass="windowsPE">
|
||||
<component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<SetupUILanguage><UILanguage>en-GB</UILanguage></SetupUILanguage>
|
||||
<InputLocale>0809:00000809</InputLocale>
|
||||
<SystemLocale>en-GB</SystemLocale>
|
||||
<UILanguage>en-GB</UILanguage>
|
||||
<UserLocale>en-GB</UserLocale>
|
||||
</component>
|
||||
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<!-- TODO-M2: DiskConfiguration (GPT, ESP + MSR + Windows), single GPT disk, BitLocker-ready.
|
||||
ImageInstall/OSImage/InstallFrom MetaData = IoT Enterprise LTSC index (see inputs.manifest.json). -->
|
||||
<UserData>
|
||||
<ProductKey><!-- TODO-M2: IoT Enterprise LTSC key, build-time injected; NOT committed --></ProductKey>
|
||||
<AcceptEula>true</AcceptEula>
|
||||
</UserData>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
<settings pass="oobeSystem">
|
||||
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<OOBE>
|
||||
<HideEULAPage>true</HideEULAPage>
|
||||
<HideOnlineAccountScreens>true</HideOnlineAccountScreens> <!-- force local account -->
|
||||
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
|
||||
<ProtectYourPC>3</ProtectYourPC> <!-- disable "send data" express settings -->
|
||||
</OOBE>
|
||||
<UserAccounts>
|
||||
<!-- TODO-M2: provision a local admin (no MSA). Password set at provisioning, not committed. -->
|
||||
<LocalAccounts>
|
||||
<LocalAccount wcm:action="add" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
|
||||
<Name>silvermetal</Name>
|
||||
<Group>Administrators</Group>
|
||||
<DisplayName>SilverMetal</DisplayName>
|
||||
</LocalAccount>
|
||||
</LocalAccounts>
|
||||
</UserAccounts>
|
||||
<FirstLogonCommands>
|
||||
<SynchronousCommand wcm:action="add" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
|
||||
<Order>1</Order>
|
||||
<CommandLine>cmd /c C:\Windows\Setup\Scripts\SetupComplete.cmd</CommandLine>
|
||||
<Description>SilverMetal first-boot hardening</Description>
|
||||
</SynchronousCommand>
|
||||
</FirstLogonCommands>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
</unattend>
|
||||
100
windows/installer/build.ps1
Normal file
100
windows/installer/build.ps1
Normal file
@@ -0,0 +1,100 @@
|
||||
#Requires -Version 5.1
|
||||
<#
|
||||
.SYNOPSIS
|
||||
SilverMetal Enhanced - Windows : custom packed ISO build pipeline.
|
||||
|
||||
.DESCRIPTION
|
||||
Turns an official Windows 11 IoT Enterprise LTSC ISO (an INPUT, never
|
||||
redistributed) plus the SilverMetal config layer into a hardened, branded,
|
||||
UEFI-bootable ISO with a signed build attestation.
|
||||
|
||||
Design: ../iso-builder.md Controls: ../hardening-spec.md
|
||||
|
||||
Build host requirement: Windows + Windows ADK (DISM + oscdimg).
|
||||
|
||||
.NOTES
|
||||
SCAFFOLD (M0). Stage bodies are stubbed; they are fleshed out at M2.
|
||||
Each stage maps 1:1 to iso-builder.md section 3.
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)] [string] $SourceIso, # licensed IoT Enterprise LTSC ISO
|
||||
[string] $Manifest = "$PSScriptRoot\inputs.manifest.json",
|
||||
[string] $WorkDir = "$env:TEMP\silvermetal-build",
|
||||
[string] $OutputIso = "$PSScriptRoot\out\SilverMetal-Enhanced-Windows.iso",
|
||||
[switch] $SkipInputVerify
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Write-Stage { param([string]$Msg) Write-Host "==> $Msg" -ForegroundColor Cyan }
|
||||
|
||||
# --- 1. Verify input -------------------------------------------------------
|
||||
function Invoke-VerifyInput {
|
||||
Write-Stage 'Stage 1: verify input ISO against pinned manifest'
|
||||
$m = Get-Content $Manifest -Raw | ConvertFrom-Json
|
||||
$expected = $m.baseImage.isoSha256
|
||||
if ($SkipInputVerify -or $expected -like 'TODO*') {
|
||||
Write-Warning 'Input hash not pinned yet (M2). Skipping verification.'
|
||||
return
|
||||
}
|
||||
$actual = (Get-FileHash -Algorithm SHA256 -Path $SourceIso).Hash
|
||||
if ($actual -ne $expected) { throw "Source ISO SHA-256 mismatch.`n expected: $expected`n actual: $actual" }
|
||||
Write-Host ' ISO hash verified.'
|
||||
}
|
||||
|
||||
# --- 2. Extract ------------------------------------------------------------
|
||||
function Invoke-Extract {
|
||||
Write-Stage 'Stage 2: extract ISO to work dir'
|
||||
# TODO-M2: mount $SourceIso, copy contents to $WorkDir\iso, export install.wim to $WorkDir\wim
|
||||
throw 'NotImplemented (M2): extract'
|
||||
}
|
||||
|
||||
# --- 3. Service the WIM offline (DISM) -------------------------------------
|
||||
function Invoke-ServiceWim {
|
||||
Write-Stage 'Stage 3: offline-service install.wim (drivers, updates, debloat, baseline policy, Stack staging)'
|
||||
# TODO-M2: DISM /Mount-Image; /Add-Driver (windows\drivers); /Add-Package (cumulative);
|
||||
# remove appx from windows\debloat; load offline hives + apply windows\policies baseline;
|
||||
# stage Stack + $OEM$ payload; /Unmount-Image /Commit
|
||||
throw 'NotImplemented (M2): service WIM'
|
||||
}
|
||||
|
||||
# --- 4. Inject answer file + first-boot payload ----------------------------
|
||||
function Invoke-InjectUnattend {
|
||||
Write-Stage 'Stage 4: inject autounattend.xml + $OEM$\SetupComplete.cmd + hardening modules'
|
||||
# TODO-M2: copy autounattend\autounattend.xml to ISO root; lay $OEM$\SetupComplete.cmd
|
||||
# + windows\hardening\* into the image so first boot can run them
|
||||
throw 'NotImplemented (M2): inject unattend'
|
||||
}
|
||||
|
||||
# --- 5. Brand --------------------------------------------------------------
|
||||
function Invoke-Brand {
|
||||
Write-Stage 'Stage 5: apply branding (boot/OOBE wallpaper, computer-name pattern)'
|
||||
# TODO-M4: from ..\..\shared\branding
|
||||
Write-Warning ' Branding deferred to M4.'
|
||||
}
|
||||
|
||||
# --- 6. Repack -------------------------------------------------------------
|
||||
function Invoke-Repack {
|
||||
Write-Stage 'Stage 6: repack UEFI-bootable ISO via oscdimg'
|
||||
# TODO-M2: oscdimg -m -o -u2 -udfver102 -bootdata:2#... -> $OutputIso
|
||||
throw 'NotImplemented (M2): repack'
|
||||
}
|
||||
|
||||
# --- 7. Attest -------------------------------------------------------------
|
||||
function Invoke-Attest {
|
||||
Write-Stage 'Stage 7: emit SHA-256 + SBOM + signed build attestation'
|
||||
# TODO-M3: hash $OutputIso; build SBOM from manifest + tool versions; sign (trust-model.md)
|
||||
throw 'NotImplemented (M3): attest'
|
||||
}
|
||||
|
||||
# --- orchestrate -----------------------------------------------------------
|
||||
Invoke-VerifyInput
|
||||
Invoke-Extract
|
||||
Invoke-ServiceWim
|
||||
Invoke-InjectUnattend
|
||||
Invoke-Brand
|
||||
Invoke-Repack
|
||||
Invoke-Attest
|
||||
Write-Host "`nBuild complete: $OutputIso" -ForegroundColor Green
|
||||
38
windows/installer/inputs.manifest.json
Normal file
38
windows/installer/inputs.manifest.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"$comment": "Pinned inputs for a reproducible SilverMetal Enhanced - Windows ISO build. The base Windows ISO is licensed and NEVER committed; it is referenced by SHA-256 only. Fill the TODO hashes/versions at M2 against the actual licensed media and driver pack.",
|
||||
"schemaVersion": 1,
|
||||
"product": "SilverMetal Enhanced - Windows",
|
||||
"referenceDevice": "GPD Pocket 4 (AMD Ryzen AI 9 HX 370 / Strix Point)",
|
||||
"baseImage": {
|
||||
"edition": "Windows 11 IoT Enterprise LTSC",
|
||||
"arch": "x64",
|
||||
"isoSha256": "TODO-M2-pin-against-licensed-media",
|
||||
"wimImageName": "Windows 11 IoT Enterprise LTSC",
|
||||
"wimImageIndex": null
|
||||
},
|
||||
"driverPack": {
|
||||
"name": "GPD Pocket 4 driver pack",
|
||||
"version": "TODO-M2",
|
||||
"sha256": "TODO-M2",
|
||||
"source": "https://gpd.hk (verify) — confirm redistribution terms"
|
||||
},
|
||||
"cumulativeUpdate": {
|
||||
"kb": "TODO-M2-latest-at-build",
|
||||
"sha256": "TODO-M2"
|
||||
},
|
||||
"stack": {
|
||||
"$comment": "Native Windows builds; some components are Linux-MVP per windows/README.md and may lag.",
|
||||
"SilverBrowser": "TODO",
|
||||
"SilverVPN": "from SilverLABS/SilverVPN (MAUI Windows client)",
|
||||
"SilverSync": "TODO",
|
||||
"SilverChat": "from SilverVPN.Client.Chat",
|
||||
"SilverDuress": "TODO",
|
||||
"SilverKeys": "TODO"
|
||||
},
|
||||
"tooling": {
|
||||
"$comment": "Recorded for the build attestation (reproducibility scope: pinned inputs + recorded tools + output SHA + SBOM; not bit-identical).",
|
||||
"windowsAdk": "TODO-M2",
|
||||
"dism": "TODO-M2",
|
||||
"oscdimg": "TODO-M2"
|
||||
}
|
||||
}
|
||||
32
windows/installer/oem/SetupComplete.cmd
Normal file
32
windows/installer/oem/SetupComplete.cmd
Normal file
@@ -0,0 +1,32 @@
|
||||
@echo off
|
||||
REM ===========================================================================
|
||||
REM SilverMetal Enhanced - Windows : first-boot entry point.
|
||||
REM Invoked once by autounattend.xml FirstLogonCommands. Runs the shared
|
||||
REM hardening/ modules in order, logs to disk, then schedules verification.
|
||||
REM
|
||||
REM The hardening/ modules are staged into C:\Windows\Setup\Scripts\hardening
|
||||
REM by build.ps1 (stage 4). They are SHARED with the self-apply track.
|
||||
REM
|
||||
REM Design: ../../iso-builder.md Controls: ../../hardening-spec.md
|
||||
REM SCAFFOLD (M0): module bodies stubbed; safe to run (modules log and no-op
|
||||
REM until implemented at M1).
|
||||
REM ===========================================================================
|
||||
|
||||
set LOG=C:\Windows\Setup\Scripts\silvermetal-firstboot.log
|
||||
set HARD=C:\Windows\Setup\Scripts\hardening
|
||||
|
||||
echo [%DATE% %TIME%] SilverMetal first-boot start >> "%LOG%"
|
||||
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
|
||||
"$ErrorActionPreference='Stop';" ^
|
||||
"Get-ChildItem '%HARD%\0*.ps1' | Sort-Object Name | ForEach-Object {" ^
|
||||
" Write-Host \"--> $($_.Name)\";" ^
|
||||
" & $_.FullName *>> '%LOG%'" ^
|
||||
"}" >> "%LOG%" 2>&1
|
||||
|
||||
REM Register the verification task to run after the first full boot/login.
|
||||
schtasks /Create /TN "SilverMetal\Verify" /SC ONLOGON /RL HIGHEST /F ^
|
||||
/TR "powershell -NoProfile -ExecutionPolicy Bypass -File %HARD%\Verify-SilverMetalWindows.ps1" >> "%LOG%" 2>&1
|
||||
|
||||
echo [%DATE% %TIME%] SilverMetal first-boot done >> "%LOG%"
|
||||
exit /b 0
|
||||
131
windows/iso-builder.md
Normal file
131
windows/iso-builder.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# SilverMetal Enhanced — Windows: ISO Builder
|
||||
|
||||
> **Status**: v1 design — 2026-06-08. Implements the productized SKU build for the hardening defined in [`hardening-spec.md`](hardening-spec.md). Reference device: GPD Pocket 4.
|
||||
|
||||
This document describes the **reproducible build pipeline** that turns an official Windows 11 IoT Enterprise LTSC ISO plus the SilverMetal config layer into a hardened, branded, UEFI-bootable **custom packed ISO**, with a signed build attestation.
|
||||
|
||||
It is bound by the same documents as the hardening spec: [`../docs/threat-model.md`](../docs/threat-model.md), [`../docs/design-principles.md`](../docs/design-principles.md), and [`../docs/trust-model.md`](../docs/trust-model.md).
|
||||
|
||||
## 1. Licensing frame (why this is legitimate)
|
||||
|
||||
Windows 11 **IoT Enterprise LTSC** is licensed through the OEM / embedded channel, whose explicit purpose is building **customized, locked-down, preinstalled images** on devices a solution-builder ships. Creating a custom packed image and preinstalling it on hardware we sell is the *intended, blessed* use — not a grey area.
|
||||
|
||||
| Track | Status under IoT Enterprise LTSC |
|
||||
|---|---|
|
||||
| **Preflashed SilverMetal SKU** (we sell the device) | ✅ Build + ship our custom image — licensed per device, intended use |
|
||||
| **Self-apply free track** (user hardens own device) | ⚠️ No public prebuilt-ISO redistribution. Ships as a **builder** that consumes the user's own official ISO + license — the same `hardening/` modules, applied to their image |
|
||||
|
||||
The Microsoft ISO is therefore always an **input**, never committed to this repo. We ship *our layer*; the licensee provides the base.
|
||||
|
||||
> **Procurement note (verify before pricing the SKU):** IoT Enterprise LTSC is obtained via authorized OEM distributors; per-device licensing may carry minimum-order / agreement terms. Confirm with the distributor.
|
||||
|
||||
## 2. Inputs
|
||||
|
||||
All inputs are pinned by hash in [`installer/inputs.manifest.json`](installer/inputs.manifest.json):
|
||||
|
||||
| Input | Source | In repo? |
|
||||
|---|---|---|
|
||||
| Windows 11 IoT Enterprise LTSC ISO | Licensed (operator/distributor) | No — pinned by SHA-256 |
|
||||
| GPD Pocket 4 driver pack | GPD (verified source) | `drivers/` or sourced manifest |
|
||||
| SilverLABS Stack (native Windows builds) | Stack component repos / artifacts | Referenced by version |
|
||||
| SilverMetal config layer | This repo (`hardening/`, `policies/`, `wdac/`, `debloat/`, `autounattend/`, `oem/`, branding) | Yes |
|
||||
|
||||
## 3. Build stages
|
||||
|
||||
Orchestrated by [`installer/build.ps1`](installer/build.ps1). Runs on a **Windows host with the Windows ADK** (DISM + `oscdimg`).
|
||||
|
||||
1. **Verify input** — assert the source ISO SHA-256 matches the pinned manifest (supply-chain integrity).
|
||||
2. **Extract** — expand the ISO to a working directory.
|
||||
3. **Service the WIM offline (DISM)**:
|
||||
- Select the IoT Enterprise LTSC image index.
|
||||
- `/Add-Driver` the GPD Pocket 4 driver pack (Strix Point GPU, sensors/auto-rotate, Wi-Fi, fingerprint).
|
||||
- `/Add-Package` the latest cumulative update (slipstream).
|
||||
- Trim residual provisioned appx (LTSC is already lean — minimal list in `debloat/`).
|
||||
- Load offline registry hives → apply the **offline-able baseline** (telemetry floor, service disables) from `policies/`.
|
||||
- Stage the Stack installers + first-boot payload into the image.
|
||||
- Commit + unmount.
|
||||
4. **Inject answer file + first-boot payload**:
|
||||
- `autounattend.xml` — OOBE automation, **local account** (no MSA), regional settings, BitLocker-ready disk layout.
|
||||
- `$OEM$\SetupComplete.cmd` — first-boot entry point that runs the online `hardening/` modules and installs the Stack.
|
||||
5. **Brand** — boot/OOBE wallpaper + computer-name pattern from [`../shared/branding`](../shared/branding).
|
||||
6. **Repack** — `oscdimg` produces a UEFI-bootable ISO (efisys boot image, El Torito).
|
||||
7. **Attest** — emit output ISO SHA-256, an **SBOM** (every component + version), and a signed build attestation (design-principle #4).
|
||||
|
||||
## 4. Where each hardening control is applied
|
||||
|
||||
The control domains in [`hardening-spec.md`](hardening-spec.md) split across three layers:
|
||||
|
||||
| Layer | Controls | Mechanism |
|
||||
|---|---|---|
|
||||
| **Baked offline (in WIM)** | Telemetry floor, service disables, appx trim, drivers, baseline registry policy, Stack staging | DISM + offline hive edits |
|
||||
| **First-boot (online)** | Local account, VBS/HVCI/Credential Guard, ASR rules, **WDAC (audit)**, firewall, encrypted DNS, Stack + SilverVPN install, scheduled `Verify` task | `SetupComplete.cmd` → `hardening/` modules |
|
||||
| **Interactive / firmware — NOT in ISO** | Secure Boot custom-key enrollment, **BitLocker PIN**, BIOS admin password | Operator at provisioning (SKU) or documented user step (self-apply). The ISO *enables* BitLocker and *forces* PIN enrollment; it cannot ship a PIN or touch firmware. |
|
||||
|
||||
**The `hardening/` modules are shared.** The same module set is invoked by the ISO's first-boot path *and* by the self-apply / milestone-1 standalone path. Write once, used both ways.
|
||||
|
||||
## 5. Reproducibility (honest scope)
|
||||
|
||||
Windows image servicing is **not bit-for-bit deterministic** the way the Linux ISO pipeline is (WIM internal timestamps, servicing-stack non-determinism). So for this product, "reproducible" means:
|
||||
|
||||
- **Pinned inputs** (every source hashed in the manifest)
|
||||
- **Recorded tool versions** (ADK, DISM, servicing stack)
|
||||
- **Output ISO SHA-256 + SBOM** published per build
|
||||
- **Signed build attestation** linking published artifact ↔ published source + inputs
|
||||
|
||||
Bit-identical rebuild is a **stretch goal**, documented as such — we do not claim it (design-principle #2). This is weaker than the Linux line's reproducible-build guarantee, and we say so to buyers.
|
||||
|
||||
## 6. Directory layout
|
||||
|
||||
```
|
||||
windows/
|
||||
├── installer/
|
||||
│ ├── build.ps1 # pipeline orchestrator
|
||||
│ ├── inputs.manifest.json # pinned ISO SHA, driver-pack ver, Stack vers, tool vers
|
||||
│ ├── autounattend/
|
||||
│ │ └── autounattend.xml # OOBE automation + local account + disk layout
|
||||
│ ├── oem/
|
||||
│ │ └── SetupComplete.cmd # first-boot entry → runs hardening/ modules
|
||||
│ └── README.md
|
||||
├── hardening/ # §A–H PowerShell modules + Verify ← SHARED (ISO + self-apply)
|
||||
│ ├── 00-provisioning.ps1 # A
|
||||
│ ├── 01-boot-firmware.ps1 # B (stages keys; firmware steps documented)
|
||||
│ ├── 02-data-at-rest.ps1 # C (BitLocker TPM+PIN)
|
||||
│ ├── 03-kernel-credential.ps1# D (VBS/HVCI/CredGuard/DMA)
|
||||
│ ├── 04-app-control.ps1 # E (WDAC audit, ASR, Defender)
|
||||
│ ├── 05-network-radios.ps1 # F (firewall, DNS, WiFi-only)
|
||||
│ ├── 06-physical-lock.ps1 # G (lock-screen, DMA lock, cam/mic)
|
||||
│ ├── 07-privacy-update.ps1 # H (telemetry trim, update integrity)
|
||||
│ ├── 08-stack-install.ps1 # SilverLABS Stack
|
||||
│ └── Verify-SilverMetalWindows.ps1
|
||||
├── policies/ # GP/ADMX exports + offline .reg/.pol baseline
|
||||
├── wdac/ # WDAC base policy (XML) + compiled .cip
|
||||
├── debloat/ # appx removal list, service-disable scripts
|
||||
├── stack-installer/ # Stack package builders/installers
|
||||
├── drivers/ # GPD Pocket 4 driver pack (or sourced manifest)
|
||||
└── tests/ # telemetry-leak test, hardening-baseline test
|
||||
```
|
||||
|
||||
## 7. Milestones
|
||||
|
||||
| Milestone | Deliverable | Needs hardware? |
|
||||
|---|---|---|
|
||||
| **M0** | This design + scaffolded tree | No |
|
||||
| **M1** | `autounattend.xml` + `hardening/` modules runnable standalone — hardens the Pocket 4 with no pipeline | Yes (the unit) |
|
||||
| **M2** | DISM servicing + `oscdimg` repack → first packed ISO, built locally on a Windows + ADK box | Driver pack |
|
||||
| **M3** | `.gitea/workflows/build-iso-windows.yaml` (Windows runner) + attestation/SBOM + telemetry-leak gate | Windows runner |
|
||||
| **M4** | Branding, full Stack integration, all verification gates green | Stack Windows builds |
|
||||
|
||||
## 8. Build environment & deferred items
|
||||
|
||||
- **Build host**: Windows + Windows ADK (DISM + `oscdimg`). A Windows CI runner is required for M3 (mirrors the existing Linux `.gitea/workflows/build-iso-linux.yaml`).
|
||||
- **Cross-build on Linux** (wimlib + xorriso) is possible but UEFI boot-file assembly is fiddly — **deferred**, Windows-runner path is canonical.
|
||||
- **Stack Windows builds**: some Stack components are still "Linux MVP" per [`README.md`](README.md); their native Windows builds may lag M4.
|
||||
- **Driver-pack sourcing**: confirm redistribution terms for the GPD Pocket 4 driver pack, or source at build time from the verified GPD location.
|
||||
|
||||
## 9. Open questions
|
||||
|
||||
Carried from [`hardening-spec.md`](hardening-spec.md) §8 (resolve on the physical unit), plus builder-specific:
|
||||
|
||||
1. Does the IoT Enterprise LTSC media expose the expected image index and OOBE bypass path for `autounattend.xml`?
|
||||
2. Which Pocket 4 drivers are absent from a vanilla LTSC install and must be injected?
|
||||
3. Does `oscdimg` produce a Pocket 4-bootable UEFI image with the device's firmware (test on the unit)?
|
||||
9
windows/policies/README.md
Normal file
9
windows/policies/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# windows/policies
|
||||
|
||||
Group Policy / ADMX exports and the **offline-applicable baseline** (`.reg` / `.pol`)
|
||||
that `build.ps1` applies into the WIM via offline hive editing (telemetry floor,
|
||||
service disables). The online/runtime policy is applied by the `../hardening/`
|
||||
modules at first boot.
|
||||
|
||||
Populated at **M2** by exporting the prototype unit's applied policy
|
||||
(`LGPO.exe` / registry export) after the `hardening/` modules run on the device.
|
||||
16
windows/stack-installer/README.md
Normal file
16
windows/stack-installer/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# windows/stack-installer
|
||||
|
||||
Native Windows installers for the SilverLABS Application Stack, staged into the
|
||||
image and run by [`../hardening/08-stack-install.ps1`](../hardening/08-stack-install.ps1).
|
||||
|
||||
| Component | hardening-spec mapping | Status |
|
||||
|---|---|---|
|
||||
| SilverBrowser | A, H (default browser) | Linux MVP — Windows build TBD |
|
||||
| SilverVPN | F (always-on kill-switch) | Existing — MAUI Windows client (`SilverLABS/SilverVPN`) |
|
||||
| SilverSync | A (replaces OneDrive) | Linux MVP — Windows build TBD |
|
||||
| SilverChat | F (E2EE over VPN) | Existing (`SilverVPN.Client.Chat`) |
|
||||
| SilverDuress | G (duress / panic-wipe) | v1.1 |
|
||||
| SilverKeys | C, A (pwd/2FA + offline BL recovery key) | v1.1 |
|
||||
|
||||
Installers must be **signature-verified against the SilverLABS signing key**
|
||||
([`../../docs/trust-model.md`](../../docs/trust-model.md)) before install. Lands at **M4**.
|
||||
14
windows/tests/README.md
Normal file
14
windows/tests/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# windows/tests
|
||||
|
||||
Verification gates for a SilverMetal Enhanced — Windows build
|
||||
([`../hardening-spec.md`](../hardening-spec.md) §6).
|
||||
|
||||
| Test | What it proves | Status |
|
||||
|---|---|---|
|
||||
| **Hardening-baseline** | All control gates pass | [`../hardening/Verify-SilverMetalWindows.ps1`](../hardening/Verify-SilverMetalWindows.ps1) (M1) |
|
||||
| **Telemetry-leak** | Captures egress on a clean build; classifies every Microsoft contact; **publishes the residual** (we do not claim zero) | TODO-M3 |
|
||||
| **VPN kill-switch** | Tunnel-drop → zero egress | TODO-M1 |
|
||||
| **Update path** | A test update applies + rolls back (update-or-die) | TODO-M3 |
|
||||
|
||||
The telemetry-leak test is the honesty gate: it documents the minimum-feasible
|
||||
Microsoft contact that remains, per design-principle #2.
|
||||
11
windows/wdac/README.md
Normal file
11
windows/wdac/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# windows/wdac
|
||||
|
||||
WDAC (App Control for Business) policy — the **primary**, kernel-enforced
|
||||
application-control engine for SilverMetal Enhanced — Windows. AppLocker is the
|
||||
documented fallback only.
|
||||
|
||||
**Workflow (design-principle: balanced / audit-first):**
|
||||
1. **M1** — author `silvermetal-base.xml` and deploy in **AUDIT** mode on the prototype unit; run real workloads; collect `CodeIntegrity` audit events.
|
||||
2. **M2** — regenerate the policy from audit events (Windows + Stack + approved dev tools signed/allowed), compile to `.cip`, and **PROMOTE to ENFORCE**.
|
||||
|
||||
The base policy ships pre-authored in the SKU; the prototype builds it from its own audit logs. See [`../hardening-spec.md`](../hardening-spec.md) Domain E.
|
||||
Reference in New Issue
Block a user