RedFlag/installer/linux/debian/postinst
Fimeg 765ec4188f publish: carry the Windows product into the projection
The tree adds the installer, service and test paths admitted by this source commit. Nothing else changes about what may cross.

Source-Sha: 3e4a3aa4ce092e9e3f51bc78daf3ddc14d9638f8

Policy-Sha: 3e4a3aa4ce092e9e3f51bc78daf3ddc14d9638f8

Tree-Digest: 89d6fce3828a0e0de0c8eeb41ee6750f4462217e2a04b5190297134d7f4a50c3
2026-09-09 12:47:34 -04:00

187 lines
7.7 KiB
Shell

#!/bin/sh
# RedFlag Debian postinst.
#
# Idempotent by construction: every step either verifies existing state or
# creates it. Existing configuration, keys and fleet credentials are never
# overwritten, and a fleet-enrolled host is never converted to standalone —
# standalone provisioning is skipped entirely when fleet material is present.
set -e
AGENT_USER=redflag-agent
LOCAL_GROUP=redflag-local
PKG_BIN_DIR=/usr/bin
RUN_BIN_DIR=/usr/local/bin
CONFIG_DIR=/etc/redflag
AGENT_CONFIG_DIR=$CONFIG_DIR/agent
AGENT_CONFIG=$AGENT_CONFIG_DIR/config.json
SERVER_KEY_DIR=$CONFIG_DIR/server
BASE_DIR=/var/lib/redflag
AGENT_HOME=$BASE_DIR/agent
LOG_DIR=/var/log/redflag/agent
PROVISION=/usr/lib/redflag/provision-standalone-authority.sh
VERSION="@VERSION@"
log() { echo "[INFO] [deb] [postinst] $*"; }
warn() { echo "[WARN] [deb] [postinst] $*" >&2; }
case "$1" in
configure) ;;
abort-upgrade|abort-remove|abort-deconfigure) exit 0 ;;
*) exit 0 ;;
esac
# Also guard reconfiguration and recovery after an interrupted installation.
for b in redflag-agent redflag-helper redflag-desktop; do
path="$RUN_BIN_DIR/$b"
if [ -L "$path" ]; then
[ "$(readlink "$path")" = "$PKG_BIN_DIR/$b" ] && continue
elif [ ! -e "$path" ]; then
continue
fi
warn "$path is not the package runtime link; explicit migration is required"
exit 1
done
# ---- user, groups -----------------------------------------------------------
if ! getent group "$LOCAL_GROUP" >/dev/null 2>&1; then
addgroup --system "$LOCAL_GROUP"
fi
if ! id "$AGENT_USER" >/dev/null 2>&1; then
adduser --system --group --home "$AGENT_HOME" --no-create-home \
--shell /usr/sbin/nologin "$AGENT_USER"
fi
if ! id -nG "$AGENT_USER" | tr ' ' '\n' | grep -qx "$LOCAL_GROUP"; then
usermod -aG "$LOCAL_GROUP" "$AGENT_USER"
fi
# Container scanner reaches the docker socket by group membership, not sudo.
if getent group docker >/dev/null 2>&1; then
if ! id -nG "$AGENT_USER" | tr ' ' '\n' | grep -qx docker; then
usermod -aG docker "$AGENT_USER"
fi
fi
# ---- runtime paths ----------------------------------------------------------
# Re-asserted on every configure: upgrades from script installs carry
# agent:agent 0700 dirs that block redflag-local traversal to the local API
# socket, leaving Desktop installed but unable to connect.
install -d -m 0755 "$CONFIG_DIR" "$AGENT_CONFIG_DIR" "$SERVER_KEY_DIR"
# BASE_DIR is root-owned: rename permission comes from the parent directory, so
# an agent-owned BASE_DIR lets the agent swap the root-only helper staging dir
# for a symlink. Group execute still lets the agent reach its own subtree.
install -d -m 0710 -o root -g "$LOCAL_GROUP" "$BASE_DIR"
install -d -m 0710 -o "$AGENT_USER" -g "$LOCAL_GROUP" "$AGENT_HOME"
install -d -m 0750 -o "$AGENT_USER" -g "$LOCAL_GROUP" "$AGENT_HOME/localapi"
install -d -m 0750 -o "$AGENT_USER" -g "$AGENT_USER" \
"$AGENT_HOME/cache" "$AGENT_HOME/state" "$AGENT_HOME/results"
install -d -m 0700 -o "$AGENT_USER" -g "$AGENT_USER" "$AGENT_HOME/tokens"
install -d -m 0700 -o root -g root "$BASE_DIR/helper"
install -d -m 0750 -o "$AGENT_USER" -g "$AGENT_USER" "$LOG_DIR"
chown "$AGENT_USER":"$AGENT_USER" "$AGENT_CONFIG_DIR" "$SERVER_KEY_DIR"
# ---- runtime symlinks -------------------------------------------------------
# The agent, helper and their sudoers/service contracts all reference
# /usr/local/bin (agent/internal/constants/paths.go). Debian policy keeps
# package files out of /usr/local, so ship in /usr/bin and link. The preflight
# above refuses foreign paths; the package-managed helper refuses self-update.
for b in redflag-agent redflag-helper redflag-desktop; do
if [ -L "$RUN_BIN_DIR/$b" ] || [ ! -e "$RUN_BIN_DIR/$b" ]; then
install -d -m 0755 "$RUN_BIN_DIR"
ln -sfn "$PKG_BIN_DIR/$b" "$RUN_BIN_DIR/$b"
else
warn "$RUN_BIN_DIR/$b changed during configuration — refusing runtime takeover"
exit 1
fi
done
if command -v setcap >/dev/null 2>&1; then
setcap cap_sys_ptrace=eip "$PKG_BIN_DIR/redflag-agent" || \
warn "setcap failed — display/process discovery may be limited"
fi
# ---- configuration ----------------------------------------------------------
# Not a dpkg conffile: it holds credentials and is rewritten by the agent.
if [ -f "$AGENT_CONFIG" ]; then
log "existing configuration preserved at $AGENT_CONFIG"
else
log "fresh install — writing standalone configuration"
umask 077
cat > "$AGENT_CONFIG" <<EOF
{
"version": 5,
"agent_version": "${VERSION}",
"agent_id": "",
"token": "",
"refresh_token": "",
"registration_token": "",
"machine_id": "",
"check_in_interval": 300,
"server_url": "",
"network": {"timeout": 30000000000, "retry_count": 3, "retry_delay": 5000000000, "max_idle_conn": 10},
"proxy": {"enabled": false},
"tls": {"enabled": false, "insecure_skip_verify": false},
"logging": {"level": "info", "max_size": 100, "max_backups": 3, "max_age": 28},
"subsystems": {
"system": {"enabled": true, "timeout": 10000000000},
"filesystem": {"enabled": true, "timeout": 10000000000},
"network": {"enabled": true, "timeout": 30000000000},
"processes": {"enabled": true, "timeout": 30000000000},
"updates": {"enabled": true, "timeout": 30000000000},
"storage": {"enabled": true, "timeout": 10000000000}
},
"security": {"ed25519_verification": true, "nonce_validation": true, "machine_id_binding": true}
}
EOF
fi
chown "$AGENT_USER":"$AGENT_USER" "$AGENT_CONFIG"
chmod 0600 "$AGENT_CONFIG"
# ---- fleet detection --------------------------------------------------------
# Any of token / refresh_token / registration_token means this host answers to a
# server. Config.IsStandalone() is false for partial enrollment too, so the
# provisioning script would refuse — we refuse first and say why.
fleet_material() {
grep -Eq '"(token|refresh_token|registration_token)"[[:space:]]*:[[:space:]]*"[^"]+"' "$AGENT_CONFIG" 2>/dev/null
}
if fleet_material; then
log "fleet enrollment material present — standalone authority NOT provisioned"
log "this host keeps its fleet credentials; standalone-to-fleet conversion is not implemented in either direction"
elif [ -x "$PROVISION" ]; then
# The script is the single source of authority provisioning (key init,
# exchange dirs, mint sudoers). It is idempotent and refuses to overwrite an
# existing local authority.
if REDFLAG_BIN_DIR="$RUN_BIN_DIR" \
REDFLAG_CONFIG_DIR="$CONFIG_DIR" \
REDFLAG_STATE_DIR="$BASE_DIR" \
"$PROVISION"; then
log "standalone authority provisioned"
else
warn "standalone authority provisioning failed — agent installed, local approval unavailable"
warn "re-run once resolved: sudo REDFLAG_BIN_DIR=$RUN_BIN_DIR $PROVISION"
exit 1
fi
else
warn "$PROVISION missing or not executable — standalone authority not provisioned"
exit 1
fi
# ---- desktop access ---------------------------------------------------------
# The installing operator needs redflag-local to reach the agent's local API
# socket. Takes effect on next login.
if [ -n "${SUDO_USER:-}" ] && [ "$SUDO_USER" != root ]; then
if ! id -nG "$SUDO_USER" 2>/dev/null | tr ' ' '\n' | grep -qx "$LOCAL_GROUP"; then
usermod -aG "$LOCAL_GROUP" "$SUDO_USER"
log "added $SUDO_USER to $LOCAL_GROUP (Desktop socket access — re-login required)"
fi
fi
# ---- service ----------------------------------------------------------------
if [ -d /run/systemd/system ]; then
systemctl daemon-reload
systemctl enable redflag-agent.service
if ! systemctl restart redflag-agent.service; then
warn "redflag-agent did not start — check: journalctl -u redflag-agent"
exit 1
fi
fi
exit 0