SockguardSockguard

Introduction

Sockguard is a Docker socket proxy that inspects the bodies it proxies, not just the URLs.

A Docker socket proxy that actually inspects what it proxies.

Why Sockguard?

The Docker socket (/var/run/docker.sock) is effectively root access to your host. Any container with socket access can create privileged containers, mount the host filesystem, and escape containment entirely.

Most existing proxies stop at method/path or regex filtering. Sockguard goes further:

  • Request body inspection — Docker write bodies across container create/update/exec/archive, image pull/load/build, volume/network/secret/config/service/swarm/node, and plugin endpoints are inspected before Docker sees the request
  • Owner label isolation — stamp label-capable creates and build images with an owner label, auto-filter labeled list/prune, deny cross-owner access across workload and control-plane resources
  • Per-client policies — gate callers by source CIDR, certificate selectors including SPKI pins, unix peer credentials, or calling container labels, then apply named profiles
  • mTLS for remote TCP — non-loopback TCP requires mutual TLS 1.3 by default, plaintext TCP is an explicit legacy opt-in
  • Structured access logging — JSON logs with method, raw path, normalized policy path, decision, matched rule, latency, canonical request ID, preserved client request ID when present, and W3C trace correlation fields
  • Operator observability — opt-in /metrics scrape endpoint, active upstream watchdog signals for Docker socket reachability, and trace/log correlation without an OTLP exporter
  • Abuse controls — per-profile token-bucket rate limits, concurrency caps, per-endpoint cost weighting, and a system-wide priority-aware fairness gate keep noisy callers from starving the rest
  • Dynamic policy delivery — per-profile enforce|warn|audit rollout modes for safe staged rollouts, fsnotify + SIGHUP hot-reload with an immutable-field gate, monotonic policy versioning at GET /admin/policy/version and on sockguard_policy_version, an optional dedicated admin listener, and cosign-signed policy bundles verified at startup and every reload
  • Default-deny — everything blocked unless explicitly allowed
  • Tecnativa compatible — drop-in replacement for the current Tecnativa environment-variable surface

Quick Start

services:
  sockguard:
    image: codeswhat/sockguard:latest
    restart: unless-stopped
    read_only: true
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - sockguard-socket:/var/run/sockguard
    environment:
      - SOCKGUARD_LISTEN_SOCKET=/var/run/sockguard/sockguard.sock
      - SOCKGUARD_INSECURE_ALLOW_READ_EXFILTRATION=true
      - CONTAINERS=1
      - IMAGES=1
      - EVENTS=1

  your-app:
    depends_on:
      - sockguard
    volumes:
      - sockguard-socket:/var/run/sockguard:ro
    environment:
      - DOCKER_HOST=unix:///var/run/sockguard/sockguard.sock

volumes:
  sockguard-socket:

The published image runs as UID 65532 (Chainguard nonroot) inside the container. On stock Docker hosts where /var/run/docker.sock is owned by the docker group you may need a group_add override with the socket's numeric group ID or a matching user: override. The meaningful hardening levers are the proxy policy, read_only, dropped capabilities, no-new-privileges, and your runtime's seccomp/AppArmor/SELinux defaults.

SOCKGUARD_INSECURE_ALLOW_READ_EXFILTRATION=true is only there to preserve broad CONTAINERS=1 / IMAGES=1 compatibility, including raw archive/export and log/attach streaming endpoints. Remove it once you switch to tighter YAML list/inspect rules.

If you choose TCP instead of a unix socket, Sockguard only allows loopback TCP by default. Non-loopback TCP requires mutual TLS unless you explicitly opt into legacy plaintext mode with both SOCKGUARD_LISTEN_INSECURE_ALLOW_PLAIN_TCP=true and SOCKGUARD_LISTEN_INSECURE_ALLOW_UNAUTHENTICATED_CLIENTS=true.

On this page