civodul pushed a commit to branch master
in repository guix.

commit a9239a769c5611f12061c9a895e4e218b3445e2f
Author: Ludovic Courtès <[email protected]>
AuthorDate: Thu Jan 23 12:48:01 2025 +0100

    guix-install.sh: Support the unprivileged daemon where possible.
    
    * etc/guix-install.sh (create_account): New function.
    (sys_create_build_user): Use it.  When ‘guix-daemon.service’ contains
    “User=guix-daemon” only create the ‘guix-daemon’ user and group.
    (sys_delete_build_user): Delete the ‘guix-daemon’ user and group.
    (can_install_unprivileged_daemon): New function.
    (sys_create_store): When installing the unprivileged daemon, change
    ownership of /gnu and /var/guix, and create /var/log/guix.
    (sys_authorize_build_farms): When the ‘guix-daemon’ account exists,
    change ownership of /etc/guix.
    
    Change-Id: I73e573f1cc5c0cb3794aaaa6b576616b66e0c5e9
---
 etc/guix-install.sh | 124 +++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 99 insertions(+), 25 deletions(-)

diff --git a/etc/guix-install.sh b/etc/guix-install.sh
index 8887204df4..b5d833cd64 100755
--- a/etc/guix-install.sh
+++ b/etc/guix-install.sh
@@ -414,6 +414,11 @@ sys_create_store()
     cd "$tmp_path"
     _msg_info "Installing /var/guix and /gnu..."
     # Strip (skip) the leading ‘.’ component, which fails on read-only ‘/’.
+    #
+    # TODO: Eventually extract with ‘--owner=guix-daemon’ when installing
+    # and unprivileged guix-daemon service; for now, this script may install
+    # from both an old release that does not support unprivileged guix-daemon
+    # and a new release that does, so ‘chown -R’ later if needed.
     tar --extract --strip-components=1 --file "$pkg" -C /
 
     _msg_info "Linking the root user's profile"
@@ -441,38 +446,95 @@ sys_delete_store()
     rm -rf ~root/.config/guix
 }
 
+create_account()
+{
+    local user="$1"
+    local group="$2"
+    local supplementary_groups="$3"
+    local comment="$4"
+
+    if id "$user" &>/dev/null; then
+       _msg_info "user '$user' is already in the system, reset"
+       usermod -g "$group" -G "$supplementary_groups"  \
+               -d /var/empty -s "$(which nologin)"     \
+               -c "$comment" "$user"
+    else
+       useradd -g "$group" -G "$supplementary_groups"  \
+               -d /var/empty -s "$(which nologin)"     \
+               -c "$comment" --system "$user"
+       _msg_pass "user added <$user>"
+    fi
+}
+
+install_unprivileged_daemon()
+{ # Return true when installing guix-daemon running without privileges.
+    [ "$INIT_SYS" = systemd ] && \
+       grep -q "User=guix-daemon" \
+            ~root/.config/guix/current/lib/systemd/system/guix-daemon.service
+}
+
 sys_create_build_user()
 { # Create the group and user accounts for build users.
 
     _debug "--- [ ${FUNCNAME[0]} ] ---"
 
-    if getent group guixbuild > /dev/null; then
-        _msg_info "group guixbuild exists"
-    else
-        groupadd --system guixbuild
-        _msg_pass "group <guixbuild> created"
-    fi
-
     if getent group kvm > /dev/null; then
         _msg_info "group kvm exists and build users will be added to it"
         local KVMGROUP=,kvm
     fi
 
-    for i in $(seq -w 1 10); do
-        if id "guixbuilder${i}" &>/dev/null; then
-            _msg_info "user is already in the system, reset"
-            usermod -g guixbuild -G guixbuild"$KVMGROUP"     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i"             \
-                    "guixbuilder${i}";
-        else
-            useradd -g guixbuild -G guixbuild"$KVMGROUP"     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i" --system    \
-                    "guixbuilder${i}";
-            _msg_pass "user added <guixbuilder${i}>"
-        fi
-    done
+    if install_unprivileged_daemon
+    then
+       _msg_info "installing guix-daemon to run as an unprivileged user"
+
+       # Installing guix-daemon to run as a non-root user requires
+       # unprivileged user namespaces.
+       if [ -f /proc/sys/kernel/unprivileged_userns_clone ] \
+              && [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -ne 1 ]
+       then
+           echo 1 > /proc/sys/kernel/unprivileged_userns_clone || \
+               _err "failed to enable unprivileged user namespaces"
+
+           _msg_warn "Unprivileged user namespaces were disabled and have been 
enabled now."
+           _msg_warn "This Linux feature is required by guix-daemon.  To 
enable it permanently, run:"
+           _msg_warn '  echo 1 > /proc/sys/kernel/unprivileged_userns_clone'
+           _msg_warn "from the relevant startup script."
+       fi
+
+
+       if getent group guix-daemon > /dev/null; then
+           _msg_info "group guix-daemon exists"
+       else
+           groupadd --system guix-daemon
+           _msg_pass "group guix-daemon created"
+       fi
+
+       create_account guix-daemon guix-daemon          \
+                      guix-daemon$KVMGROUP             \
+                      "Unprivileged Guix Daemon User"
+
+       # ‘tar xf’ creates root:root files.  Change that.
+       chown -R guix-daemon:guix-daemon /gnu /var/guix
+       chown -R root:root /var/guix/profiles/per-user/root
+
+       # The unprivileged daemon cannot create the log directory by itself.
+       mkdir -p /var/log/guix
+       chown guix-daemon:guix-daemon /var/log/guix
+       chmod 755 /var/log/guix
+    else
+       if getent group guixbuild > /dev/null; then
+            _msg_info "group guixbuild exists"
+       else
+            groupadd --system guixbuild
+            _msg_pass "group <guixbuild> created"
+       fi
+
+       for i in $(seq -w 1 10); do
+           create_account "guixbuilder${i}" "guixbuild"        \
+                          "guixbuild${KVMGROUP}"               \
+                          "Guix build user $i"
+       done
+    fi
 }
 
 sys_delete_build_user()
@@ -487,6 +549,14 @@ sys_delete_build_user()
     if getent group guixbuild &>/dev/null; then
         groupdel -f guixbuild
     fi
+
+    _msg_info "remove guix-daemon user"
+    if id guix-daemon &>/dev/null; then
+       userdel -f guix-daemon
+    fi
+    if getent group guix-daemon &>/dev/null; then
+       groupdel -f guix-daemon
+    fi
 }
 
 sys_enable_guix_daemon()
@@ -529,11 +599,11 @@ sys_enable_guix_daemon()
 
               # Install after guix-daemon.service to avoid a harmless warning.
               # systemd .mount units must be named after the target directory.
-              # Here we assume a hard-coded name of /gnu/store.
-              install_unit gnu-store.mount
+             install_unit gnu-store.mount
 
               systemctl daemon-reload &&
-                  systemctl start  guix-daemon; } &&
+                  systemctl start guix-daemon &&
+                 systemctl start gnu-store.mount; } &&
                 _msg_pass "enabled Guix daemon via systemd"
             ;;
         sysv-init)
@@ -654,6 +724,10 @@ project's build farms?"; then
                && guix archive --authorize < "$key" \
                && _msg_pass "Authorized public key for $host"
        done
+       if id guix-daemon &>/dev/null; then
+           # /etc/guix/acl must be readable by the unprivileged guix-daemon.
+           chown -R guix-daemon:guix-daemon /etc/guix
+       fi
     else
         _msg_info "Skipped authorizing build farm public keys"
     fi

Reply via email to