veza/scripts/bootstrap/runner-grant-incus.sh
senke c7649c5aa4 feat(bootstrap): grant runner real incus admin via privilege + idmap
deploy_data/deploy_app plays now run from INSIDE the forgejo-runner
container with ansible_connection=local, but the unprivileged runner's
root user (mapped to a high host UID) was being rejected by the incus
daemon — \"You don't have the needed permissions to talk to the incus
daemon\".

runner-grant-incus.sh: privileged + nesting + raw.idmap=\"both 0 0\"
so root inside the runner = root on the host. The mounted incus socket
becomes fully usable. One-shot script; idempotent.

Threat-model note in the script header: we accept this because the
deploy workflow already has incus-admin scope via socket+nesting, and
the trigger surface is gated to push:main + workflow_dispatch (no fork
PRs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 14:53:18 +02:00

58 lines
1.9 KiB
Bash
Executable file

#!/usr/bin/env bash
# Give the forgejo-runner container real admin access to the host's
# Incus daemon. Required for deploy_data.yml + deploy_app.yml plays
# that run `incus launch` / `incus exec` from inside the runner.
#
# Run on the R720: sudo bash runner-grant-incus.sh
#
# Trade-off: the runner becomes a privileged container with full
# root access to incus. Consistent with the existing threat model
# (deploy.yml workflow already has incus admin via socket + nesting),
# but worth re-evaluating if the runner is ever exposed to untrusted
# inputs (PR triggers from forks etc — currently gated, see
# .forgejo/workflows/deploy.yml header).
set -euo pipefail
CONT=forgejo-runner
echo "→ stopping ${CONT}"
incus stop "${CONT}" --force 2>/dev/null || true
echo "→ enabling privileged + nesting + idmap-passthrough"
incus config set "${CONT}" security.privileged true
incus config set "${CONT}" security.nesting true
# Map host root (uid/gid 0) to container root so the mounted incus
# socket is readable+writable by root inside the container.
incus config set "${CONT}" raw.idmap "both 0 0"
echo "→ ensuring incus socket is mounted in"
if ! incus config device show "${CONT}" | grep -q "^incus-socket:"; then
incus config device add "${CONT}" incus-socket disk \
source=/var/lib/incus/unix.socket \
path=/var/lib/incus/unix.socket
fi
echo "→ starting ${CONT}"
incus start "${CONT}"
# Wait for the runner's userspace to come up
for i in $(seq 1 30); do
if incus exec "${CONT}" -- /bin/true 2>/dev/null; then
break
fi
sleep 1
done
echo
echo "→ verifying incus access from inside the runner"
incus exec "${CONT}" -- bash -c '
if incus info >/dev/null 2>&1; then
echo " ✓ runner can talk to incus daemon"
else
echo " ✗ runner still cannot reach incus daemon"
exit 1
fi
'
echo
echo "✓ runner now has incus admin. Re-trigger Veza deploy."