7.2 KiB
Generating Disk Images with Secrets Included using Disko
Using Disko on NixOS allows you to efficiently create .raw
disk images from a system configuration.
Follow the steps below to generate disk images:
Generating the .raw
Image
- Create a NixOS configuration that includes the disko and the disk configuration of your choice
In the this example we create a flake containing a nixos configuration for
myhost
.
# save this as flake.nix
{
description = "A disko images example";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
disko.url = "github:nix-community/disko/latest";
disko.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, disko, nixpkgs, ... }: {
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
# You can get this file from here: https://github.com/nix-community/disko/blob/master/example/simple-efi.nix
./simple-efi.nix
disko.nixosModules.disko
({ config, modulesPath, ... }: {
imports = [
# include this line to boot to boot the image inside a VM
# "${modulesPath}/profiles/qemu-guest.nix"
# On other hardware, you may need a hardware-configuration.nix as generated by nixos-generate-config or use nixos-facter (https://github.com/numtide/nixos-facter)
# ./hardware-configuration.nix
];
# Optional. Useful for testing
# users.users.root.initialPassword = "root";
boot.loader.grub.efiSupport = lib.mkDefault true;
boot.loader.grub.efiInstallAsRemovable = lib.mkDefault true;
# shut up state version warning
system.stateVersion = config.system.nixos.release;
# Adjust this to your liking.
# WARNING: if you set a too low value the image might be not big enough to contain the nixos installation
disko.devices.disk.main.imageSize = "10G";
})
];
};
};
}
-
Build the disko image script: Replace
myhost
in the command below with your specific system configuration name:nix build .#nixosConfigurations.myhost.config.system.build.diskoImagesScript
-
Execute the disko image script: Execute the generated disko image script. Running
./result --help
will output the available options:./result --help Usage: $script [options] Options: * --pre-format-files <src> <dst> copies the src to the dst on the VM, before disko is run This is useful to provide secrets like LUKS keys, or other files you need for formatting * --post-format-files <src> <dst> copies the src to the dst on the finished image These end up in the images later and is useful if you want to add some extra stateful files They will have the same permissions but will be owned by root:root * --build-memory <amt> specify the amount of memory in MiB that gets allocated to the build VM This can be useful if you want to build images with a more involed NixOS config The default is 1024 MiB
An example run may look like this:
sudo ./result --build-memory 2048
The script will generate the actual image outside of the nix store in the current working directory. The create image names depend on the names used in
disko.devices.disk
attrset in the NixOS configuration. In our code example it will produce the following image:$ ls -la main.raw .rw-r--r-- root root 10 GB 2 minutes ago main.raw
Additional Configuration
-
For custom image name output, define the image name in your Disko configuration:
disko.devices.disk.<drive>.imageName = "nixos-x86_64-linux-generic-btrfs"; # Set your preferred name
The image scirpt will produce
nixos-x86_64-linux-generic-btrfs.raw
instead of<drive>.raw
. -
For virtual drive use, define the image size in your Disko configuration:
disko.devices.disk.<drive>.imageSize = "32G"; # Set your preferred size
-
To build an image for another target platform, enable binfmt emulation support.
disko.imageBuilder.enableBinfmt = true;
This requires a working binfmt setup for your target platform on your build machine. Setup instructions are available for NixOS and other distros (Arch Linux, Debian).
The relevant configuration for building
aarch64-linux
images on ax86_64-linux
host looks like this:disko = { imageBuilder = { enableBinfmt = true; pkgs = inputs.nixpkgs.legacyPackages.x86_64-linux; kernelPackages = inputs.nixpkgs.legacyPackages.x86_64-linux.linuxPackages_latest; }; nixpkgs.hostPlatform = "aarch64-linux";
Understanding the Image Generation Process
- Files specified in
--pre-format-files
and--post-format-files
are temporarily copied to/tmp
. - Files are then moved to their respective locations in the VM both before and after the Disko partitioning script runs.
- The NixOS installer is executed, having access only to
--post-format-files
. - Upon installer completion, the VM is shutdown, and the
.raw
disk files are moved to the local directory.
Note
: The auto-resizing feature is currently not available in Disko. Contributions for this feature are welcomed. Adjust the
imageSize
configuration to prevent issues related to file size and padding.
By following these instructions and understanding the process, you can smoothly generate disk images with Disko for your NixOS system configurations.
Test the image inside a VM
Make sure you uncommented the "${modulesPath}/profiles/qemu-guest.nix"
import in the example above!
Write the following script to qemu.nix
. Note that it expects an UEFI compatible image!
with import <nixpkgs> {};
writeShellApplication {
name = "test-image";
runtimeInputs = [ qemu ];
text = ''
if [ -z "$1" ]; then
echo "Usage: $0 <path-to-boot-image>"
exit 1
fi
tmpFile=$(mktemp /tmp/test-image.XXXXXX)
trap 'rm -f $tmpFile' EXIT
cp "$1" "$tmpFile"
qemu-system-x86_64 \
-enable-kvm \
-m 2G \
-cpu max \
-smp 2 \
-netdev user,id=net0,hostfwd=tcp::2222-:22 \
-device virtio-net-pci,netdev=net0 \
-drive if=pflash,format=raw,readonly=on,file=${OVMF.firmware} \
-drive if=pflash,format=raw,readonly=on,file=${OVMF.variables} \
-drive "if=virtio,format=raw,file=$tmpFile"
'';
}
This command will run a qemu vm with your image:
$(nix-build ./qemu.nix)/bin/test-image ./main.raw
Replace main.raw
with the image that you build!
Tip: You can customize memory (-m
flag) or cpu (-smp
flag) available to the VM to your liking.
Build the image inside the nix sandbox
Instead of the diskoImagesScript, we can also build the image inside the nix store. This approach is slower because it requires copying the image after the build and we also don't have a secure way to embed secrets this way.
nix build .#nixosConfigurations.myhost.config.system.build.diskoImages
ls -a ./result/main.raw