Skip to content

feat: replace chisel broker with purpose-built mTLS Go daemon - #1

Open
sarrafgsarraf wants to merge 2 commits into
mainfrom
gs/go-daemon-rewrite
Open

feat: replace chisel broker with purpose-built mTLS Go daemon#1
sarrafgsarraf wants to merge 2 commits into
mainfrom
gs/go-daemon-rewrite

Conversation

@sarrafgsarraf

@sarrafgsarraf sarrafgsarraf commented Jul 25, 2026

Copy link
Copy Markdown

What this is

Replaces the chisel-based reverse-SOCKS broker with a purpose-built, self-contained Go daemon — the on-prem component customers run so SaaS ZeroPath can reach private hosts (GHES, GitLab self-managed, Bitbucket DC, Jira DC) over one outbound mTLS + yamux connection, with no inbound firewall changes.

The old chisel implementation disabled server auth (--tls-skip-verify, no pinning), defaulted to a whole-network SOCKS proxy, and required NET_ADMIN. This daemon fixes all of that.

Why replace the old broker

  • mTLS + SPKI pinning, InsecureSkipVerify is never set (old broker used --tls-skip-verify).
  • Pure byte pipe — never terminates TLS to the target or to zeropath.com; never sees repo contents, credentials, or API tokens.
  • Default-deny intersection allowlist (gateway-pushed ∩ local allowlist.yaml) + resolved-IP re-screen (loopback/metadata/CGNAT refused) instead of a whole-network SOCKS proxy.
  • No NET_ADMIN/NET_RAW, distroless static, non-root (uid 65532), read-only rootfs friendly.
  • Enrollment: generates its keypair locally, exchanges a one-time token + CSR for a short-lived client cert; instantly revocable server-side.

Contents

  • Go daemon at repo root: main.go, enroll.go, tunnel.go, reverse.go, forward.go, allowlist.go, framing.go, tests, go.mod, go.sum, Dockerfile.
  • DEPLOYMENT.md — Kubernetes + systemd deployment steps.
  • Updated README.md, .gitignore.
  • Removes the old chisel files (Dockerfile.client, Dockerfile.server, *-entrypoint.sh, deploy-example.sh, test-client.sh).

Build & test

go build ./..., go vet ./..., and go test ./... all pass. go.sum is committed (covers hashicorp/yamux, yaml.v3, and its indirect gopkg.in/check.v1); go.mod stays at go 1.22 so the golang:1.22-alpine Docker stage builds it unchanged.

Relationship to the SaaS side

The ZeroPath-side counterpart (broker-gateway, /api/broker/enroll, tRPC admin API, Prisma model, dialers, Pulumi infra) lives in the ZeroPathAI/cunningham monorepo (PR #1868).

Enrollment SPKI-pin contract — resolved

This daemon requires a serverSpkiPin field in the enrollment response to pin the gateway's leaf (tunnel.go spkiPin = sha256/base64(SubjectPublicKeyInfo DER)). The cunningham /api/broker/enroll endpoint now computes and returns it (with a golden test asserting byte-parity against the openssl/Go value), so first-boot enrollment works end to end.

🤖 Generated with Claude Code

sarrafgsarraf and others added 2 commits July 25, 2026 18:42
Replace the chisel-based reverse-SOCKS broker (client/server Dockerfiles +
entrypoint scripts) with a purpose-built, self-contained Go daemon.

The daemon dials one outbound TLS 1.3 mTLS connection to the ZeroPath
broker-gateway, SPKI-pins the gateway (InsecureSkipVerify is never set),
multiplexes with yamux, and splices reverse streams to a default-deny
intersection allowlist of internal hosts. It also runs a forward CONNECT proxy
that permits only zeropath.com:443. It is a pure byte pipe: it never terminates
TLS to the internal target or to zeropath.com, so it never sees repository
contents, credentials, or ZeroPath API tokens.

Distroless static image, non-root (uid 65532), no NET_ADMIN/NET_RAW. Adds
DEPLOYMENT.md with Kubernetes and systemd deployment steps.

The ZeroPath SaaS-side counterpart (broker-gateway, enrollment endpoint, admin
API, dialers) lives in the ZeroPathAI/cunningham monorepo.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Generate go.sum via `go mod tidy` so the module builds reproducibly without a
network fetch of checksums at build time. Covers hashicorp/yamux, yaml.v3, and
its indirect gopkg.in/check.v1. go.mod stays at `go 1.22` with no toolchain pin,
so the golang:1.22-alpine Docker build stage still compiles it.

Validated locally: `go build ./...`, `go vet ./...`, and `go test ./...` all pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant