about summary refs log tree commit diff
path: root/nixos/modules/virtualisation
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/virtualisation')
-rw-r--r--nixos/modules/virtualisation/lxc-container.nix23
-rw-r--r--nixos/modules/virtualisation/lxd.nix4
-rw-r--r--nixos/modules/virtualisation/nixos-containers.nix11
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix68
4 files changed, 91 insertions, 15 deletions
diff --git a/nixos/modules/virtualisation/lxc-container.nix b/nixos/modules/virtualisation/lxc-container.nix
index 25c253036ec8..61d7c4cb73fe 100644
--- a/nixos/modules/virtualisation/lxc-container.nix
+++ b/nixos/modules/virtualisation/lxc-container.nix
@@ -9,15 +9,16 @@ in {
 
   options = {
     virtualisation.lxc = {
-      privilegedContainer = lib.mkOption {
-        type = lib.types.bool;
-        default = false;
-        description = lib.mdDoc ''
-          Whether this LXC container will be running as a privileged container or not. If set to `true` then
-          additional configuration will be applied to the `systemd` instance running within the container as
-          recommended by [distrobuilder](https://linuxcontainers.org/distrobuilder/introduction/).
-        '';
-      };
+      nestedContainer = lib.mkEnableOption (lib.mdDoc ''
+        Whether this container is configured as a nested container. On LXD containers this is recommended
+        for all containers and is enabled with `security.nesting = true`.
+      '');
+
+      privilegedContainer = lib.mkEnableOption (lib.mdDoc ''
+        Whether this LXC container will be running as a privileged container or not. If set to `true` then
+        additional configuration will be applied to the `systemd` instance running within the container as
+        recommended by [distrobuilder](https://linuxcontainers.org/distrobuilder/introduction/).
+      '');
     };
   };
 
@@ -81,9 +82,11 @@ in {
 
     system.build.installBootLoader = pkgs.writeScript "install-lxd-sbin-init.sh" ''
       #!${pkgs.runtimeShell}
-      ln -fs "$1/init" /sbin/init
+      ${pkgs.coreutils}/bin/ln -fs "$1/init" /sbin/init
     '';
 
+    systemd.additionalUpstreamSystemUnits = lib.mkIf cfg.nestedContainer ["systemd-udev-trigger.service"];
+
     # Add the overrides from lxd distrobuilder
     # https://github.com/lxc/distrobuilder/blob/05978d0d5a72718154f1525c7d043e090ba7c3e0/distrobuilder/main.go#L630
     systemd.packages = [
diff --git a/nixos/modules/virtualisation/lxd.nix b/nixos/modules/virtualisation/lxd.nix
index e30fbebb662c..6f628c4a6e32 100644
--- a/nixos/modules/virtualisation/lxd.nix
+++ b/nixos/modules/virtualisation/lxd.nix
@@ -145,9 +145,7 @@ in {
       };
 
       ui = {
-        enable = lib.mkEnableOption (lib.mdDoc ''
-          Enables the (experimental) LXD UI.
-        '');
+        enable = lib.mkEnableOption (lib.mdDoc "(experimental) LXD UI");
 
         package = lib.mkPackageOption pkgs.lxd-unwrapped "ui" { };
       };
diff --git a/nixos/modules/virtualisation/nixos-containers.nix b/nixos/modules/virtualisation/nixos-containers.nix
index 5df9942dbc04..aa85665af695 100644
--- a/nixos/modules/virtualisation/nixos-containers.nix
+++ b/nixos/modules/virtualisation/nixos-containers.nix
@@ -649,6 +649,15 @@ in
               '';
             };
 
+            restartIfChanged = mkOption {
+              type = types.bool;
+              default = true;
+              description = lib.mdDoc ''
+                Whether the container should be restarted during a NixOS
+                configuration switch if its definition has changed.
+              '';
+            };
+
             timeoutStartSec = mkOption {
               type = types.str;
               default = "1min";
@@ -826,7 +835,7 @@ in
                 containerConfig.path
                 config.environment.etc."${configurationDirectoryName}/${name}.conf".source
               ];
-              restartIfChanged = true;
+              restartIfChanged = containerConfig.restartIfChanged;
             }
           )
       )) config.containers)
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index e0004df6f6b2..55d23b6fb8b5 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -198,6 +198,39 @@ let
         fi
       ''}
 
