Enable mac_do framework during bootstrap (Codex)

Configure FreeBSD 15 installs to load mac_do with an empty rule set for future narrowly scoped UID transitions.
This commit is contained in:
Sam & Claude 2026-05-10 21:55:47 +02:00
parent 988bdf367a
commit 0841e96abe
4 changed files with 90 additions and 15 deletions

View file

@ -27,13 +27,12 @@ Instead, guide the operator with exact commands to run on the FreeBSD system.
## System Configuration
**Privilege escalation:** Unified on `sudo` (not doas), with `mac_do` adoption planned
**Privilege model:** operator commands use `sudo`; agent runtime privilege goes through hostd.
- All documentation uses sudo
- Admin panel uses sudo for privileged operations
- Agents should use sudo in examples and commands
- mac_do (kernel MAC module) will be added for per-jail privilege isolation
- See `Clawdie-AI/docs/internal/SUDO_REPLACEMENT.md` for the adoption plan
- All operator-facing documentation uses sudo for interactive host administration
- Agent runtime code must not shell out to sudo for privileged host changes
- Privileged agent operations go through the Clawdie-AI hostd RPC layer
- The ISO enables FreeBSD `mac_do` with an empty rule set so future in-jail UID transitions can be added narrowly when there is a concrete consumer
**Unified ISO:** Single image works on VPS, baremetal, and cloud

View file

@ -9,6 +9,8 @@ set -eu
# Configuration (can be overridden for testing)
RC_CONF="${RC_CONF:-/etc/rc.conf}"
LOADER_CONF="${LOADER_CONF:-/boot/loader.conf}"
SYSCTL_CONF="${SYSCTL_CONF:-/etc/sysctl.conf}"
HOSTNAME_FILE="${HOSTNAME_FILE:-/etc/hostname}"
PROFILE_DIR="${PROFILE_DIR:-/etc/profile.d}"
LOG_FILE="${LOG_FILE:-/var/log/clawdie-firstboot.log}"
@ -59,6 +61,10 @@ clawdie_shell_system_config() {
clawdie_shell_system_setup_locale
log_msg "[system] Setup locale"
# Enable FreeBSD mac_do framework with no credential grants yet
clawdie_shell_system_setup_mac_do
log_msg "[system] Setup mac_do framework"
# Enable services
clawdie_shell_system_enable_services
log_msg "[system] Enabled services"
@ -100,19 +106,54 @@ clawdie_shell_system_sysrc() {
# Add or update a variable in rc.conf
# Input: VAR=VALUE
local var_assignment="$1"
local var_name var_value
clawdie_shell_system_set_config_line "$RC_CONF" "$1"
}
clawdie_shell_system_set_config_line() {
# Add or update KEY=VALUE in a config file.
# Input: FILE KEY=VALUE
local config_file="$1"
local var_assignment="$2"
local var_name
var_name=$(echo "$var_assignment" | cut -d= -f1)
var_value=$(echo "$var_assignment" | cut -d= -f2-)
# Check if var already set (idempotence)
if grep -q "^${var_name}=" "$RC_CONF" 2>/dev/null; then
# Update existing (use | as delimiter to avoid issues with / in values)
sed -i '' "s|^${var_name}=.*|${var_assignment}|" "$RC_CONF"
if [ ! -f "$config_file" ]; then
mkdir -p "$(dirname "$config_file")"
touch "$config_file"
fi
if grep -q "^${var_name}=" "$config_file" 2>/dev/null; then
sed -i '' "s|^${var_name}=.*|${var_assignment}|" "$config_file"
else
# Append new
echo "$var_assignment" >> "$RC_CONF"
echo "$var_assignment" >> "$config_file"
fi
}
# ============================================================================
# MAC_DO FRAMEWORK
# ============================================================================
clawdie_shell_system_setup_mac_do() {
# Load FreeBSD mac_do at boot, but grant no credential transitions yet.
# FreeBSD 15 accepts an empty rule list as no-op policy: security.mac.do.rules=
clawdie_shell_system_set_config_line "$LOADER_CONF" 'mac_do_load="YES"'
clawdie_shell_system_set_config_line "$SYSCTL_CONF" 'security.mac.do.rules='
# Best-effort live activation for the firstboot session. The persistent
# loader/sysctl files above are the source of truth after reboot.
if command -v kldload >/dev/null 2>&1; then
kldload mac_do 2>/dev/null || true
elif [ -x /sbin/kldload ]; then
/sbin/kldload mac_do 2>/dev/null || true
fi
if command -v sysctl >/dev/null 2>&1; then
sysctl security.mac.do.rules= >/dev/null 2>&1 || true
elif [ -x /sbin/sysctl ]; then
/sbin/sysctl security.mac.do.rules= >/dev/null 2>&1 || true
fi
}
@ -249,6 +290,17 @@ clawdie_shell_system_validate() {
return 1
fi
# Check mac_do framework config exists. Empty rules intentionally grant no
# credential transitions.
if ! grep -q '^mac_do_load="YES"' "$LOADER_CONF" 2>/dev/null; then
echo "ERROR: mac_do_load not set in $LOADER_CONF" >&2
return 1
fi
if ! grep -q '^security.mac.do.rules=' "$SYSCTL_CONF" 2>/dev/null; then
echo "ERROR: security.mac.do.rules not set in $SYSCTL_CONF" >&2
return 1
fi
# Check environment profile exists
if [ ! -f "$PROFILE_DIR/clawdie.sh" ]; then
echo "ERROR: $PROFILE_DIR/clawdie.sh not created" >&2

View file

@ -22,6 +22,19 @@ export ZFSBOOT_POOL_NAME="clawdie"
set -e
set_config_line() {
_file="$1"
_assignment="$2"
_name=$(echo "$_assignment" | cut -d= -f1)
mkdir -p "$(dirname "$_file")"
touch "$_file"
if grep -q "^${_name}=" "$_file" 2>/dev/null; then
sed -i '' "s|^${_name}=.*|${_assignment}|" "$_file"
else
echo "$_assignment" >> "$_file"
fi
}
USB_SHARE="/usr/local/share/clawdie-iso"
HDD_SHARE="/mnt/usr/local/share/clawdie-iso"
HDD_RCD="/mnt/usr/local/etc/rc.d"
@ -49,6 +62,10 @@ mkdir -p "$HDD_RCD"
cp "${USB_SHARE}/firstboot/rc.d/clawdie-firstboot" "${HDD_RCD}/clawdie-firstboot"
chmod +x "${HDD_RCD}/clawdie-firstboot"
# Enable mac_do framework at first HDD boot with no credential grants yet.
set_config_line /mnt/boot/loader.conf 'mac_do_load="YES"'
set_config_line /mnt/etc/sysctl.conf 'security.mac.do.rules='
# Enable service in rc.conf on HDD
echo 'clawdie_firstboot_enable="YES"' >> /mnt/etc/rc.conf

View file

@ -167,6 +167,13 @@ EOF
# loader.conf
cat > /mnt/boot/loader.conf <<EOF
zfs_load="YES"
mac_do_load="YES"
EOF
# mac_do framework starts with no credential grants. Specific rules are added
# only when a concrete operator workflow needs them.
cat > /mnt/etc/sysctl.conf <<EOF
security.mac.do.rules=
EOF
# Minimal rc.conf (firstboot.sh will configure the rest)