diff --git a/Config.psm1 b/Config.psm1 index 8317b51..2f2acac 100644 --- a/Config.psm1 +++ b/Config.psm1 @@ -115,12 +115,24 @@ function Get-AvailableConfigOptions { @{"Name" = "install_qemu_ga"; "GroupName" = "custom";"DefaultValue" = "False"; "Description" = "Installs QEMU guest agent services from the Fedora VirtIO website. Defaults to 'False' (no installation will be performed). - If set to 'True', the following MSI installer will be downloaded and installed: + If set to 'True', by default the following MSI installer will be downloaded and installed: * for x86: https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-qemu-ga/qemu-ga-win-100.0.0.0-3.el7ev/qemu-ga-x86.msi * for x64: https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-qemu-ga/qemu-ga-win-100.0.0.0-3.el7ev/qemu-ga-x64.msi The value can be changed to a custom URL, to allow other QEMU guest agent versions to be installed. + For a safer alternative that also verifies the installer integrity, set 'install_qemu_ga = True' + and use the 'url' and 'checksum' options in the [virtio_qemu_guest_agent] section instead. Note: QEMU guest agent requires VirtIO drivers to be present on the image. "}, + @{"Name" = "url"; "GroupName" = "virtio_qemu_guest_agent"; + "Description" = "Optional custom URL for the QEMU guest agent MSI installer. + When set, it overrides the default installer URL selected by 'install_qemu_ga'. + Requires 'install_qemu_ga' to be set to 'True' and is intended to be used together + with the 'checksum' option below to verify the downloaded installer."}, + @{"Name" = "checksum"; "GroupName" = "virtio_qemu_guest_agent"; + "Description" = "Optional SHA256 checksum of the QEMU guest agent MSI installer. + When set, the downloaded installer is verified against this value and the build + fails on mismatch. It applies to the installer selected by 'url' or by 'install_qemu_ga'. + Compute it with: (Get-FileHash -Algorithm SHA256 ).Hash"}, @{"Name" = "drivers_path"; "GroupName" = "drivers"; "Description" = "The location where additional drivers that are needed for the image are located."}, @{"Name" = "install_updates"; "GroupName" = "updates"; "DefaultValue" = $false; "AsBoolean" = $true; diff --git a/Examples/windows-image-config-example.ini b/Examples/windows-image-config-example.ini index e0a7aa4..1ea593d 100644 --- a/Examples/windows-image-config-example.ini +++ b/Examples/windows-image-config-example.ini @@ -140,12 +140,24 @@ drivers_path="" # * for x86: https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-qemu-ga/qemu-ga-win-100.0.0.0-3.el7ev/qemu-ga-x86.msi # * for x64: https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-qemu-ga/qemu-ga-win-100.0.0.0-3.el7ev/qemu-ga-x64.msi # The value can be changed to a custom URL, to allow other QEMU guest agent versions to be installed. +# For a safer alternative that also verifies the installer integrity, keep 'install_qemu_ga=True' +# and use the 'url' and 'checksum' options in the [virtio_qemu_guest_agent] section below. # Note: QEMU guest agent requires VirtIO drivers to be present on the image. install_qemu_ga=False # Set a custom timezone for the Windows image. time_zone="" # Set custom ntp servers(space separated) for the Windows image ntp_servers="" +[virtio_qemu_guest_agent] +# Optional custom URL for the QEMU guest agent MSI installer. +# When set, it overrides the default installer URL selected by 'install_qemu_ga' +# (which must be set to 'True'). Intended to be used together with 'checksum' below. +url="" +# Optional SHA256 checksum of the QEMU guest agent MSI installer. +# When set, the downloaded installer is verified against this value and the build +# fails on mismatch. Applies to the installer selected by 'url' or by 'install_qemu_ga'. +# Compute it with: (Get-FileHash -Algorithm SHA256 ).Hash +checksum="" [updates] # If set to true, the latest updates will be downloaded and installed. install_updates=False diff --git a/README.md b/README.md index c8b3224..f8a59fb 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,34 @@ popd ``` +## QEMU Guest Agent installer verification + +When `install_qemu_ga` is set to `True`, the QEMU guest agent MSI is downloaded from the +default Fedora VirtIO location. You can optionally pin and verify the installer through the +`[virtio_qemu_guest_agent]` section of the config file: + +```ini +[custom] +install_qemu_ga=True + +[virtio_qemu_guest_agent] +# Optional custom installer URL (overrides the default selected by install_qemu_ga) +url=https://example.com/qemu-ga-x86-64.msi +# Optional SHA256 checksum; the build fails if the downloaded installer does not match +checksum=ABCDEF0123456789... +``` + +- `url` overrides the default installer URL. It requires `install_qemu_ga=True`. +- `checksum` is the SHA256 hash of the installer. When set, the downloaded MSI is verified + and the image build fails on mismatch. It applies whether the installer comes from `url` + or from the default URL. + +Compute the checksum with: + +```powershell +(Get-FileHash -Algorithm SHA256 .\qemu-ga.msi).Hash +``` + ## Image generation workflow ### New-WindowsCloudImage diff --git a/WinImageBuilder.psm1 b/WinImageBuilder.psm1 index 5b0d576..63aa6d7 100755 --- a/WinImageBuilder.psm1 +++ b/WinImageBuilder.psm1 @@ -571,11 +571,17 @@ function Download-QemuGuestAgent { [Parameter(Mandatory=$true)] [string]$ResourcesDir, [Parameter(Mandatory=$true)] - [string]$OsArch + [string]$OsArch, + [Parameter(Mandatory=$false)] + [string]$CustomUrl, + [Parameter(Mandatory=$false)] + [string]$Checksum ) $QemuGuestAgentUrl = $QemuGuestAgentConfig - if ($QemuGuestAgentConfig -eq 'True') { + if ($CustomUrl) { + $QemuGuestAgentUrl = $CustomUrl + } elseif ($QemuGuestAgentConfig -eq 'True') { $arch = "x86" if ($OsArch -eq "AMD64") { $arch = "x64" @@ -589,6 +595,21 @@ function Download-QemuGuestAgent { Execute-Retry { (New-Object System.Net.WebClient).DownloadFile($QemuGuestAgentUrl, $dst) } + + if ($Checksum) { + Write-Log "Verifying QEMU guest agent installer SHA256 checksum ..." + $expectedChecksum = $Checksum.Trim().ToUpper() + $actualChecksum = (Get-FileHash -Path $dst -Algorithm SHA256).Hash.ToUpper() + if ($actualChecksum -ne $expectedChecksum) { + throw ("QEMU guest agent checksum verification failed. " + ` + "Expected: ${expectedChecksum}, got: ${actualChecksum}") + } + Write-Log "QEMU guest agent installer checksum verified successfully." + } elseif ($CustomUrl) { + Write-Log ("WARNING: a custom QEMU guest agent URL was provided without a checksum; " + ` + "the installer integrity will not be verified.") + } + Write-Log "QEMU guest agent installer path is: $dst" } @@ -1713,7 +1734,8 @@ function New-WindowsCloudImage { } if ($windowsImageConfig.install_qemu_ga -and $windowsImageConfig.install_qemu_ga -ne 'False') { Download-QemuGuestAgent -QemuGuestAgentConfig $windowsImageConfig.install_qemu_ga ` - -ResourcesDir $resourcesDir -OsArch ([string]$image.ImageArchitecture) + -ResourcesDir $resourcesDir -OsArch ([string]$image.ImageArchitecture) ` + -CustomUrl $windowsImageConfig.url -Checksum $windowsImageConfig.checksum } Download-CloudbaseInit -resourcesDir $resourcesDir -osArch ([string]$image.ImageArchitecture) ` -BetaRelease:$windowsImageConfig.beta_release -MsiPath $windowsImageConfig.msi_path ` @@ -1894,7 +1916,8 @@ function New-WindowsFromGoldenImage { } if ($windowsImageConfig.install_qemu_ga -and $windowsImageConfig.install_qemu_ga -ne 'False') { Download-QemuGuestAgent -QemuGuestAgentConfig $windowsImageConfig.install_qemu_ga ` - -ResourcesDir $resourcesDir -OsArch $imageInfo.imageArchitecture + -ResourcesDir $resourcesDir -OsArch $imageInfo.imageArchitecture ` + -CustomUrl $windowsImageConfig.url -Checksum $windowsImageConfig.checksum } Download-CloudbaseInit -resourcesDir $resourcesDir -osArch $imageInfo.imageArchitecture ` -BetaRelease:$windowsImageConfig.beta_release -MsiPath $windowsImageConfig.msi_path `