+      ${lib.optionalString cfg.tpm.enable ''
+        NIX_SWTPM_DIR=$(readlink -f "''${NIX_SWTPM_DIR:-${config.system.name}-swtpm}")
+        mkdir -p "$NIX_SWTPM_DIR"
+        ${lib.getExe cfg.tpm.package} \
+          socket \
+          --tpmstate dir="$NIX_SWTPM_DIR" \
+          --ctrl type=unixio,path="$NIX_SWTPM_DIR"/socket,terminate \
+          --pid file="$NIX_SWTPM_DIR"/pid --daemon \
+          --tpm2 \
+          --log file="$NIX_SWTPM_DIR"/stdout,level=6
+
+        # Enable `fdflags` builtin in Bash
+        # We will need it to perform surgical modification of the file descriptor
+        # passed in the coprocess to remove `FD_CLOEXEC`, i.e. close the file descriptor
+        # on exec.
+        # If let alone, it will trigger the coprocess to read EOF when QEMU is `exec`
+        # at the end of this script. To work around that, we will just clear
+        # the `FD_CLOEXEC` bits as a first step.
+        enable -f ${hostPkgs.bash}/lib/bash/fdflags fdflags
+        # leave a dangling subprocess because the swtpm ctrl socket has
+        # "terminate" when the last connection disconnects, it stops swtpm.
+        # When qemu stops, or if the main shell process ends, the coproc will
+        # get signaled by virtue of the pipe between main and coproc ending.
+        # Which in turns triggers a socat connect-disconnect to swtpm which
+        # will stop it.
+        coproc waitingswtpm {
+          read || :
+          echo "" | ${lib.getExe hostPkgs.socat} STDIO UNIX-CONNECT:"$NIX_SWTPM_DIR"/socket
+        }
+        # Clear `FD_CLOEXEC` on the coprocess' file descriptor stdin.
+        fdflags -s-cloexec ''${waitingswtpm[1]}
+      ''}
+
       cd "$TMPDIR"
 
       ${lib.optionalString (cfg.emptyDiskImages != []) "idx=0"}
@@ -267,6 +300,7 @@ let
   };
 
   storeImage = import ../../lib/make-disk-image.nix {
+    name = "nix-store-image";
     inherit pkgs config lib;
     additionalPaths = [ regInfo ];
     format = "qcow2";
@@ -862,6 +896,32 @@ in
       };
     };
 
+    virtualisation.tpm = {
+      enable = mkEnableOption "a TPM device in the virtual machine with a driver, using swtpm.";
+
+      package = mkPackageOptionMD cfg.host.pkgs "swtpm" { };
+
+      deviceModel = mkOption {
+        type = types.str;
+        default = ({
+          "i686-linux" = "tpm-tis";
+          "x86_64-linux" = "tpm-tis";
+          "ppc64-linux" = "tpm-spapr";
+          "armv7-linux" = "tpm-tis-device";
+          "aarch64-linux" = "tpm-tis-device";
+        }.${pkgs.hostPlatform.system} or (throw "Unsupported system for TPM2 emulation in QEMU"));
+        defaultText = ''
+          Based on the guest platform Linux system:
+
+          - `tpm-tis` for (i686, x86_64)
+          - `tpm-spapr` for ppc64
+          - `tpm-tis-device` for (armv7, aarch64)
+        '';
+        example = "tpm-tis-device";
+        description = lib.mdDoc "QEMU device model for the TPM, uses the appropriate default based on th guest platform system and the package passed.";
+      };
+    };
+
     virtualisation.useDefaultFilesystems =
       mkOption {
         type = types.bool;
@@ -1027,7 +1087,8 @@ in
 
     boot.initrd.availableKernelModules =
       optional cfg.writableStore "overlay"
-      ++ optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx";
+      ++ optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx"
+      ++ optional (cfg.tpm.enable) "tpm_tis";
 
     virtualisation.additionalPaths = [ config.system.build.toplevel ];
 
@@ -1098,6 +1159,11 @@ in
       (mkIf (!cfg.graphics) [
         "-nographic"
       ])
+      (mkIf (cfg.tpm.enable) [
+        "-chardev socket,id=chrtpm,path=\"$NIX_SWTPM_DIR\"/socket"
+        "-tpmdev emulator,id=tpm_dev_0,chardev=chrtpm"
+        "-device ${cfg.tpm.deviceModel},tpmdev=tpm_dev_0"
+      ])
     ];
 
     virtualisation.qemu.drives = mkMerge [