security: Fix Docker port bindings and externalize all passwords

CRITICAL SECURITY FIXES:
- Bind all Docker services to localhost only (127.0.0.1)
- Prevents external access to Liquidsoap telnet (port 1234)
- Prevents direct Icecast access without HAproxy (port 8000)
- Secures PostgreSQL port (5432)

DOCKER CHANGES (docker-compose.yml):
- Icecast: 127.0.0.1:8000:8000 (was 8000:8000)
- Liquidsoap: 127.0.0.1🔢1234 (was 1234:1234)
- PostgreSQL: 127.0.0.1:5432:5432 (was 5432:5432)
- All passwords now use environment variables

CONFIG TEMPLATE:
- Added ICECAST_SOURCE_PASSWORD
- Added ICECAST_RELAY_PASSWORD
- Documented all Docker password variables

Addresses TODO items from b612.asteroid.radio deployment:
- Problem 1: Liquidsoap telnet exposed  FIXED
- Problem 2: Icecast binding to 0.0.0.0  FIXED

This prevents the security issues that forced Fade to shut down
the production server. Services are now only accessible via
HAproxy on the host machine.

Ref: TODO.org lines 25-27
This commit is contained in:
glenneth 2025-11-03 19:47:53 +03:00
parent 3a7fb4b223
commit ce4fced380
3 changed files with 47 additions and 13 deletions

View File

@ -71,23 +71,52 @@ Eliminated hardcoded Icecast admin password from codebase.
- ~*supported-formats*~~(config-supported-formats *config*)~
- ~*stream-base-url*~~(config-stream-base-url *config*)~
** Docker Security Fixes (~docker/docker-compose.yml~) - CRITICAL
*** Port Bindings Secured
All services now bind to localhost only (127.0.0.1) instead of 0.0.0.0:
- *Icecast*: ~127.0.0.1:8000:8000~ - Use HAproxy to expose publicly
- *Liquidsoap telnet*: ~127.0.0.1:1234:1234~ - Never expose to internet
- *PostgreSQL*: ~127.0.0.1:5432:5432~ - Database access from host only
This prevents external access to:
- Liquidsoap telnet management interface (Problem 1)
- Direct Icecast access without HAproxy (Problem 2)
- PostgreSQL database port
*** Passwords Externalized
All Docker container passwords now use environment variables:
#+BEGIN_SRC yaml
environment:
- ICECAST_SOURCE_PASSWORD=${ICECAST_SOURCE_PASSWORD:-default}
- ICECAST_ADMIN_PASSWORD=${ICECAST_ADMIN_PASSWORD:-default}
- ICECAST_RELAY_PASSWORD=${ICECAST_RELAY_PASSWORD:-default}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-default}
#+END_SRC
* TODO Items Addressed
** DONE Problem 4: Templates no longer advertise default admin password
** DONE Server runtime configuration: All configuration parameterized and loaded from environment
** DONE Problem 1: Liquidsoap telnet binding secured (localhost only)
** DONE Problem 2: Icecast external binding secured (localhost only)
** TODO Problem 3: Database backend selection implemented (PostgreSQL support ready, migration needed)
* Production Deployment Issues (From b612.asteroid.radio Test)
** Critical Security (Must fix before public launch)
- [ ] *Problem 1*: Fix Liquidsoap telnet binding (currently exposed on external interface)
- [X] *Problem 1*: Fix Liquidsoap telnet binding ✅ FIXED
- Issue: ~telnet asteroid.radio 1234~ works from anywhere
- Fix: Bind to localhost only in Docker config
- Fix: Bind to ~127.0.0.1:1234:1234~ in docker-compose.yml
- [ ] *Problem 2*: Fix Icecast external binding
- [X] *Problem 2*: Fix Icecast external binding ✅ FIXED
- Issue: Icecast binding to 0.0.0.0
- Fix: Bind to localhost only, use HAproxy to proxy
- Fix: Bind to ~127.0.0.1:8000:8000~, use HAproxy to proxy
- [ ] *Problem 5*: Set up TLS/Let's Encrypt with HAproxy

View File

@ -30,6 +30,11 @@ ASTEROID_STREAM_URL=http://localhost:8000
ICECAST_ADMIN_USER=admin
ICECAST_ADMIN_PASSWORD=CHANGE_THIS_PASSWORD
# Additional Icecast passwords (used by Docker containers)
# These are for Liquidsoap source connection and relay
ICECAST_SOURCE_PASSWORD=CHANGE_THIS_PASSWORD
ICECAST_RELAY_PASSWORD=CHANGE_THIS_PASSWORD
# ============================================================================
# DATABASE CONFIGURATION
# ============================================================================

View File

@ -3,13 +3,13 @@ services:
image: infiniteproject/icecast:latest
container_name: asteroid-icecast
ports:
- "8000:8000"
- "127.0.0.1:8000:8000" # Bind to localhost only - use HAproxy to expose publicly
volumes:
- ./icecast.xml:/etc/icecast.xml
environment:
- ICECAST_SOURCE_PASSWORD=H1tn31EhsyLrfRmo
- ICECAST_ADMIN_PASSWORD=asteroid_admin_2024
- ICECAST_RELAY_PASSWORD=asteroid_relay_2024
- ICECAST_SOURCE_PASSWORD=${ICECAST_SOURCE_PASSWORD:-H1tn31EhsyLrfRmo}
- ICECAST_ADMIN_PASSWORD=${ICECAST_ADMIN_PASSWORD:-asteroid_admin_2024}
- ICECAST_RELAY_PASSWORD=${ICECAST_RELAY_PASSWORD:-asteroid_relay_2024}
restart: unless-stopped
networks:
- asteroid-network
@ -20,7 +20,7 @@ services:
dockerfile: Dockerfile.liquidsoap
container_name: asteroid-liquidsoap
ports:
- "1234:1234"
- "127.0.0.1:1234:1234" # Bind telnet to localhost only - SECURITY: Never expose to internet
depends_on:
- icecast
volumes:
@ -35,11 +35,11 @@ services:
image: postgres:16-alpine
container_name: asteroid-postgres
environment:
POSTGRES_DB: asteroid
POSTGRES_USER: asteroid
POSTGRES_PASSWORD: asteroid_db_2025
POSTGRES_DB: ${POSTGRES_DB:-asteroid}
POSTGRES_USER: ${POSTGRES_USER:-asteroid}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-asteroid_db_2025}
ports:
- "5432:5432"
- "127.0.0.1:5432:5432" # Bind to localhost only
volumes:
- postgres-data:/var/lib/postgresql/data
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro