Files
RustProxy/docs/V0.28.2_IMPLEMENTATION.md
T
2026-10-08 11:27:18 +02:00

3.7 KiB

RustProxy 0.28.2 implementation note

External certificate path hardening

0.28.2 keeps the 0.28.1 direct-file workflow for Certbot/acme.sh certificates but changes validation from an exact-mode expectation to a security-policy check. POSIX ACLs are supported: a private key may be owner-readable or group/ACL-readable by the rustproxy service identity. RustProxy rejects a private key that is world-readable and rejects group/world write access on every external certificate/key file. Execute bits alone are not treated as key disclosure.

For an absolute external path RustProxy validates the configured parent chain before resolving the final file, resolves the final Certbot-style live/*.pem symlink, validates the resolved parent chain again, and opens the final regular file with O_NOFOLLOW. On Unix, parent directories must be owned by root or the running RustProxy service user and must not be group/world-writable. Root-owned sticky ancestors such as /tmp remain accepted for controlled test/custom trees.

This closes the writable-parent/path-redirection gap while preserving Certbot renewal semantics: after certbot renew, a targeted reload follows the current live/ -> archive/ generation and publishes a new immutable TLS snapshot only after the pair validates.

ACL example

The packaged systemd unit keeps RustProxy writable only in its data/log directories and explicitly marks /etc/letsencrypt and /etc/ssl read-only when those paths exist:

ReadWritePaths=/var/lib/rustproxy /var/log/rustproxy
ReadOnlyPaths=-/etc/letsencrypt -/etc/ssl

ReadOnlyPaths does not grant Unix access. For traversal-only access to protected directories and read access to the actual PEM files, use narrow POSIX ACLs. Example:

setfacl -m u:rustproxy:--x /etc/ssl/
setfacl -m u:rustproxy:--x /etc/letsencrypt/ /etc/letsencrypt/live/ /etc/letsencrypt/archive/
setfacl -m u:rustproxy:--x /etc/letsencrypt/live/example.com/ /etc/letsencrypt/archive/example.com/
setfacl -m u:rustproxy:r-- /etc/letsencrypt/archive/example.com/fullchain*.pem /etc/letsencrypt/archive/example.com/privkey*.pem
setfacl -m d:u:rustproxy:r-- /etc/letsencrypt/archive/example.com/

A default ACL on the archive lineage is useful, but a renewer may recreate a private key as 0600 and mask inherited named-user access. A renewal hook should therefore reapply u:rustproxy:r-- to the current resolved fullchain.pem and privkey.pem targets before calling the reload API. Do not grant w to the rustproxy identity on the Certbot tree.

Least-privilege Certificate API

SQLite schema 9 adds certificate_api_grants. New Certificate API credentials require 1-32 explicit certificate IDs and are reload-only unless Also allow deploy is enabled. Token authentication is accepted only for targeted POST /api/certificates/{certificate_id}/reload; the global POST /api/certificates/reload remains administrator-session only. Deploy tokens must have both explicit deploy permission and an allowlisted request certificate ID.

Credentials created before 0.28.2 migrate to reload-only compatibility grants covering all certificate IDs (*). Rotate those credentials in Settings -> Certificate API to replace the broad compatibility grant with explicit IDs.

Normal administrator session + CSRF access remains unchanged. Certificate API tokens still cannot read configuration or call unrelated administration APIs, and non-loopback token use still requires HTTPS.

Compatibility

  • SQLite schema: 9 (additive migration from schema 8).
  • Saved proxy configuration: unchanged from 0.28.1.
  • COLD cache format: 3, unchanged.
  • External certificate paths/backups: same semantics as 0.28.1; external PEM bytes are not copied into RustProxy backups.