spiffe_rustls/lib.rs
1//! # spiffe-rustls
2//!
3//! `spiffe-rustls` integrates [`rustls`] with SPIFFE/SPIRE using a live
4//! [`spiffe::X509Source`] (SPIFFE Workload API).
5//!
6//! Provides builders for [`rustls::ClientConfig`] and
7//! [`rustls::ServerConfig`] backed by an `X509Source`. When the SPIRE
8//! agent rotates X.509 SVIDs or trust bundles, **new TLS handshakes automatically
9//! use the updated material**, without restarting the application.
10//!
11//! Focuses on TLS authentication and **connection-level authorization
12//! via SPIFFE IDs**, while delegating all cryptography and TLS mechanics to
13//! `rustls`.
14//!
15//! When SPIFFE federation is configured, the crate automatically selects the correct
16//! trust domain bundle based on the peer's SPIFFE ID. Authorization is applied **after**
17//! cryptographic verification succeeds.
18//!
19//! By default, builders use [`TrustDomainPolicy::AnyInBundleSet`] and
20//! [`authorizer::any`]. This accepts any authenticated SPIFFE ID from any trust domain
21//! present in the source bundle set. For non-federated deployments, use
22//! [`TrustDomainPolicy::LocalOnly`]; for production deployments, configure an
23//! authorizer that matches the peer identities your application expects.
24//!
25//! For outbound TLS, peer identity is the SPIFFE ID in the URI SAN, not the TLS server name.
26//! Connecting to `localhost` or an IP is supported even when the X.509-SVID has no matching DNS SAN.
27//!
28//! ## Feature flags
29//!
30//! Exactly **one** `rustls` crypto provider must be enabled:
31//!
32//! * `ring` (default)
33//! * `aws-lc-rs`
34//!
35//! Enabling more than one provider results in a compile-time error.
36
37#![cfg_attr(
38 test,
39 expect(
40 unused_crate_dependencies,
41 reason = "dev-dependencies are used by integration tests and examples"
42 )
43)]
44#![expect(clippy::multiple_crate_versions, reason = "transitive")]
45
46#[cfg(all(feature = "ring", feature = "aws-lc-rs"))]
47compile_error!("Enable only one crypto provider feature: `ring` or `aws-lc-rs`.");
48
49#[cfg(not(any(feature = "ring", feature = "aws-lc-rs")))]
50compile_error!("Enable one crypto provider feature: `ring` (default) or `aws-lc-rs`.");
51
52pub mod authorizer;
53
54mod crypto;
55mod error;
56mod material;
57
58mod observability;
59mod prelude;
60
61mod client;
62mod policy;
63mod resolve;
64mod server;
65mod verifier;
66
67// Public re-exports
68pub use authorizer::{any, exact, trust_domains, Authorizer};
69pub use client::ClientConfigBuilder;
70pub use error::{Error, Result};
71pub use policy::TrustDomainPolicy;
72pub use policy::TrustDomainPolicy::{AllowList, AnyInBundleSet, LocalOnly};
73pub use server::ServerConfigBuilder;
74pub use spiffe::{SpiffeId, TrustDomain};
75
76/// Constructor for the mTLS client builder.
77///
78/// Creates a client builder with default settings:
79///
80/// * authorizer: [`authorizer::any`], which accepts any authenticated SPIFFE ID
81/// from any trust domain accepted by the configured trust-domain policy. By default,
82/// this means every trust domain in the source bundle set.
83/// * trust-domain policy: [`TrustDomainPolicy::AnyInBundleSet`], which accepts any
84/// trust domain present in the source bundle set
85///
86/// Production deployments should usually configure a more specific authorizer. Non-federated
87/// deployments should usually configure [`TrustDomainPolicy::LocalOnly`].
88///
89/// # Examples
90///
91/// ```no_run
92/// use spiffe_rustls::{authorizer, mtls_client};
93///
94/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
95/// let source = spiffe::X509Source::new().await?;
96///
97/// let client_config = mtls_client(source)
98/// .authorize(authorizer::exact([
99/// "spiffe://example.org/myservice",
100/// ])?)
101/// .build()?;
102/// # Ok(())
103/// # }
104/// ```
105pub fn mtls_client(source: spiffe::X509Source) -> ClientConfigBuilder {
106 ClientConfigBuilder::new(source)
107}
108
109/// Constructor for the mTLS server builder.
110///
111/// Creates a server builder with default settings:
112///
113/// * authorizer: [`authorizer::any`], which accepts any authenticated SPIFFE ID
114/// from any trust domain accepted by the configured trust-domain policy. By default,
115/// this means every trust domain in the source bundle set.
116/// * trust-domain policy: [`TrustDomainPolicy::AnyInBundleSet`], which accepts any
117/// trust domain present in the source bundle set
118///
119/// Production deployments should usually configure a more specific authorizer. Non-federated
120/// deployments should usually configure [`TrustDomainPolicy::LocalOnly`].
121///
122/// # Examples
123///
124/// ```no_run
125/// use spiffe_rustls::{authorizer, mtls_server};
126///
127/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
128/// let source = spiffe::X509Source::new().await?;
129///
130/// let server_config = mtls_server(source)
131/// .authorize(authorizer::trust_domains(["example.org"])?)
132/// .build()?;
133/// # Ok(())
134/// # }
135/// ```
136pub fn mtls_server(source: spiffe::X509Source) -> ServerConfigBuilder {
137 ServerConfigBuilder::new(source)
138}