acme_proxy_protocol/acme/mod.rs
1//! The ACME domain: what an order, an authorization, a challenge and an account
2//! may do, independent of the HTTP request that asked.
3//!
4//! Nothing in this module routes, extracts or renders a response — the one
5//! axum name it touches is `StatusCode`, which comes with `Problem`. The resource
6//! handlers in
7//! [`crate::handlers`] are the HTTP edge — an extractor, a call into this module,
8//! a rendered response — and the operator front ends (`admin`, the
9//! relay's background settlement) reach the same rules through the same
10//! functions, so a state transition has one implementation however it is
11//! triggered.
12//!
13//! - [`rules`] — pure rules over values: the identifier shape a `dns` name must
14//! have, the CSR-to-order correspondence, the CSR projection the filters see,
15//! the `contact` shapes RFC 8555 §7.3 refuses.
16//! - [`access`] — who may touch what: the signer's account, and the ownership
17//! walk from a challenge up to its order.
18//! - [`policy`] — the configured policy applied to a request: the filter's
19//! identifier stage, and the problem a failed challenge validation maps to.
20//! - [`order`] — [`OrderService`], the order state machine: creating an order,
21//! deactivating an authorization, claiming and validating a challenge,
22//! finalizing. The issuance bookkeeping the `signer_issue` job and the relay
23//! share — `record_issuance`, `announce_issuance`, `record_issue_failure` —
24//! is `acme_proxy_signer::issuance`, below both of them, since the relay
25//! completes an issuance with no request in scope at all.
26//! - [`issue`] — the `signer_issue` job `finalize` queues: the one place a
27//! backend is asked to sign, and it runs in the `worker` role, the only one
28//! that holds a backend.
29//! - [`account`] — [`AccountService`]: `newAccount` (with EAB), the account
30//! update, key rollover and the orders list, plus the deactivation and
31//! contact update the operator front ends share.
32//! - [`revoke`] — certificate revocation, by certificate for an ACME client and
33//! by order for an operator, sharing one tail.
34//! - [`validate`] — the `challenge_validate` job the trigger queues, since the
35//! outbound check outlives the request that asked for it.
36//!
37//! **Logging:** whoever builds an [`Error`] logs it. The edge only maps it to a
38//! response, so a refusal is one log line however many layers it crossed —
39//! and every event name stayed what it was when the code lived in the handler,
40//! since `monitoring.md` and the e2e lab grep for them. Nothing here carries
41//! `#[instrument]`: the handler's span already covers the request, and the
42//! attribute hides a body from coverage.
43//!
44//! Refusals the client reads as they are travel as [`acme_proxy_core::error::Problem`]
45//! values, wrapped in [`Error`]. `Problem` is a data type as much as a response
46//! — the documents stored in `challenges.error` and `orders.error` are its
47//! RFC 7807 JSON — and only its `IntoResponse` impl belongs to the edge.
48
49pub mod access;
50pub mod account;
51pub mod error;
52pub mod issue;
53pub mod order;
54pub mod policy;
55pub mod revoke;
56pub mod rules;
57pub mod validate;
58
59pub use account::AccountService;
60pub use error::Error;
61pub use order::OrderService;
62
63/// The entry a process mounts under `name`, if any.
64///
65/// Every job handler here holds the same shape — the profiles, signers or
66/// notifiers of *this* generation, as `(name, value)` pairs — and asks it the
67/// same question about a row it just read. A profile that is absent is not an
68/// error: another process, or the next generation of this one, may mount it,
69/// which is why each caller answers `Retry` rather than `Failed`.
70pub(crate) fn mounted<'a, T>(entries: &'a [(String, T)], name: &str) -> Option<&'a T> {
71 entries
72 .iter()
73 .find(|(mounted, _)| mounted == name)
74 .map(|(_, entry)| entry)
75}