From f886a1bd8a101e6dd8f8ed86a6d1e1eeb7fa2361 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Sun, 28 Jan 2024 12:33:57 -0600 Subject: [PATCH] sudo: Configure pam_ssh_agent_auth I do not like how Fedora CoreOS configures `sudo` to allow the *core* user to run privileged processes without authentication. Rather than assign the user a password, which would then have to be stored somewhere, we'll install *pam_ssh_agent_auth* and configure `sudo` to use it for authentication. This way, only users with the private key corresponding to one of the configured public keys can run `sudo`. Naturally, *pam_ssh_agent_auth* has to be installed on the host system. We achieve this by executing `rpm-ostree` via `nsenter` to escape the container. Once it is installed, we configure the PAM stack for `sudo` to use it and populate the authorized keys database. We also need to configure `sudo` to keep the `SSH_AUTH_SOCK` environment variable, so *pam_ssh_agent_auth* knows where to look for the private keys. Finally, we disable the default NOPASSWD rule for `sudo`, if and only if the new configuration was installed. --- app/sudo/schema/schema.cue | 6 ++++++ app/sudo/templates.cue | 21 +++++++++++++++++++++ env/prod/sudo.cue | 13 +++++++++++++ host/nut0.pyrocufflink.blue.cue | 2 ++ host/nut0.pyrocufflink.blue.post.sh | 1 + host/nut0.pyrocufflink.blue.pre.sh | 5 +++++ host/nvr1.pyrocufflink.blue.cue | 2 ++ host/nvr1.pyrocufflink.blue.post.sh | 1 + host/nvr1.pyrocufflink.blue.pre.sh | 5 +++++ host/serial1.pyrocufflink.blue.cue | 6 ++++++ host/serial1.pyrocufflink.blue.post.sh | 1 + host/serial1.pyrocufflink.blue.pre.sh | 5 +++++ instructions/nut0.pyrocufflink.blue.cue | 2 ++ instructions/nvr1.pyrocufflink.blue.cue | 2 ++ instructions/serial1.pyrocufflink.blue.cue | 2 ++ scripts/no-coreos-default-sudo.sh | 6 ++++++ scripts/pam-ssh-agent-auth.sh | 3 +++ scripts/rpm-ostree-install.sh | 16 ++++++++++++++++ templates/sudo/authorized_keys | 1 + templates/sudo/ssh-auth-sock.sudoers | 3 +++ templates/sudo/sudo.pam.conf | 10 ++++++++++ 21 files changed, 113 insertions(+) create mode 100644 app/sudo/schema/schema.cue create mode 100644 app/sudo/templates.cue create mode 100644 env/prod/sudo.cue create mode 100644 host/nut0.pyrocufflink.blue.post.sh create mode 100644 host/nut0.pyrocufflink.blue.pre.sh create mode 100644 host/nvr1.pyrocufflink.blue.post.sh create mode 100644 host/nvr1.pyrocufflink.blue.pre.sh create mode 100644 host/serial1.pyrocufflink.blue.post.sh create mode 100644 host/serial1.pyrocufflink.blue.pre.sh create mode 100644 scripts/no-coreos-default-sudo.sh create mode 100644 scripts/pam-ssh-agent-auth.sh create mode 100644 scripts/rpm-ostree-install.sh create mode 100644 templates/sudo/authorized_keys create mode 100644 templates/sudo/ssh-auth-sock.sudoers create mode 100644 templates/sudo/sudo.pam.conf diff --git a/app/sudo/schema/schema.cue b/app/sudo/schema/schema.cue new file mode 100644 index 0000000..8592c27 --- /dev/null +++ b/app/sudo/schema/schema.cue @@ -0,0 +1,6 @@ +package schema + +#Sudo: { + use_pam_ssh_agent: bool | *false + authorized_keys?: string +} diff --git a/app/sudo/templates.cue b/app/sudo/templates.cue new file mode 100644 index 0000000..2298183 --- /dev/null +++ b/app/sudo/templates.cue @@ -0,0 +1,21 @@ +package sudo + +import "du5t1n.me/cfg/base/schema/instructions" + +templates: [...instructions.#RenderInstruction] & [ + { + template: "sudo/sudo.pam.conf" + dest: "/etc/pam.d/sudo" + }, + { + template: "sudo/authorized_keys" + dest: "/etc/security/sudo.authorized_keys" + }, + { + template: "sudo/ssh-auth-sock.sudoers" + dest: "/etc/sudoers.d/ssh-auth-sock" + owner: "root" + group: "root" + mode: "u=rw,g=r,o=" + }, +] diff --git a/env/prod/sudo.cue b/env/prod/sudo.cue new file mode 100644 index 0000000..9c4d725 --- /dev/null +++ b/env/prod/sudo.cue @@ -0,0 +1,13 @@ +package prod + +import ( + "du5t1n.me/cfg/app/sudo/schema" +) + +sudo: schema.#Sudo & { + use_pam_ssh_agent: true + authorized_keys: """ + sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAINZCN2cxMDwedJ1Ke23Z3CZRcOYjqW8fFqsooRus7RK0AAAABHNzaDo= dustin@rosalina.pyrocufflink.blue + sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIAB6xTCSNz+AcQCWcyVKs84tThXN4wpLgCo2Lc48L6EsAAAABHNzaDo= dustin@luma.pyrocufflink.blue + """ +} diff --git a/host/nut0.pyrocufflink.blue.cue b/host/nut0.pyrocufflink.blue.cue index 9460779..5757cac 100644 --- a/host/nut0.pyrocufflink.blue.cue +++ b/host/nut0.pyrocufflink.blue.cue @@ -12,3 +12,5 @@ nut: monitor: prod.#nut_monitor & { } collectd: prod.collectd + +sudo: prod.sudo diff --git a/host/nut0.pyrocufflink.blue.post.sh b/host/nut0.pyrocufflink.blue.post.sh new file mode 100644 index 0000000..17c32eb --- /dev/null +++ b/host/nut0.pyrocufflink.blue.post.sh @@ -0,0 +1 @@ +. scripts/no-coreos-default-sudo.sh diff --git a/host/nut0.pyrocufflink.blue.pre.sh b/host/nut0.pyrocufflink.blue.pre.sh new file mode 100644 index 0000000..92a083e --- /dev/null +++ b/host/nut0.pyrocufflink.blue.pre.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +. scripts/pam-ssh-agent-auth.sh + +install_packages diff --git a/host/nvr1.pyrocufflink.blue.cue b/host/nvr1.pyrocufflink.blue.cue index 3069ed0..f015c0a 100644 --- a/host/nvr1.pyrocufflink.blue.cue +++ b/host/nvr1.pyrocufflink.blue.cue @@ -10,3 +10,5 @@ nut: monitor: schema.#NutMonitor nut: monitor: prod.#nut_monitor & { #username: "nvr1" } + +sudo: prod.sudo diff --git a/host/nvr1.pyrocufflink.blue.post.sh b/host/nvr1.pyrocufflink.blue.post.sh new file mode 100644 index 0000000..17c32eb --- /dev/null +++ b/host/nvr1.pyrocufflink.blue.post.sh @@ -0,0 +1 @@ +. scripts/no-coreos-default-sudo.sh diff --git a/host/nvr1.pyrocufflink.blue.pre.sh b/host/nvr1.pyrocufflink.blue.pre.sh new file mode 100644 index 0000000..92a083e --- /dev/null +++ b/host/nvr1.pyrocufflink.blue.pre.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +. scripts/pam-ssh-agent-auth.sh + +install_packages diff --git a/host/serial1.pyrocufflink.blue.cue b/host/serial1.pyrocufflink.blue.cue index 1331366..e16597a 100644 --- a/host/serial1.pyrocufflink.blue.cue +++ b/host/serial1.pyrocufflink.blue.cue @@ -1 +1,7 @@ package serial1 + +import ( + "du5t1n.me/cfg/env/prod" +) + +sudo: prod.sudo diff --git a/host/serial1.pyrocufflink.blue.post.sh b/host/serial1.pyrocufflink.blue.post.sh new file mode 100644 index 0000000..17c32eb --- /dev/null +++ b/host/serial1.pyrocufflink.blue.post.sh @@ -0,0 +1 @@ +. scripts/no-coreos-default-sudo.sh diff --git a/host/serial1.pyrocufflink.blue.pre.sh b/host/serial1.pyrocufflink.blue.pre.sh new file mode 100644 index 0000000..92a083e --- /dev/null +++ b/host/serial1.pyrocufflink.blue.pre.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +. scripts/pam-ssh-agent-auth.sh + +install_packages diff --git a/instructions/nut0.pyrocufflink.blue.cue b/instructions/nut0.pyrocufflink.blue.cue index aed1c12..5bf12d9 100644 --- a/instructions/nut0.pyrocufflink.blue.cue +++ b/instructions/nut0.pyrocufflink.blue.cue @@ -5,6 +5,7 @@ import ( "du5t1n.me/cfg/app/collectd" "du5t1n.me/cfg/app/nut" + "du5t1n.me/cfg/app/sudo" ) render: list.Concat([ @@ -12,4 +13,5 @@ render: list.Concat([ nut.templates, nut.monitor.templates, nut.collectd.templates, + sudo.templates, ]) diff --git a/instructions/nvr1.pyrocufflink.blue.cue b/instructions/nvr1.pyrocufflink.blue.cue index 3e3988b..4d21428 100644 --- a/instructions/nvr1.pyrocufflink.blue.cue +++ b/instructions/nvr1.pyrocufflink.blue.cue @@ -4,9 +4,11 @@ import ( "list" "du5t1n.me/cfg/app/nut" + "du5t1n.me/cfg/app/sudo" ) render: list.Concat([ nut.sysusers.templates, nut.monitor.templates, + sudo.templates, ]) diff --git a/instructions/serial1.pyrocufflink.blue.cue b/instructions/serial1.pyrocufflink.blue.cue index 302a39b..8b3b7c5 100644 --- a/instructions/serial1.pyrocufflink.blue.cue +++ b/instructions/serial1.pyrocufflink.blue.cue @@ -4,8 +4,10 @@ import ( "list" "du5t1n.me/cfg/app/collectd" + "du5t1n.me/cfg/app/sudo" ) render: list.Concat([ collectd.templates, + sudo.templates, ]) diff --git a/scripts/no-coreos-default-sudo.sh b/scripts/no-coreos-default-sudo.sh new file mode 100644 index 0000000..542236f --- /dev/null +++ b/scripts/no-coreos-default-sudo.sh @@ -0,0 +1,6 @@ +if [ -f /host/etc/sudoers.d/coreos-sudo-group ] && + [ -s /host/etc/sudoers.d/ssh-auth-sock ] && + [ -s /host/etc/security/sudo.authorized_keys ] +then + rm -f /host/etc/sudoers.d/coreos-sudo-group +fi diff --git a/scripts/pam-ssh-agent-auth.sh b/scripts/pam-ssh-agent-auth.sh new file mode 100644 index 0000000..1d53113 --- /dev/null +++ b/scripts/pam-ssh-agent-auth.sh @@ -0,0 +1,3 @@ +. scripts/rpm-ostree-install.sh + +check_install /host/lib*/security/pam_ssh_agent_auth.so pam_ssh_agent_auth diff --git a/scripts/rpm-ostree-install.sh b/scripts/rpm-ostree-install.sh new file mode 100644 index 0000000..acee6ef --- /dev/null +++ b/scripts/rpm-ostree-install.sh @@ -0,0 +1,16 @@ +INSTALL_PACKAGES='' + +check_install() { + if [ ! -e "${1}" ]; then + INSTALL_PACKAGES="${INSTALL_PACKAGES} ${2}" + fi +} + +install_packages() { + if [ ! -z "${INSTALL_PACKAGES}" ]; then + echo "Installing packages: ${INSTALL_PACKAGES}" >&2 + nsenter -m -u -i -n -p -t 1 \ + rpm-ostree install -y --allow-inactive --idempotent --apply-live \ + ${INSTALL_PACKAGES} + fi +} diff --git a/templates/sudo/authorized_keys b/templates/sudo/authorized_keys new file mode 100644 index 0000000..a55f72d --- /dev/null +++ b/templates/sudo/authorized_keys @@ -0,0 +1 @@ +{{ sudo.authorized_keys }} diff --git a/templates/sudo/ssh-auth-sock.sudoers b/templates/sudo/ssh-auth-sock.sudoers new file mode 100644 index 0000000..6d1583c --- /dev/null +++ b/templates/sudo/ssh-auth-sock.sudoers @@ -0,0 +1,3 @@ +{% if sudo.use_pam_ssh_agent -%} +Defaults env_keep += "SSH_AUTH_SOCK" +{% endif -%} diff --git a/templates/sudo/sudo.pam.conf b/templates/sudo/sudo.pam.conf new file mode 100644 index 0000000..2348503 --- /dev/null +++ b/templates/sudo/sudo.pam.conf @@ -0,0 +1,10 @@ +#%PAM-1.0 +{% if sudo.use_pam_ssh_agent -%} +-auth sufficient pam_ssh_agent_auth.so file=/etc/security/sudo.authorized_keys +{% endif -%} +auth include system-auth +account include system-auth +password include system-auth +session optional pam_keyinit.so revoke +session required pam_limits.so +session include system-auth