Skip to content
v1.4.1· Open Source · Apache-2.0

Control what
gets through

We put a default-deny proxy in front of your Docker socket. Every request is filtered by method, path, and body before it reaches the daemon — then we layer on signed policy bundles, per-profile rollout modes, rate limits, hot-reload, and Prometheus metrics.

19features
5alternatives compared
96%+coverage
Apache-2.0license

In the real CLI

See it work

A looping recreation of the real CLI — inspect a config, dry-run a single request through the rules, and watch the proxy stream access logs.

sockguard — zsh
# One command, and every Docker API call runs through your rules.
$

A hand-rendered recreation of the real CLI — every frame mirrors what sockguard actually prints. Use the controls above to pause, restart, or change speed.

Batteries included

What we enforce

We ship a lean Go binary with a stdlib request hot path and zero daemon dependencies. Default-deny, ready to drop in front of your socket.

sockguard capabilities19 modules
01

Default-Deny Posture

Security

Everything blocked unless explicitly allowed. Request paths are percent-decoded and canonicalized before matching, so `%2e%2e` and encoded-separator tricks cannot slip past an allowlist.

02

Request Body Inspection

Security

We parse every container, image, build, volume, network, secret, config, service, swarm, node, and plugin write to block privileged or host-namespace workloads, non-allowlisted mounts/devices, device requests, device cgroup rules, commands, remotes, unsafe network/swarm/node controls, archive writes, and tar imports. We inspect multipart plugin uploads too, and reject oversized bounded bodies with 413 before the inspector runs.

03

mTLS for Remote TCP

Security

We require mutual TLS 1.3 on non-loopback TCP listeners by default. Plaintext remote TCP is an explicit legacy opt-in only.

04

Owner Label Isolation

Control

Stamp label-capable creates, node/swarm claim updates, and build images with an owner label. Labeled list, prune, and event reads are auto-filtered, and cross-owner access is denied across workload and control-plane resources.

05

Client ACL Primitives

Control

Gate callers by source CIDR, bridge-network container labels, mTLS certificate selectors (CN, DNS/IP/URI SAN, SHA-256 SPKI pin), and unix peer credentials before the global policy runs.

06

Granular Control

Control

You can allow start/stop while blocking create/exec. We give you per-operation POST controls with glob matching.

07

Structured Access Logging

Operations

We emit JSON access logs with method, raw and normalized paths, decision, matched rule index, latency, canonical request_id, preserved client request IDs, and W3C trace correlation fields.

08

Operator Observability

Operations

Our opt-in Prometheus metrics expose request totals, deny counts, latency buckets, active requests, watchdog state, plus build_info and start_time gauges for version panels and uptime alerts. We feed /health from the active Docker socket watchdog and log state transitions; trace/log correlation works without an OTLP exporter.

09

YAML Configuration

Control

We use declarative YAML rules with glob patterns, first-match-wins evaluation, and 15 bundled workload presets (drydock, Traefik, Portainer, Watchtower, Homepage, Homarr, Diun, Autoheal, read-only, CIS Docker Benchmark, GitHub Actions self-hosted runner, GitLab Runner, Portwing, Portwing with exec, Drydock with self-update) plus the default config.

10

Tecnativa Compatible

Operations

Migrating from Tecnativa? We match its full env surface: section vars, ALLOW_RESTARTS, SOCKET_PATH, and LOG_LEVEL. Swap us in without touching your config.

11

Minimal Attack Surface

Security

We ship a Wolfi-based image, cosign-signed with SBOM and build provenance.

12

Signed Policy Bundles

Security

Treat the on-disk YAML config as untrusted until a cosign / sigstore bundle confirms it. Supports keyed (PEM ECDSA/RSA/ed25519) and keyless (Fulcio + Rekor) verification. Bundle is checked at startup and on every hot reload — a bad signature rejects the reload and leaves the running policy untouched.

13

Container Image Trust

Security

