Skip to main content

ClientConfigBuilder

Struct ClientConfigBuilder 

Source
pub struct ClientConfigBuilder { /* private fields */ }
Expand description

Builds a rustls::ClientConfig backed by a live SPIFFE X509Source.

The resulting client configuration:

  • presents the current SPIFFE X.509 SVID as the client certificate
  • validates the server certificate chain against trust bundles from the Workload API
  • authorizes the server by SPIFFE ID (URI SAN)

The builder retains an Arc<X509Source>. When the underlying SVID or trust bundle is rotated by the SPIRE agent, new TLS handshakes automatically use the updated material.

§Trust Domain Selection

The builder uses the bundle set from X509Source, which may contain bundles for multiple trust domains (when SPIFFE federation is configured). The verifier automatically selects the correct bundle based on the peer’s SPIFFE ID—no manual configuration is required. You can optionally restrict which trust domains are accepted using Self::trust_domain_policy.

The default policy is TrustDomainPolicy::AnyInBundleSet, which accepts any trust domain present in the source bundle set. For non-federated deployments, prefer TrustDomainPolicy::LocalOnly to restrict verification to the local trust domain.

§Authorization

Server authorization is performed by invoking the provided Authorizer with the server’s SPIFFE ID extracted from the certificate’s URI SAN.

The default authorizer is crate::authorizer::any. It accepts any authenticated SPIFFE ID from any trust domain accepted by the configured trust-domain policy. By default, this means every trust domain in the source bundle set. Production deployments should usually configure a more specific authorizer.

§Examples

use spiffe_rustls::{authorizer, mtls_client, AllowList};
use std::collections::BTreeSet;

let source = spiffe::X509Source::new().await?;

// Pass string literals directly - exact() and trust_domains() will convert them
let allowed_server_ids = [
    "spiffe://example.org/myservice",
    "spiffe://example.org/myservice2",
];

let mut allowed_trust_domains = BTreeSet::new();
allowed_trust_domains.insert("example.org".try_into()?);

let client_config = mtls_client(source)
    .authorize(authorizer::exact(allowed_server_ids)?)
    .trust_domain_policy(AllowList(allowed_trust_domains))
    .build()?;

Implementations§

Source§

impl ClientConfigBuilder

Source

pub fn new(source: X509Source) -> Self

Creates a new builder from an X509Source.

Defaults:

  • Authorization: crate::authorizer::any, which accepts any authenticated SPIFFE ID from any trust domain accepted by the configured trust-domain policy. By default, this means every trust domain in the source bundle set.
  • Trust domain policy: TrustDomainPolicy::AnyInBundleSet, which accepts any trust domain present in the source bundle set
  • ALPN protocols: empty (no ALPN)

Production deployments should usually configure a more specific authorizer. Non-federated deployments should usually configure TrustDomainPolicy::LocalOnly.

Source

pub fn authorize<A: Authorizer>(self, authorizer: A) -> Self

Sets the authorization policy for server SPIFFE IDs.

Accepts any type that implements Authorizer, including closures.

§Examples
use spiffe_rustls::{authorizer, mtls_client};

let source = spiffe::X509Source::new().await?;

// Pass string literals directly
let config = mtls_client(source.clone())
    .authorize(authorizer::exact([
        "spiffe://example.org/service",
        "spiffe://example.org/service2",
    ])?)
    .build()?;

// Using a closure
let config = mtls_client(source.clone())
    .authorize(|id: &spiffe::SpiffeId| id.path().starts_with("/api/"))
    .build()?;

// Using the Any authorizer (default)
let config = mtls_client(source)
    .authorize(authorizer::any())
    .build()?;
Source

pub fn trust_domain_policy(self, policy: TrustDomainPolicy) -> Self

Sets the trust domain policy.

Defaults to TrustDomainPolicy::AnyInBundleSet, which accepts any trust domain present in the source bundle set. For non-federated deployments, prefer TrustDomainPolicy::LocalOnly to restrict verification to the local trust domain.

Source

pub fn with_alpn_protocols<I, P>(self, protocols: I) -> Self
where I: IntoIterator<Item = P>, P: AsRef<[u8]>,

Sets the ALPN (Application-Layer Protocol Negotiation) protocols.

The protocols are advertised during the TLS handshake. Common values:

  • b"h2" for HTTP/2 (required for gRPC)
  • b"http/1.1" for HTTP/1.1

Protocols should be specified in order of preference (most preferred first).

§Examples
use spiffe_rustls::mtls_client;

let source = spiffe::X509Source::new().await?;
let config = mtls_client(source)
    .with_alpn_protocols([b"h2"])
    .build()?;
Source

pub fn with_config_customizer<F>(self, customizer: F) -> Self
where F: FnOnce(&mut ClientConfig) + Send + 'static,

Applies a customizer function to the ClientConfig after it’s built.

This is an advanced API for configuration not directly exposed by the builder. The customizer is called last, after all other builder settings (including ALPN) have been applied, and gives direct access to the underlying rustls configuration.

Warning: Replacing the verifier or resolver disables SPIFFE authentication. Do not use this hook for that purpose; build a custom rustls configuration instead.

§Examples
use spiffe_rustls::mtls_client;

let source = spiffe::X509Source::new().await?;
let config = mtls_client(source)
    .with_config_customizer(|cfg| {
        // Example: adjust cipher suite preferences
    })
    .build()?;
Source

pub fn build(self) -> Result<ClientConfig>

Builds the rustls::ClientConfig.

The returned configuration:

  • presents the current SPIFFE X.509 SVID as the client certificate
  • validates the server certificate chain against trust bundles from the Workload API
  • authorizes the server by SPIFFE ID (URI SAN)

The configuration is backed by a live X509Source. When the underlying SVID or trust bundle is rotated by the SPIRE agent, new TLS handshakes automatically use the updated material.

§Errors

Returns an error if:

  • the Rustls crypto provider is not installed
  • no current X.509 SVID is available from the X509Source
  • building the underlying Rustls certificate verifier fails

Trait Implementations§

Source§

impl Debug for ClientConfigBuilder

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more