package main import ( "fmt" "os" "strings" "golang.org/x/crypto/acme/autocert" ) // The certificate-cache seam (issue #550 Part 12, Phase 0 item 8): router // boxes in a pool must eventually SHARE issued certs — the per-host autocert // certs, the DNS-01 wildcard PEMs, and the wildcard ACME account key — so // every issuance artifact goes through one autocert.Cache chosen here, never // direct file I/O. autocert already defines exactly the interface a remote // backend needs (Get/Put/Delete with ctx, ErrCacheMiss for absent), so there // is no parallel abstraction: an S3 backend is a drop-in behind this // constructor. // newCertCache returns the certificate cache selected by LCHAT_CERT_CACHE. // Unset (or "dir") is today's on-disk layout — autocert.DirCache over dir, // cache keys as plain file names — byte-identical to what a box already has // at /data/acme, so an existing cache keeps working over a restart with no // migration. "s3" is reserved for the pooled-router backend; until it exists // it refuses to start, because failing loudly beats silently minting certs // into a local dir the rest of the pool can't see. func newCertCache(dir string) (autocert.Cache, error) { switch backend := strings.TrimSpace(os.Getenv("LCHAT_CERT_CACHE")); backend { case "", "dir": return autocert.DirCache(dir), nil case "s3": // TODO(#550): a thin Get/Put/Delete over S3 GetObject/PutObject/ // DeleteObject, mapping a missing key to autocert.ErrCacheMiss. The // AWS SDK v2 S3 client is already a module dependency // (internal/activator uses it for hibernation), so no new client code // is needed — only bucket/prefix config and the pooled-router rollout. return nil, fmt.Errorf("LCHAT_CERT_CACHE=s3: reserved, not implemented yet") default: return nil, fmt.Errorf("LCHAT_CERT_CACHE=%q: want unset, \"dir\", or \"s3\"", backend) } }