Verify cosign signatures on a container's image before `POST /containers/create` reaches the daemon. Keyed (PEM ECDSA/RSA/ed25519) and keyless (Fulcio issuer + SAN, optional Rekor inclusion) verification, configurable per client profile. `enforce` denies unsigned or wrong-signer images; `warn` logs the failure and forwards the request.

14

Visibility-Controlled Reads

Security

We use label selectors to hide labeled list, inspect, and selected service/task log reads for non-matching resources. Env/mount/network/config/plugin/swarm-sensitive metadata is redacted by default, and raw archive/export reads stay behind explicit opt-in.

15

Named Client Profiles

Control

Route callers to named profiles with their own rules and request-body policy by source CIDR, mTLS client certificate selectors including SPKI pins, or unix peer credentials, with a configurable default fallback.

16

Rate Limits & Concurrency Caps

Control

We return `429 Too Many Requests` with `Retry-After` when per-profile token-bucket rate limits (`limits.rate`) or in-flight concurrency caps (`limits.concurrency`) are exhausted. A system-wide priority fairness gate (`clients.global_concurrency`) prevents low-priority callers from starving high-priority profiles. Anonymous callers bucket under `_anonymous` so they can't bypass limits by skipping identification.

17

Per-Profile Rollout Modes

Control

Stage policy changes without blocking traffic. Set a profile to `warn` or `audit` to serve requests while logging `decision=would_deny` audit records — then compare blocked vs. would-have-been-blocked in your dashboards before flipping to `enforce`. Pre-auth gates (CIDR allowlist, identity failures) always stay in enforce regardless of profile mode.

18

Hot-Reload + Admin API

Operations

We watch for config changes with fsnotify and support SIGHUP reload with immutable-field gating: listener, upstream socket, and trust-material fields require a restart. `POST /admin/validate` dry-runs a candidate config without touching the running policy. `GET /admin/policy/version` returns the generation counter, config SHA-256, and verified bundle signer. Optionally bind the admin API to a dedicated listener so admin traffic never traverses the Docker-API filter chain.

19

Remote Upstreams & Failover

Operations

Dial a remote Docker daemon over TCP with mutual TLS instead of the local socket. Configure an ordered set of redundant endpoints for the same daemon or swarm node with active health checks and automatic failover.

Get running

Get started in minutes

Add sockguard to your compose file and point your app at its scoped socket.

Terminal
$ docker run -d \
  --name sockguard \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  -v /var/run/sockguard:/var/run/sockguard \
  -e SOCKGUARD_LISTEN_SOCKET=/var/run/sockguard/sockguard.sock \
  codeswhat/sockguard

Mounts the Docker socket directly — fine for a local try, not for production.

On the horizon

Roadmap

Where we've been and where we're headed.

ReleasedCurrent (HEAD)Planned
roadmap
v1.5.0🔧Safer Defaults & Namespace Hardening

upstream.request_timeout now defaults to 60s (was unlimited); 'off' restores unlimited

ownership.allow_cross_owner_namespace_sharing defaults to false — cross-owner container:<id> namespace joins denied by default when ownership.owner is set

+6 more

Namespace-sharing gate: restrict_namespace_sharing + allowed_namespace_sharing_containers gate container:<id> joins across NetworkMode/PidMode/IpcMode/UsernsMode; deny_namespace_path_mode blocks raw ns:<path> on NetworkMode only

require_cpu_limit_hard — opt-in hard CPU-time cap (NanoCpus/CpuQuota), independent of require_cpu_limit

Exec Env allow/denylisting — request_body.exec.allowed_env_vars/denied_env_vars, denylist wins

New presets: portwing-with-compose.yaml, drydock-with-compose.yaml, plus a tri-tool compose example

Helm chart: pod-level podSecurityContext

Config Viper-default registration generated by reflection off Defaults()

HEAD -> v1.4.0🌐Remote Upstreams & Fleet Presets

Remote Docker daemon over TCP with mutual TLS and active/passive failover

