Skip to content

feat(agent): HAPROXY_AGENT_TLS_HOSTS for self-signed cert SANs - #110

Merged
sarg3nt merged 2 commits into
mainfrom
fix/agent-tls-hosts-san
May 17, 2026
Merged

feat(agent): HAPROXY_AGENT_TLS_HOSTS for self-signed cert SANs#110
sarg3nt merged 2 commits into
mainfrom
fix/agent-tls-hosts-san

Conversation

@sarg3nt

@sarg3nt sarg3nt commented May 17, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds HAPROXY_AGENT_TLS_HOSTS env 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).
  • LoadOrCreateTLSCert now 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 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 ./... clean
  • New unit tests:
    • TestLoad_TLSHosts — 6 cases covering unset, whitespace-only, single host, comma list, surrounding whitespace, empty entries
    • TestGenerateSelfSignedCert_IncludesHosts strengthened to parse the cert and assert both requested SANs and the loopback set are present
    • TestLoadOrCreateTLSCert_RegenOnMissingSAN — verifies reuse on identical hosts (same serial), regen on added host (new serial, both SANs present)
  • markdownlint-cli clean on touched markdown
  • Smoke: deploy the new image with HAPROXY_AGENT_TLS_HOSTS=mjolnir,172.16.2.3,10.0.0.1, wipe data/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 verifyCertCoversHosts in 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 by net.IP.String() to handle equivalent forms (e.g. ::1 vs 0:0:0:0:0:0:0:1).

No config change required for existing deployments: HAPROXY_AGENT_TLS_HOSTS defaults to nil, behaviour matches before for any client that was already reaching the agent over localhost / 127.0.0.1 / ::1.

🤖 Generated with Claude Code

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>
Copilot AI review requested due to automatic review settings May 17, 2026 00:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_HOSTS parsing 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.

Comment thread gearbox-agent/internal/framework/config/config.go Outdated
Comment thread gearbox-agent/internal/framework/crypto/tls.go
…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>
@sarg3nt
sarg3nt merged commit 0799f82 into main May 17, 2026
22 checks passed
@sarg3nt
sarg3nt deleted the fix/agent-tls-hosts-san branch May 28, 2026 16:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants