46 lines
3.7 KiB
Markdown
46 lines
3.7 KiB
Markdown
# 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:
|
|
|
|
```ini
|
|
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:
|
|
|
|
```bash
|
|
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.
|