Skip to content

[Bug] Docker Labels Race Condition #83

@ElioDiNino

Description

@ElioDiNino

Describe the bug
When Docker labels are used to control socket-proxy access, if an application boots up and attempts to access the proxy right away, it will be blocked before the proxy reads the labels and applies the correct policy.

To Reproduce
Steps to reproduce the behavior:

  1. Deploy a Beszel agent similar to my configuration
  2. Observe the Beszel agent's attempt to access the socket and get blocked (based on forbidden IP) despite the request abiding by the regex
  3. Observe the socket proxy update with the correct access policy too late

Expected behavior
Requests made at container creation/restart time should not get blocked and the access policy should be queried/fetched first.

Desktop (please complete the following information):

  • OS: Debian Linux
  • Version: 1.11.0

Additional context

In the logs below, you can see me doing a mix of a) applying new regex policies to the Beszel agent container and b) restarting it, which both result in the following sequence:

  1. The allowlist is correctly removed for the container as it disappears
  2. The request by the Beszel agent is blocked based on IP (hasn't even gotten to the allowed paths)
  3. The allowlist is correctly propagated for the container

Not sure if it's relevant or not, but I run two Beszel agents on the host, and they share a Docker network, whereas the rest of my services using the socket proxy have their own network. Both are having the same issue and is blocking me from getting the Docker statistics I was getting before.

2026-01-19T21:30:17.274260651Z time=2026-01-19T21:30:17.273Z level=INFO msg="starting socket-proxy" version=1.11.0 os=linux arch=arm64 runtime=go1.25.6 URL=github.com/wollomatic/socket-proxy
2026-01-19T21:30:17.274437909Z time=2026-01-19T21:30:17.274Z level=INFO msg="configuration info" socketpath=/var/run/docker.sock listenaddress=0.0.0.0:2375 loglevel=INFO logjson=false allowfrom=127.0.0.1/32 shutdowngracetime=10
2026-01-19T21:30:17.274472702Z time=2026-01-19T21:30:17.274Z level=INFO msg="watchdog disabled"
2026-01-19T21:30:17.274484703Z time=2026-01-19T21:30:17.274Z level=INFO msg="Proxy container name provided" proxycontainername=socket-proxy
2026-01-19T21:30:17.274495411Z time=2026-01-19T21:30:17.274Z level=INFO msg="per-container allowlists enabled!"
2026-01-19T21:30:17.274505620Z time=2026-01-19T21:30:17.274Z level=INFO msg="socket proxy networks detected" socketproxynetworks="[socket-proxy-tinyauth socket-proxy-beszel-agent socket-proxy-caddy socket-proxy-diun socket-proxy-homepage]"
2026-01-19T21:30:17.274517204Z Default request allowlist:
2026-01-19T21:30:17.274527580Z    Method   Regex
2026-01-19T21:30:17.274537580Z    GET      ^(/v1\.\d{1,2})?/(_ping|version)$
2026-01-19T21:30:17.274547164Z    HEAD     ^(/v1\..{1,2})?/_ping$
2026-01-19T21:30:17.274820510Z time=2026-01-19T21:30:17.274Z level=INFO msg="socket-proxy running and listening..."
2026-01-19T21:30:17.279974205Z Request allowlist for c67060cd9dd4 (172.20.0.3):
2026-01-19T21:30:17.280028833Z    Method   Regex
2026-01-19T21:30:17.280034625Z    HEAD     ^(/v1\.\d{1,2})?/_ping$
2026-01-19T21:30:17.280039542Z    GET      ^(/v1\.\d{1,2})?/(info|containers/json(\?\S+)?|events(\?\S+)?|networks(/\w+)?)$
2026-01-19T21:30:17.280044375Z Request allowlist for ff712e71df1c (172.18.0.2):
2026-01-19T21:30:17.280048667Z    Method   Regex
2026-01-19T21:30:17.280052709Z    GET      ^(/v1\.\d{1,2})?/(version|containers/json(\?\S+)?|images/[\w./:+-]+/json)$
2026-01-19T21:30:17.280057042Z    HEAD     ^(/v1\.\d{1,2})?/_ping$
2026-01-19T21:30:17.280060876Z Request allowlist for a7fef33ed3e2 (172.30.0.2):
2026-01-19T21:30:17.280064709Z    Method   Regex
2026-01-19T21:30:17.280068209Z    HEAD     ^(/v1\.\d{1,2})?/_ping$
2026-01-19T21:30:17.280071960Z    GET      ^(/v1\.\d{1,2})?/containers/(json|[\w.-]+/json)(\?\S+)?$
2026-01-19T21:30:17.280076043Z Request allowlist for ab99a9d0a726 (172.19.0.3):
2026-01-19T21:30:17.280079793Z    Method   Regex
2026-01-19T21:30:17.280083419Z    GET      ^(/v1\.\d{1,2})?/containers/(json|[\w.-]+/(json|stats))(\?\S+)?$
2026-01-22T06:29:25.148084580Z time=2026-01-22T06:29:25.143Z level=INFO msg="removed allowlist for container" id=ab99a9d0a726 ip=172.19.0.3
2026-01-22T06:29:26.311599748Z time=2026-01-22T06:29:26.310Z level=WARN msg="blocked request" reason="forbidden IP" method=GET URL=/version client=172.19.0.3:41356 response=403
2026-01-22T06:29:26.316413183Z Request allowlist for 9ed3b64d531e (172.19.0.3):
2026-01-22T06:29:26.316513312Z    Method   Regex
2026-01-22T06:29:26.316530563Z    GET      ^(/v1\.\d{1,2})?/(info|containers/(json|[\w.-]+/(json|stats))(\?\S+)?)$
2026-01-22T06:31:53.171126074Z time=2026-01-22T06:31:53.170Z level=INFO msg="removed allowlist for container" id=9ed3b64d531e ip=172.19.0.3
2026-01-22T06:31:53.558768071Z time=2026-01-22T06:31:53.558Z level=WARN msg="blocked request" reason="forbidden IP" method=GET URL=/version client=172.19.0.3:51192 response=403
2026-01-22T06:31:53.566160567Z Request allowlist for 9ed3b64d531e (172.19.0.3):
2026-01-22T06:31:53.566238987Z    Method   Regex
2026-01-22T06:31:53.566247779Z    GET      ^(/v1\.\d{1,2})?/(info|containers/(json|[\w.-]+/(json|stats))(\?\S+)?)$
2026-01-22T06:31:53.568447657Z Request allowlist for 9ed3b64d531e (172.19.0.3):
2026-01-22T06:31:53.568467449Z    Method   Regex
2026-01-22T06:31:53.568475199Z    GET      ^(/v1\.\d{1,2})?/(info|containers/(json|[\w.-]+/(json|stats))(\?\S+)?)$
2026-01-22T06:32:52.051984892Z time=2026-01-22T06:32:52.051Z level=INFO msg="removed allowlist for container" id=9ed3b64d531e ip=172.19.0.3
2026-01-22T06:32:53.204537656Z time=2026-01-22T06:32:53.204Z level=WARN msg="blocked request" reason="forbidden IP" method=GET URL=/version client=172.19.0.3:59116 response=403
2026-01-22T06:32:53.218934970Z Request allowlist for c5f83da70ca7 (172.19.0.3):
2026-01-22T06:32:53.219005472Z    Method   Regex
2026-01-22T06:32:53.219013806Z    GET      ^(/v1\.\d{1,2})?/(version|info|containers/(json|[\w.-]+/(json|stats))(\?\S+)?)$
2026-01-22T06:33:38.873435441Z time=2026-01-22T06:33:38.873Z level=INFO msg="removed allowlist for container" id=c5f83da70ca7 ip=172.19.0.3
2026-01-22T06:33:39.263954237Z time=2026-01-22T06:33:39.263Z level=WARN msg="blocked request" reason="forbidden IP" method=GET URL=/version client=172.19.0.3:34116 response=403
2026-01-22T06:33:39.272622577Z Request allowlist for c5f83da70ca7 (172.19.0.3):
2026-01-22T06:33:39.272711622Z    Method   Regex
2026-01-22T06:33:39.272721206Z    GET      ^(/v1\.\d{1,2})?/(version|info|containers/(json|[\w.-]+/(json|stats))(\?\S+)?)$
2026-01-22T06:33:39.274679408Z Request allowlist for c5f83da70ca7 (172.19.0.3):
2026-01-22T06:33:39.274719576Z    Method   Regex
2026-01-22T06:33:39.274725243Z    GET      ^(/v1\.\d{1,2})?/(version|info|containers/(json|[\w.-]+/(json|stats))(\?\S+)?)$
2026-01-22T06:34:45.990249369Z time=2026-01-22T06:34:45.990Z level=INFO msg="removed allowlist for container" id=c5f83da70ca7 ip=172.19.0.3
2026-01-22T06:34:50.752432138Z time=2026-01-22T06:34:50.752Z level=WARN msg="blocked request" reason="forbidden IP" method=GET URL=/version client=172.19.0.3:49316 response=403
2026-01-22T06:34:50.757763682Z Request allowlist for 2ce4d13e5e89 (172.19.0.3):
2026-01-22T06:34:50.757853602Z    Method   Regex
2026-01-22T06:34:50.757869895Z    GET      ^(/v1\.\d{1,2})?/(version|info|containers/(json|[\w.-]+/(json|stats))(\?\S+)?)$

In terms of ideas for a fix, maybe before blocking a request based on IP, the socket-proxy should do a manual query of that container to see if it has the expected labels instead of relying on the Docker socket event stream to have updated the allowlist in time.

cc: @amanda-wee

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions