[bug#75810,6/6] guix-install.sh: Support the unprivileged daemon where possible.
Commit Message
* 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.
(sys_enable_guix_daemon): Do not install ‘gnu-store.mount’ when running
an unprivileged daemon.
Change-Id: I73e573f1cc5c0cb3794aaaa6b576616b66e0c5e9
---
etc/guix-install.sh | 114 +++++++++++++++++++++++++++++++++++---------
1 file changed, 91 insertions(+), 23 deletions(-)
@@ -389,6 +389,11 @@ sys_create_store()
cd "$tmp_path"
_msg "${INF}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 "${INF}Linking the root user's profile"
@@ -414,38 +419,82 @@ 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 "${INF}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 "${PAS}user added <$user>"
+ fi
+}
+
+can_install_unprivileged_daemon()
+{ # Return true if we can install guix-daemon running without privileges.
+ [ "$INIT_SYS" = systemd ] && \
+ grep -q "User=guix-daemon" \
+ ~root/.config/guix/current/lib/systemd/system/guix-daemon.service \
+ && ([ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
+ || [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ])
+}
+
sys_create_build_user()
{ # Create the group and user accounts for build users.
_debug "--- [ ${FUNCNAME[0]} ] ---"
- if getent group guixbuild > /dev/null; then
- _msg "${INF}group guixbuild exists"
- else
- groupadd --system guixbuild
- _msg "${PAS}group <guixbuild> created"
- fi
-
if getent group kvm > /dev/null; then
_msg "${INF}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 "${INF}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 "${PAS}user added <guixbuilder${i}>"
- fi
- done
+ if [ "$INIT_SYS" = systemd ] && \
+ grep -q "User=guix-daemon" \
+ ~root/.config/guix/current/lib/systemd/system/guix-daemon.service
+ then
+ if getent group guix-daemon > /dev/null; then
+ _msg "${INF}group guix-daemon exists"
+ else
+ groupadd --system guix-daemon
+ _msg "${PAS}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
+
+ # The unprivileged cannot create the log directory by itself.
+ mkdir /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 "${INF}group guixbuild exists"
+ else
+ groupadd --system guixbuild
+ _msg "${PAS}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()
@@ -460,6 +509,14 @@ sys_delete_build_user()
if getent group guixbuild &>/dev/null; then
groupdel -f guixbuild
fi
+
+ _msg "${INF}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()
@@ -503,7 +560,14 @@ 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
+ #
+ # FIXME: This feature is unavailable when running an
+ # unprivileged daemon.
+ if ! grep -q "User=guix-daemon" \
+ /etc/systemd/system/guix-daemon.service
+ then
+ install_unit gnu-store.mount
+ fi
systemctl daemon-reload &&
systemctl start guix-daemon; } &&
@@ -627,6 +691,10 @@ project's build farms?"; then
&& guix archive --authorize < "$key" \
&& _msg "${PAS}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 "${INF}Skipped authorizing build farm public keys"
fi