Files
RustProxy/docs/ACME_RFC2136.md
T
2026-10-04 09:29:10 +02:00

161 lines
8.0 KiB
Markdown

# Basic Let's Encrypt / RFC2136 integration - historical 0.5.0 record
> Historical implementation record. For current certificate-provider behavior, use [ACME_PROVIDERS.md](ACME_PROVIDERS.md) and [RENEWAL.md](RENEWAL.md).
For the multi-provider UI, HTTP-01, Cloudflare and OVH, see ACME_PROVIDERS.md.
Managed automatic renewal added in 0.7 is documented in RENEWAL.md.
The RFC2136 fields and private account paths below remain supported.
## Scope and prerequisites
This is an integrated control-plane adapter for **Certbot + certbot-dns-rfc2136**,
not a newly written ACME or DNS-update protocol client. The plugin creates and
cleans up DNS-01 TXT records through TSIG-signed RFC2136 updates. It must be
installed separately. No real CA issuance or authoritative-DNS update has been
performed in the packaging environment.
Rust compilation, process integration and actual certificate deployment remain
acceptance work (TEST_REPORT.md).
Use Linux/Unix with Python 3.10+, a current compatible Certbot/plugin installation,
and `python3` and `certbot` available in the RustProxy service's PATH. Check:
```bash
bash dev.sh acme --doctor
certbot --version
certbot plugins --authenticators
```
The doctor command reports executable discovery and the required plugin's name;
it does NOT verify the plugin, DNS permissions or network connectivity. Nothing
is installed automatically, and RustProxy never invokes sudo. A service hardening
policy must allow child processes, the cert directory, DNS updates/queries to the
chosen server and outbound HTTPS to the CA. Do not run the proxy as root just to
make Certbot available. Use a private, service-owned cert directory (0700).
The operator must control publicly valid DNS names and an authoritative DNS
server that permits the configured TSIG identity to change **only the necessary
_acme-challenge TXT names**. Do not grant zone-wide update authority merely for
certificates. A private update-server IP is acceptable when the resulting TXT
records are visible to the public validation resolvers. Split DNS/views, CAA,
replication delays and delegation must be checked on the operator's DNS setup.
DNS-01 does not require opening the application's HTTP listener for a challenge.
## Panel workflow
Open **Certificates > Let's Encrypt / RFC2136**. Enter a certificate library ID,
contact email, comma-separated DNS names (including optional `*.example.org`),
DNS update server IP/port, TSIG name, base64 secret, algorithm and propagation
wait. ASCII/punycode DNS names only; up to 16 names. SHA256 is the default TSIG
algorithm; SHA384/SHA512 are also allowed. SHA1/MD5 are not exposed. A TSIG key
name may be a single label such as `keyname.`. Optional signed SOA queries support
DNS servers/views that require them. Port defaults to 53; propagation defaults
to 60 seconds (allowed 10..900).
Start with **staging**. Its certificates are not publicly trusted. Production
requires a separate explicit confirmation, in addition to agreement with the
Let's Encrypt subscriber agreement. The CA directory is fixed for each mode;
arbitrary directory URLs, shell hooks and arbitrary extra Certbot options are
not accepted by this interface.
Requesting starts one bounded asynchronous job, not a proxy-path operation. Refresh
shows running, failed, or ready. At ready, the Rust control plane has checked PEM
parsing, matching key and every requested DNS name before exposing only metadata.
Click **Add issued certificate to library**, then select its ID in the vhost SSL
tab and save. Replacing an existing ID requires confirmation and retains its
legacy SNI host assignments; the whole current configuration is revalidated with
revision CAS. Failed issuance/validation/import leaves active configuration alone.
Certificates are loaded for new handshakes; changing listener protocols still
requires restart. Existing connections retain their negotiated certificate.
## Renewal and operator responsibilities
Configured RFC2136 managed profiles participate in the 0.7 renewal scheduler.
Validated changed certificate material is published automatically; there is a
per-certificate opt-out, explicit Check now and Dry run. Initial issuance/import
remains explicit. The old 0.5 helper alone was issuance-only; do not confuse
retained files or an unrelated OS Certbot timer with RustProxy publication.
See RENEWAL.md for prerequisites, timing, rollback boundaries and legacy profiles.
No external expiry notification, revocation UI or account manager is included.
Account state and TSIG credentials are kept privately under:
```text
data/certs/acme/<staging-or-production>-<certificate-id>/
rfc2136.ini # SECRET, mode 0600
profile.json # non-secret parameters, mode 0600
config/ # Certbot account, renewal, live and archive data
work/
logs/ # private Certbot diagnostics
```
The location follows the configured certificate directory, not always `data/certs`.
There is one job per RustProxy process and a filesystem lock per profile. Bounds:
16 KiB request, 128 profiles, 128 staged ACME pairs and 128 KiB per PEM file. The
provider timeout is 1200 seconds plus propagation wait; the Rust worker has a
2160-second outer deadline and stops its process group on cancellation/shutdown.
Normal TXT cleanup belongs to the plugin. A hard kill, machine crash or DNS error
can leave challenge TXT records: inspect DNS and clean only the failed challenge
values, not unrelated records. Only the latest job status lives in memory; restart
loses that status, not the private Certbot files.
TSIG/API credentials are supplied through stdin to the helper, never argv, exports
or job responses. RustProxy encrypts DNS-provider credentials in the Secret Store;
Certbot-compatible `.ini` files are recreated with private permissions only for the
external operation and removed afterwards. The browser clears submitted secret
fields and does not put them in local/session storage. Protect the Certbot account
state and private logs as secrets.
Use `rust-proxy backup create` for current installations. The encrypted full backup
includes the durable ACME profile/account state, certificates and Secret Store key
material needed for renewal. The historical `dev.sh backup` helper is not sufficient
after Secret Store migration. See SECRET_STORE_BACKUP.md.
## API and local helper
`GET /api/acme` returns the latest sanitized job, provider name and
`automatic_renewal: false`. `POST /api/acme/issue` requires the normal authenticated
session, Origin/CSRF protections and an explicit bounded JSON request:
```json
{
"certificate_id": "example",
"email": "operator@example.org",
"domains": ["example.org", "*.example.org"],
"environment": "staging",
"agree_tos": true,
"confirm_production": false,
"dns_server": "192.0.2.53",
"dns_port": 53,
"key_name": "rustproxy.example.org.",
"key_secret": "REPLACE_WITH_YOUR_PRIVATE_BASE64_TSIG_SECRET",
"key_algorithm": "HMAC-SHA256",
"sign_query": false,
"propagation_seconds": 60
}
```
This documentation example is intentionally not an executable credential. A
successful job submission returns 202; busy returns 429. Invalid input, consent
and provider failures use fixed `acme.*` diagnostics rather than returning
provider stderr or credentials. Look in the private profile logs for DNS/plugin
errors. A 202 response means accepted, not issued.
Advanced local staging without the running API:
```bash
# request.json must be private (0600), with real operator-owned parameters.
bash dev.sh acme --cert-dir /absolute/private/cert-directory < request.json
```
This CLI only stages files and prints metadata. Unlike the integrated API, it
cannot run Rust's key/SAN validation on its own and never activates a certificate.
Import through the normal validated library/config workflow. Do not post secret
JSON into shell arguments, source examples, tickets or logs.
## Primary references
- Plugin: https://certbot-dns-rfc2136.readthedocs.io/en/stable/
- Certbot CLI: https://eff-certbot.readthedocs.io/en/stable/man/certbot.html
- Staging: https://letsencrypt.org/docs/staging-environment/
- Challenge background: https://letsencrypt.org/docs/challenge-types/