forked from M-Labs/wfvm
Compare commits
14 Commits
c0d09940d7
...
110fe11f00
Author | SHA1 | Date | |
---|---|---|---|
110fe11f00 | |||
07813c3c4f | |||
54d9f41a6d | |||
ec54c9bf9b | |||
4771cee64b | |||
78c9363b64 | |||
9f8a1b6e17 | |||
f1b52c0da7 | |||
0becb115f6 | |||
84ef1ec7e5 | |||
1357f493bd | |||
e8232ab89a | |||
90cc7b14a4 | |||
fbd5b97d79 |
@ -13,7 +13,9 @@
|
||||
, timeZone ? "UTC"
|
||||
, services ? {}
|
||||
, impureShellCommands ? []
|
||||
, driveLetter ? "E:"
|
||||
, driveLetter ? "D:"
|
||||
, efi ? true
|
||||
, imageSelection ? "Windows 10 Pro"
|
||||
, ...
|
||||
}:
|
||||
|
||||
@ -48,12 +50,8 @@ let
|
||||
# mkDirsDesc ++ writeKeysDesc ++
|
||||
[
|
||||
{
|
||||
Path = ''powershell.exe Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 -Source ${driveLetter}\fod -LimitAccess'';
|
||||
Description = "Add OpenSSH service.";
|
||||
}
|
||||
{
|
||||
Path = ''powershell.exe Set-Service -Name sshd -StartupType Automatic'';
|
||||
Description = "Enable SSH by default.";
|
||||
Path = ''powershell.exe ${driveLetter}\install-ssh.ps1'';
|
||||
Description = "Install OpenSSH service.";
|
||||
}
|
||||
];
|
||||
|
||||
@ -75,7 +73,7 @@ let
|
||||
++ setupCommands
|
||||
++ [
|
||||
{
|
||||
Path = ''powershell.exe ${driveLetter}\ssh-setup.ps1'';
|
||||
Path = ''powershell.exe ${driveLetter}\setup.ps1'';
|
||||
Description = "Setup SSH and keys";
|
||||
}
|
||||
]
|
||||
@ -123,6 +121,9 @@ let
|
||||
# Windows expects a flat list of users while we want to manage them as a set
|
||||
flatUsers = builtins.attrValues (builtins.mapAttrs (name: s: s // { inherit name; }) users);
|
||||
|
||||
diskId =
|
||||
if efi then 2 else 1;
|
||||
|
||||
autounattendXML = pkgs.writeText "autounattend.xml" ''
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
||||
@ -135,6 +136,15 @@ let
|
||||
<PathAndCredentials wcm:action="add" wcm:keyValue="2">
|
||||
<Path>E:\</Path>
|
||||
</PathAndCredentials>
|
||||
<PathAndCredentials wcm:action="add" wcm:keyValue="3">
|
||||
<Path>C:\virtio\amd64\w10</Path>
|
||||
</PathAndCredentials>
|
||||
<PathAndCredentials wcm:action="add" wcm:keyValue="4">
|
||||
<Path>C:\virtio\NetKVM\w10\amd64</Path>
|
||||
</PathAndCredentials>
|
||||
<PathAndCredentials wcm:action="add" wcm:keyValue="5">
|
||||
<Path>C:\virtio\qxldod\w10\amd64</Path>
|
||||
</PathAndCredentials>
|
||||
</DriverPaths>
|
||||
</component>
|
||||
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
@ -144,12 +154,12 @@ let
|
||||
<CreatePartitions>
|
||||
<CreatePartition wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<Type>EFI</Type>
|
||||
<Size>100</Size>
|
||||
<Type>${if efi then "EFI" else "Primary"}</Type>
|
||||
<Size>300</Size>
|
||||
</CreatePartition>
|
||||
<CreatePartition wcm:action="add">
|
||||
<Order>2</Order>
|
||||
<Type>MSR</Type>
|
||||
<Type>${if efi then "MSR" else "Primary"}</Type>
|
||||
<Size>16</Size>
|
||||
</CreatePartition>
|
||||
<CreatePartition wcm:action="add">
|
||||
@ -161,7 +171,7 @@ let
|
||||
<ModifyPartitions>
|
||||
<ModifyPartition wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<Format>FAT32</Format>
|
||||
<Format>${if efi then "FAT32" else "NTFS"}</Format>
|
||||
<Label>System</Label>
|
||||
<PartitionID>1</PartitionID>
|
||||
</ModifyPartition>
|
||||
@ -177,7 +187,7 @@ let
|
||||
<PartitionID>3</PartitionID>
|
||||
</ModifyPartition>
|
||||
</ModifyPartitions>
|
||||
<DiskID>0</DiskID>
|
||||
<DiskID>${toString diskId}</DiskID>
|
||||
<WillWipeDisk>true</WillWipeDisk>
|
||||
</Disk>
|
||||
</DiskConfiguration>
|
||||
@ -185,13 +195,13 @@ let
|
||||
<ImageInstall>
|
||||
<OSImage>
|
||||
<InstallTo>
|
||||
<DiskID>0</DiskID>
|
||||
<DiskID>${toString diskId}</DiskID>
|
||||
<PartitionID>3</PartitionID>
|
||||
</InstallTo>
|
||||
<InstallFrom>
|
||||
<MetaData wcm:action="add">
|
||||
<Key>/IMAGE/INDEX</Key>
|
||||
<Value>1</Value>
|
||||
<Key>/IMAGE/NAME</Key>
|
||||
<Value>${imageSelection}</Value>
|
||||
</MetaData>
|
||||
</InstallFrom>
|
||||
</OSImage>
|
||||
@ -262,14 +272,12 @@ let
|
||||
</AutoLogon>
|
||||
''}
|
||||
|
||||
<FirstLogonCommands>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<CommandLine>cmd /C shutdown /s /f /t 00</CommandLine>
|
||||
<Description>ChangeHideFiles</Description>
|
||||
</SynchronousCommand>
|
||||
</FirstLogonCommands>
|
||||
|
||||
</component>
|
||||
<component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Reseal>
|
||||
<ForceShutdownNow>true</ForceShutdownNow>
|
||||
<Mode>OOBE</Mode>
|
||||
</Reseal>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
@ -291,7 +299,7 @@ let
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
<cpi:offlineImage cpi:source="wim:c:/wim/windows-10/install.wim#Windows 10 Enterprise LTSC 2019 Evaluation" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
|
||||
<cpi:offlineImage cpi:source="wim:c:/wim/windows-10/install.wim#${imageSelection}" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
|
||||
</unattend>
|
||||
'';
|
||||
|
||||
@ -302,7 +310,7 @@ in {
|
||||
'';
|
||||
|
||||
# autounattend.xml is _super_ picky about quotes and other things
|
||||
setupScript = pkgs.writeText "ssh-setup.ps1" (
|
||||
setupScript = pkgs.writeText "setup.ps1" (
|
||||
''
|
||||
# Setup SSH and keys
|
||||
'' +
|
||||
|
@ -37,7 +37,17 @@ wfvm.makeWindowsImage {
|
||||
# administratorPassword = "12345";
|
||||
|
||||
# Imperative installation commands, to be installed incrementally
|
||||
installCommands = with wfvm.layers; [ anaconda3 msys2 msvc msvc-ide-unbreak ];
|
||||
installCommands =
|
||||
if impureMode
|
||||
then []
|
||||
else with wfvm.layers; [
|
||||
(collapseLayers [
|
||||
disable-autosleep
|
||||
disable-autolock
|
||||
disable-firewall
|
||||
])
|
||||
anaconda3 msys2 msvc msvc-ide-unbreak
|
||||
];
|
||||
|
||||
# services = {
|
||||
# # Enable remote management
|
||||
|
42
wfvm/install-ssh.ps1
Normal file
42
wfvm/install-ssh.ps1
Normal file
@ -0,0 +1,42 @@
|
||||
Write-Host "Expanding OpenSSH"
|
||||
Expand-Archive D:\OpenSSH-Win64.zip C:\
|
||||
|
||||
Push-Location C:\OpenSSH-Win64
|
||||
|
||||
Write-Host "Installing OpenSSH"
|
||||
& .\install-sshd.ps1
|
||||
|
||||
Write-Host "Generating host keys"
|
||||
.\ssh-keygen.exe -A
|
||||
|
||||
Write-Host "Fixing host file permissions"
|
||||
& .\FixHostFilePermissions.ps1 -Confirm:$false
|
||||
|
||||
Write-Host "Fixing user file permissions"
|
||||
& .\FixUserFilePermissions.ps1 -Confirm:$false
|
||||
|
||||
Pop-Location
|
||||
|
||||
$newPath = 'C:\OpenSSH-Win64;' + [Environment]::GetEnvironmentVariable("PATH", [EnvironmentVariableTarget]::Machine)
|
||||
[Environment]::SetEnvironmentVariable("PATH", $newPath, [EnvironmentVariableTarget]::Machine)
|
||||
|
||||
#Write-Host "Adding public key to authorized_keys"
|
||||
#$keyPath = "~\.ssh\authorized_keys"
|
||||
#New-Item -Type Directory ~\.ssh > $null
|
||||
#$sshKey | Out-File $keyPath -Encoding Ascii
|
||||
|
||||
Write-Host "Opening firewall port 22"
|
||||
New-NetFirewallRule -Protocol TCP -LocalPort 22 -Direction Inbound -Action Allow -DisplayName SSH
|
||||
|
||||
Write-Host "Setting sshd service startup type to 'Automatic'"
|
||||
Set-Service sshd -StartupType Automatic
|
||||
Set-Service ssh-agent -StartupType Automatic
|
||||
Write-Host "Setting sshd service restart behavior"
|
||||
sc.exe failure sshd reset= 86400 actions= restart/500
|
||||
|
||||
#Write-Host "Configuring sshd"
|
||||
#(Get-Content C:\ProgramData\ssh\sshd_config).replace('#TCPKeepAlive yes', 'TCPKeepAlive yes').replace('#ClientAliveInterval 0', 'ClientAliveInterval 300').replace('#ClientAliveCountMax 3', 'ClientAliveCountMax 3') | Set-Content C:\ProgramData\ssh\sshd_config
|
||||
|
||||
Write-Host "Starting sshd service"
|
||||
Start-Service sshd
|
||||
Start-Service ssh-agent
|
@ -122,4 +122,47 @@ in
|
||||
sleep 40
|
||||
'';
|
||||
};
|
||||
# Disable the Windows firewall
|
||||
disable-firewall = {
|
||||
name = "disable-firewall";
|
||||
script = ''
|
||||
echo Disabling firewall
|
||||
win-exec "netsh advfirewall set allprofiles state off"
|
||||
'';
|
||||
};
|
||||
# Disable automatic power management which causes the machine to go
|
||||
# into standby after periods without mouse wiggling.
|
||||
disable-autosleep = {
|
||||
name = "disable-autosleep";
|
||||
script = ''
|
||||
echo Disabling autosleep
|
||||
win-exec "powercfg /x -hibernate-timeout-ac 0"
|
||||
win-exec "powercfg /x -hibernate-timeout-dc 0"
|
||||
win-exec "powercfg /x -disk-timeout-ac 0"
|
||||
win-exec "powercfg /x -disk-timeout-dc 0"
|
||||
win-exec "powercfg /x -monitor-timeout-ac 0"
|
||||
win-exec "powercfg /x -monitor-timeout-dc 0"
|
||||
win-exec "powercfg /x -standby-timeout-ac 0"
|
||||
win-exec "powercfg /x -standby-timeout-dc 0"
|
||||
'';
|
||||
};
|
||||
# Turn off automatic locking of idle user sessions
|
||||
disable-autolock = {
|
||||
name = "disable-autolock";
|
||||
script = ''
|
||||
echo Disabling autolock
|
||||
win-exec "reg add HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Personalization /v NoLockScreen /t REG_DWORD /d 1"
|
||||
'';
|
||||
};
|
||||
|
||||
# Chain together layers that are quick to run so that the VM does
|
||||
# not have to be started/shutdown for each.
|
||||
collapseLayers = scripts: {
|
||||
name = pkgs.lib.concatMapStringsSep "-" ({ name, ... }: name) scripts;
|
||||
script = builtins.concatStringsSep "\n" (
|
||||
map ({ script, ... }: script) scripts
|
||||
);
|
||||
buildInputs =
|
||||
builtins.concatMap ({ buildInputs ? [], ... }: buildInputs) scripts;
|
||||
};
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
This file is not publicaly acessible anywhere so had to be extracted from a connected instance
|
Binary file not shown.
@ -1,4 +1,4 @@
|
||||
{ pkgs, baseRtc ? "2020-04-20T14:21:42", cores ? "4", qemuMem ? "4G" }:
|
||||
{ pkgs, baseRtc ? "2020-04-20T14:21:42", cores ? "4", qemuMem ? "4G", efi ? true }:
|
||||
|
||||
rec {
|
||||
# qemu_test is a smaller closure only building for a single system arch
|
||||
@ -9,10 +9,13 @@ rec {
|
||||
"-cpu host"
|
||||
"-smp ${cores}"
|
||||
"-m ${qemuMem}"
|
||||
"-bios ${pkgs.OVMF.fd}/FV/OVMF.fd"
|
||||
"-M q35"
|
||||
"-vga qxl"
|
||||
"-rtc base=${baseRtc}"
|
||||
"-device piix3-usb-uhci"
|
||||
"-device e1000,netdev=n1"
|
||||
"-device qemu-xhci"
|
||||
"-device virtio-net-pci,netdev=n1"
|
||||
] ++ pkgs.lib.optionals efi [
|
||||
"-bios ${pkgs.OVMF.fd}/FV/OVMF.fd"
|
||||
] ++ extraFlags;
|
||||
|
||||
# Pass empty config file to prevent ssh from failing to create ~/.ssh
|
||||
|
39
wfvm/win.nix
39
wfvm/win.nix
@ -5,12 +5,15 @@
|
||||
, impureMode ? false
|
||||
, installCommands ? []
|
||||
, users ? {}
|
||||
# autounattend always installs index 1, so this default is backward-compatible
|
||||
, imageSelection ? "Windows 10 Pro"
|
||||
, efi ? true
|
||||
, ...
|
||||
}@attrs:
|
||||
|
||||
let
|
||||
lib = pkgs.lib;
|
||||
utils = import ./utils.nix { inherit pkgs; };
|
||||
utils = import ./utils.nix { inherit pkgs efi; };
|
||||
libguestfs = pkgs.libguestfs-with-appliance;
|
||||
|
||||
# p7zip on >20.03 has known vulns but we have no better option
|
||||
@ -38,7 +41,16 @@ let
|
||||
sha256 = "668fe1af70c2f7416328aee3a0bb066b12dc6bbd2576f40f812b95741e18bc3a";
|
||||
};
|
||||
|
||||
openSshServerPackage = ./openssh/server-package.cab;
|
||||
# stable as of 2021-04-08
|
||||
virtioWinIso = pkgs.fetchurl {
|
||||
url = "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.185-2/virtio-win-0.1.185.iso";
|
||||
sha256 = "11n3kjyawiwacmi3jmfmn311g9xvfn6m0ccdwnjxw1brzb4kqaxg";
|
||||
};
|
||||
|
||||
openSshServerPackage = pkgs.fetchurl {
|
||||
url = "https://github.com/PowerShell/Win32-OpenSSH/releases/download/V8.6.0.0p1-Beta/OpenSSH-Win64.zip";
|
||||
sha256 = "1dw6n054r0939501dpxfm7ghv21ihmypdx034van8cl21gf1b4lz";
|
||||
};
|
||||
|
||||
autounattend = import ./autounattend.nix (
|
||||
attrs // {
|
||||
@ -60,15 +72,16 @@ let
|
||||
# Packages required to drive installation of other packages
|
||||
bootstrapPkgs =
|
||||
runQemuCommand "bootstrap-win-pkgs.img" ''
|
||||
mkdir -p pkgs/fod
|
||||
7z x -y ${virtioWinIso} -opkgs/virtio
|
||||
|
||||
cp ${bundleInstaller} pkgs/"$(stripHash "${bundleInstaller}")"
|
||||
|
||||
# Install optional windows features
|
||||
cp ${openSshServerPackage} pkgs/fod/OpenSSH-Server-Package~31bf3856ad364e35~amd64~~.cab
|
||||
cp ${openSshServerPackage} pkgs/OpenSSH-Win64.zip
|
||||
|
||||
# SSH setup script goes here because windows XML parser sucks
|
||||
cp ${autounattend.setupScript} pkgs/ssh-setup.ps1
|
||||
cp ${./install-ssh.ps1} pkgs/install-ssh.ps1
|
||||
cp ${autounattend.setupScript} pkgs/setup.ps1
|
||||
|
||||
virt-make-fs --partition --type=fat pkgs/ $out
|
||||
'';
|
||||
@ -83,12 +96,12 @@ let
|
||||
"usb-storage,drive=virtio-win"
|
||||
# USB boot
|
||||
"-drive"
|
||||
"id=win-install,file=usbimage.img,if=none,format=raw,readonly=on"
|
||||
"id=win-install,file=${if efi then "usb" else "cd"}image.img,if=none,format=raw,readonly=on,media=${if efi then "disk" else "cdrom"}"
|
||||
"-device"
|
||||
"usb-storage,drive=win-install"
|
||||
# Output image
|
||||
"-drive"
|
||||
"file=c.img,index=0,media=disk,cache=unsafe"
|
||||
"file=c.img,index=0,media=disk,if=virtio,cache=unsafe"
|
||||
# Network
|
||||
"-netdev user,id=n1,net=192.168.1.0/24,restrict=on"
|
||||
]);
|
||||
@ -96,7 +109,7 @@ let
|
||||
''
|
||||
#!${pkgs.runtimeShell}
|
||||
set -euxo pipefail
|
||||
export PATH=${lib.makeBinPath [ p7zip utils.qemu libguestfs ]}:$PATH
|
||||
export PATH=${lib.makeBinPath [ p7zip utils.qemu libguestfs pkgs.wimlib ]}:$PATH
|
||||
|
||||
# Create a bootable "USB" image
|
||||
# Booting in USB mode circumvents the "press any key to boot from cdrom" prompt
|
||||
@ -106,9 +119,17 @@ let
|
||||
mkdir -p win/nix-win
|
||||
7z x -y ${windowsIso} -owin
|
||||
|
||||
# Split image so it fits in FAT32 partition
|
||||
wimsplit win/sources/install.wim win/sources/install.swm 4090
|
||||
rm win/sources/install.wim
|
||||
|
||||
cp ${autounattend.autounattendXML} win/autounattend.xml
|
||||
|
||||
${if efi then ''
|
||||
virt-make-fs --partition --type=fat win/ usbimage.img
|
||||
'' else ''
|
||||
${pkgs.cdrkit}/bin/mkisofs -iso-level 4 -l -R -udf -D -b boot/etfsboot.com -no-emul-boot -boot-load-size 8 -hide boot.catalog -eltorito-alt-boot -o cdimage.img win/
|
||||
''}
|
||||
rm -rf win
|
||||
|
||||
# Qemu requires files to be rw
|
||||
@ -131,7 +152,7 @@ let
|
||||
qemuParams = utils.mkQemuFlags (lib.optional (!impureMode) "-display none" ++ [
|
||||
# Output image
|
||||
"-drive"
|
||||
"file=c.img,index=0,media=disk,cache=unsafe"
|
||||
"file=c.img,index=0,media=disk,if=virtio,cache=unsafe"
|
||||
# Network - enable SSH forwarding
|
||||
"-netdev user,id=n1,net=192.168.1.0/24,restrict=on,hostfwd=tcp::2022-:22"
|
||||
]);
|
||||
|
Loading…
Reference in New Issue
Block a user