Stop shipping "hackme" as the Icecast password
Build edge-node / build (push) Failing after 6s
CI / lint (push) Successful in 6s
CI / test (push) Successful in 40s
Build op25 / build (push) Successful in 1m48s
Build icecast / build (push) Successful in 3m16s

The source password had a `hackme` fallback in five places -- entrypoint.sh,
docker-compose.yml, setup.sh's prompt default, .env.example, edge-node's
config.py -- plus op25-container's os.getenv default and two README rows. Any
node whose operator pressed Enter through setup.sh is running a credential
that is written down in this repo.

That matters more than the usual default-password case because Icecast binds
all interfaces and the SOURCE password is write access: it does not just let a
LAN neighbour listen, it lets them PUSH audio into the stream the frontend and
mobile clients play as live radio. Injecting fake traffic into a public-safety
feed is the failure worth preventing.

Approach: remove every fallback rather than change them to a better default.
- icecast/entrypoint.sh refuses to start if either password is empty, and says
  how to generate one. This is the single hard gate; everything else is
  defence in depth behind it.
- docker-compose.yml uses ${VAR:?message} so a missing value stops the stack
  at compose time with a readable error instead of becoming an empty string.
- setup.sh GENERATES a random password when the operator presses Enter, via
  openssl rand -base64 24 with a /dev/urandom fallback. Pressing Enter now
  gives you a random password rather than a known one, which is the actual
  behaviour change -- a prompt default nobody types over is not a default, it
  is the value.
- .env.example ships the keys empty with the generation command in a comment,
  and README.md now marks both as required with no default.

Client suite: 185 passed.

Note this does NOT rotate anything already deployed. node-002's .env still has
whatever it was set up with; that is an operational step, tracked in the issue.

Closes logan/node-26#3
This commit is contained in:
Logan Cusano
2026-08-20 03:12:44 -04:00
parent 28266b4441
commit e6aab7589a
7 changed files with 45 additions and 13 deletions
+19 -3
View File
@@ -95,10 +95,26 @@ read -rp "MQTT username [drb-node]: " MQTT_USER; MQTT_USER="${MQTT_USER:-drb-nod
read -rsp "MQTT password: " MQTT_PASS; echo ""; MQTT_PASS="${MQTT_PASS:-change-me-node}"
# --- Icecast ---
# Generated, not defaulted. Icecast binds all interfaces, and the SOURCE
# password is what lets a caller push audio into the stream users listen to as
# live radio -- so a shared default is worse here than a forgotten password.
# Pressing Enter gives you a random one rather than a known one.
gen_password() {
if command -v openssl >/dev/null 2>&1; then
openssl rand -base64 24 | tr -d '
'
else
head -c 24 /dev/urandom | base64 | tr -d '
'
fi
}
echo ""
echo "Icecast passwords (local container)"
read -rsp "Source password [hackme]: " ICECAST_SOURCE; echo ""; ICECAST_SOURCE="${ICECAST_SOURCE:-hackme}"
read -rsp "Admin password [admin]: " ICECAST_ADMIN; echo ""; ICECAST_ADMIN="${ICECAST_ADMIN:-admin}"
echo "Icecast passwords (local container). Press Enter to generate a random one."
read -rsp "Source password [generate]: " ICECAST_SOURCE; echo ""
if [ -z "$ICECAST_SOURCE" ]; then ICECAST_SOURCE="$(gen_password)"; echo " generated a random source password"; fi
read -rsp "Admin password [generate]: " ICECAST_ADMIN; echo ""
if [ -z "$ICECAST_ADMIN" ]; then ICECAST_ADMIN="$(gen_password)"; echo " generated a random admin password"; fi
# --- Write .env ---
cat > .env <<EOF