129 lines
7.3 KiB
Markdown
129 lines
7.3 KiB
Markdown
> 0.7 update: configured managed certificates now have automatic renewal and
|
|
> validated hot deployment. Initial issuance/import remains explicit. Read
|
|
> [RENEWAL.md](RENEWAL.md) for defaults, retained profiles and opt-out.
|
|
|
|
# Certificate providers (0.6.0)
|
|
|
|
Source implementation; real provider/DNS/CA issuance and Rust runtime have not been
|
|
verified in the packaging environment. Offline tests substitute Certbot, so they
|
|
cannot establish that a DNS token, zone policy or CA deployment works.
|
|
|
|
## Workflow
|
|
|
|
Open Certificates -> Add certificate. Choose one provider or import mode, enter
|
|
the domains and metadata, then request issuance. Production is selected by default
|
|
in the panel and still requires the separate explicit production confirmation. Staging
|
|
remains available for testing and its certificates are not browser-trusted.
|
|
After a successful job, import its validated pair into the library, then assign the
|
|
certificate to a vhost. No CA operation occurs on startup or merely opening a form.
|
|
|
|
| Selection | Mechanism and required configuration |
|
|
|---|---|
|
|
| HTTP-01 / domain validation | Certbot webroot; domain names and a publicly reachable plaintext HTTP listener |
|
|
| Cloudflare | DNS-01; scoped API token; `certbot-dns-cloudflare` installed |
|
|
| OVH | DNS-01; `ovh-eu` or `ovh-ca`, application key/secret, consumer key; `certbot-dns-ovh` installed |
|
|
| RFC2136 | DNS-01; server/port, TSIG name/secret/algorithm; `certbot-dns-rfc2136` installed |
|
|
| PEM import | Upload fullchain/certificate and corresponding private key, then validate |
|
|
| Existing server files | Advanced: reference a PEM pair already in the certificate directory |
|
|
|
|
Python 3 and Certbot must be executable by the RustProxy service user. Install
|
|
plugins in that SAME Certbot environment. The application does not install packages
|
|
or execute sudo. Check the CLI installation with `bash dev.sh acme --doctor` and
|
|
`certbot plugins`; this does not validate provider credentials or DNS reachability.
|
|
DNS uses the API/plugin appropriate to the selected provider, not a Cloudflare
|
|
Tunnel integration or a hand-written replacement for ACME.
|
|
|
|
## HTTP-01 requirements and scope
|
|
|
|
Public TCP port **80** for every requested name must reach an active plaintext
|
|
RustProxy listener. NAT from public 80 to a private/custom HTTP port is allowed;
|
|
setting only port 8080 in public DNS is not sufficient. Check all published A/AAAA
|
|
addresses and multi-node routing. TLS-only listeners are not enough. There is no
|
|
TLS-ALPN-01 mode. This implementation accepts DNS names, not IP certificates.
|
|
Wildcard certificates require one of the DNS-01 providers, not HTTP-01.
|
|
|
|
During a running HTTP-01 job, RustProxy serves only
|
|
`/.well-known/acme-challenge/<token>` for that job's exact normalized hostnames.
|
|
Only GET/HEAD and bounded regular files from `certs/acme-http01` are accepted;
|
|
queries, traversal, unrelated names, HTTPS requests and inactive jobs cannot read
|
|
these files. The reserved path precedes application auth/cache/static pages so a
|
|
CA can validate ownership without logging in. This exception does not bypass
|
|
application authentication for any other path. Responses are no-store.
|
|
|
|
A CDN or upstream proxy must forward this path and the correct Host without
|
|
rewriting it. There is no automatic forwarding configuration at your DNS/CDN vendor.
|
|
Expired challenge jobs do not leave an open generic file server.
|
|
|
|
## DNS credentials and least privilege
|
|
|
|
Cloudflare: use an API token with `Zone:DNS:Edit` restricted to the zones used for
|
|
issuance. The adapter intentionally does not accept the account-wide Global API Key.
|
|
|
|
OVH: use a consumer key allowing `GET /domain/zone/` and GET/PUT/POST/DELETE for
|
|
`/domain/zone/<YOUR_ZONE>/*`. Repeat only for required zones, not the whole account.
|
|
Choose the region matching the account. Consult the official plugin docs if API
|
|
policies change. A domain registered at OVH but DNS hosted elsewhere must use the
|
|
actual authoritative DNS provider; registration alone is not sufficient.
|
|
|
|
RFC2136: retain the TSIG-limited update policy described in ACME_RFC2136.md. DNS
|
|
provider propagation delay is configurable. The helper rejects malformed tokens,
|
|
unknown/cross-provider fields and INI injection. It does not test your DNS policy
|
|
in advance. Wildcard DNS-01 issuance does not add wildcard HOST routing: vhost
|
|
hostnames remain exact matches.
|
|
|
|
## API input
|
|
|
|
Common fields: `provider`, `certificate_id`, `domains` (one or more DNS names), `email`,
|
|
`environment` (`staging`/`production`), `agree_tos`, `confirm_production`. RustProxy
|
|
does not impose its own domain-count ceiling; the selected CA/provider may still
|
|
apply its external certificate/SAN policy.
|
|
DNS providers accept `propagation_seconds`.
|
|
|
|
Provider-specific fields:
|
|
|
|
- `http01`: none; wildcard domains are rejected.
|
|
- `cloudflare`: `api_token`.
|
|
- `ovh`: `endpoint`, `application_key`, `application_secret`, `consumer_key`.
|
|
- `rfc2136`: `dns_server`, `dns_port`, `key_name`, `key_secret`, `key_algorithm`, `sign_query`.
|
|
|
|
`POST /api/acme/issue` is authenticated and CSRF-protected; one job runs at a time.
|
|
`GET /api/acme` is safe status metadata only. Job status is process-local; account
|
|
and credential files persist. A completed certificate has optional issuer metadata
|
|
with provider/environment, not a copy of request credentials.
|
|
|
|
## Secret storage, renewal and limitations
|
|
|
|
Provider secrets are sent to the private worker on stdin, not command arguments.
|
|
They are not stored in exported JSON, SQLite, localStorage or audit records.
|
|
Files are private (0600 credentials, 0700 directories); these permissions do NOT
|
|
encrypt them. The service user/root can read them. Certbot account/lineage state
|
|
and provider credential files persist for managed renewal under
|
|
`certs/acme/<environment>-<id>-<provider>`; RFC2136 keeps its old path without a
|
|
provider suffix. Issued PEM outputs use new immutable names before library import.
|
|
|
|
Back up these private profiles separately while issuance is idle: the standard
|
|
SQLite/configured-PEM backup does not include every account/credential profile.
|
|
Do not put real credentials into shell history or source-control examples.
|
|
Restrict the admin interface and service environment. Rotate exposed API credentials.
|
|
|
|
Configured managed certificates in 0.7 renew through the shared RustProxy worker;
|
|
validated changed material is published automatically while failed checks preserve
|
|
the active generation. Use the certificate's toggle to disable scheduled renewal.
|
|
PEM-only imports remain manual. A separate system Certbot timer may own a **different,
|
|
manual RustProxy certificate id** and publish it with `tls deploy --id ...`; it must not
|
|
also own a RustProxy-managed ACME profile. There is no external expiry alert, revocation
|
|
or certificate garbage collector. Cancellation
|
|
kills the worker group; interrupted DNS cleanup can leave TXT records an operator
|
|
must remove. See [renewal and recovery](RENEWAL.md) and test CA staging first.
|
|
|
|
## Primary references
|
|
|
|
- HTTP-01/DNS-01 constraints: https://letsencrypt.org/docs/challenge-types/
|
|
- Certbot webroot and operational use: https://eff-certbot.readthedocs.io/en/latest/using.html
|
|
- Cloudflare plugin/API scope: https://certbot-dns-cloudflare.readthedocs.io/en/stable/
|
|
- OVH plugin/API scopes: https://certbot-dns-ovh.readthedocs.io/en/latest/
|
|
- RFC2136 plugin: https://certbot-dns-rfc2136.readthedocs.io/en/stable/
|
|
|
|
These document upstream requirements, not evidence that this RustProxy build has
|
|
passed live provider or CA acceptance.
|