spiffe-rustls
spiffe-rustls integrates rustls with SPIFFE/SPIRE using the
spiffe crate’s X509Source (SPIFFE Workload API).
It provides builders for rustls::ClientConfig and rustls::ServerConfig backed by a live
X509Source. When the SPIRE agent rotates SVIDs or trust bundles, new TLS handshakes automatically
use the updated material, without restarting the application.
The crate focuses on TLS-level authentication and authorization via SPIFFE IDs, while delegating
all cryptography and TLS mechanics to rustls.
Key Features
- Federation support — Automatically handles multiple trust domains when SPIFFE federation is configured
- Typed authorization — Strongly-typed
Authorizertrait for SPIFFE ID–based access control - Live updates — Material rotates automatically when SPIRE updates SVIDs or bundles
- Production-ready — Zero unsafe code, conservative parsing, graceful degradation
Quick Start
1. Create an X509Source
The source is configured via SPIFFE_ENDPOINT_SOCKET:
let source = new.await?;
2. Build a rustls client configuration
use ;
let source = new.await?;
// Pass string literals directly — exact() will convert them
let client_cfg = mtls_client
.authorize
.build?;
The resulting ClientConfig can be used directly with rustls, or integrated into
tokio-rustls, tonic-rustls, or similar libraries.
Federation
When SPIFFE federation is configured, the Workload API delivers trust bundles for multiple
trust domains. spiffe-rustls automatically handles this:
- Extracts the SPIFFE ID from the peer certificate
- Derives the trust domain from that SPIFFE ID
- Selects the correct root certificate bundle from the bundle set
- Verifies the certificate chain using the selected bundle
No federation-specific configuration is required. Federation works automatically whenever the Workload API provides bundles for multiple trust domains.
Trust Domain Policy
You may optionally restrict which trust domains are accepted using [TrustDomainPolicy].
This is a defense-in-depth mechanism—the primary trust model comes from the bundle set
delivered by the Workload API.
use ;
use BTreeSet;
// Choose exactly one policy variant:
// Default: use all bundles from the Workload API
let policy = AnyInBundleSet;
// Restrict to specific trust domains
let mut allowed = new;
allowed.insert;
allowed.insert;
let policy = AllowList;
// Only trust a single trust domain
let policy = LocalOnly;
// Full path variant (equivalent)
let policy = AnyInBundleSet;
Authorization
Authorization is performed after cryptographic verification succeeds.
The crate provides a strongly-typed [Authorizer] trait for SPIFFE ID–based authorization.
Using the Authorizer trait
use ;
use SpiffeId;
use Arc;
// Accept any SPIFFE ID (authentication only)
let auth: = new;
// Accept only exact SPIFFE IDs
let auth = exact?;
// Accept any SPIFFE ID from specific trust domains
let auth = trust_domains?;
// Custom authorization logic
let auth: = new;
API Overview
Builders
ClientConfigBuilder— buildsrustls::ClientConfigServerConfigBuilder— buildsrustls::ServerConfig
Each builder:
- retains an
Arc<X509Source>internally - always uses the latest SVIDs and trust bundles
- authorizes peers by SPIFFE ID (URI SAN)
Authorization helpers
- [
Authorizer] — trait for SPIFFE ID–based authorization authorizer::any()authorizer::exact()authorizer::trust_domains()
Trust Domain Policy types
- [
TrustDomainPolicy] AnyInBundleSet— use all bundles from the Workload API (default)AllowList— restrict to specific trust domainsLocalOnly— trust exactly one trust domain
Policy variants are re-exported at the crate root for convenience.
Client Configuration
ClientConfigBuilder
Builds a rustls::ClientConfig that:
- presents the current SPIFFE X.509 SVID
- validates the server certificate chain using Workload API bundles
- selects the correct trust domain automatically
- authorizes the server by SPIFFE ID
use ;
use BTreeSet;
let source = new.await?;
let allowed_server_ids = ;
let mut allowed_trust_domains = new;
allowed_trust_domains.insert;
let client_cfg = mtls_client
.authorize
.trust_domain_policy
.build?;
Server Configuration
ServerConfigBuilder
Builds a rustls::ServerConfig that:
- presents the current SPIFFE X.509 SVID
- requires and validates client certificates (mTLS)
- selects the correct trust domain automatically
- authorizes the client by SPIFFE ID
use ;
use ;
let source = new.await?;
let allowed_trust_domains = ;
let local_trust_domain: TrustDomain = "example.org".try_into?;
let server_cfg = mtls_server
.authorize
.trust_domain_policy
.build?;
Features
Most features are additive and opt-in. Crypto provider features are mutually exclusive—exactly one must be enabled.
Crypto providers
[]
= ["ring"]
= ["rustls/ring"]
= ["rustls/aws_lc_rs"]
- Default:
ring - Optional:
aws-lc-rs
Example (AWS-LC):
Provider choice affects only cryptographic primitives; SPIFFE semantics and API behavior are identical across providers.
Observability
Observability is optional and controlled via features:
logging— emit events via thelogcratetracing— emit events via thetracingcrate
Both features are disabled by default.
Precedence
tracing(if enabled)logging(only iftracingis disabled)- no-op (if neither is enabled)
Example:
= { = "0.4", = ["tracing"] }
Examples
Prerequisites
All examples require:
- a running SPIRE agent
- a valid Workload API socket (
SPIFFE_ENDPOINT_SOCKET) - local DNS resolution for
example.org
For local testing, add to /etc/hosts:
127.0.0.1 example.org
Raw TLS (tokio-rustls)
gRPC (tonic-rustls)
gRPC examples live in a separate crate (spiffe-rustls-grpc-examples) to avoid pulling
gRPC/protobuf dependencies into the library.
Security Considerations
- Certificates must contain exactly one SPIFFE ID URI SAN
- Trust bundles come exclusively from the Workload API
- Trust domain selection is automatic and deterministic
- Authorization runs after cryptographic verification
- Material updates are atomic; new handshakes use fresh material
License
Licensed under the Apache License, Version 2.0. See LICENSE for details.