diff --git a/flake.lock b/flake.lock index d86135f54..ac23e475f 100644 --- a/flake.lock +++ b/flake.lock @@ -315,16 +315,17 @@ }, "impermanence": { "locked": { - "lastModified": 1727649413, - "narHash": "sha256-FA53of86DjFdeQzRDVtvgWF9o52rWK70VHGx0Y8fElQ=", + "lastModified": 1728049659, + "narHash": "sha256-lGtad92Y/TnqpXRlZ1syiEq5czpvblKmcypeqGPiVF4=", "owner": "nix-community", "repo": "impermanence", - "rev": "d0b38e550039a72aff896ee65b0918e975e6d48e", + "rev": "32b1094d28d5fbedcc85a403bc08c8877b396255", "type": "github" }, "original": { "owner": "nix-community", "repo": "impermanence", + "rev": "32b1094d28d5fbedcc85a403bc08c8877b396255", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 14b150def..9a469d1c6 100644 --- a/flake.nix +++ b/flake.nix @@ -139,7 +139,7 @@ }; impermanence = { - url = "github:nix-community/impermanence"; + url = "github:nix-community/impermanence/32b1094d28d5fbedcc85a403bc08c8877b396255"; }; givc = { diff --git a/modules/common/services/xdgopener.nix b/modules/common/services/xdgopener.nix index a7e7985d4..080096353 100644 --- a/modules/common/services/xdgopener.nix +++ b/modules/common/services/xdgopener.nix @@ -53,7 +53,7 @@ in serviceConfig = { # The user 'ghaf' is used here to access SSH keys for the scp command # This is required to copy files to the zathuravm - User = "ghaf"; + User = "${config.ghaf.users.accounts.user}"; ExecStart = "${ghaf-xdg-open}/bin/ghaf-xdg-open"; StandardInput = "socket"; StandardOutput = "journal"; diff --git a/modules/common/users/accounts.nix b/modules/common/users/accounts.nix index 3c337101f..cc7ce3dc5 100644 --- a/modules/common/users/accounts.nix +++ b/modules/common/users/accounts.nix @@ -20,7 +20,13 @@ in { #TODO Extend this to allow definition of multiple users options.ghaf.users.accounts = { - enable = mkEnableOption "Default account Setup"; + enable = mkOption { + default = true; + type = types.bool; + description = '' + Enable Ghaf user accounts. Defaults to true. + ''; + }; user = mkOption { default = "ghaf"; type = types.str; @@ -28,16 +34,16 @@ in The admin account with sudo rights. ''; }; - password = mkOption { + initialPassword = mkOption { default = "ghaf"; type = types.str; description = '' - Default password for the admin user. + Default password for the admin and login user accounts. ''; }; enableLoginUser = mkEnableOption "Enable login user setup for UI."; loginuser = mkOption { - default = "manuel"; + default = "user"; type = types.str; description = '' Default user account for UI. @@ -50,16 +56,40 @@ in Default UID for the login user. ''; }; + # TODO Remove proxy user with ssh functionality + enableProxyUser = mkEnableOption "Enable proxy for login user."; + proxyuser = mkOption { + default = "proxyuser"; + type = types.str; + description = '' + Default user account for dbus proxy functionality. + ''; + }; + proxyuserGroups = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + Extra groups for the proxy user. + ''; + }; }; config = mkIf cfg.enable { + + assertions = [ + { + assertion = !(cfg.enableLoginUser && cfg.enableProxyUser); + message = "You cannot enable both login and proxy users at the same time"; + } + ]; + users = { mutableUsers = cfg.enableLoginUser; users = { "${cfg.user}" = { isNormalUser = true; - inherit (cfg) password; + inherit (cfg) initialPassword; extraGroups = [ "wheel" @@ -73,11 +103,19 @@ in "${cfg.loginuser}" = { isNormalUser = true; uid = cfg.loginuid; - inherit (cfg) password; + inherit (cfg) initialPassword; extraGroups = [ "video" ]; }; + } + // optionalAttrs cfg.enableProxyUser { + "${cfg.proxyuser}" = { + isNormalUser = true; + createHome = false; + uid = cfg.loginuid; + extraGroups = cfg.proxyuserGroups; + }; }; groups = { @@ -91,11 +129,25 @@ in name = cfg.loginuser; members = [ cfg.loginuser ]; }; + } + // optionalAttrs cfg.enableProxyUser { + "${cfg.proxyuser}" = { + name = cfg.proxyuser; + members = [ cfg.proxyuser ]; + }; }; }; # to build ghaf as ghaf-user with caches nix.settings.trusted-users = mkIf config.ghaf.profiles.debug.enable [ cfg.user ]; - #services.userborn.enable = true; + + # Enable userborn + services.userborn = + { + enable = true; + } + // optionalAttrs cfg.enableLoginUser { + passwordFilesLocation = "/etc"; + }; }; } diff --git a/modules/givc/appvm.nix b/modules/givc/appvm.nix index 2274124de..7fdc109c2 100644 --- a/modules/givc/appvm.nix +++ b/modules/givc/appvm.nix @@ -44,7 +44,7 @@ in admin = config.ghaf.givc.adminConfig; }; - # Quick fix to allow linger (linger option in user def. currently doesn't work, e.g., bc mutable) - systemd.tmpfiles.rules = [ "f /var/lib/systemd/linger/${config.ghaf.users.accounts.user}" ]; + # Enable lingering + users.users.${config.ghaf.users.accounts.user}.linger = true; }; } diff --git a/modules/microvm/virtualization/microvm/adminvm.nix b/modules/microvm/virtualization/microvm/adminvm.nix index 32672ae2c..546ba5207 100644 --- a/modules/microvm/virtualization/microvm/adminvm.nix +++ b/modules/microvm/virtualization/microvm/adminvm.nix @@ -10,6 +10,7 @@ let adminvmBaseConfiguration = { imports = [ + inputs.impermanence.nixosModules.impermanence inputs.self.nixosModules.givc-adminvm (import ./common/vm-networking.nix { inherit @@ -20,6 +21,7 @@ let ; internalIP = 10; }) + ./common/storagevm.nix # We need to retrieve mac address and start log aggregator ../../../common/logging/hw-mac-retrieve.nix ../../../common/logging/logs-aggregator.nix @@ -27,7 +29,7 @@ let { lib, ... }: { ghaf = { - users.accounts.enable = lib.mkDefault configHost.ghaf.users.accounts.enable; + # Profiles profiles.debug.enable = lib.mkDefault configHost.ghaf.profiles.debug.enable; development = { # NOTE: SSH port also becomes accessible on the network interface @@ -36,6 +38,8 @@ let debug.tools.enable = lib.mkDefault configHost.ghaf.development.debug.tools.enable; nix-setup.enable = lib.mkDefault configHost.ghaf.development.nix-setup.enable; }; + + # System systemd = { enable = true; withName = "adminvm-systemd"; @@ -47,10 +51,15 @@ let withDebug = configHost.ghaf.profiles.debug.enable; withHardenedConfigs = true; }; - givc.adminvm.enable = true; - # Log aggregation configuration + # Storage + storagevm = { + enable = true; + name = "adminvm"; + }; + + # Services logging = { client.enable = isLoggingEnabled; listener = { diff --git a/modules/microvm/virtualization/microvm/appvm.nix b/modules/microvm/virtualization/microvm/appvm.nix index 4445d2e89..d79168418 100644 --- a/modules/microvm/virtualization/microvm/appvm.nix +++ b/modules/microvm/virtualization/microvm/appvm.nix @@ -60,14 +60,15 @@ let in { ghaf = { - users.accounts.enable = lib.mkDefault configHost.ghaf.users.accounts.enable; + # Profiles profiles.debug.enable = lib.mkDefault configHost.ghaf.profiles.debug.enable; - development = { ssh.daemon.enable = lib.mkDefault configHost.ghaf.development.ssh.daemon.enable; debug.tools.enable = lib.mkDefault configHost.ghaf.development.debug.tools.enable; nix-setup.enable = lib.mkDefault configHost.ghaf.development.nix-setup.enable; }; + + # Systemd systemd = { enable = true; withName = "appvm-systemd"; @@ -80,11 +81,7 @@ let withHardenedConfigs = true; }; - ghaf-audio = { - inherit (vm.ghafAudio) enable; - name = "${vm.name}"; - }; - + # Storage storagevm = { enable = true; name = "${vm.name}"; @@ -98,7 +95,11 @@ let ]; }; - # Logging client configuration + # Services + ghaf-audio = { + inherit (vm.ghafAudio) enable; + name = "${vm.name}"; + }; logging.client.enable = configHost.ghaf.logging.client.enable; logging.client.endpoint = configHost.ghaf.logging.client.endpoint; }; diff --git a/modules/microvm/virtualization/microvm/audiovm.nix b/modules/microvm/virtualization/microvm/audiovm.nix index f30e455ca..231990039 100644 --- a/modules/microvm/virtualization/microvm/audiovm.nix +++ b/modules/microvm/virtualization/microvm/audiovm.nix @@ -39,14 +39,23 @@ let imports = [ ../../../common ]; ghaf = { - users.accounts.enable = lib.mkDefault configHost.ghaf.users.accounts.enable; + # Profiles profiles.debug.enable = lib.mkDefault configHost.ghaf.profiles.debug.enable; - development = { ssh.daemon.enable = lib.mkDefault configHost.ghaf.development.ssh.daemon.enable; debug.tools.enable = lib.mkDefault configHost.ghaf.development.debug.tools.enable; nix-setup.enable = lib.mkDefault configHost.ghaf.development.nix-setup.enable; }; + users.accounts = { + enableProxyUser = true; + proxyuserGroups = [ + "audio" + "video" + "pipewire" + ]; + }; + + # System systemd = { enable = true; withName = "audiovm-systemd"; @@ -60,14 +69,18 @@ let withHardenedConfigs = true; }; givc.audiovm.enable = true; - services.audio.enable = true; - # Logging client configuration - logging.client.enable = configHost.ghaf.logging.client.enable; - logging.client.endpoint = configHost.ghaf.logging.client.endpoint; + + # Storage storagevm = { enable = true; name = "audiovm"; }; + + # Services + services.audio.enable = true; + # Logging client configuration + logging.client.enable = configHost.ghaf.logging.client.enable; + logging.client.endpoint = configHost.ghaf.logging.client.endpoint; }; environment = { @@ -78,17 +91,6 @@ let ] ++ lib.optional config.ghaf.development.debug.tools.enable pkgs.alsa-utils; }; - users.users."proxy-user-audio" = { - isNormalUser = true; - uid = config.ghaf.users.accounts.loginuid; - createHome = false; - extraGroups = [ - "audio" - "video" - "pipewire" - ]; - }; - time.timeZone = config.time.timeZone; system.stateVersion = lib.trivial.release; diff --git a/modules/microvm/virtualization/microvm/common/storagevm.nix b/modules/microvm/virtualization/microvm/common/storagevm.nix index aa431e23c..1df69d694 100644 --- a/modules/microvm/virtualization/microvm/common/storagevm.nix +++ b/modules/microvm/virtualization/microvm/common/storagevm.nix @@ -1,6 +1,10 @@ # Copyright 2022-2024 TII (SSRC) and the Ghaf contributors # SPDX-License-Identifier: Apache-2.0 -{ lib, config, ... }: +{ + lib, + config, + ... +}: let cfg = config.ghaf.storagevm; inherit (lib) @@ -8,11 +12,9 @@ let mkOption mkIf mkMerge - mkForce types optionals ; - mountPath = "/guestStorage"; in { options.ghaf.storagevm = { @@ -25,6 +27,14 @@ in type = types.str; }; + mountPath = mkOption { + description = '' + Mount path for the storage virtual machine. + ''; + type = types.str; + default = "/guestStorage"; + }; + directories = mkOption { # FIXME: Probably will lead to disgraceful error messages, as we # put typechecking on nix impermanence option. But other, @@ -70,7 +80,7 @@ in }; config = lib.mkIf cfg.enable { - fileSystems.${mountPath} = { + fileSystems.${cfg.mountPath} = { neededForBoot = true; options = [ "rw" @@ -79,7 +89,7 @@ in "noexec" ]; }; - virtualisation.fileSystems.${mountPath}.device = "/dev/vda"; + virtualisation.fileSystems.${cfg.mountPath}.device = "/dev/vda"; microvm.shares = [ { @@ -87,11 +97,11 @@ in proto = "virtiofs"; securityModel = "passthrough"; source = "/storagevm/${cfg.name}"; - mountPoint = mountPath; + mountPoint = cfg.mountPath; } ]; - environment.persistence.${mountPath} = lib.mkMerge [ + environment.persistence.${cfg.mountPath} = mkMerge [ { hideMounts = true; directories = @@ -99,11 +109,9 @@ in "/var/lib/nixos" ] ++ optionals config.ghaf.users.accounts.enableLoginUser [ - # TODO Replace with userborn setup "/etc" ]; - - files = [ + files = optionals (!config.ghaf.users.accounts.enableLoginUser) [ "/etc/ssh/ssh_host_ed25519_key.pub" "/etc/ssh/ssh_host_ed25519_key" ]; diff --git a/modules/microvm/virtualization/microvm/guivm.nix b/modules/microvm/virtualization/microvm/guivm.nix index 1b1ae856a..f567c0f48 100644 --- a/modules/microvm/virtualization/microvm/guivm.nix +++ b/modules/microvm/virtualization/microvm/guivm.nix @@ -33,25 +33,21 @@ let { lib, pkgs, ... }: { ghaf = { - users.accounts.enable = lib.mkDefault config.ghaf.users.accounts.enable; - users.accounts.enableLoginUser = true; + # Profiles profiles = { debug.enable = lib.mkDefault config.ghaf.profiles.debug.enable; applications.enable = false; graphics.enable = true; }; - - # To enable screen locking set to true - graphics.labwc = { - autolock.enable = lib.mkDefault config.ghaf.graphics.labwc.autolock.enable; - autologinUser = lib.mkDefault config.ghaf.graphics.labwc.autologinUser; - }; + users.accounts.enableLoginUser = true; development = { ssh.daemon.enable = lib.mkDefault config.ghaf.development.ssh.daemon.enable; debug.tools.enable = lib.mkDefault config.ghaf.development.debug.tools.enable; nix-setup.enable = lib.mkDefault config.ghaf.development.nix-setup.enable; }; + + # System systemd = { enable = true; withName = "guivm-systemd"; @@ -63,9 +59,8 @@ let withHardenedConfigs = true; }; givc.guivm.enable = true; - # Logging client configuration - logging.client.enable = config.ghaf.logging.client.enable; - logging.client.endpoint = config.ghaf.logging.client.endpoint; + + # Storage storagevm = { enable = true; name = "guivm"; @@ -77,6 +72,15 @@ let "Videos" ]; }; + + # Services + # To enable screen locking set to true + graphics.labwc = { + autolock.enable = lib.mkDefault config.ghaf.graphics.labwc.autolock.enable; + autologinUser = lib.mkDefault config.ghaf.graphics.labwc.autologinUser; + }; + logging.client.enable = config.ghaf.logging.client.enable; + logging.client.endpoint = config.ghaf.logging.client.endpoint; services.disks.enable = true; services.disks.fileManager = "${pkgs.pcmanfm}/bin/pcmanfm"; services.xdghandlers.enable = true; @@ -91,10 +95,10 @@ let echo -en "\n\n\n" | ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f /run/waypipe-ssh/id_ed25519 -C "" chown ${config.ghaf.users.accounts.user}:${config.ghaf.users.accounts.user} /run/waypipe-ssh/* cp /run/waypipe-ssh/id_ed25519.pub /run/waypipe-ssh-public-key/id_ed25519.pub - echo -en "\n\n\n" | ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f /run/user-ssh/id_ed25519_net -C "proxy-user-network@net-vm" + echo -en "\n\n\n" | ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f /run/user-ssh/id_ed25519_net -C "proxyuser@net-vm" chown ${config.ghaf.users.accounts.loginuser}:${config.ghaf.users.accounts.loginuser} /run/user-ssh/* cp /run/user-ssh/id_ed25519_net.pub /run/waypipe-ssh-public-key/id_ed25519_net.pub - echo -en "\n\n\n" | ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f /run/user-ssh/id_ed25519_ad -C "proxy-user-audio@audio-vm" + echo -en "\n\n\n" | ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f /run/user-ssh/id_ed25519_ad -C "proxyuser@audio-vm" chown ${config.ghaf.users.accounts.loginuser}:${config.ghaf.users.accounts.loginuser} /run/user-ssh/* cp /run/user-ssh/id_ed25519_ad.pub /run/waypipe-ssh-public-key/id_ed25519_ad.pub ''; diff --git a/modules/microvm/virtualization/microvm/microvm-host.nix b/modules/microvm/virtualization/microvm/microvm-host.nix index ab9fcd09b..b383bd696 100644 --- a/modules/microvm/virtualization/microvm/microvm-host.nix +++ b/modules/microvm/virtualization/microvm/microvm-host.nix @@ -44,23 +44,26 @@ in (mkIf cfg.enable { microvm.host.enable = true; microvm.host.useNotifySockets = true; - ghaf.systemd = { - withName = "host-systemd"; - enable = true; - withAudit = config.ghaf.profiles.debug.enable; - withPolkit = true; - withTpm2Tss = pkgs.stdenv.hostPlatform.isx86; - withRepart = true; - withFido2 = true; - withCryptsetup = true; - withTimesyncd = cfg.networkSupport; - withNss = cfg.networkSupport; - withResolved = cfg.networkSupport; - withSerial = config.ghaf.profiles.debug.enable; - withDebug = config.ghaf.profiles.debug.enable; - withHardenedConfigs = true; + ghaf = { + # System + systemd = { + withName = "host-systemd"; + enable = true; + withAudit = config.ghaf.profiles.debug.enable; + withPolkit = true; + withTpm2Tss = pkgs.stdenv.hostPlatform.isx86; + withRepart = true; + withFido2 = true; + withCryptsetup = true; + withTimesyncd = cfg.networkSupport; + withNss = cfg.networkSupport; + withResolved = cfg.networkSupport; + withSerial = config.ghaf.profiles.debug.enable; + withDebug = config.ghaf.profiles.debug.enable; + withHardenedConfigs = true; + }; + givc.host.enable = true; }; - ghaf.givc.host.enable = true; # TODO: remove hardcoded paths systemd.services."microvm@audio-vm".serviceConfig = diff --git a/modules/microvm/virtualization/microvm/netvm.nix b/modules/microvm/virtualization/microvm/netvm.nix index 410156134..2cf9fb30a 100644 --- a/modules/microvm/virtualization/microvm/netvm.nix +++ b/modules/microvm/virtualization/microvm/netvm.nix @@ -43,7 +43,7 @@ let imports = [ ../../../common ]; ghaf = { - users.accounts.enable = lib.mkDefault config.ghaf.users.accounts.enable; + # Profiles profiles.debug.enable = lib.mkDefault config.ghaf.profiles.debug.enable; development = { # NOTE: SSH port also becomes accessible on the network interface @@ -52,6 +52,14 @@ let debug.tools.enable = lib.mkDefault config.ghaf.development.debug.tools.enable; nix-setup.enable = lib.mkDefault config.ghaf.development.nix-setup.enable; }; + users.accounts = { + enableProxyUser = true; + proxyuserGroups = [ + "networkmanager" + ]; + }; + + # System systemd = { enable = true; withName = "netvm-systemd"; @@ -63,14 +71,19 @@ let withHardenedConfigs = true; }; givc.netvm.enable = true; - # Logging client configuration - logging.client.enable = config.ghaf.logging.client.enable; - logging.client.endpoint = config.ghaf.logging.client.endpoint; + + # Storage storagevm = { enable = true; name = "netvm"; directories = [ "/etc/NetworkManager/system-connections/" ]; }; + + # Services + # Logging client configuration + logging.client.enable = config.ghaf.logging.client.enable; + logging.client.endpoint = config.ghaf.logging.client.endpoint; + }; time.timeZone = config.time.timeZone; @@ -139,15 +152,6 @@ let ${config.ghaf.security.sshKeys.waypipeSshPublicKeyDir}.options = [ "ro" ]; }; - users.users."proxy-user-network" = { - isNormalUser = true; - createHome = false; - uid = config.ghaf.users.accounts.loginuid; - extraGroups = [ - "networkmanager" - ]; - }; - # SSH is very picky about to file permissions and ownership and will # accept neither direct path inside /nix/store or symlink that points # there. Therefore we copy the file to /etc/ssh/get-auth-keys (by diff --git a/packages/bt-launcher/default.nix b/packages/bt-launcher/default.nix index 706ece2b8..309a01139 100644 --- a/packages/bt-launcher/default.nix +++ b/packages/bt-launcher/default.nix @@ -17,7 +17,7 @@ writeShellApplication { export DBUS_SESSION_BUS_ADDRESS=unix:path=/tmp/ssh_session_dbus.sock export DBUS_SYSTEM_BUS_ADDRESS=unix:path=/tmp/ssh_system_dbus.sock ${openssh}/bin/ssh -M -S /tmp/control_socket_bt \ - -f -N -q proxy-user-audio@audio-vm \ + -f -N -q proxyuser@audio-vm \ -i /run/user-ssh/id_ed25519_ad \ -o StrictHostKeyChecking=no \ -o UserKnownHostsFile=/dev/null \ @@ -27,7 +27,7 @@ writeShellApplication { -L /tmp/ssh_system_dbus.sock:/run/dbus/system_bus_socket # Use the control socket to close the ssh tunnel. close-tunnel() { - ${openssh}/bin/ssh -q -S /tmp/control_socket_bt -O exit proxy-user-audio@audio-vm + ${openssh}/bin/ssh -q -S /tmp/control_socket_bt -O exit proxyuser@audio-vm } launch-blueman() { diff --git a/packages/nm-launcher/default.nix b/packages/nm-launcher/default.nix index d433b388f..2186739fb 100644 --- a/packages/nm-launcher/default.nix +++ b/packages/nm-launcher/default.nix @@ -19,7 +19,7 @@ writeShellApplication { # export DBUS_SESSION_BUS_ADDRESS=unix:path=/tmp/ssh_session_dbus.sock export DBUS_SYSTEM_BUS_ADDRESS=unix:path=/tmp/ssh_system_dbus.sock ${openssh}/bin/ssh -M -S /tmp/control_socket \ - -f -N -q proxy-user-network@net-vm \ + -f -N -q proxyuser@net-vm \ -i /run/user-ssh/id_ed25519_net \ -o StrictHostKeyChecking=no \ -o UserKnownHostsFile=/dev/null \ @@ -29,7 +29,7 @@ writeShellApplication { -L /tmp/ssh_system_dbus.sock:/run/dbus/system_bus_socket ${networkmanagerapplet}/bin/nm-applet --indicator # Use the control socket to close the ssh tunnel. - ${openssh}/bin/ssh -q -S /tmp/control_socket -O exit proxy-user-network@net-vm + ${openssh}/bin/ssh -q -S /tmp/control_socket -O exit proxyuser@net-vm ''; meta = {