Ordered endpoint failover — connect failure instantly promotes next endpoint without retry

+5 more

Portwing presets (portwing.yaml, portwing-with-exec.yaml) and drydock-with-selfupdate.yaml

Drydock preset conformance audit — runc runtime, multi-network connect, self-update finalize exec all fixed

Swarm service seccomp/AppArmor confinement rails (deny_unconfined_seccomp, deny_unconfined_apparmor)

Rate-limit token bucket: allocation-free hot path, 0 allocs/0 B per op at ~36 ns

Enforced CI coverage floor (96%) with Qlty Cloud reporting

v1.3.0🛡️Posture Hardening

Swarm service create/update enforces container-create identity/privilege rails (non-root, no-new-privileges, readonly rootfs, drop ALL)

Zero-padded UID bypass sealed — '00', '000', '0:0' all parsed numerically as root

+5 more

Wide-open dedicated admin listener rejected at config validation, not just warned

Admin endpoint paths normalized before matching — trailing-slash and dot-segment variants closed

signature_path hot-reload wedge fixed — verification reads from candidate config

Non-upgrade hijack responses strip hop-by-hop headers

Multi-arch images cross-compile natively (no QEMU emulation in CI)

v1.2.0📊Resilience & Observability

Opt-in upstream readiness probe (GET /containers/json health check — returns 503 on a wedged daemon)

upstream.request_timeout — 504 Gateway Timeout on hung proxied finite requests

+3 more

Upstream response-header timeout hardened across all side-channel transports

drydock preset: allowlisted runc runtime to fix update recreate rollbacks

Go toolchain bumped to 1.26.4 — clears two reachable stdlib advisories (GO-2026-5037, GO-2026-5039)

v1.1.0🔒Security Hardening

21 HIGH + MEDIUM security findings fixed across a full multi-axis audit

Image-trust wired end-to-end — cosign signatures verified against resolved manifest digest, TOCTOU sealed

+5 more

Plugin install, service create/update, and docker load bypass vectors closed

Ownership isolation: bounded LRU caches, negative-cache closed, image /get gated

Response redaction gaps closed (Mounts source, PreviousSpec, MaskedPaths/ReadonlyPaths)

Constant-time SPKI pin comparison; gzip-bomb guards on build and plugin paths

QA harness: proxy-vs-daemon differential, mTLS edge-case suite, fuzz targets, goroutine-leak soak

v1.0.0Foundation

Default-deny proxy: method + path filtering with percent-decoded path canonicalization

Request body inspection (container, exec, image, build, volume, network, secret, config, service, swarm, node, plugin)

+7 more

Mutual TLS 1.3 enforced on all non-loopback TCP listeners

Signed policy bundles (cosign keyed + keyless, Rekor inclusion proof)

Container image trust (cosign verify before /containers/create, enforce / warn modes)

Owner label isolation for workload and control-plane resources

Client ACL primitives: CIDR, mTLS cert selectors, unix peer credentials

Named client profiles with per-profile rollout modes (enforce / warn / audit)

12 bundled policy presets: drydock, Traefik, Portainer, Watchtower, CIS Docker Benchmark, GitHub Actions runner, GitLab Runner, and more

(initial commit)

Community

Star History

Growing every week — join us on GitHub.

Star History Chart

Why Sockguard

How we compare

A quick look at what we support that Tecnativa, CetusGuard, and wollomatic don't.

FeatureSockguardTecnativaCetusGuardwollomatic
Method + path filteringYesYesPartialPartial
Request body inspectionYesNoNoPartial
Per-client policiesYesNoNoPartial
Remote TCP mTLSYesNoYesNo
Signed policy bundlesYesNoNoNo
Prometheus metricsYesNoNoNo
Yes Partial No

Ecosystem

Part of the CodesWhat stack

Sockguard is one piece of a small, focused toolkit — each tool does one job, and they compose.

FAQ

Frequently asked questions

Common questions about how Sockguard works and how we compare.

What is Sockguard and how does the default-deny model work?

