openmoat_proxy/lib.rs
1//! `openmoat-proxy`: the default-deny egress proxy behind `moat proxy` (ADR-020).
2//!
3//! It serves HTTP `CONNECT` tunnels and absolute-form plain-HTTP requests on a
4//! loopback port:
5//!
6//! - Hosts are decided by openmoat-core's [`CompiledPolicy`](openmoat_core::CompiledPolicy)
7//! as `moat guard` decides a fetch tool's URL: only an `allow` passes. A host
8//! is reached on 443 and 80 unless a rule names `host:port` ([`port_policy`]).
9//! - Cloud metadata and link-local addresses are refused whatever the policy
10//! says, by name and on every address the proxy resolves. Private and CGNAT
11//! addresses are refused unless an allow rule names the address.
12//! - A tunnel's TLS `ClientHello` must name the CONNECT host (SNI). Nothing is
13//! decrypted except, with [`Tls`] set, a tunnel to the host of a secret that
14//! says `tls: terminate` (ADR-043): its one request is checked against the
15//! leak check and the secret's `allow` rules, given the value, sent over the
16//! proxy's own verified TLS, and its answer searched for every value. A
17//! host with [`Requests`] rules (ADR-062 step 0, a proof of concept) is
18//! terminated the same way, and a request its `deny` rules name is refused.
19//! - A request that carries a brokered secret's placeholder or value to a host
20//! other than the secret's own is refused ([`Broker`]).
21//! - Every decision is recorded through a [`Recorder`]; a failed record is a
22//! refused connection.
23//! - In session mode ([`Sessions`], ADR-027, ADR-044) every request must
24//! carry its session's credential: one the proxy holds ([`Credential`]) or
25//! one a [`Verify`] accepts. The session's audit id goes on each row, a
26//! session that read secret material reaches only that secret's host, and
27//! no session holds more than half the connections.
28//! - A connection that starts with a [`LocalService`]'s prefix goes to that
29//! service of the proxy's own process (ADR-028), not upstream.
30//! - Apart from the proxy, [`Poster`] makes live audit delivery's one `POST`
31//! (ADR-081) with the same upstream TLS and address checks.
32//!
33//! Plain `std::net` and one thread per connection, capped by [`Limits`]; the
34//! choice is explained in `docs/ARCHITECTURE.md` ยง12.
35
36#![warn(missing_docs)]
37// A library reports to its caller; only the `moat` binary prints.
38#![warn(clippy::print_stdout, clippy::print_stderr)]
39
40mod audit;
41mod body;
42mod broker;
43pub mod coalesce;
44mod decide;
45mod exchange;
46mod local;
47mod post;
48mod request;
49mod requests;
50mod server;
51mod session;
52mod slots;
53mod sni;
54mod tls;
55mod tunnel;
56mod upstream;
57
58pub use audit::{Connection, RecordError, Recorder};
59pub use broker::{
60 Broker, BrokerError, Carried, Leak, RULE_SECRET, RULE_SECRET_EXPIRED, RULE_SECRET_ROUTE,
61 Rotation,
62};
63pub use decide::{
64 DEFAULT_PORTS, Forbidden, RULE_ADDRESS, RULE_AUDIT, RULE_PORT, RULE_REQUEST, RULE_SNI,
65 RULE_UPSTREAM, address_policy, denied as address_denied, forbidden, host as decide_host,
66 host_port as decide_host_port, named as address_named, named_on as address_named_on,
67 port_policy, tainted as decide_tainted,
68};
69pub use local::LocalService;
70pub use post::{Answer, Endpoint, MAX_BODY, PostError, Poster, Scheme};
71pub use request::{
72 MAX_HEADERS, ProxyCredential, Request, RequestError, Target, parse as parse_request,
73};
74pub use requests::{RULE_REQUEST_RULE, RequestRuleError, Requests};
75pub use server::{Limits, Proxy, RULE_CAPACITY};
76pub use session::{
77 AuthError, Credential, CredentialError, MIN_TOKEN_LEN, RULE_SESSION, Sessions, TaintLookup,
78 Verify, base64, constant_time_eq,
79};
80pub use sni::{Hello, HelloError, MAX_HELLO, server_name};
81pub use tls::{CA_VALID_DAYS, CaFiles, RULE_TLS, Roots, Tls, TlsError, new_ca};
82pub use upstream::{Refusal, Resolve, SystemResolver, connect};