From 626481f2f346a1b4460156e8782635302b45ce16 Mon Sep 17 00:00:00 2001 From: "Jiaxiao (mossaka) Zhou" Date: Thu, 5 Mar 2026 18:57:56 +0000 Subject: [PATCH 1/3] fix(security): run Squid container as non-root user Install gosu in the Squid container and use it to drop from root to the proxy user (UID 13) before starting Squid. The entrypoint still runs as root initially to fix mounted volume permissions, then drops privileges via `gosu proxy` before exec'ing squid. Changes: - Dockerfile: install gosu, create and chown /var/spool/squid, /var/run/squid, and /etc/squid for the proxy user - entrypoint.sh: use `exec gosu proxy squid -N -d 1` instead of `exec squid -N -d 1` Fixes #250 Co-Authored-By: Claude Opus 4.6 (1M context) --- containers/squid/Dockerfile | 9 +++++---- containers/squid/entrypoint.sh | 7 +++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/containers/squid/Dockerfile b/containers/squid/Dockerfile index c5a695eed..19ecff143 100644 --- a/containers/squid/Dockerfile +++ b/containers/squid/Dockerfile @@ -1,9 +1,10 @@ FROM ubuntu/squid:latest # Install additional tools for debugging, healthcheck, and SSL Bump +# gosu is used to drop from root to proxy user after permission setup # Retry logic handles transient 404s when Ubuntu archive supersedes package versions mid-build RUN set -eux; \ - PKGS="curl dnsutils net-tools netcat-openbsd openssl squid-openssl"; \ + PKGS="curl dnsutils gosu net-tools netcat-openbsd openssl squid-openssl"; \ apt-get update && \ apt-get install -y --only-upgrade gpgv && \ ( apt-get install -y --no-install-recommends $PKGS || \ @@ -11,9 +12,9 @@ RUN set -eux; \ apt-get install -y --no-install-recommends $PKGS) ) && \ rm -rf /var/lib/apt/lists/* -# Create log directory and SSL database directory -RUN mkdir -p /var/log/squid && \ - chown -R proxy:proxy /var/log/squid +# Create log directory and SSL database directory, ensure proxy user owns them +RUN mkdir -p /var/log/squid /var/spool/squid /var/run/squid && \ + chown -R proxy:proxy /var/log/squid /var/spool/squid /var/run/squid /etc/squid # Copy entrypoint script COPY entrypoint.sh /usr/local/bin/entrypoint.sh diff --git a/containers/squid/entrypoint.sh b/containers/squid/entrypoint.sh index d6d2fa598..00aa684cc 100644 --- a/containers/squid/entrypoint.sh +++ b/containers/squid/entrypoint.sh @@ -19,5 +19,8 @@ if [ -d "/var/spool/squid_ssl_db" ]; then echo "[squid-entrypoint] SSL certificate database ready" fi -# Start Squid -exec squid -N -d 1 +# Ensure Squid config directory and run directory are writable by proxy +chown -R proxy:proxy /etc/squid /var/run/squid /var/spool/squid 2>/dev/null || true + +# Drop to proxy user and start Squid +exec gosu proxy squid -N -d 1 From 9b742cd35175241936c9cfd22fc25578d0cc8656 Mon Sep 17 00:00:00 2001 From: "Jiaxiao (mossaka) Zhou" Date: Thu, 5 Mar 2026 19:08:44 +0000 Subject: [PATCH 2/3] fix(squid): ensure /run/squid.pid is writable by proxy user Squid's default pid_filename is /run/squid.pid, which is not writable by the proxy user after dropping privileges via gosu. Create and chown the pid file before starting Squid. Co-Authored-By: Claude Opus 4.6 (1M context) --- containers/squid/entrypoint.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/containers/squid/entrypoint.sh b/containers/squid/entrypoint.sh index 00aa684cc..e8639f591 100644 --- a/containers/squid/entrypoint.sh +++ b/containers/squid/entrypoint.sh @@ -22,5 +22,8 @@ fi # Ensure Squid config directory and run directory are writable by proxy chown -R proxy:proxy /etc/squid /var/run/squid /var/spool/squid 2>/dev/null || true +# Ensure pid file is writable by proxy user (default: /run/squid.pid) +touch /run/squid.pid && chown proxy:proxy /run/squid.pid + # Drop to proxy user and start Squid exec gosu proxy squid -N -d 1 From b82ef194896a9ca7203b4f7bade81180dc71320c Mon Sep 17 00:00:00 2001 From: "Jiaxiao (mossaka) Zhou" Date: Thu, 5 Mar 2026 19:18:40 +0000 Subject: [PATCH 3/3] fix(squid): make squid.conf readable by proxy user The squid.conf was written with mode 0o600 (owner-only), but since Squid now runs as the proxy user via gosu, it couldn't read its own config file. Changed to 0o644 so the proxy user can read it. The docker-compose.yml retains 0o600 since it contains sensitive environment variables. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/docker-manager.test.ts | 4 ++-- src/docker-manager.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/docker-manager.test.ts b/src/docker-manager.test.ts index a431c66c0..5b0bf958a 100644 --- a/src/docker-manager.test.ts +++ b/src/docker-manager.test.ts @@ -2008,11 +2008,11 @@ describe('docker-manager', () => { // May fail after writing configs } - // Verify squid.conf has restricted permissions + // Verify squid.conf is readable by proxy user (0o644) for non-root Squid const squidConfPath = path.join(testDir, 'squid.conf'); if (fs.existsSync(squidConfPath)) { const stats = fs.statSync(squidConfPath); - expect((stats.mode & 0o777).toString(8)).toBe('600'); + expect((stats.mode & 0o777).toString(8)).toBe('644'); } // Verify docker-compose.yml has restricted permissions diff --git a/src/docker-manager.ts b/src/docker-manager.ts index aff4bad9a..e0ba703c9 100644 --- a/src/docker-manager.ts +++ b/src/docker-manager.ts @@ -1254,7 +1254,7 @@ export async function writeConfigs(config: WrapperConfig): Promise { allowHostPorts: config.allowHostPorts, }); const squidConfigPath = path.join(config.workDir, 'squid.conf'); - fs.writeFileSync(squidConfigPath, squidConfig, { mode: 0o600 }); + fs.writeFileSync(squidConfigPath, squidConfig, { mode: 0o644 }); logger.debug(`Squid config written to: ${squidConfigPath}`); // Write Docker Compose config