Skip to content

feat: web dashboard, client ACL, hot-applied settings, and bounded certificate cache - #58

Closed
mprasodjo wants to merge 1 commit into
esnet:mainfrom
mprasodjo:feat/dashboard-acl-settings
Closed

feat: web dashboard, client ACL, hot-applied settings, and bounded certificate cache#58
mprasodjo wants to merge 1 commit into
esnet:mainfrom
mprasodjo:feat/dashboard-acl-settings

Conversation

@mprasodjo

Copy link
Copy Markdown

Summary

This PR adds an operational layer on top of acme-proxy: an admin web dashboard, a client access-control list, hot-applied runtime settings, and a rate-limit-safe certificate cache. It also upgrades lego to v5, supports # comments in ca.json, and refreshes the documentation.

What's New

1. Transient HTTP-01 challenge listener

The shared HTTP-01 challenge server on port 80 now starts only when a certificate request begins and closes itself as soon as the last challenge completes. Port 80 is no longer held open for the lifetime of the process, it is only exposed while a challenge is actually being served.

2. Admin web dashboard

An optional, login-protected web console (dashboard block in ca.json, enabled when port > 0) served from the same process on its own listener:

  • Overview
    issuance/failure/revocation counts, certificates expiring within 7 days, recent activity feed
  • Certificates
    domain-grouped master/detail view: every issuance record per domain with client IPs, timestamps, status, failure reasons, validity windows; server-side search and pagination
  • Failed requests
    full failure reason per request (no truncation), source IP, requested names
  • Revocations, certificate cache (with per-domain cache deletion), and a live ACME request log
  • TLS
    the dashboard serves the same certificate as the client-facing :443 listener, same key and identity resolved through the shared cert cache, so enabling it never causes an extra upstream issuance; renewal happens in the background and swaps without restart
  • Client IP attribution and failure reasons are recorded on issuance and revocation records

3. Client ACL

An optional file-based allow-list (acl.file) gates every ACME API request:

  • One IP or CIDR subnet per line, # comments supported
  • Hot-reloaded on file change, edits apply to the next request, no restart
  • X-Forwarded-For aware for reverse-proxy deployments; fails closed (deny all, logged) if the configured file becomes unreadable
  • Editable from the dashboard with pre-save validation

4. Hot-applied runtime settings

The dashboard's Settings tab edits a safe subset of ca.json and applies changes without restarting the daemon: upstream CA identity (with automatic ACME account re-registration), challenge type/DNS provider, timeouts, cache bounds, concurrency limit (live semaphore resize), dashboard credentials and listener (rebind with graceful drain). Saves are validated end-to-end before anything is written; every save keeps a backup at ca.json.bak-settings. You need to Restart when you change bind ip address.

5. Bounded certificate cache

  • cert_cache_max_age (default 30 days): cached certificates stop being served once they exceed this age, forcing a fresh issuance. This bounds the renewal cadence so upstream per-name rate limits (e.g. Let's Encrypt's 5 certs/week) are never tripped by stale cache reuse
  • dashboard.tls_max_age_days (default 30): same bound for the proxy's own certificate, with background renewal and atomic swap

6. Configuration ergonomics

  • ca.json supports # comments outside string literals (string-aware stripper in the config loader); the _comment_* field workaround is gone
  • dashboard and acl are top-level config blocks, outside authority

About the fork/certificates directory

This PR carries a vendored copy of smallstep/certificates in-tree under fork/, replacing the current module redirect
(replace github.com/smallstep/certificates => github.com/esnet/certificates v0.30.2-patch.2).

Why: the new features require small hooks inside step-ca itself, a per-request metadata hook (client IP / CSR / serial), an optional per-request ACL gate in the ACME middleware, # comment support in the config loader, and a persistent CA TLS key. Vendoring keeps this branch fully self-contained and reviewable in one place.

Scope: the copy is based on esnet/certificates v0.30.2-patch.2; the actual delta is small and self-contained:

