| Crates.io | spiffe-rustls |
| lib.rs | spiffe-rustls |
| version | 0.4.6 |
| created_at | 2025-12-23 18:00:46.669111+00 |
| updated_at | 2026-01-22 04:19:33.694496+00 |
| description | SPIFFE-based mutual TLS integration for rustls |
| homepage | |
| repository | https://github.com/maxlambrecht/rust-spiffe |
| max_upload_size | |
| id | 2002044 |
| size | 191,837 |
SPIFFE-based mutual TLS integration for rustls.
Builds rustls::ClientConfig and rustls::ServerConfig from spiffe's X509Source.
Handles certificate rotation, trust domain selection, and TLS-level peer authorization based on SPIFFE IDs.
All cryptography and TLS protocol handling are delegated to rustls.
X509SourceThe source is configured via the SPIFFE_ENDPOINT_SOCKET environment variable.
let source = spiffe::X509Source::new().await?;
use spiffe_rustls::{authorizer, mtls_client};
let source = spiffe::X509Source::new().await?;
// Authorize only specific server SPIFFE IDs
let client_cfg = mtls_client(source)
.authorize(authorizer::exact([
"spiffe://example.org/myservice",
"spiffe://example.org/myservice2",
])?)
.build()?;
The resulting ClientConfig can be used directly with rustls, or integrated into
spiffe-rustls-tokio, tokio-rustls, tonic-rustls, or similar libraries.
When SPIFFE federation is configured, the Workload API delivers trust bundles for multiple
trust domains. spiffe-rustls automatically handles this during certificate verification:
No federation-specific configuration is required. Federation works automatically whenever the Workload API provides bundles for multiple trust domains.
You may optionally restrict which trust domains are allowed during certificate verification
using TrustDomainPolicy.
This is a defense-in-depth mechanism. The primary trust model comes from the bundle set delivered by the Workload API.
use spiffe_rustls::TrustDomainPolicy;
// Default: trust all domains present in the Workload API bundle set
let policy = TrustDomainPolicy::AnyInBundleSet;
// Restrict verification to a fixed set of trust domains
let policy = TrustDomainPolicy::AllowList([
"broker.example".try_into()?,
"stockmarket.example".try_into()?,
].into_iter().collect());
// Restrict verification to exactly one trust domain
let policy = TrustDomainPolicy::LocalOnly("example.org".try_into()?);
Note: Trust domain policy affects verification only. Authorization is handled separately via
Authorizer.
Authorization is applied after cryptographic verification succeeds.
The crate provides a strongly-typed Authorizer trait and constructors for
common authorization strategies.
use spiffe_rustls::authorizer;
// 1) Authentication only (allow any SPIFFE ID)
let auth = authorizer::any();
// 2) Allow only specific SPIFFE IDs
let auth = authorizer::exact([
"spiffe://example.org/payment",
"spiffe://example.org/checkout",
])?;
// 3) Allow any SPIFFE ID from specific trust domains
let auth = authorizer::trust_domains([
"broker.example",
"stockmarket.example",
])?;
use spiffe::SpiffeId;
// Custom rule using a closure
let auth = |peer: &SpiffeId| {
peer.path().starts_with("/api/")
};
Closures automatically implement Authorizer and require no allocation.
ClientConfigBuilderBuilds a rustls::ClientConfig that:
use spiffe_rustls::{authorizer, mtls_client, TrustDomainPolicy};
let source = spiffe::X509Source::new().await?;
let client_cfg = mtls_client(source)
.authorize(authorizer::exact([
"spiffe://example.org/myservice",
])?)
.trust_domain_policy(
TrustDomainPolicy::LocalOnly("example.org".try_into()?)
)
.with_alpn_protocols(&[b"h2"]) // Optional: for gRPC/HTTP/2
.build()?;
ServerConfigBuilderBuilds a rustls::ServerConfig that:
use spiffe_rustls::{authorizer, mtls_server, TrustDomainPolicy};
let source = spiffe::X509Source::new().await?;
let server_cfg = mtls_server(source)
.authorize(authorizer::trust_domains([
"example.org",
])?)
.trust_domain_policy(
TrustDomainPolicy::LocalOnly("example.org".try_into()?)
)
.with_alpn_protocols(&[b"h2"]) // Optional: for gRPC/HTTP/2
.build()?;
Configure ALPN protocols for protocol negotiation during the TLS handshake. Protocols are advertised in order of preference (most preferred first):
use spiffe_rustls::mtls_client;
let source = spiffe::X509Source::new().await?;
// HTTP/2 preferred, HTTP/1.1 fallback
let config = mtls_client(source)
.with_alpn_protocols([b"h2".as_ref(), b"http/1.1".as_ref()])
.build()?;
// Also accepts owned vectors
let protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
let config = mtls_client(source)
.with_alpn_protocols(protocols)
.build()?;
Common protocols:
b"h2" — HTTP/2 (required for gRPC)b"http/1.1" — HTTP/1.1For configuration not directly exposed by the builder, use with_config_customizer.
The customizer runs last, after all other builder settings (including ALPN)
have been applied, allowing you to override any configuration:
use spiffe_rustls::mtls_server;
let source = spiffe::X509Source::new().await?;
let config = mtls_server(source)
.with_config_customizer(|cfg| {
// Example: adjust cipher suite preferences
// cfg.cipher_suites = ...;
})
.build()?;
Warning: Do not modify or replace the verifier or certificate resolver, as they are required for SPIFFE authentication and authorization. Safe to modify: ALPN, cipher suites, protocol versions, and other non-security-critical settings.
Most features are additive and opt-in.
Crypto provider features are mutually exclusive — exactly one must be enabled.
[features]
default = ["ring"]
ring = ["rustls/ring"]
aws-lc-rs = ["rustls/aws_lc_rs"]
ringaws-lc-rsExample (AWS-LC):
cargo add spiffe-rustls --no-default-features --features aws-lc-rs
Provider choice affects only cryptographic primitives. SPIFFE semantics and API behavior are identical across providers.
parking-lotEnable parking-lot to use a faster internal synchronization strategy.
This can improve throughput under high concurrency and reduce contention
during cold-start bursts.
cargo add spiffe-rustls --features parking-lot
Note: This feature does not change the public API or SPIFFE semantics. It only affects internal synchronization.
All examples require:
SPIFFE_ENDPOINT_SOCKET)example.orgFor local testing, add to /etc/hosts:
127.0.0.1 example.org
tokio-rustls)cargo run --example mtls_tcp_server
cargo run --example mtls_tcp_client
spiffe-rustls-tokio)For Tokio integration with automatic peer identity extraction, use the
spiffe-rustls-tokio crate:
cargo run -p spiffe-rustls-tokio --example mtls_tcp_server
cargo run -p spiffe-rustls-tokio --example mtls_tcp_client
See the spiffe-rustls-tokio README for details.
tonic-rustls)gRPC examples live in a separate crate (spiffe-rustls-grpc-examples) to avoid pulling
gRPC/protobuf dependencies into the library.
cargo run -p spiffe-rustls-grpc-examples --bin grpc_server_mtls
cargo run -p spiffe-rustls-grpc-examples --bin grpc_client_mtls
Performance characteristics:
Arc referencesAuthorizer trait allows zero-allocation checksspiffe-rustls builds rustls::ClientConfig and rustls::ServerConfig from spiffe::X509Source.
Authorization is applied after TLS verification succeeds, ensuring cryptographic security before policy checks.
Licensed under the Apache License, Version 2.0. See LICENSE for details.