From 8a5910c516af26e52e330d393d393a3a86bbb89b Mon Sep 17 00:00:00 2001 From: Oliver Papst Date: Mon, 18 Aug 2025 21:18:44 +0200 Subject: [PATCH 1/9] add IPv6 support to listenip Accept IPv6 addresses in the standard notation. Examples: --listenip=:: --listenip=fd00::1 --- internal/config/config.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index bd99114..c7a73cb 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -180,13 +180,20 @@ func InitConfig() (*Config, error) { } // check listenIP and proxyPort - if net.ParseIP(listenIP) == nil { - return nil, fmt.Errorf("invalid IP \"%s\" for listenip", listenIP) - } if proxyPort < 1 || proxyPort > 65535 { - return nil, errors.New("port number has to be between 1 and 65535") + return nil, errors.New("port number has to be between 1 and 65535") + } + ip := net.ParseIP(listenIP) + if ip == nil { + return nil, fmt.Errorf("invalid IP \"%s\" for listenip", listenIP) + } + + // Properly format address for both IPv4 and IPv6 + if ip.To4() == nil { + cfg.ListenAddress = fmt.Sprintf("[%s]:%d", listenIP, proxyPort) + } else { + cfg.ListenAddress = fmt.Sprintf("%s:%d", listenIP, proxyPort) } - cfg.ListenAddress = fmt.Sprintf("%s:%d", listenIP, proxyPort) // parse defaultLogLevel and setup logging handler depending on defaultLogJSON switch strings.ToUpper(logLevel) { From 7f6c8c17ecd8a8575f88aef07348ebc6d92c9650 Mon Sep 17 00:00:00 2001 From: wollomatic Date: Sat, 23 Aug 2025 12:15:01 +0200 Subject: [PATCH 2/9] update to Go 1.25.0 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index b7e74d6..8449c24 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -FROM --platform=$BUILDPLATFORM golang:1.24.5-alpine3.22 AS build +FROM --platform=$BUILDPLATFORM golang:1.25.0-alpine3.22 AS build WORKDIR /application COPY . ./ ARG TARGETOS From 9e7b8f024a95c68ff9e56fa2ef15066027eb76ce Mon Sep 17 00:00:00 2001 From: wollomatic Date: Sat, 23 Aug 2025 12:40:06 +0200 Subject: [PATCH 3/9] clarify bind mount restrictions logging --- cmd/socket-proxy/main.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cmd/socket-proxy/main.go b/cmd/socket-proxy/main.go index 0f3d7bf..5d1366a 100644 --- a/cmd/socket-proxy/main.go +++ b/cmd/socket-proxy/main.go @@ -58,9 +58,9 @@ func main() { // print configuration slog.Info("starting socket-proxy", "version", version, "os", runtime.GOOS, "arch", runtime.GOARCH, "runtime", runtime.Version(), "URL", programURL) if cfg.ProxySocketEndpoint == "" { - slog.Info("configuration info", "socketpath", cfg.SocketPath, "listenaddress", cfg.ListenAddress, "loglevel", cfg.LogLevel, "logjson", cfg.LogJSON, "allowfrom", cfg.AllowFrom, "shutdowngracetime", cfg.ShutdownGraceTime, "allowbindmountfrom", cfg.AllowBindMountFrom) + slog.Info("configuration info", "socketpath", cfg.SocketPath, "listenaddress", cfg.ListenAddress, "loglevel", cfg.LogLevel, "logjson", cfg.LogJSON, "allowfrom", cfg.AllowFrom, "shutdowngracetime", cfg.ShutdownGraceTime) } else { - slog.Info("configuration info", "socketpath", cfg.SocketPath, "proxysocketendpoint", cfg.ProxySocketEndpoint, "proxysocketendpointfilemode", cfg.ProxySocketEndpointFileMode, "loglevel", cfg.LogLevel, "logjson", cfg.LogJSON, "allowfrom", cfg.AllowFrom, "shutdowngracetime", cfg.ShutdownGraceTime, "allowbindmountfrom", cfg.AllowBindMountFrom) + slog.Info("configuration info", "socketpath", cfg.SocketPath, "proxysocketendpoint", cfg.ProxySocketEndpoint, "proxysocketendpointfilemode", cfg.ProxySocketEndpointFileMode, "loglevel", cfg.LogLevel, "logjson", cfg.LogJSON, "allowfrom", cfg.AllowFrom, "shutdowngracetime", cfg.ShutdownGraceTime) slog.Info("proxysocketendpoint is set, so the TCP listener is deactivated") } if cfg.WatchdogInterval > 0 { @@ -68,8 +68,14 @@ func main() { } else { slog.Info("watchdog disabled") } + if len(cfg.AllowBindMountFrom) > 0 { + slog.Info("Docker bind mount restrictions:", cfg.AllowBindMountFrom) + } else { + // we only log this on DEBUG level because bind mount restrictions are a very special use case + slog.Debug("no Docker bind mount restrictions") + } - // print request allow list + // print request allowlist if cfg.LogJSON { for method, regex := range cfg.AllowedRequests { slog.Info("configured allowed request", "method", method, "regex", regex) From 6b4a2706a7965ac11be1d55fb9179901a8548da7 Mon Sep 17 00:00:00 2001 From: wollomatic Date: Sat, 23 Aug 2025 13:22:34 +0200 Subject: [PATCH 4/9] fix logging error --- cmd/socket-proxy/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/socket-proxy/main.go b/cmd/socket-proxy/main.go index 5d1366a..a01aa0b 100644 --- a/cmd/socket-proxy/main.go +++ b/cmd/socket-proxy/main.go @@ -69,7 +69,7 @@ func main() { slog.Info("watchdog disabled") } if len(cfg.AllowBindMountFrom) > 0 { - slog.Info("Docker bind mount restrictions:", cfg.AllowBindMountFrom) + slog.Info("Docker bind mount restrictions enabled", "allowbindmountfrom", cfg.AllowBindMountFrom) } else { // we only log this on DEBUG level because bind mount restrictions are a very special use case slog.Debug("no Docker bind mount restrictions") From 8e2d773eac7a68c5d36dbec296abc8c82c9eeb4c Mon Sep 17 00:00:00 2001 From: wollomatic Date: Sat, 23 Aug 2025 13:51:50 +0200 Subject: [PATCH 5/9] remove "allowfrom" from logging if the TCP listener is deactivated --- cmd/socket-proxy/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/socket-proxy/main.go b/cmd/socket-proxy/main.go index a01aa0b..dd76bd0 100644 --- a/cmd/socket-proxy/main.go +++ b/cmd/socket-proxy/main.go @@ -60,7 +60,7 @@ func main() { if cfg.ProxySocketEndpoint == "" { slog.Info("configuration info", "socketpath", cfg.SocketPath, "listenaddress", cfg.ListenAddress, "loglevel", cfg.LogLevel, "logjson", cfg.LogJSON, "allowfrom", cfg.AllowFrom, "shutdowngracetime", cfg.ShutdownGraceTime) } else { - slog.Info("configuration info", "socketpath", cfg.SocketPath, "proxysocketendpoint", cfg.ProxySocketEndpoint, "proxysocketendpointfilemode", cfg.ProxySocketEndpointFileMode, "loglevel", cfg.LogLevel, "logjson", cfg.LogJSON, "allowfrom", cfg.AllowFrom, "shutdowngracetime", cfg.ShutdownGraceTime) + slog.Info("configuration info", "socketpath", cfg.SocketPath, "proxysocketendpoint", cfg.ProxySocketEndpoint, "proxysocketendpointfilemode", cfg.ProxySocketEndpointFileMode, "loglevel", cfg.LogLevel, "logjson", cfg.LogJSON, "shutdowngracetime", cfg.ShutdownGraceTime) slog.Info("proxysocketendpoint is set, so the TCP listener is deactivated") } if cfg.WatchdogInterval > 0 { From 2f7eab346c2998fb50aee161c70c3066691556a6 Mon Sep 17 00:00:00 2001 From: wollomatic Date: Sat, 23 Aug 2025 14:01:06 +0200 Subject: [PATCH 6/9] avoid confusion with IPv6 addresses in logging cfg.AllowFrom --- cmd/socket-proxy/main.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/socket-proxy/main.go b/cmd/socket-proxy/main.go index dd76bd0..77837cc 100644 --- a/cmd/socket-proxy/main.go +++ b/cmd/socket-proxy/main.go @@ -12,6 +12,7 @@ import ( "os" "os/signal" "runtime" + "strings" "syscall" "time" @@ -58,7 +59,9 @@ func main() { // print configuration slog.Info("starting socket-proxy", "version", version, "os", runtime.GOOS, "arch", runtime.GOARCH, "runtime", runtime.Version(), "URL", programURL) if cfg.ProxySocketEndpoint == "" { - slog.Info("configuration info", "socketpath", cfg.SocketPath, "listenaddress", cfg.ListenAddress, "loglevel", cfg.LogLevel, "logjson", cfg.LogJSON, "allowfrom", cfg.AllowFrom, "shutdowngracetime", cfg.ShutdownGraceTime) + // join the cfg.AllowFrom slice to a string to avoid the brackets in the logging (avoid confusion with IPv6 addresses) + allowFromString := strings.Join(cfg.AllowFrom, ",") + slog.Info("configuration info", "socketpath", cfg.SocketPath, "listenaddress", cfg.ListenAddress, "loglevel", cfg.LogLevel, "logjson", cfg.LogJSON, "allowfrom", allowFromString, "shutdowngracetime", cfg.ShutdownGraceTime) } else { slog.Info("configuration info", "socketpath", cfg.SocketPath, "proxysocketendpoint", cfg.ProxySocketEndpoint, "proxysocketendpointfilemode", cfg.ProxySocketEndpointFileMode, "loglevel", cfg.LogLevel, "logjson", cfg.LogJSON, "shutdowngracetime", cfg.ShutdownGraceTime) slog.Info("proxysocketendpoint is set, so the TCP listener is deactivated") From 3bf5d9ed3174bf0aa2e9dc9e34ef55f6dccf786e Mon Sep 17 00:00:00 2001 From: wollomatic Date: Sat, 23 Aug 2025 14:06:07 +0200 Subject: [PATCH 7/9] explicitly set permissions for GitHub workflow --- .github/workflows/docker-image-testing.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/docker-image-testing.yaml b/.github/workflows/docker-image-testing.yaml index 19d4bc0..7b71480 100644 --- a/.github/workflows/docker-image-testing.yaml +++ b/.github/workflows/docker-image-testing.yaml @@ -1,4 +1,7 @@ name: Build and Publish Testing +permissions: + contents: read + packages: write on: push: From 78559e8fcf46dc0a8904af71c17136a43e6991c7 Mon Sep 17 00:00:00 2001 From: wollomatic Date: Sat, 23 Aug 2025 18:43:21 +0200 Subject: [PATCH 8/9] explicitly set permissions for GitHub workflow (prod workflow) --- .github/workflows/docker-image-release.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/docker-image-release.yaml b/.github/workflows/docker-image-release.yaml index 344cfaa..625e9c4 100644 --- a/.github/workflows/docker-image-release.yaml +++ b/.github/workflows/docker-image-release.yaml @@ -1,4 +1,7 @@ name: Build and Publish Release +permissions: + contents: read + packages: write on: push: From 9f85bb10a38d168189731419fc67d90717ba6739 Mon Sep 17 00:00:00 2001 From: wollomatic Date: Sat, 23 Aug 2025 18:48:18 +0200 Subject: [PATCH 9/9] update README --- README.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bcc0fa3..0ce9206 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # socket-proxy ## Latest image -- `wollomatic/socket-proxy:1.8.1` / `ghcr.io/wollomatic/socket-proxy:1.8.1` +- `wollomatic/socket-proxy:1.9.0` / `ghcr.io/wollomatic/socket-proxy:1.9.0` - `wollomatic/socket-proxy:1` / `ghcr.io/wollomatic/socket-proxy:1` ## About @@ -33,7 +33,7 @@ You should know what you are doing. Never expose socket-proxy to a public networ The container image is available on [Docker Hub (wollomatic/socket-proxy)](https://hub.docker.com/r/wollomatic/socket-proxy) and on the [GitHub Container Registry (ghcr.io/wollomatic/socket-proxy)](https://github.com/wollomatic/socket-proxy/pkgs/container/socket-proxy). -To pin one specific version, use the version tag (for example, `wollomatic/socket-proxy:1.6.0` or `ghcr.io/wollomatic/socket-proxy:1.6.0`). +To pin one specific version, use the version tag (for example, `wollomatic/socket-proxy:1.9.0` or `ghcr.io/wollomatic/socket-proxy:1.9.0`). To always use the most recent version, use the `1` tag (`wollomatic/socket-proxy:1` or `ghcr.io/wollomatic/socket-proxy:1`). This tag will be valid as long as there is no breaking change in the deployment. There may be an additional docker image with the `testing`-tag. This image is only for testing. Likely, documentation for the `testing` image could only be found in the GitHub commit messages. It is not recommended to use the `testing` image in production. @@ -75,7 +75,7 @@ The name of a parameter should be "-allow", followed by the HTTP method name (fo It is also possible to configure the allowlist via environment variables. The variables are called "SP_ALLOW_", followed by the HTTP method (for example, `SP_ALLLOW_GET`). -If both commandline parameter and environment variable is configured for a particular HTTP method, the environment variable is ignored. +If both commandline parameter and environment variable are configured for a particular HTTP method, the environment variable is ignored. Use Go's regexp syntax to create the patterns for these parameters. To avoid insecure configurations, the characters ^ at the beginning and $ at the end of the string are automatically added. Note: invalid regexp results in program termination. @@ -159,7 +159,7 @@ services: # it is not the same as the traefik-servicenet traefik: - # [...] see github.com/wollomatic/traefik2-hardened for a full example + # [...] see github.com/wollomatic/traefik-hardened for a full example depends_on: - dockerproxy networks: @@ -197,7 +197,7 @@ socket-proxy can be configured via command line parameters or via environment va | Parameter | Environment Variable | Default Value | Description | |--------------------------------|----------------------------------|------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `-allowfrom` | `SP_ALLOWFROM` | `127.0.0.1/32` | Specifies the IP addresses or hostnames (comma-separated) of the clients or the hostname of one specific client allowed to connect to the proxy. The default value is `127.0.0.1/32`, which means only localhost is allowed. This default configuration may not be useful in most cases, but it is because of a secure-by-default design. To allow all IPv4 addresses, set `-allowfrom=0.0.0.0/0`. Alternatively, hostnames can be set, for example `-allowfrom=traefik`, or `-allowfrom=traefik,dozzle`. Please remember that socket-proxy should never be exposed to a public network, regardless of this extra security layer. | -| `-allowbindmountfrom` | `SP_ALLOWBINDMOUNTFROM` | (not set) | Specifies the directories (comma-separated) that are allowed as bind mount sources. If not set, no bind mount restrictions are applied. When set, only bind mounts from the specified directories or their subdirectories are allowed. Each directory must start with `/`. For example, `-allowbindmountfrom=/home,/var/log` allows bind mounts from `/home`, `/var/log`, and any subdirectories. | +| `-allowbindmountfrom` | `SP_ALLOWBINDMOUNTFROM` | (not set) | Specifies the directories (comma-separated) that are allowed as bind mount sources. If not set, no bind mount restrictions are applied. When set, only bind mounts from the specified directories or their subdirectories are allowed. Each directory must start with `/`. For example, `-allowbindmountfrom=/home,/var/log` allows bind mounts from `/home`, `/var/log`, and any subdirectories. | | `-allowhealthcheck` | `SP_ALLOWHEALTHCHECK` | (not set/false) | If set, it allows the included health check binary to check the socket connection via TCP port 55555 (socket-proxy then listens on `127.0.0.1:55555/health`) | | `-listenip` | `SP_LISTENIP` | `127.0.0.1` | Specifies the IP address the server will bind on. Default is only the internal network. | | `-logjson` | `SP_LOGJSON` | (not set/false) | If set, it enables logging in JSON format. If unset, docker-proxy logs in plain text format. | @@ -228,7 +228,9 @@ socket-proxy can be configured via command line parameters or via environment va 1.7 - also allow comma-separated CIDRs in `-allowfrom` (not only hostnames as in versions > 1.3) -1.8 - add optional bind mount restrictions (thanks [@powerman](https://github.com/powerman)) +1.8 - add optional bind mount restrictions (thanks [@powerman](https://github.com/powerman), [@C4tWithShell](https://github.com/C4tWithShell)) + +1.9 - add IPv6 support to `-listenip` (thanks [@op3](https://github.com/op3)) ## License This project is licensed under the MIT License – see the [LICENSE](LICENSE) file for details. @@ -241,3 +243,8 @@ See the comments in this file and the LICENSE file for more information. + [Chris Wiegman: Protecting Your Docker Socket With Traefik 2](https://chriswiegman.com/2019/11/protecting-your-docker-socket-with-traefik-2/) [@ChrisWiegman](https://github.com/ChrisWiegman) + [tecnativa/docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) + [@justsomescripts](https://github.com/justsomescripts) fix parsing environment variable to configure unix socket + +## Alternatives + ++ [hectorm/cetusguard](https://github.com/hectorm/cetusguard) ++ [11notes/docker-socket-proxy](https://github.com/11notes/docker-socket-proxy) \ No newline at end of file