You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Flynn currently generates self-signed TLS certificates during bootstrap (pkg/certgen) and stores them in PostgreSQL. There is no integration with any ACME certificate authority. This feature adds automatic Let's Encrypt certificate provisioning and renewal, supporting both HTTP-01 (webserver-based) and DNS-01 (DNS record-based) challenges.
Uses go-acme/lego (v4) as the ACME client library, including lego's built-in autodns provider for DNS-01 challenges via the AutoDNS JSON API (api.autodns.com/v1/). No separate AutoDNS library is needed.
lego ships a first-class AutoDNS provider (providers/dns/autodns, added in v3.2.0) that talks to the AutoDNS JSON API (https://api.autodns.com/v1/, overridable via AUTODNS_ENDPOINT). Use it directly — no custom adapter, no extra dependency:
POST /certs/letsencrypt — provision a Let's Encrypt cert
GET /certs/letsencrypt/:id — check provisioning status
DELETE /certs/letsencrypt/:id — revoke a cert
GET /certs/letsencrypt/config — get/set ACME configuration
Verify /.well-known/acme-challenge/* is served on HTTP (port 80)
Test hot-swap on certificate renewal
Phase 4: CLI
flynn cert letsencrypt command
Status and revoke subcommands
Phase 5: Bootstrap Integration
Optional: auto-provision cluster domain cert during bootstrap
ACME config in bootstrap manifest
Phase 6: Testing
Unit tests for pkg/autocert/ (mock lego client)
Integration test with Let's Encrypt staging
Test HTTP-01 and DNS-01 challenge flows
Test certificate renewal lifecycle
Test hot-swap (renew cert while traffic is flowing)
Design Decisions
lego vs manual ACME: Use lego — handles account management, challenge orchestration, certificate parsing, and renewal logic.
lego's built-in autodns provider vs a custom adapter: lego ships a native providers/dns/autodns provider (since v3.2.0, PR Godeps: Update BurntSushi/toml. flynn/flynn#957, actively maintained upstream) using the AutoDNS JSON API (api.autodns.com/v1/). Use it via autodns.NewDNSProviderConfig and drop consolving/autodns.go (a separate XML-API binding). Fall back to an XML-API adapter only if the AutoDNS account lacks JSON API access.
Certificate storage: Reuse existing certificates table with new columns (source, expires_at, etc.) — keeps the existing route→certificate mapping and router sync unchanged.
Challenge handler location: Mount on the controller's HTTP port (port 80). Router needs to ensure /.well-known/acme-challenge/* reaches the controller.
Renewal timing: Renew at 30 days before expiry (Let's Encrypt certs are 90 days). Check daily via background goroutine.
Open Questions
Should the ACME account private key be stored in PostgreSQL (encrypted) or a separate secret store?
How to handle wildcard certificates (require DNS-01)?
Support multiple DNS providers beyond AutoDNS, or AutoDNS-only for now?
Port 80: does the Flynn router already handle HTTP on port 80, or do we need explicit HTTP listener support?
Confirm the AutoDNS account has JSON API access (api.autodns.com/v1/); if not, fall back to consolving/autodns.go via the XML endpoint (gateway.autodns.com)
Rate limits: how to handle Let's Encrypt rate limits (50 certs/week) in a multi-node cluster?
Summary
Flynn currently generates self-signed TLS certificates during bootstrap (
pkg/certgen) and stores them in PostgreSQL. There is no integration with any ACME certificate authority. This feature adds automatic Let's Encrypt certificate provisioning and renewal, supporting both HTTP-01 (webserver-based) and DNS-01 (DNS record-based) challenges.Uses go-acme/lego (v4) as the ACME client library, including lego's built-in
autodnsprovider for DNS-01 challenges via the AutoDNS JSON API (api.autodns.com/v1/). No separate AutoDNS library is needed.Current Certificate Architecture
Key files:
pkg/certgen/certgen.go— self-signed cert generationpkg/tlscert/tlscert.go— wrapper (CA + leaf)controller/data/schema.go:707-721—certificates+route_certificatestablescontroller/data/route.go:104-133— cert CRUD with dedup (cert_sha256unique index)router/http.go:352-417— TLS listener withGetCertificateSNI callbackrouter/types/types.go:8-22—Certificatestruct (ID, Cert, Key, Routes)Proposed Design
1. New Package:
pkg/autocert/A new
pkg/autocert/package that encapsulates ACME certificate management:2. Configuration
Add an
autocertsection to the controller config (or cluster environment variables):3. ACME Client Setup (lego)
4. AutoDNS DNS-01 Provider (lego built-in)
lego ships a first-class AutoDNS provider (
providers/dns/autodns, added in v3.2.0) that talks to the AutoDNS JSON API (https://api.autodns.com/v1/, overridable viaAUTODNS_ENDPOINT). Use it directly — no custom adapter, no extra dependency:Credentials are supplied via
NewDNSProviderConfigfrom controller config (not env vars).5. HTTP-01 Challenge Handler
For HTTP-01, the controller serves
/.well-known/acme-challenge/<token>on port 80 (plain HTTP, before TLS termination):6. Certificate Lifecycle
certificatestable, linked to the route viaroute_certificates.GetCertificateserves the real cert.Renew()→ challenge re-issued → new cert stored → event fired → router hot-swaps.7. API Changes
New controller endpoints:
CLI commands:
8. Database Schema Change
Implementation Plan
Phase 1: Core ACME Library
pkg/autocert/with lego client setupautodnsprovider (autodns.NewDNSProviderConfig) for DNS-01certificatestablePhase 2: Controller Integration
/certs/letsencrypt/*API endpointssource,expires_at,acme_account_id,domainscolumns)Phase 3: Router Integration
/.well-known/acme-challenge/*is served on HTTP (port 80)Phase 4: CLI
flynn cert letsencryptcommandPhase 5: Bootstrap Integration
Phase 6: Testing
pkg/autocert/(mock lego client)Design Decisions
lego vs manual ACME: Use lego — handles account management, challenge orchestration, certificate parsing, and renewal logic.
lego's built-in autodns provider vs a custom adapter: lego ships a native
providers/dns/autodnsprovider (since v3.2.0, PR Godeps: Update BurntSushi/toml. flynn/flynn#957, actively maintained upstream) using the AutoDNS JSON API (api.autodns.com/v1/). Use it viaautodns.NewDNSProviderConfigand dropconsolving/autodns.go(a separate XML-API binding). Fall back to an XML-API adapter only if the AutoDNS account lacks JSON API access.Certificate storage: Reuse existing
certificatestable with new columns (source,expires_at, etc.) — keeps the existing route→certificate mapping and router sync unchanged.Challenge handler location: Mount on the controller's HTTP port (port 80). Router needs to ensure
/.well-known/acme-challenge/*reaches the controller.Renewal timing: Renew at 30 days before expiry (Let's Encrypt certs are 90 days). Check daily via background goroutine.
Open Questions
api.autodns.com/v1/); if not, fall back toconsolving/autodns.govia the XML endpoint (gateway.autodns.com)