diff --git a/.docker/docker-entrypoint.sh b/.docker/docker-entrypoint.sh index 9bbad5d0..c4151887 100755 --- a/.docker/docker-entrypoint.sh +++ b/.docker/docker-entrypoint.sh @@ -34,21 +34,30 @@ mkdir -p /app/data/geoip 2>/dev/null || true # Docker Socket Permission Handling # ============================================================================ # The Docker integration feature requires access to the Docker socket. -# When running as non-root user (charon), we need to ensure the user is in -# the same group as the mounted socket for permission access. +# This section runs as root to configure group membership, then privileges +# are dropped to the charon user at the end of this script. if [ -S "/var/run/docker.sock" ]; then DOCKER_SOCK_GID=$(stat -c '%g' /var/run/docker.sock 2>/dev/null || echo "") if [ -n "$DOCKER_SOCK_GID" ] && [ "$DOCKER_SOCK_GID" != "0" ]; then # Check if a group with this GID exists if ! getent group "$DOCKER_SOCK_GID" >/dev/null 2>&1; then - echo "Docker socket detected (gid=$DOCKER_SOCK_GID). Note: Container integration requires socket access." - echo " To enable Docker container discovery:" - echo " 1. Run container with --user root:root, OR" - echo " 2. Add host docker group: docker run --group-add $DOCKER_SOCK_GID ..., OR" - echo " 3. Change socket permissions: chmod 666 /var/run/docker.sock (not recommended)" + echo "Docker socket detected (gid=$DOCKER_SOCK_GID) - creating docker group and adding charon user..." + # Create docker group with the socket's GID + addgroup -g "$DOCKER_SOCK_GID" docker 2>/dev/null || true + # Add charon user to the docker group + addgroup charon docker 2>/dev/null || true + echo "Docker integration enabled for charon user" + else + # Group exists, just add charon to it + GROUP_NAME=$(getent group "$DOCKER_SOCK_GID" | cut -d: -f1) + echo "Docker socket detected (gid=$DOCKER_SOCK_GID, group=$GROUP_NAME) - adding charon user..." + addgroup charon "$GROUP_NAME" 2>/dev/null || true + echo "Docker integration enabled for charon user" fi fi +else + echo "Note: Docker socket not found. Docker container discovery will be unavailable." fi # ============================================================================ @@ -187,9 +196,10 @@ fi echo "CrowdSec configuration initialized. Agent lifecycle is GUI-controlled." # Start Caddy in the background with initial empty config +# Run Caddy as charon user for security echo '{"admin":{"listen":"0.0.0.0:2019"},"apps":{}}' > /config/caddy.json # Use JSON config directly; no adapter needed -caddy run --config /config/caddy.json & +su-exec charon:charon caddy run --config /config/caddy.json & CADDY_PID=$! echo "Caddy started (PID: $CADDY_PID)" @@ -206,6 +216,8 @@ while [ "$i" -le 30 ]; do done # Start Charon management application +# Drop privileges to charon user before starting the application +# This maintains security while allowing Docker socket access via group membership echo "Starting Charon management application..." DEBUG_FLAG=${CHARON_DEBUG:-$CPMP_DEBUG} DEBUG_PORT=${CHARON_DEBUG_PORT:-$CPMP_DEBUG_PORT} @@ -215,13 +227,13 @@ if [ "$DEBUG_FLAG" = "1" ]; then if [ ! -f "$bin_path" ]; then bin_path=/app/cpmp fi - /usr/local/bin/dlv exec "$bin_path" --headless --listen=":$DEBUG_PORT" --api-version=2 --accept-multiclient --continue --log -- & + su-exec charon:charon /usr/local/bin/dlv exec "$bin_path" --headless --listen=":$DEBUG_PORT" --api-version=2 --accept-multiclient --continue --log -- & else bin_path=/app/charon if [ ! -f "$bin_path" ]; then bin_path=/app/cpmp fi - "$bin_path" & + su-exec charon:charon "$bin_path" & fi APP_PID=$! echo "Charon started (PID: $APP_PID)" diff --git a/Dockerfile b/Dockerfile index de126460..b3266253 100644 --- a/Dockerfile +++ b/Dockerfile @@ -247,9 +247,10 @@ FROM ${CADDY_IMAGE} WORKDIR /app # Install runtime dependencies for Charon, including bash for maintenance scripts +# su-exec is used for dropping privileges after Docker socket group setup # Explicitly upgrade c-ares to fix CVE-2025-62408 # hadolint ignore=DL3018 -RUN apk --no-cache add bash ca-certificates sqlite-libs sqlite tzdata curl gettext \ +RUN apk --no-cache add bash ca-certificates sqlite-libs sqlite tzdata curl gettext su-exec \ && apk --no-cache upgrade \ && apk --no-cache upgrade c-ares @@ -369,8 +370,9 @@ HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ RUN ln -sf /app/data/crowdsec/config /etc/crowdsec # Security: Run as non-root user (CIS Docker Benchmark 4.1) -# The entrypoint script handles any required permission fixes for volumes -USER charon +# NOTE: The entrypoint script starts as root to handle Docker socket permissions, +# then drops privileges to the charon user before starting applications. +# This is necessary for Docker integration while maintaining security. # Use custom entrypoint to start both Caddy and Charon ENTRYPOINT ["/docker-entrypoint.sh"]