Skip to content

Commit

Permalink
WIP:
Browse files Browse the repository at this point in the history
- removes userborn for gui-vm, allowing name change would require
  significant changes. "/etc" persisted without restrictions atm.
  password change alone works fine with userborn
- userborn enabled for all vms except gui

- USERS: admin (ghaf) user, proxy user (audio/net vms), app user (app vms),
  and loginuser (guivm)
- proxy/app users allow unprivileged application/service

- Login user name and password can be set at first (gui-vm) boot
- Additional script required to adjust home (impermanence name
  'hardcoded' in nix store)
- Password can be changed anytime using passwd
- Name can be changed by admin/root removing the lock file

Signed-off-by: Manuel Bluhm <[email protected]>
  • Loading branch information
mbssrc committed Oct 22, 2024
1 parent b54e20c commit 41acb1a
Show file tree
Hide file tree
Showing 16 changed files with 330 additions and 108 deletions.
7 changes: 4 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
};

impermanence = {
url = "github:nix-community/impermanence";
url = "github:nix-community/impermanence/32b1094d28d5fbedcc85a403bc08c8877b396255";
};

givc = {
Expand Down
2 changes: 1 addition & 1 deletion modules/common/services/xdgopener.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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.admin}";
ExecStart = "${ghaf-xdg-open}/bin/ghaf-xdg-open";
StandardInput = "socket";
StandardOutput = "journal";
Expand Down
215 changes: 202 additions & 13 deletions modules/common/users/accounts.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
{
config,
lib,
pkgs,
...
}:
# account for the development time login with sudo rights
Expand All @@ -20,24 +21,30 @@ in
{
#TODO Extend this to allow definition of multiple users
options.ghaf.users.accounts = {
enable = mkEnableOption "Default account Setup";
user = mkOption {
enable = mkOption {
default = true;
type = types.bool;
description = ''
Enable Ghaf user accounts. Defaults to true.
'';
};
admin = mkOption {
default = "ghaf";
type = types.str;
description = ''
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.
Expand All @@ -50,16 +57,63 @@ 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.
'';
};
enableAppUser = mkEnableOption "Enable app for user to run applications.";
appuser = mkOption {
default = "appuser";
type = types.str;
description = ''
Default user account to run applications.
'';
};
appuserGroups = mkOption {
default = [ ];
type = types.listOf types.str;
description = ''
Extra groups for the app user.
'';
};
};

config = mkIf cfg.enable {

assertions = [
{
assertion = !(cfg.enableLoginUser && cfg.enableProxyUser);
message = "You cannot enable both login and proxy users at the same time";
}
{
assertion = !(cfg.enableLoginUser && cfg.enableAppUser);
message = "You cannot enable both login and app users at the same time";
}
{
assertion = !(cfg.enableAppUser && cfg.enableProxyUser);
message = "You cannot enable both app and proxy users at the same time";
}
];

users = {
mutableUsers = cfg.enableLoginUser;
users =
{
"${cfg.user}" = {
"${cfg.admin}" = {
isNormalUser = true;
inherit (cfg) password;
inherit (cfg) initialPassword;
extraGroups =
[
"wheel"
Expand All @@ -73,29 +127,164 @@ 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;
};
}
// optionalAttrs cfg.enableAppUser {
"${cfg.appuser}" = {
isNormalUser = true;
createHome = true;
uid = cfg.loginuid;
extraGroups = cfg.appuserGroups;
};
};
groups =
{
"${cfg.user}" = {
name = cfg.user;
members = [ cfg.user ];
"${cfg.admin}" = {
name = cfg.admin;
members = [ cfg.admin ];
};
}
// optionalAttrs cfg.enableLoginUser {
"${cfg.loginuser}" = {
name = cfg.loginuser;
members = [ cfg.loginuser ];
};
}
// optionalAttrs cfg.enableProxyUser {
"${cfg.proxyuser}" = {
name = cfg.proxyuser;
members = [ cfg.proxyuser ];
};
}
// optionalAttrs cfg.enableAppUser {
"${cfg.appuser}" = {
name = cfg.appuser;
members = [ cfg.appuser ];
};
};
};

# to build ghaf as ghaf-user with caches
nix.settings.trusted-users = mkIf config.ghaf.profiles.debug.enable [ cfg.user ];
#services.userborn.enable = true;
nix.settings.trusted-users = mkIf config.ghaf.profiles.debug.enable [ cfg.admin ];

# Enable userborn
services.userborn = optionalAttrs (!cfg.enableLoginUser) {
enable = true;
};

# First boot login user setup
systemd.services.ghaf-loginuser-setup =
let
userSetupScript = pkgs.writeShellApplication {
name = "ghaf-user-setup";
runtimeInputs = [
pkgs.su
pkgs.shadow
pkgs.coreutils
pkgs.ncurses
];
text = ''
clear
echo -e "\e[1;32;1m Ghaf User Setup \e[0m"
echo ""
echo "Create your user account and set your password."
echo ""
# Read new user name
ACCEPTABLE_USER=false
until $ACCEPTABLE_USER; do
echo -n "Enter your user name: "
read -e -r USERNAME
USERNAME=''${USERNAME//_/}
USERNAME=''${USERNAME// /_}
USERNAME=''${USERNAME//[^a-zA-Z0-9_]/}
USERNAME=''$(echo -n "$USERNAME" | tr '[:upper:]' '[:lower:]')
if grep -q -w "$USERNAME:" /etc/passwd; then
echo "User $USERNAME already exists. Please choose another user name."
else
ACCEPTABLE_USER=true
fi
done
# Change login user name and home
usermod -l "$USERNAME" -d /home/"$USERNAME" -m ${cfg.loginuser}
groupmod -n "$USERNAME" ${cfg.loginuser}
chown -R "$USERNAME":users /home/"$USERNAME"
chmod -R 0760 /home/"$USERNAME"
# Change password
until passwd "$USERNAME"; do
echo "Please try again."
done
# Create user.lock file
install -m 000 /dev/null /etc/user.lock
echo "User $USERNAME created."
sleep 1
'';
};
in
optionalAttrs cfg.enableLoginUser {
description = "First boot setup of login user";
enable = true;
requiredBy = [ "multi-user.target" ];
before = [ "systemd-user-sessions.service" ];
after = [ "userborn.service" ];
path = [ userSetupScript ];
unitConfig.ConditionPathExists = "!/etc/user.lock";
serviceConfig = {
Type = "oneshot";
StandardInput = "tty";
StandardOutput = "tty";
StandardError = "tty";
TTYPath = "/dev/tty1";
TTYReset = true;
TTYVHangup = true;
ExecStart = "${userSetupScript}/bin/ghaf-user-setup";
};
};

systemd.services.ghaf-home-setup =
let
homeSetupScript = pkgs.writeShellApplication {
name = "ghaf-home-setup";
runtimeInputs = [
pkgs.coreutils
pkgs.getent
];
text = ''
# Change home dir permissions
USERNAME=$(getent passwd ${toString cfg.loginuid} | cut -d: -f1)
mv /home/${cfg.loginuser} /home/"$USERNAME"
chown -R "$USERNAME":users /home/"$USERNAME"
chmod -R 0760 /home/"$USERNAME"
'';
};
in
optionalAttrs cfg.enableLoginUser {
description = "Correct login user home permissions";
enable = true;
requiredBy = [ "multi-user.target" ];
before = [ "greetd.service" ];
path = [ homeSetupScript ];
unitConfig.ConditionPathExists = "/etc/user.lock";
serviceConfig = {
Type = "oneshot";
ExecStart = "${homeSetupScript}/bin/ghaf-home-setup";
};
};
};
}
4 changes: 2 additions & 2 deletions modules/givc/appvm.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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.appuser}.linger = true;
};
}
2 changes: 1 addition & 1 deletion modules/givc/common.nix
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let
mitmEnabled =
config.ghaf.virtualization.microvm.idsvm.enable
&& config.ghaf.virtualization.microvm.idsvm.mitmproxy.enable;
mitmExtraArgs = lib.optionalString mitmEnabled "--user-data-dir=/home/${config.ghaf.users.accounts.user}/.config/chromium/Default --test-type --ignore-certificate-errors-spki-list=Bq49YmAq1CG6FuBzp8nsyRXumW7Dmkp7QQ/F82azxGU=";
mitmExtraArgs = lib.optionalString mitmEnabled "--user-data-dir=/home/${config.ghaf.users.accounts.admin}/.config/chromium/Default --test-type --ignore-certificate-errors-spki-list=Bq49YmAq1CG6FuBzp8nsyRXumW7Dmkp7QQ/F82azxGU=";
in
{
options.ghaf.givc = {
Expand Down
15 changes: 12 additions & 3 deletions modules/microvm/virtualization/microvm/adminvm.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ let

adminvmBaseConfiguration = {
imports = [
inputs.impermanence.nixosModules.impermanence
inputs.self.nixosModules.givc-adminvm
(import ./common/vm-networking.nix {
inherit
Expand All @@ -20,14 +21,15 @@ 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
(
{ 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
Expand All @@ -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";
Expand All @@ -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 = {
Expand Down
Loading

0 comments on commit 41acb1a

Please sign in to comment.