File Change
acme/api/meta_hooks.go (new) RequestMetaHook + RequestACLHook variables
acme/api/{handler,order,revoke}.go invoke the hooks (new-order, finalize, revoke, common middleware)
acme/challenge.go SkipChallengeValidation toggle (proxy deployments)
authority/config/config.go # comment stripping in LoadConfiguration; exported LoadedFilepath
authority/tls.go persistent CA HTTPS key (tls_key.pem next to ca.json) so restarts reuse the cached upstream certificate
ca/ca.go wire SkipChallengeValidation from config

For maintainers: if you prefer keeping step-ca patches in esnet/certificates (the current pattern), these nine files can be contributed there as a follow-up tag instead, happy to split this PR or prepare the module patch separately. The in-tree copy is offered purely to keep this contribution self-contained.

Upgrade Notes / Breaking Changes

  • lego upgraded v4.33.0 -> v5.4.1 (context threading, acme.ExtendedAccount, dns01 client options, challenge.Provider signatures)
  • dashboard/acl live at the top level of ca.json
  • _comment_* fields are no longer needed; use # comments
  • Dashboard credentials default to admin/kambing, change them via settings or config before exposing the dashboard

Testing

  • Unit tests: ACL parsing/hot-reload/fail-closed, request-meta bridge, comment stripper, cache max-age semantics, settings merge/validate/reject and hot-apply, dynamic semaphore resize under in-flight acquisitions, dashboard auth and API handlers, domain aggregation and pagination
  • go test -race ./externalcas, gitleaks, govulncheck, staticcheck all pass (repo pre-commit hooks)
  • Verified end-to-end against Let's Encrypt on a live deployment (http-01, dashboard over shared certificate, ACL allow/deny, settings hot-apply)

Documentation

README.md and docs/content/configuration.md document the dashboard, ACL, runtime settings, bounded cache, # comments, and the new config blocks.

Notes

On going: TLS-ALPN-01 challenge to have same behaviour such as HTTP-01 challenge.

Dashboard Screenshot

image

…d cert cache

Fork of esnet/acme-proxy with an operational layer on top:

- Admin web dashboard (login + sessions) on a dedicated port: overview,
  domain-grouped certificate history with per-domain request details
  (client IPs, timestamps, status, failure reasons), failed-request
  analysis, revocation history, certificate cache management with
  per-domain cache deletion, live ACME request log, ACL editor, settings
  editor. HTTPS shares the client-facing :443 certificate (same key and
  identity resolved through the cert cache) so no extra upstream
  issuance; background renewal swaps certs without restart.
- File-based client ACL (IPs/CIDRs, '#' comments, hot reload, X-Forwarded-For
  aware, fail-closed) enforced at the ACME API layer.
- Dashboard settings tab edits ca.json and applies changes without a
  daemon restart: atomic config swap, ACME account re-registration on
  upstream identity change, challenge provider rebuild, dynamic
  concurrency semaphore, dashboard listener rebind, manual TLS swap.
  Validated end-to-end before write; backup per save.
- Bounded certificate cache (cert_cache_max_age, default 30 days) and
  proxy-own-cert age bound (tls_max_age_days) to stay safely inside
  upstream rate limits such as Let's Encrypt 5 certs/week/name.
- HTTP-01 challenge listener closes when idle.
- '#' comments supported in ca.json; dashboard and acl as top-level
  config blocks.
- go-acme/lego upgraded to v5.4.1.
@netops2devops netops2devops added the low-effort Low effort drive by submission. Very likely AI slop. label Sep 2, 2026
@netops2devops netops2devops added the violates-contributor-guidelines https://github.com/esnet/acme-proxy/blob/main/CONTRIBUTING.md label Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

low-effort Low effort drive by submission. Very likely AI slop. violates-contributor-guidelines https://github.com/esnet/acme-proxy/blob/main/CONTRIBUTING.md

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants