fedora-remote: minimal headless GNOME Remote Desktop host with Kanidm
New image built from upstream base-atomic (no desktop), adding only gnome-shell + gdm + gnome-remote-desktop + pipewire/portal + foot + Flatpak + Kanidm. recommends=false to stay lean. Configures GNOME Remote Desktop headless remote login on first boot (TLS + credentials + enable). Firefox preinstalled as a per-user Flatpak. Add it to the CI matrix and prune both images.
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
# Fetch authorized SSH public keys from Kanidm (uploaded to the account).
|
||||
# Name this 10-* so it is read before systemd-userdbd's AuthorizedKeysCommand
|
||||
# drop-in, since sshd honours the first directive it sees.
|
||||
PubkeyAuthentication yes
|
||||
UsePAM yes
|
||||
AuthorizedKeysCommand /usr/bin/kanidm_ssh_authorizedkeys %u
|
||||
AuthorizedKeysCommandUser nobody
|
||||
|
||||
# Hardening: key-only auth through Kanidm. Make sure you have uploaded an SSH
|
||||
# public key to your account before relying on this, or you can lock yourself
|
||||
# out of SSH.
|
||||
PermitRootLogin no
|
||||
PasswordAuthentication no
|
||||
PermitEmptyPasswords no
|
||||
GSSAPIAuthentication no
|
||||
KerberosAuthentication no
|
||||
@@ -0,0 +1,4 @@
|
||||
# GNOME Remote Desktop headless remote login.
|
||||
enable gdm.service
|
||||
enable gnome-remote-desktop.service
|
||||
enable grd-firstboot.service
|
||||
@@ -0,0 +1,3 @@
|
||||
# Kanidm Unix authentication daemons.
|
||||
enable kanidm-unixd.service
|
||||
enable kanidm-unixd-tasks.service
|
||||
@@ -0,0 +1 @@
|
||||
enable flatpak-user-firstboot.service
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
# Install the per-user Flatpaks listed in /usr/share/flatpak/flatpaks.list on
|
||||
# the first login of each user. Run as a systemd --user oneshot unit.
|
||||
set -euo pipefail
|
||||
|
||||
LIST="/usr/share/flatpak/flatpaks.list"
|
||||
MARKER="${HOME}/.config/flatpak-user-firstboot.done"
|
||||
|
||||
[[ -f "${LIST}" ]] || exit 0
|
||||
|
||||
# Make Flathub available for the current user.
|
||||
flatpak remote-add --user --if-not-exists flathub \
|
||||
https://flathub.org/repo/flathub.flatpakrepo
|
||||
|
||||
mapfile -t apps < <(
|
||||
sed -e 's/#.*//' -e 's/[[:space:]]//g' "${LIST}" | grep -v '^$' || true
|
||||
)
|
||||
|
||||
if [[ ${#apps[@]} -gt 0 ]]; then
|
||||
flatpak install --user --noninteractive --assumeyes "${apps[@]}"
|
||||
fi
|
||||
|
||||
install -dm0755 "$(dirname "${MARKER}")"
|
||||
touch "${MARKER}"
|
||||
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Install per-user Flatpak applications on first login
|
||||
Documentation=https://docs.flatpak.org/en/latest/flatpak-command-reference.html
|
||||
ConditionPathExists=!%h/.config/flatpak-user-firstboot.done
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/libexec/flatpak-user-firstboot
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,3 @@
|
||||
# Flatpaks installed into each user's per-user installation on first login.
|
||||
# foot is installed as an RPM (no Flathub build), so only Firefox here.
|
||||
org.mozilla.firefox
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
# One-time configuration of GNOME Remote Desktop (system / headless remote
|
||||
# login). Runs on first boot because grdctl talks to the running daemon.
|
||||
#
|
||||
# Optional /etc/gnome-remote-desktop/rdp.env:
|
||||
# GRD_SYSTEM_USER=rdp
|
||||
# GRD_SYSTEM_PASSWORD=...
|
||||
# If unset, remote login is enabled but no greeter credential is configured
|
||||
# (set one with: printf '%s\n%s\n' USER PASS | grdctl --system rdp set-credentials).
|
||||
set -euo pipefail
|
||||
|
||||
GRD_USER=gnome-remote-desktop
|
||||
STATE="/var/lib/${GRD_USER}"
|
||||
TLS_DIR="${STATE}/.local/share/gnome-remote-desktop"
|
||||
MARKER="${STATE}/.configured"
|
||||
|
||||
[[ -f "${MARKER}" ]] && exit 0
|
||||
|
||||
install -d -o "${GRD_USER}" -g "${GRD_USER}" "${TLS_DIR}"
|
||||
|
||||
if [[ ! -f "${TLS_DIR}/tls.key" ]]; then
|
||||
sudo -u "${GRD_USER}" openssl req -new -newkey rsa:4096 -days 720 -nodes -x509 \
|
||||
-subj "/CN=${GRD_CERT_CN:-fedora-remote}" \
|
||||
-out "${TLS_DIR}/tls.crt" -keyout "${TLS_DIR}/tls.key"
|
||||
fi
|
||||
|
||||
grdctl --system rdp set-tls-key "${TLS_DIR}/tls.key"
|
||||
grdctl --system rdp set-tls-cert "${TLS_DIR}/tls.crt"
|
||||
|
||||
if [[ -n "${GRD_SYSTEM_PASSWORD:-}" ]]; then
|
||||
printf '%s\n%s\n' "${GRD_SYSTEM_USER:-rdp}" "${GRD_SYSTEM_PASSWORD}" \
|
||||
| grdctl --system rdp set-credentials
|
||||
fi
|
||||
|
||||
grdctl --system rdp enable
|
||||
systemctl restart gnome-remote-desktop.service || true
|
||||
|
||||
touch "${MARKER}"
|
||||
@@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=Configure GNOME Remote Desktop on first boot
|
||||
Documentation=https://github.com/GNOME/gnome-remote-desktop/blob/main/docs/configuration.md
|
||||
After=network-online.target gnome-remote-desktop.service
|
||||
Wants=network-online.target
|
||||
ConditionPathExists=!/var/lib/gnome-remote-desktop/.configured
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
EnvironmentFile=-/etc/gnome-remote-desktop/rdp.env
|
||||
ExecStart=/usr/libexec/grd-firstboot
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1 @@
|
||||
uri = "https://auth.plabble.org"
|
||||
@@ -0,0 +1,14 @@
|
||||
passwd: kanidm compat systemd
|
||||
group: kanidm compat systemd
|
||||
shadow: files
|
||||
hosts: files dns myhostname
|
||||
services: files
|
||||
netgroup: files
|
||||
automount: files
|
||||
aliases: files
|
||||
ethers: files
|
||||
gshadow: files
|
||||
networks: files dns
|
||||
protocols: files
|
||||
publickey: files
|
||||
rpc: files
|
||||
@@ -0,0 +1,19 @@
|
||||
auth required pam_env.so
|
||||
auth required pam_faildelay.so delay=2000000
|
||||
auth sufficient pam_kanidm.so ignore_unknown_user
|
||||
auth sufficient pam_unix.so nullok
|
||||
auth required pam_deny.so
|
||||
|
||||
account sufficient pam_kanidm.so
|
||||
account required pam_unix.so
|
||||
|
||||
password requisite pam_pwquality.so
|
||||
password sufficient pam_unix.so yescrypt shadow nullok use_authtok
|
||||
password required pam_deny.so
|
||||
|
||||
session optional pam_keyinit.so revoke
|
||||
session required pam_limits.so
|
||||
-session optional pam_systemd.so
|
||||
session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
|
||||
session optional pam_kanidm.so
|
||||
session required pam_unix.so
|
||||
@@ -0,0 +1,20 @@
|
||||
auth required pam_env.so
|
||||
auth required pam_faildelay.so delay=2000000
|
||||
auth sufficient pam_fprintd.so
|
||||
auth sufficient pam_kanidm.so ignore_unknown_user
|
||||
auth sufficient pam_unix.so nullok
|
||||
auth required pam_deny.so
|
||||
|
||||
account sufficient pam_kanidm.so ignore_unknown_user
|
||||
account required pam_unix.so
|
||||
|
||||
password requisite pam_pwquality.so
|
||||
password sufficient pam_unix.so yescrypt shadow nullok use_authtok
|
||||
password required pam_deny.so
|
||||
|
||||
session optional pam_keyinit.so revoke
|
||||
session required pam_limits.so
|
||||
-session optional pam_systemd.so
|
||||
session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
|
||||
session optional pam_kanidm.so
|
||||
session required pam_unix.so
|
||||
@@ -0,0 +1,33 @@
|
||||
version = "2"
|
||||
|
||||
# Bind cached credentials to the local TPM when one is available.
|
||||
hsm_type = "tpm_if_possible"
|
||||
|
||||
default_shell = "/bin/bash"
|
||||
home_prefix = "/home/"
|
||||
home_attr = "uuid"
|
||||
home_alias = "name"
|
||||
use_etc_skel = true
|
||||
selinux = true
|
||||
|
||||
# Present the short login name ("misthios"), not the SPN, to NSS/PAM. With the
|
||||
# default (spn) the passwd entry name is "misthios@auth.plabble.org", which
|
||||
# confuses logins.
|
||||
uid_attr_map = "name"
|
||||
gid_attr_map = "name"
|
||||
|
||||
[kanidm]
|
||||
# Members of this Kanidm POSIX group are allowed to log in via PAM.
|
||||
pam_allowed_login_groups = ["unix_users"]
|
||||
|
||||
# A host almost always already has a local account at uid 1000. Kanidm ignores
|
||||
# its own entry when a local account with the same name exists, so logins would
|
||||
# use the local account (and the Kanidm password would fail). Let Kanidm take
|
||||
# over these local accounts. Add more names as needed.
|
||||
allow_local_account_override = ["misthios"]
|
||||
|
||||
# NOTE: kanidm-unixd runs with DynamicUser=yes and cannot read a root-only file,
|
||||
# so the service account token (when seeded) is passed as a systemd credential
|
||||
# via the build.sh-generated drop-in
|
||||
# /usr/lib/systemd/system/kanidm-unixd.service.d/10-token.conf.
|
||||
# Do not set service_account_token_path here.
|
||||
@@ -0,0 +1,21 @@
|
||||
; Kanidm ships no SELinux policy. Without these allows, nss/pam consumers
|
||||
; (sshd, the display manager, systemd-userdbd, ...) are denied write access to
|
||||
; the kanidm-unixd sockets in /run/kanidm-unixd (labeled var_run_t), so Kanidm
|
||||
; users cannot be resolved or authenticated and logins fail (sshd reports
|
||||
; "invalid user"). This is the allow set produced by:
|
||||
; grep avc: /var/log/audit/audit.log | audit2allow
|
||||
(allow accountsd_t var_run_t (sock_file (write)))
|
||||
(allow auditd_t var_run_t (sock_file (write)))
|
||||
(allow chkpwd_t var_run_t (sock_file (write)))
|
||||
(allow local_login_t var_run_t (sock_file (write)))
|
||||
(allow policykit_t var_run_t (sock_file (write)))
|
||||
(allow ssh_keygen_t var_run_t (sock_file (write)))
|
||||
(allow sshd_auth_t var_run_t (sock_file (write)))
|
||||
(allow sshd_keygen_t var_run_t (sock_file (write)))
|
||||
(allow sshd_session_t var_run_t (sock_file (write)))
|
||||
(allow sshd_t var_run_t (sock_file (write)))
|
||||
(allow systemd_bootc_generator_t var_run_t (sock_file (write)))
|
||||
(allow systemd_selinux_autorelabel_generator_t var_run_t (sock_file (write)))
|
||||
(allow systemd_userdbd_t var_run_t (sock_file (write)))
|
||||
(allow xdm_t var_run_t (sock_file (write)))
|
||||
(allow init_t unconfined_service_t (unix_stream_socket (connectto)))
|
||||
Reference in New Issue
Block a user