161 lines
8.0 KiB
Markdown
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/
|