Sockguard is a Docker socket proxy we built in Go. Every Docker API request is blocked unless an explicit rule in your YAML config allows it — method, path, and request body are all evaluated before the request reaches the daemon. A client that connects without a matching allow rule gets a 403; there is no fallback to 'pass everything'. This posture means a compromised container or CI job can only do what you deliberately permitted.

How is Sockguard different from Tecnativa's docker-socket-proxy?

Tecnativa filters by URL path using environment variables. Sockguard adds request body inspection — we parse every container, exec, image, build, volume, network, service, swarm, and plugin write to block privileged workloads, non-allowlisted mounts and devices, unsafe sysctls, and more. We also support per-client policy profiles (route different callers to different rule sets by CIDR, mTLS certificate, or unix peer), signed policy bundles (cosign), container image trust verification, per-profile rollout modes (enforce / warn / audit), Prometheus metrics, and hot-reload with an admin API. Tecnativa has none of these. We also ship a Tecnativa-compatible env surface so you can swap us in without touching your existing config.

Does Sockguard inspect request bodies?

Yes — request body inspection is one of our core differentiators. We parse the JSON body on every write endpoint: container create and exec, image build and load, volume create, network create, secret and config create, service create and update, swarm init and join, node update, and plugin install. We check for privileged mode, host namespace sharing, non-allowlisted bind mounts and devices, capability additions, unsafe sysctls, non-allowlisted runtimes, and more. Oversized bodies return 413 before the inspector runs. We also inspect multipart plugin uploads and gzip-bomb guard all archive paths.

Can Sockguard listen over TCP, and is remote access secure?

Yes. Sockguard can listen on a TCP port in addition to (or instead of) a unix socket. For any non-loopback TCP listener we require mutual TLS 1.3 by default — plaintext remote TCP needs two explicit insecure acknowledgement flags before we accept it. Client identity on TCP is established via mTLS certificate selectors (CN, DNS/IP/URI SAN, SHA-256 SPKI pin). Sockguard can also dial a remote Docker daemon over TCP with mTLS and automatic endpoint failover (added in v1.4.0).

What are signed policy bundles and container image trust?

Signed policy bundles let you treat the on-disk YAML config as untrusted until a cosign / sigstore bundle confirms it. We support keyed (PEM ECDSA/RSA/ed25519) and keyless (Fulcio + Rekor) verification. The bundle is checked at startup and on every hot reload — a bad signature rejects the reload and leaves the running policy untouched. Container image trust goes further: before forwarding a POST /containers/create to the daemon, we resolve the image to its registry manifest digest, discover cosign signatures, and verify them against your configured signer identity. In enforce mode a container create is denied if the image is unsigned or signed by the wrong identity.

Is Sockguard production-ready and what license does it use?

Sockguard is Apache-2.0 licensed and has been in production use since v1.0.0. The proxy binary ships as a minimal Wolfi-based container image, cosign-signed with an SBOM and build provenance attached. We enforce a 96%+ Go statement-coverage floor in CI, run a proxy-vs-daemon differential fuzz harness on every PR, and have a published security policy at security@getsockguard.com. The v1.1.0 release incorporated fixes for 21 HIGH and MEDIUM findings from a full multi-axis security audit.

How do I migrate from Tecnativa's docker-socket-proxy?

We match Tecnativa's full environment-variable surface — CONTAINERS, EVENTS, SERVICES, NETWORKS, VOLUMES, TASKS, NODES, CONFIGS, SECRETS, ALLOW_RESTARTS, SOCKET_PATH, LOG_LEVEL, and the full section-variable set. Point DOCKER_HOST at the Sockguard socket instead of Tecnativa's and your existing env config continues to work. Sockguard's built-in Tecnativa env-var compatibility layer covers the same allow surface. Once migrated you can layer on body inspection, per-client profiles, and signed policies incrementally without breaking running workloads — use a profile in warn mode to measure what would have been denied before flipping to enforce.