From 718fb12ef716e69da7689f4f4a19470e6d3f46c7 Mon Sep 17 00:00:00 2001 From: jochens Date: Tue, 29 Sep 2026 23:39:36 +0200 Subject: [PATCH] icecast: its passwords are a file the mesh writes, not the image's environment The image seds ICECAST_*_PASSWORD from the environment into /etc/icecast.xml; ADR 0086 wants secrets as files. icecast starts as root, reads its config, then drops to uid 100, so a root-owned 0600 icecast.xml rendered with ${secret:...} and mounted read-only works and the entrypoint's seds never fire (no env set). The "secrets-in-environment" exemption and server.env are gone. Also: directories are placed (state, logs owned 100:101 so the image's VOLUME /var/log/icecast is not an anonymous volume per container, as HAL learned); the server and sidecar share a module network, so the sidecar reaches http://icecast:8000 instead of assuming machine port 8000 on the host; the stream endpoint is routed (label "icecast"), as HAL served it via traefik. Secrets remain mesh-vault grants (requires secret), now under ${dir:state}. Verified: catalogue tests with MESH_CATALOGUE pointed at this tree; a throwaway container of the pinned digest (the one ace runs) with the rendered file (dummy secrets, root 0600, :ro): runs as icecast, status-json 200, admin 401 without / 200 with the admin secret, a source PUT with the source secret mounts, a listener receives it, a wrong source password gets 401, logs land in the uid-100 directory. --- modules/icecast/module.json | 69 +++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/modules/icecast/module.json b/modules/icecast/module.json index 3a3e5a6..b3a1df1 100644 --- a/modules/icecast/module.json +++ b/modules/icecast/module.json @@ -1,6 +1,26 @@ { "module": "icecast", "version": "1", + "requires": [ + "route", + "secret" + ], + "contributes": { + "route": { + "label": "icecast", + "endpoint": "stream" + } + }, + "binds": { + "route": "${dir:state}/route.json" + }, + "secrets": { + "secret": { + "source": "${dir:state}/source.secret", + "admin": "${dir:state}/admin.secret", + "relay": "${dir:state}/relay.secret" + } + }, "capabilities": [ "container-runtime" ], @@ -17,7 +37,7 @@ "port": 8000, "protocol": "tcp", "from": "mesh", - "why": "streams in from sources and out to listeners" + "why": "streams in from sources (HTTP PUT) and out to listeners, plus the status and admin pages; a public name is its route" } ], "resources": [ @@ -30,28 +50,43 @@ { "id": "state", "type": "directory", - "path": "/var/lib/icecast-module", - "mode": "0700" + "mode": "0700", + "place": "." }, { - "id": "server-env", + "id": "logs", + "type": "directory", + "mode": "0700", + "owner": "100:101" + }, + { + "id": "server-conf", "type": "file", - "path": "/var/lib/icecast-module/server.env", + "path": "${dir:state}/icecast.xml", "mode": "0600", - "content": "ICECAST_SOURCE_PASSWORD=${secret:source}\nICECAST_ADMIN_PASSWORD=${secret:admin}\nICECAST_RELAY_PASSWORD=${secret:relay}\nICECAST_ADMIN_USERNAME=admin\n" + "content": "\n \n Earth\n icemaster@localhost\n \n 100\n 2\n 524288\n 30\n 15\n 10\n 1\n 65535\n \n \n ${secret:source}\n ${secret:relay}\n admin\n ${secret:admin}\n \n \n localhost\n \n 8000\n \n \n
\n \n 1\n \n /usr/share/icecast\n /var/log/icecast\n /usr/share/icecast/web\n /usr/share/icecast/admin\n \n \n \n access.log\n error.log\n 3\n 10000\n \n \n 0\n \n \n icecast\n icecast\n \n \n\n" + }, + { + "id": "net", + "type": "network", + "name": "icecast" }, { "id": "server", "type": "container", "name": "icecast", "image": "infiniteproject/icecast@sha256:cd506cf3dfe31ce05fd37d7e672dbd1213e7255cc93d28ecf5a3b547af4e162c", - "env-file": [ - "/var/lib/icecast-module/server.env" - ], + "network": "icecast", "ports": [ "8000" ], - "secrets-in-environment": "the image seds ICECAST_*_PASSWORD into icecast.xml and has no _FILE; convertible by mounting a generated icecast.xml, not yet done" + "volumes": [ + "${dir:state}/icecast.xml:/etc/icecast.xml:ro", + "${dir:logs}:/var/log/icecast" + ], + "restart-on": [ + "server-conf" + ] }, { "id": "runtime-config", @@ -65,14 +100,14 @@ "id": "runtime", "type": "container", "name": "mesh-icecast", - "network": "host", + "network": "icecast", "volumes": [ "/var/lib/mesh/icecast/broker:/run/secrets/broker:ro", "/var/lib/mesh/icecast/config.json:/run/config/config.json:ro" ], "env": { "MESH_BROKER_FILE": "/run/secrets/broker", - "MESH_ICECAST_URL": "http://127.0.0.1:8000", + "MESH_ICECAST_URL": "http://icecast:8000", "MESH_ICECAST_CONFIG_FILE": "/run/config/config.json" }, "restart-on": [ @@ -101,15 +136,5 @@ "from": "Dockerfile" } ] - }, - "requires": [ - "secret" - ], - "secrets": { - "secret": { - "source": "/var/lib/icecast-module/source.secret", - "admin": "/var/lib/icecast-module/admin.secret", - "relay": "/var/lib/icecast-module/relay.secret" - } } }