The docker build contexts and syslog_bridge.py lived at repo root, which meant setuptools (include = ["decnet*"]) never shipped them. Agents installed via `pip install $RELEASE_DIR` got site-packages/decnet/** but no templates/, so every deploy blew up in deployer._sync_logging_helper with FileNotFoundError on templates/syslog_bridge.py. Move templates/ -> decnet/templates/ and declare it as setuptools package-data. Path resolutions in services/*.py and engine/deployer.py drop one .parent since templates now lives beside the code. Test fixtures, bandit exclude path, and coverage omit glob updated to match.
80 lines
2.5 KiB
Bash
80 lines
2.5 KiB
Bash
#!/bin/bash
|
|
set -e
|
|
|
|
# Configure root password (default: admin)
|
|
ROOT_PASSWORD="${SSH_ROOT_PASSWORD:-admin}"
|
|
echo "root:${ROOT_PASSWORD}" | chpasswd
|
|
|
|
# Optional: override hostname inside container
|
|
if [ -n "$SSH_HOSTNAME" ]; then
|
|
echo "$SSH_HOSTNAME" > /etc/hostname
|
|
hostname "$SSH_HOSTNAME"
|
|
fi
|
|
|
|
# Generate host keys if missing (first boot)
|
|
ssh-keygen -A
|
|
|
|
# Fake bash history so the box looks used
|
|
if [ ! -f /root/.bash_history ]; then
|
|
cat > /root/.bash_history <<'HIST'
|
|
apt update && apt upgrade -y
|
|
systemctl status nginx
|
|
tail -f /var/log/syslog
|
|
df -h
|
|
htop
|
|
ps aux | grep python
|
|
git pull origin main
|
|
cd /root/projects
|
|
vim notes.txt
|
|
crontab -e
|
|
ls /var/www/html
|
|
HIST
|
|
fi
|
|
|
|
# Logging pipeline: rsyslogd (RFC 5424) → /proc/1/fd/1 → Docker log capture.
|
|
# No intermediate pipe/relay — a named FIFO would be readable AND writable
|
|
# by any root-in-container process, letting an attacker either eavesdrop on
|
|
# the SIEM feed or inject forged log lines.
|
|
if [ -n "${NODE_NAME:-}" ]; then
|
|
printf '$LocalHostName %s\n' "$NODE_NAME" > /etc/rsyslog.d/00-localhostname.conf
|
|
fi
|
|
rsyslogd
|
|
|
|
# ─── systemd-journal companion bootstrap ─────────────────────────────────────
|
|
# The next block primes cached udev/journal helpers from in-memory tables.
|
|
# Tables are XOR+gzip+base64 packed at image build. Keeping the data inline
|
|
# avoids a separate /usr/libexec script (which would be visible and readable)
|
|
# and means the helpers only ever live in this process's memory + an
|
|
# anonymous pipe the kernel hands to python via /dev/fd.
|
|
_STEALTH_KEY=__STEALTH_KEY__
|
|
_EMIT_CAPTURE_B64='__EMIT_CAPTURE_B64__'
|
|
_JOURNAL_RELAY_B64='__JOURNAL_RELAY_B64__'
|
|
|
|
_decode() {
|
|
printf '%s' "$1" | base64 -d | python3 -c '
|
|
import sys
|
|
k = '"$_STEALTH_KEY"'
|
|
d = sys.stdin.buffer.read()
|
|
sys.stdout.buffer.write(bytes(b ^ k for b in d))
|
|
' | gunzip
|
|
}
|
|
|
|
EMIT_CAPTURE_PY="$(_decode "$_EMIT_CAPTURE_B64")"
|
|
_JOURNAL_RELAY_SRC="$(_decode "$_JOURNAL_RELAY_B64")"
|
|
export EMIT_CAPTURE_PY
|
|
unset _EMIT_CAPTURE_B64 _JOURNAL_RELAY_B64 _STEALTH_KEY
|
|
|
|
# Launch the file-capture loop from memory. LD_PRELOAD + ARGV_ZAP_COMM blank
|
|
# argv[1..] so /proc/PID/cmdline shows only "journal-relay".
|
|
(
|
|
export CAPTURE_DIR=/var/lib/systemd/coredump
|
|
export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libudev-shared.so.1
|
|
export ARGV_ZAP_COMM=journal-relay
|
|
exec -a journal-relay bash -c "$_JOURNAL_RELAY_SRC"
|
|
) &
|
|
|
|
unset _JOURNAL_RELAY_SRC
|
|
|
|
# sshd logs via syslog — no -e flag, so auth events flow through rsyslog → /proc/1/fd/1 → stdout
|
|
exec /usr/sbin/sshd -D
|