feat(agent): HAPROXY_AGENT_TLS_HOSTS for self-signed cert SANs - #110
Merged
Conversation
The agent auto-generates a self-signed cert covering only localhost, 127.0.0.1, ::1 and a random container hostname. Clients reaching the agent by a static container IP (e.g. the homelab gearbox-agent at 172.16.2.3) hit cert-verification failures — the previous workaround was disabling TLS verification on the dashboard side. HAPROXY_AGENT_TLS_HOSTS accepts a comma-separated list of extra SANs that get baked into the auto-generated cert. LoadOrCreateTLSCert now also regenerates the cert when an existing one is missing a requested SAN, so adding a host to the env var takes effect on the next restart with no manual cleanup. Dropped the os.Hostname() auto-SAN — in a container it's a random short ID that changes per recreation and would trigger needless regen. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds operator-configurable SANs to the gearbox-agent’s auto-generated self-signed TLS certificate via a new HAPROXY_AGENT_TLS_HOSTS env var, and ensures the cert is automatically regenerated when the requested SAN set expands.
Changes:
- Add
HAPROXY_AGENT_TLS_HOSTSparsing to agent config and pass it into self-signed cert generation. - Reuse existing self-signed certs only when they’re valid and cover all requested SANs; otherwise regenerate.
- Update docs and strengthen unit tests to assert SAN contents and regeneration behavior.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
gearbox-agent/internal/framework/crypto/tls.go |
Adds SAN coverage verification and triggers regeneration when required SANs are missing. |
gearbox-agent/cmd/gearbox-agent/main.go |
Stops adding os.Hostname() and wires cfg.TLSHosts into self-signed TLS initialization/logging. |
gearbox-agent/internal/framework/config/config.go |
Adds TLSHosts to config and parses HAPROXY_AGENT_TLS_HOSTS as a comma-separated list. |
gearbox-agent/internal/framework/config/config_test.go |
Adds unit tests for HAPROXY_AGENT_TLS_HOSTS parsing behavior. |
gearbox-agent/internal/framework/crypto/crypto_test.go |
Strengthens cert SAN assertions and adds regeneration-on-missing-SAN test. |
gearbox-agent/README.md |
Documents HAPROXY_AGENT_TLS_HOSTS and auto-regeneration behavior. |
gearbox-agent/docs/docker.md |
Documents how to set HAPROXY_AGENT_TLS_HOSTS for non-loopback access. |
…match - config.go: TLSHosts doc no longer claims os.Hostname() is auto-added; explains why we explicitly skip it (random container ID forces regen). - tls.go: verifyCertCoversHosts now lowercases DNS SANs and strips a trailing dot on both sides before comparison. Per RFC 6125 §6.4 DNS host matching is case-insensitive, so "Example.COM." and "example.com" must compare equal — otherwise a casing-only env-var edit would force a spurious cert regeneration. IP comparison is unchanged. - crypto_test.go: extends TestLoadOrCreateTLSCert_RegenOnMissingSAN with two new assertions covering the casing and trailing-dot equivalences. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
HAPROXY_AGENT_TLS_HOSTSenv var (comma-separated list of hostnames / IPs) — those entries are baked into the auto-generated self-signed cert as SANs alongside the always-on loopback set (localhost,127.0.0.1,::1).LoadOrCreateTLSCertnow regenerates the cert when an existing one is missing a requested SAN, so adding a host to the env var takes effect on the next restart with no manual cleanup.os.Hostname()auto-SAN: in a container that's a random short ID that changes per recreation, which would trigger needless regen now that we verify SAN coverage. Operators who want a specific hostname pin it explicitly via the new env var.Why
The agent's self-signed cert previously covered only loopback + the container's random hostname. Clients dialling the agent by a static container IP or LAN hostname hit
x509: certificate is valid for 127.0.0.1, ::1, not <IP>and the workaround was disabling TLS verification on the client side. This gives operators a clean knob to make the cert match the address clients actually use.Test plan
go test ./...(full agent suite, all green)go vet ./...cleanTestLoad_TLSHosts— 6 cases covering unset, whitespace-only, single host, comma list, surrounding whitespace, empty entriesTestGenerateSelfSignedCert_IncludesHostsstrengthened to parse the cert and assert both requested SANs and the loopback set are presentTestLoadOrCreateTLSCert_RegenOnMissingSAN— verifies reuse on identical hosts (same serial), regen on added host (new serial, both SANs present)markdownlint-cliclean on touched markdownHAPROXY_AGENT_TLS_HOSTS=mjolnir,172.16.2.3,10.0.0.1, wipedata/tls/, confirm the regenerated cert has those SANs and the dashboard can connect with TLS verification enabled. (Will run this on the homelab side once the PR is merged + image published.)Notes for reviewer
The interesting bit is
verifyCertCoversHostsin tls.go and the corresponding test — making sure operators don't have to remember to wipe the cert file after changing the env var. The check matches IPs bynet.IP.String()to handle equivalent forms (e.g.::1vs0:0:0:0:0:0:0:1).No config change required for existing deployments:
HAPROXY_AGENT_TLS_HOSTSdefaults to nil, behaviour matches before for any client that was already reaching the agent overlocalhost/127.0.0.1/::1.🤖 Generated with Claude Code