v0.34.0_fina;
This commit is contained in:
1 parent
1ca019d849
commit
c207e8a03f
69 files changed
+1496
-13838
No files matched your search
+41
-116
@@ -1,139 +1,64 @@
|
||||
> 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.
|
||||
# Certificates, ACME providers and renewal
|
||||
|
||||
# Certificate providers
|
||||
Certificates are managed under **Certificates**. You can import a PEM pair, reference accessible external certificate files or request a managed ACME certificate. Issuing a certificate does **not** automatically assign it to a Vhost; choose the certificate in the intended frontend/Vhost afterwards.
|
||||
|
||||
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.
|
||||
## Supported certificate methods
|
||||
|
||||
## 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 |
|
||||
| Mode | Requirements |
|
||||
|---|---|
|
||||
| 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 |
|
||||
| **HTTP-01 (Let's Encrypt)** | DNS for every name and a public TCP port **80** reaching a plaintext RustProxy listener; HTTP challenge endpoint is handled by RustProxy. |
|
||||
| **Cloudflare DNS-01** | A zone-limited `Zone:DNS:Edit` API token and functioning Certbot Cloudflare plugin. |
|
||||
| **OVH DNS-01** | Correct regional API endpoint plus application key/secret and consumer key scoped to the DNS zone. |
|
||||
| **RFC2136 DNS-01** | DNS server, TSIG name/secret/algorithm and an update policy restricted to the requested records. |
|
||||
| **PEM import** | A matching certificate chain and private key, validated before activation. |
|
||||
| **Existing local files** | Trusted absolute certificate/key paths accessible to the RustProxy service account. Suitable for a separately managed Certbot lineage. |
|
||||
|
||||
RustProxy now owns its preferred Certbot environment under `<data-dir>/acme-python`.
|
||||
When it is missing, RustProxy creates a virtual environment and installs pinned Certbot
|
||||
5.8.0 plus `certbot-dns-cloudflare`, `certbot-dns-ovh` and
|
||||
`certbot-dns-rfc2136` 5.8.0 with pip. No distribution Python files are modified and
|
||||
RustProxy never executes sudo. If the stdlib `venv` module is unavailable but system
|
||||
pip works, `virtualenv` is bootstrapped only inside the RustProxy data directory.
|
||||
HTTP-01 cannot create wildcard certificates; use DNS-01. A staging certificate is for testing and is not generally trusted by browsers. Production issuance requires explicit confirmation of the production operation and provider terms.
|
||||
|
||||
If local setup fails, a runnable system `certbot` from `PATH` is used as fallback. The
|
||||
Certificates panel reports whether the managed environment, the system fallback, or no
|
||||
ACME runtime is active. Systems without Python (for example some appliance layouts)
|
||||
retain PEM import and existing-file certificate modes even though ACME issuance/renewal
|
||||
is unavailable. `bash dev.sh acme --doctor` and `certbot plugins` inspect only the
|
||||
current shell/system fallback; they do not validate provider credentials or DNS reachability.
|
||||
## First issuance and assignment
|
||||
|
||||
The shipped OCI image contains Python, venv/pip and distribution Certbot packages as an
|
||||
offline fallback. Its preferred managed environment is still created in the persisted
|
||||
`/var/lib/rustproxy` data volume.
|
||||
1. Open **Certificates → Add certificate** and choose the provider/import method.
|
||||
2. Enter DNS names, a unique certificate ID, contact email where requested and provider-specific credentials or files.
|
||||
3. For HTTP-01, confirm public DNS and HTTP port 80 reach RustProxy even when a separate public HTTPS port is active. For DNS-01, validate authoritative DNS provider and propagation permissions.
|
||||
4. Run staging first when testing new credentials/DNS, then confirm production issuance deliberately.
|
||||
5. Wait for the job result; inspect errors under Certificates and the service logs.
|
||||
6. Assign the issued/imported certificate to the intended Vhost/listener and verify a real TLS handshake with the public hostname.
|
||||
|
||||
## HTTP-01 requirements and scope
|
||||
The reserved HTTP-01 challenge path is available only during eligible issuance/renewal work. It is not a generic public file server and does not bypass authentication for unrelated URLs.
|
||||
|
||||
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.
|
||||
## Managed ACME runtime
|
||||
|
||||
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.
|
||||
RustProxy prefers a **private Certbot/Python environment** under the application data directory (typically `/var/lib/rustproxy/acme-python`), with support for the Cloudflare, OVH and RFC2136 plugins. A working system Certbot may be used as fallback; systems without a usable runtime can still import or reference PEM files. The application does not run system-wide `sudo` to install plugins or modify distribution-owned Python packages.
|
||||
|
||||
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.
|
||||
Provider tokens and TSIG secrets are security credentials: use least privilege, protect files and the data directory, rotate compromised values and restrict backups. ACME DNS credentials may be stored in private provider/Certbot files; do not assume they are stored in the same way as RustProxy administration Secret Store records.
|
||||
|
||||
## DNS credentials and least privilege
|
||||
## Automatic renewal
|
||||
|
||||
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.
|
||||
Managed certificates have configurable automatic renewal. RustProxy runs the scheduler while the service is active; this is **not** a separate cron service. Certificate status and next checks are visible in Certificates. The scheduler uses spaced checks and retry/backoff on failure, without automatically forcing a CA reissue on every check.
|
||||
|
||||
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.
|
||||
After successful renewal, RustProxy validates the new pair and publishes it to new TLS handshakes without interrupting existing connections. Invalid/rejected material should leave the previous active pair in place. Keep room for archived ACME generations and monitor expiry; this is not an independent external expiry-alert service. **Do not run an overlapping system Certbot timer** against the RustProxy-managed ACME profiles.
|
||||
|
||||
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.
|
||||
## Externally managed Certbot / PEM files
|
||||
|
||||
## API input
|
||||
When another service owns the certificate, add a manual certificate with the actual certificate and key paths, for example:
|
||||
|
||||
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`.
|
||||
```text
|
||||
/etc/letsencrypt/live/example.com/fullchain.pem
|
||||
/etc/letsencrypt/live/example.com/privkey.pem
|
||||
```
|
||||
|
||||
Provider-specific fields:
|
||||
Keep the original Certbot renewal system and use the RustProxy certificate reload/deploy API or local CLI after rotation. RustProxy resolves relevant symlinks again during reload. The service account must have directory traverse and narrow read permissions to the **current** key file; `ReadOnlyPaths` alone does not grant filesystem permission. Renewal hooks may need to reapply ACLs to replaced target files.
|
||||
|
||||
- `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`.
|
||||
### Restricted certificate API
|
||||
|
||||
`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.
|
||||
Create an appropriately scoped credential in **Settings → Certificate API**. Its allowed certificate IDs and action permissions control **reload** or **deploy**; it is not a general administration token. A caller supplies both a Bearer credential and its configured `X-RustProxy-Certificate-Key` ID. Use HTTPS outside local/trusted transport and never store the clear token in the repository. See [Administration API](API.md).
|
||||
|
||||
## Secret storage, renewal and limitations
|
||||
## Problems to check
|
||||
|
||||
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.
|
||||
- **HTTP-01 validation fails:** public TCP 80, all A/AAAA DNS answers, Host forwarding and challenge path handling through any CDN/router.
|
||||
- **DNS-01 fails:** authoritative DNS provider, correct zone, TSIG/API scope and propagation interval.
|
||||
- **Certificate available but wrong site certificate displayed:** Vhost assignment, listener binding, hostname and restart/reload state.
|
||||
- **Renewal stops:** Certbot runtime, private profile files, DNS secrets, clock skew, permissions and CA limits.
|
||||
- **External file reload fails:** rotated symlink targets, certificate/key match, SAN coverage and read permissions.
|
||||
|
||||
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.
|
||||
Keep a private encrypted application backup and a separate copy of any external certificate/key material. See [Backup and recovery](BACKUP.md) and [Security](SECURITY.md).
|
||||
Reference in new issue
Block a user