4 releases
| 0.1.3 | Feb 25, 2026 |
|---|---|
| 0.1.2 | Feb 14, 2026 |
| 0.1.1 | Jan 22, 2026 |
| 0.1.0 | Jan 21, 2026 |
#1629 in Authentication
455KB
6.5K
SLoC
spiffe-rustls-tokio
Tokio-native async accept/connect helpers for spiffe-rustls configs.
Integrates tokio-rustls with automatic peer SPIFFE ID extraction. Provides TlsAcceptor and
TlsConnector that return (TlsStream, PeerIdentity) after successful handshakes. Runtime-agnostic
TLS configuration remains in spiffe-rustls.
Installation
Add spiffe-rustls-tokio to your Cargo.toml:
[dependencies]
spiffe-rustls-tokio = "0.1"
spiffe-rustls = "0.4"
spiffe = { version = "0.11", features = ["x509-source"] }
Quick Start
1. Create a spiffe-rustls configuration
use spiffe::X509Source;
use spiffe_rustls::{authorizer, mtls_client};
let source = X509Source::new().await?;
let client_config = mtls_client(source)
.authorize(authorizer::any())
.build()?;
2. Use TlsConnector or TlsAcceptor
use spiffe_rustls_tokio::TlsConnector;
use std::sync::Arc;
let connector = TlsConnector::new(Arc::new(client_config));
// ... use connector.connect() or connector.connect_addr()
Example: Using connect_addr Convenience Method
use spiffe::X509Source;
use spiffe_rustls::{authorizer, mtls_client};
use spiffe_rustls_tokio::TlsConnector;
use std::net::SocketAddr;
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let source = X509Source::new().await?;
let client_config = mtls_client(source)
.authorize(authorizer::any())
.build()?;
let connector = TlsConnector::new(Arc::new(client_config));
let addr: SocketAddr = "127.0.0.1:8443".parse()?;
let server_name = rustls::pki_types::ServerName::try_from("example.org")?;
// connect_addr combines TCP connection and TLS handshake
match connector.connect_addr(addr, server_name).await {
Ok((tls_stream, peer_identity)) => {
if let Some(spiffe_id) = peer_identity.spiffe_id() {
println!("Connected (SPIFFE ID: {})", spiffe_id);
}
// Use tls_stream...
}
Err(e) => eprintln!("Connection failed: {}", e),
}
Ok(())
}
API Overview
Main Types
TlsAcceptor— Server-side TLS acceptor that extracts peer SPIFFE identityTlsConnector— Client-side TLS connector that extracts peer SPIFFE identityPeerIdentity— Contains the extracted SPIFFE ID from the peer certificateError— Error type for TLS and identity extraction failures
Key Methods
TlsAcceptor::accept()— Accepts a TLS connection and returns(TlsStream, PeerIdentity)TlsConnector::connect()— Establishes a TLS connection and returns(TlsStream, PeerIdentity)TlsConnector::connect_addr()— Convenience method that combines TCP connection and TLS handshakePeerIdentity::spiffe_id()— Returns the peer's SPIFFE ID, if present
Examples
The crate includes complete working examples that demonstrate real mTLS connections using SPIRE.
Prerequisites
- A running SPIRE agent with Workload API accessible
- The
SPIFFE_ENDPOINT_SOCKETenvironment variable set (or use default Unix socket path) - Both client and server workloads registered with SPIRE
Running the Examples
The examples are located in the examples/ directory:
mtls_tcp_server- A server that accepts mTLS connections and extracts peer SPIFFE IDsmtls_tcp_client- A client that connects to the server and extracts peer SPIFFE IDs
To run the examples:
# Terminal 1: Start the server
cargo run --package spiffe-rustls-tokio --example mtls_tcp_server
# Terminal 2: Run the client
cargo run --package spiffe-rustls-tokio --example mtls_tcp_client
The examples will:
- Connect to SPIRE via the Workload API to obtain X.509 SVIDs and trust bundles
- Perform mutual TLS handshakes with automatic certificate rotation support
- Extract and display peer SPIFFE IDs from certificates
- Exchange messages over the encrypted connection
The server listens on 127.0.0.1:8443 by default. Both examples demonstrate:
- Authorization policies (trust domains, exact SPIFFE IDs)
- Trust domain policies (LocalOnly, AllowList)
- Peer identity extraction using
PeerIdentity::spiffe_id() - Error handling for TLS and identity extraction failures
Peer Identity Extraction
After a successful TLS handshake, the peer's SPIFFE ID is extracted from their certificate's URI SAN.
According to the SPIFFE specification, an X.509-SVID must contain exactly one SPIFFE ID. When using spiffe-rustls verifiers correctly, this is enforced during the TLS handshake.
API behavior:
- Exactly one SPIFFE ID: Extracted and stored in
PeerIdentity::spiffe_id - Missing/multiple SPIFFE IDs or no peer certificates:
spiffe_idisNone(no error;accept()/connect()succeed) - Certificate parse failure: Returns
Error::CertParse(accept()/connect()fail)
A None value for spiffe_id is unexpected in SPIFFE-compliant configurations and may indicate misconfiguration or a non-SPIFFE peer.
License
Licensed under the Apache License, Version 2.0.
Dependencies
~9–21MB
~327K SLoC