projection: begin the exact-path public epoch
The public tree and its history contain only the listed paths. Earlier projection history remains preserved internally. Source-Sha: 913fde029b935671833254797f0f20f1eb9fabba Policy-Sha: 913fde029b935671833254797f0f20f1eb9fabba Tree-Digest: 180ae530c1058a2a5c89837bdce2d323ae83e669e38590ca72e75b8d92b7262f
This commit is contained in:
commit
67e26be2d9
838 changed files with 157302 additions and 0 deletions
32
installer/linux/debian/control.in
Normal file
32
installer/linux/debian/control.in
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
Package: redflag
|
||||
Version: @VERSION@
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
Maintainer: @MAINTAINER@
|
||||
Depends: libc6 (>= 2.31),
|
||||
sudo,
|
||||
systemd,
|
||||
policykit-1 | polkitd,
|
||||
ca-certificates,
|
||||
python3,
|
||||
python3-cryptography,
|
||||
libqt6core6 | libqt6core6t64,
|
||||
libqt6gui6 | libqt6gui6t64,
|
||||
libqt6widgets6 | libqt6widgets6t64,
|
||||
libqt6qml6,
|
||||
libqt6quick6,
|
||||
qml6-module-qtquick,
|
||||
qml6-module-qtquick-controls,
|
||||
qml6-module-qtquick-layouts,
|
||||
qml6-module-qtquick-window
|
||||
Recommends: jq
|
||||
Homepage: https://github.com/Fimeg/RedFlag
|
||||
Description: RedFlag security agent, privileged helper and desktop console
|
||||
RedFlag inspects the host's package state and gates privileged mutation
|
||||
behind signed, host-bound capability tokens executed by a root helper.
|
||||
.
|
||||
This package installs the agent service, the privileged helper, and the
|
||||
Qt desktop operations console. It provisions a standalone local mint
|
||||
authority; hosts enrolled in a RedFlag fleet keep their fleet credentials
|
||||
and are never converted.
|
||||
171
installer/linux/debian/postinst
Normal file
171
installer/linux/debian/postinst
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
#!/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
|
||||
|
||||
# ---- 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. A real file at
|
||||
# the link path is left alone: that is a helper-performed self-update binary,
|
||||
# and clobbering it would silently downgrade the running install.
|
||||
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 exists and is not a symlink — leaving it (self-updated binary?); packaged build is at $PKG_BIN_DIR/$b"
|
||||
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"
|
||||
fi
|
||||
else
|
||||
warn "$PROVISION missing or not executable — standalone authority not provisioned"
|
||||
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 || true
|
||||
systemctl enable redflag-agent.service || true
|
||||
systemctl restart redflag-agent.service || \
|
||||
warn "redflag-agent did not start — check: journalctl -u redflag-agent"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
34
installer/linux/debian/postrm
Normal file
34
installer/linux/debian/postrm
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#!/bin/sh
|
||||
# Removal drops package-created state outside dpkg's file list. Config, keys and
|
||||
# the journal survive `remove` and are only destroyed on `purge` — a re-install
|
||||
# over a removed package must find its authority intact.
|
||||
set -e
|
||||
|
||||
RUN_BIN_DIR=/usr/local/bin
|
||||
|
||||
case "$1" in
|
||||
remove|purge)
|
||||
for b in redflag-agent redflag-helper redflag-desktop; do
|
||||
# Only our own symlinks; a self-updated real binary is left for the operator.
|
||||
if [ -L "$RUN_BIN_DIR/$b" ]; then
|
||||
rm -f "$RUN_BIN_DIR/$b"
|
||||
fi
|
||||
done
|
||||
[ -d /run/systemd/system ] && systemctl daemon-reload || true
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$1" = purge ]; then
|
||||
# Authority material is root-owned and irreplaceable; say what is going.
|
||||
echo "[INFO] [deb] [postrm] purging RedFlag configuration, local authority key and journal"
|
||||
rm -f /etc/sudoers.d/redflag-agent-mint
|
||||
rm -rf /etc/redflag /var/lib/redflag /var/log/redflag
|
||||
if getent passwd redflag-agent >/dev/null 2>&1; then
|
||||
deluser --system redflag-agent >/dev/null 2>&1 || true
|
||||
fi
|
||||
if getent group redflag-local >/dev/null 2>&1; then
|
||||
delgroup --system redflag-local >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
13
installer/linux/debian/prerm
Normal file
13
installer/linux/debian/prerm
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/sh
|
||||
# Stop the agent before files go away. Upgrades leave it disabled-then-restarted
|
||||
# by postinst; only a real removal disables it.
|
||||
set -e
|
||||
|
||||
if [ -d /run/systemd/system ]; then
|
||||
systemctl stop redflag-agent.service || true
|
||||
if [ "$1" = remove ] || [ "$1" = purge ]; then
|
||||
systemctl disable redflag-agent.service || true
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
Loading…
Reference in a new issue