2022-12-23 19:37:05 +00:00
|
|
|
{ config, lib, pkgs, ... }:
|
2022-12-20 00:07:02 +00:00
|
|
|
|
|
|
|
let
|
|
|
|
keysDirectory = "/var/keys";
|
|
|
|
|
|
|
|
user = "builder";
|
|
|
|
|
|
|
|
keyType = "ed25519";
|
|
|
|
|
|
|
|
in
|
|
|
|
|
|
|
|
{ imports = [
|
|
|
|
../virtualisation/qemu-vm.nix
|
|
|
|
];
|
|
|
|
|
|
|
|
# The builder is not intended to be used interactively
|
|
|
|
documentation.enable = false;
|
|
|
|
|
|
|
|
environment.etc = {
|
|
|
|
"ssh/ssh_host_ed25519_key" = {
|
|
|
|
mode = "0600";
|
|
|
|
|
|
|
|
source = ./keys/ssh_host_ed25519_key;
|
|
|
|
};
|
|
|
|
|
|
|
|
"ssh/ssh_host_ed25519_key.pub" = {
|
|
|
|
mode = "0644";
|
|
|
|
|
|
|
|
source = ./keys/ssh_host_ed25519_key.pub;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
# DNS fails for QEMU user networking (SLiRP) on macOS. See:
|
|
|
|
#
|
|
|
|
# https://github.com/utmapp/UTM/issues/2353
|
|
|
|
#
|
|
|
|
# This works around that by using a public DNS server other than the DNS
|
|
|
|
# server that QEMU provides (normally 10.0.2.3)
|
|
|
|
networking.nameservers = [ "8.8.8.8" ];
|
|
|
|
|
|
|
|
nix.settings = {
|
|
|
|
auto-optimise-store = true;
|
|
|
|
|
|
|
|
min-free = 1024 * 1024 * 1024;
|
|
|
|
|
|
|
|
max-free = 3 * 1024 * 1024 * 1024;
|
|
|
|
|
|
|
|
trusted-users = [ "root" user ];
|
|
|
|
};
|
|
|
|
|
|
|
|
services.openssh = {
|
|
|
|
enable = true;
|
|
|
|
|
|
|
|
authorizedKeysFiles = [ "${keysDirectory}/%u_${keyType}.pub" ];
|
|
|
|
};
|
|
|
|
|
|
|
|
system.build.macos-builder-installer =
|
|
|
|
let
|
|
|
|
privateKey = "/etc/nix/${user}_${keyType}";
|
|
|
|
|
|
|
|
publicKey = "${privateKey}.pub";
|
|
|
|
|
|
|
|
# This installCredentials script is written so that it's as easy as
|
|
|
|
# possible for a user to audit before confirming the `sudo`
|
2022-12-24 14:47:59 +00:00
|
|
|
installCredentials = hostPkgs.writeShellScript "install-credentials" ''
|
2022-12-20 00:07:02 +00:00
|
|
|
KEYS="''${1}"
|
|
|
|
INSTALL=${hostPkgs.coreutils}/bin/install
|
|
|
|
"''${INSTALL}" -g nixbld -m 600 "''${KEYS}/${user}_${keyType}" ${privateKey}
|
|
|
|
"''${INSTALL}" -g nixbld -m 644 "''${KEYS}/${user}_${keyType}.pub" ${publicKey}
|
|
|
|
'';
|
|
|
|
|
|
|
|
hostPkgs = config.virtualisation.host.pkgs;
|
|
|
|
|
2022-12-23 19:37:05 +00:00
|
|
|
script = hostPkgs.writeShellScriptBin "create-builder" ''
|
2022-12-20 00:07:02 +00:00
|
|
|
KEYS="''${KEYS:-./keys}"
|
|
|
|
${hostPkgs.coreutils}/bin/mkdir --parent "''${KEYS}"
|
|
|
|
PRIVATE_KEY="''${KEYS}/${user}_${keyType}"
|
|
|
|
PUBLIC_KEY="''${PRIVATE_KEY}.pub"
|
|
|
|
if [ ! -e "''${PRIVATE_KEY}" ] || [ ! -e "''${PUBLIC_KEY}" ]; then
|
|
|
|
${hostPkgs.coreutils}/bin/rm --force -- "''${PRIVATE_KEY}" "''${PUBLIC_KEY}"
|
|
|
|
${hostPkgs.openssh}/bin/ssh-keygen -q -f "''${PRIVATE_KEY}" -t ${keyType} -N "" -C 'builder@localhost'
|
|
|
|
fi
|
|
|
|
if ! ${hostPkgs.diffutils}/bin/cmp "''${PUBLIC_KEY}" ${publicKey}; then
|
|
|
|
(set -x; sudo --reset-timestamp ${installCredentials} "''${KEYS}")
|
|
|
|
fi
|
|
|
|
KEYS="$(nix-store --add "$KEYS")" ${config.system.build.vm}/bin/run-nixos-vm
|
|
|
|
'';
|
|
|
|
|
2022-12-23 19:37:05 +00:00
|
|
|
in
|
|
|
|
script.overrideAttrs (old: {
|
|
|
|
meta = (old.meta or { }) // {
|
|
|
|
platforms = lib.platforms.darwin;
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
2022-12-20 00:07:02 +00:00
|
|
|
system.stateVersion = "22.05";
|
|
|
|
|
|
|
|
users.users."${user}"= {
|
|
|
|
isNormalUser = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
virtualisation = {
|
|
|
|
diskSize = 20 * 1024;
|
|
|
|
|
|
|
|
memorySize = 3 * 1024;
|
|
|
|
|
|
|
|
forwardPorts = [
|
|
|
|
{ from = "host"; guest.port = 22; host.port = 22; }
|
|
|
|
];
|
|
|
|
|
|
|
|
# Disable graphics for the builder since users will likely want to run it
|
|
|
|
# non-interactively in the background.
|
|
|
|
graphics = false;
|
|
|
|
|
|
|
|
sharedDirectories.keys = {
|
|
|
|
source = "\"$KEYS\"";
|
|
|
|
target = keysDirectory;
|
|
|
|
};
|
|
|
|
|
|
|
|
# If we don't enable this option then the host will fail to delegate builds
|
|
|
|
# to the guest, because:
|
|
|
|
#
|
|
|
|
# - The host will lock the path to build
|
|
|
|
# - The host will delegate the build to the guest
|
|
|
|
# - The guest will attempt to lock the same path and fail because
|
|
|
|
# the lockfile on the host is visible on the guest
|
|
|
|
#
|
|
|
|
# Snapshotting the host's /nix/store as an image isolates the guest VM's
|
|
|
|
# /nix/store from the host's /nix/store, preventing this problem.
|
|
|
|
useNixStoreImage = true;
|
|
|
|
|
|
|
|
# Obviously the /nix/store needs to be writable on the guest in order for it
|
|
|
|
# to perform builds.
|
|
|
|
writableStore = true;
|
|
|
|
|
|
|
|
# This ensures that anything built on the guest isn't lost when the guest is
|
|
|
|
# restarted.
|
|
|
|
writableStoreUseTmpfs = false;
|
|
|
|
};
|
|
|
|
}
|