fix: harden container isolation in first-boot script (PENTEST-03)
Add --cap-drop ALL and --security-opt no-new-privileges:true to all containers in first-boot-containers.sh that were missing it: - Bitcoin Knots, LND, Fedimint, Fedimint Gateway (+ CHOWN/SETUID/SETGID) - BTCPay Server, Home Assistant (+ CHOWN/SETUID/SETGID/DAC_OVERRIDE) - Nextcloud (+ CHOWN/SETUID/SETGID/DAC_OVERRIDE) - Grafana, Uptime Kuma, PhotoPrism, Ollama, Vaultwarden, FileBrowser (zero extra caps + --read-only + tmpfs for /tmp and /run) - Jellyfin (zero extra caps) Tailscale retains --privileged (required for TUN/iptables/routing). SearXNG, OnlyOffice, Nginx Proxy Manager, Portainer already hardened. The Rust RPC layer already applies equivalent hardening for all UI installs; this brings the ISO first-boot path to parity. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -45,6 +45,8 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -qE 'bitcoin-knots|arch
|
||||
log "Creating Bitcoin Knots..."
|
||||
mkdir -p /var/lib/archipelago/bitcoin
|
||||
if $DOCKER run -d --name bitcoin-knots --restart unless-stopped --network archy-net \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add SETUID --cap-add SETGID \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 8332:8332 -p 8333:8333 \
|
||||
-v /var/lib/archipelago/bitcoin:/home/bitcoin/.bitcoin \
|
||||
docker.io/bitcoinknots/bitcoin:latest \
|
||||
@@ -166,6 +168,8 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q btcpay-server; then
|
||||
log "Creating BTCPay Server..."
|
||||
mkdir -p /var/lib/archipelago/btcpay
|
||||
$DOCKER run -d --name btcpay-server --restart unless-stopped --network archy-net \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add SETUID --cap-add SETGID --cap-add DAC_OVERRIDE \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 23000:49392 -v /var/lib/archipelago/btcpay:/datadir \
|
||||
-e ASPNETCORE_URLS=http://0.0.0.0:49392 -e BTCPAY_PROTOCOL=http \
|
||||
-e BTCPAY_HOST="$TARGET_IP:23000" -e BTCPAY_CHAINS=btc \
|
||||
@@ -208,6 +212,8 @@ LNDCONF
|
||||
log "LND config created (archy-net → bitcoin-knots:8332, rpcpolling)"
|
||||
fi
|
||||
$DOCKER run -d --name lnd --restart unless-stopped --network archy-net \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add SETUID --cap-add SETGID \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 9735:9735 -p 10009:10009 -p 8080:8080 \
|
||||
-v /var/lib/archipelago/lnd:/root/.lnd \
|
||||
docker.io/lightninglabs/lnd:v0.18.4-beta 2>>"$LOG" || true
|
||||
@@ -218,6 +224,8 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q fedimint; then
|
||||
log "Creating Fedimint..."
|
||||
mkdir -p /var/lib/archipelago/fedimint
|
||||
$DOCKER run -d --name fedimint --restart unless-stopped --network archy-net \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add SETUID --cap-add SETGID \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 8173:8173 -p 8174:8174 -p 8175:8175 \
|
||||
-v /var/lib/archipelago/fedimint:/data \
|
||||
-e FM_DATA_DIR=/data -e FM_BITCOIND_USERNAME=archipelago -e FM_BITCOIND_PASSWORD=archipelago123 \
|
||||
@@ -238,6 +246,8 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q fedimint-gateway; th
|
||||
if $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q '^lnd$' && [ -f "$LND_CERT" ] && [ -f "$LND_MACAROON" ]; then
|
||||
log " LND detected — using lnd mode"
|
||||
$DOCKER run -d --name fedimint-gateway --restart unless-stopped --network archy-net \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add SETUID --cap-add SETGID \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 8176:8176 \
|
||||
-v /var/lib/archipelago/fedimint-gateway:/data \
|
||||
-v "$LND_CERT":/lnd/tls.cert:ro \
|
||||
@@ -251,6 +261,8 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q fedimint-gateway; th
|
||||
else
|
||||
log " No LND found — using ldk (built-in Lightning)"
|
||||
$DOCKER run -d --name fedimint-gateway --restart unless-stopped --network archy-net \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add SETUID --cap-add SETGID \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 8176:8176 -p 9737:9737 \
|
||||
-v /var/lib/archipelago/fedimint-gateway:/data \
|
||||
docker.io/fedimint/gatewayd:v0.10.0 \
|
||||
@@ -267,6 +279,8 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -qE 'homeassistant|home
|
||||
log "Creating Home Assistant..."
|
||||
mkdir -p /var/lib/archipelago/home-assistant
|
||||
$DOCKER run -d --name homeassistant --restart unless-stopped \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add SETUID --cap-add SETGID --cap-add DAC_OVERRIDE \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 8123:8123 -v /var/lib/archipelago/home-assistant:/config \
|
||||
-e TZ=UTC \
|
||||
docker.io/homeassistant/home-assistant:2024.1 2>>"$LOG" || true
|
||||
@@ -278,6 +292,9 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q grafana; then
|
||||
mkdir -p /var/lib/archipelago/grafana
|
||||
chown 472:472 /var/lib/archipelago/grafana 2>/dev/null || true
|
||||
$DOCKER run -d --name grafana --restart unless-stopped \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add SETUID --cap-add SETGID \
|
||||
--security-opt no-new-privileges:true \
|
||||
--read-only --tmpfs /tmp:rw,noexec,nosuid,size=256m --tmpfs /run:rw,noexec,nosuid,size=64m \
|
||||
-p 3000:3000 -v /var/lib/archipelago/grafana:/var/lib/grafana \
|
||||
-e GF_PATHS_DATA=/var/lib/grafana -e GF_USERS_ALLOW_SIGN_UP=false \
|
||||
docker.io/grafana/grafana:10.2.0 2>>"$LOG" || true
|
||||
@@ -286,6 +303,8 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q uptime-kuma; then
|
||||
log "Creating Uptime Kuma..."
|
||||
mkdir -p /var/lib/archipelago/uptime-kuma
|
||||
$DOCKER run -d --name uptime-kuma --restart unless-stopped \
|
||||
--cap-drop ALL --security-opt no-new-privileges:true \
|
||||
--read-only --tmpfs /tmp:rw,noexec,nosuid,size=256m --tmpfs /run:rw,noexec,nosuid,size=64m \
|
||||
-p 3001:3001 -v /var/lib/archipelago/uptime-kuma:/app/data \
|
||||
-e TZ=UTC \
|
||||
docker.io/louislam/uptime-kuma:1 2>>"$LOG" || true
|
||||
@@ -294,6 +313,7 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q jellyfin; then
|
||||
log "Creating Jellyfin..."
|
||||
mkdir -p /var/lib/archipelago/jellyfin/config /var/lib/archipelago/jellyfin/cache
|
||||
$DOCKER run -d --name jellyfin --restart unless-stopped \
|
||||
--cap-drop ALL --security-opt no-new-privileges:true \
|
||||
-p 8096:8096 \
|
||||
-v /var/lib/archipelago/jellyfin/config:/config \
|
||||
-v /var/lib/archipelago/jellyfin/cache:/cache \
|
||||
@@ -303,6 +323,8 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q photoprism; then
|
||||
log "Creating PhotoPrism..."
|
||||
mkdir -p /var/lib/archipelago/photoprism
|
||||
$DOCKER run -d --name photoprism --restart unless-stopped \
|
||||
--cap-drop ALL --security-opt no-new-privileges:true \
|
||||
--read-only --tmpfs /tmp:rw,noexec,nosuid,size=256m --tmpfs /run:rw,noexec,nosuid,size=64m \
|
||||
-p 2342:2342 -v /var/lib/archipelago/photoprism:/photoprism/storage \
|
||||
-e PHOTOPRISM_ADMIN_PASSWORD=archipelago -e PHOTOPRISM_DEFAULT_LOCALE=en \
|
||||
docker.io/photoprism/photoprism:latest 2>>"$LOG" || true
|
||||
@@ -311,6 +333,8 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q ollama; then
|
||||
log "Creating Ollama..."
|
||||
mkdir -p /var/lib/archipelago/ollama
|
||||
$DOCKER run -d --name ollama --restart unless-stopped \
|
||||
--cap-drop ALL --security-opt no-new-privileges:true \
|
||||
--read-only --tmpfs /tmp:rw,noexec,nosuid,size=256m --tmpfs /run:rw,noexec,nosuid,size=64m \
|
||||
-p 11434:11434 -v /var/lib/archipelago/ollama:/root/.ollama \
|
||||
docker.io/ollama/ollama:latest 2>>"$LOG" || true
|
||||
fi
|
||||
@@ -318,6 +342,8 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q vaultwarden; then
|
||||
log "Creating Vaultwarden..."
|
||||
mkdir -p /var/lib/archipelago/vaultwarden
|
||||
$DOCKER run -d --name vaultwarden --restart unless-stopped \
|
||||
--cap-drop ALL --security-opt no-new-privileges:true \
|
||||
--read-only --tmpfs /tmp:rw,noexec,nosuid,size=256m --tmpfs /run:rw,noexec,nosuid,size=64m \
|
||||
-p 8082:80 -v /var/lib/archipelago/vaultwarden:/data \
|
||||
docker.io/vaultwarden/server:1.30.0-alpine 2>>"$LOG" || true
|
||||
fi
|
||||
@@ -325,6 +351,8 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q nextcloud; then
|
||||
log "Creating Nextcloud..."
|
||||
mkdir -p /var/lib/archipelago/nextcloud
|
||||
$DOCKER run -d --name nextcloud --restart unless-stopped \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add SETUID --cap-add SETGID --cap-add DAC_OVERRIDE \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 8085:80 -v /var/lib/archipelago/nextcloud:/var/www/html \
|
||||
docker.io/library/nextcloud:28 2>>"$LOG" || true
|
||||
fi
|
||||
@@ -348,6 +376,8 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q filebrowser; then
|
||||
log "Creating File Browser..."
|
||||
mkdir -p /var/lib/archipelago/filebrowser /var/lib/archipelago/filebrowser-db
|
||||
$DOCKER run -d --name filebrowser --restart unless-stopped \
|
||||
--cap-drop ALL --security-opt no-new-privileges:true \
|
||||
--read-only --tmpfs /tmp:rw,noexec,nosuid,size=256m --tmpfs /run:rw,noexec,nosuid,size=64m \
|
||||
-p 8083:80 -v /var/lib/archipelago/filebrowser:/srv \
|
||||
-v /var/lib/archipelago/filebrowser-db:/database \
|
||||
docker.io/filebrowser/filebrowser:v2.27.0 2>>"$LOG" || true
|
||||
@@ -377,6 +407,7 @@ fi
|
||||
if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q tailscale; then
|
||||
log "Creating Tailscale..."
|
||||
mkdir -p /var/lib/archipelago/tailscale
|
||||
# Tailscale requires --privileged for TUN/iptables/routing table access
|
||||
$DOCKER run -d --name tailscale --restart unless-stopped \
|
||||
--network host --privileged \
|
||||
--cap-add NET_ADMIN --cap-add NET_RAW \
|
||||
|
||||
Reference in New Issue
Block a user