How to Configure TLS Settings for Iroh Connections: A Complete Guide
Iroh uses rustls as its TLS implementation and exposes configuration through the CaTlsConfig wrapper and ClientBuilder::tls_client_config method, allowing you to customize cipher suites, root certificates, and cryptographic providers by passing a custom rustls::ClientConfig to network components.
Iroh is a Rust-based toolkit for building distributed systems that relies on secure connections for its relay and peer-to-peer networking components. Understanding how to configure TLS settings for Iroh connections enables you to customize cryptographic providers, restrict cipher suites, and manage certificate verification to meet specific security requirements. According to the n0-computer/iroh source code, all TLS configuration flows through a consistent pattern of creating a rustls::ClientConfig and passing it to component-specific builders.
Understanding Iroh's TLS Architecture
Iroh delegates all TLS operations to rustls, a modern Rust TLS library. The codebase provides a helper structure called CaTlsConfig defined in iroh-relay/src/tls.rs that wraps rustls::ClientConfig and manages root certificate verification.
The configuration flow follows three steps:
- Create a
rustls::ClientConfigwith your chosenCryptoProvider(Ring or AWS-LC-RS) and security parameters - Pass the configuration to a component builder using methods like
ClientBuilder::tls_client_configorEndpointBuilder::tls_client_config - The configuration is consumed during connection establishment by
MaybeTlsStreamBuilder::connectiniroh-relay/src/client/tls.rs
Creating a Custom TLS Configuration
To customize TLS settings, you first construct a rustls::ClientConfig with your desired cryptographic provider and cipher suites. The default provider uses Ring, but you can substitute AWS-LC-RS if preferred.
Selecting Crypto Providers and Cipher Suites
The configuration starts with selecting a CryptoProvider and building the client config with specific security parameters:
use std::sync::Arc;
use iroh_relay::tls::CaTlsConfig;
use rustls::{
client::ClientConfig,
crypto::CryptoProvider,
version::TLS13,
};
use iroh_relay::client::ClientBuilder;
// Choose a crypto provider – the default Ring provider is usually fine.
let provider: Arc<CryptoProvider> = iroh_relay::tls::default_provider();
// Start from the default configuration and tweak it.
let mut rustls_cfg = ClientConfig::builder_with_provider(provider.clone())
.with_safe_defaults()
.with_custom_certificate_verifier(Arc::new(
// Only allow TLS 1.3 and a specific cipher suite:
rustls::client::WebPkiServerVerifier::builder_with_provider(
rustls::RootCertStore::empty(),
provider.clone(),
)
.with_allowed_versions(&[TLS13])
.with_cipher_suites(&[rustls::cipher_suite::TLS13_AES_256_GCM_SHA384])
.build()
.unwrap(),
))
.with_no_client_auth(); // no client certificates
// Wrap the config in a CaTlsConfig if you also need custom roots.
let ca_cfg = CaTlsConfig::custom_roots([]).client_config(provider)?;
This example demonstrates restricting connections to TLS 1.3 only and specifying a particular cipher suite, which is critical for environments with strict compliance requirements.
Configuring Component-Specific TLS
After creating your ClientConfig, you apply it to specific Iroh components through their respective builders.
Relay Client Configuration
For the relay client, use ClientBuilder::tls_client_config defined in iroh-relay/src/client.rs:
use iroh_relay::client::ClientBuilder;
use iroh_relay::client::DnsResolver;
let client = ClientBuilder::new(
"https://my.relay.example".parse::<iroh_relay::RelayUrl>().unwrap(),
SecretKey::generate(),
DnsResolver::new(),
)
.tls_client_config(rustls_cfg) // ← custom client config
.build()
.await?;
This method stores the supplied rustls::ClientConfig in the builder, which is later used by MaybeTlsStreamBuilder when establishing the TLS session.
High-Level Endpoint Configuration
For the high-level Iroh endpoint, the configuration is exposed through iroh/src/tls.rs, which re-exports CaTlsConfig:
use iroh::{Endpoint, tls::CaTlsConfig};
let endpoint = Endpoint::builder()
.tls_client_config(client_cfg) // from previous example
.ca_tls_config(CaTlsConfig::insecure_skip_verify()) // only for tests!
.build()
.await?;
DNS-over-HTTPS Client
When using DNS-over-HTTPS (DoH), customize the TLS configuration via DnsBuilder::tls_client_config, which uses the same patterns as the relay client.
Customizing Root Certificate Verification
Iroh provides flexible options for managing root certificate trust through CaTlsConfig.
Adding Custom Root Certificates
To trust specific root certificates beyond the system defaults, load PEM-encoded certificates and build a custom root store:
use iroh_relay::tls::CaTlsConfig;
use rustls::RootCertStore;
use rustls::internal::pemfile::certs;
use std::fs::File;
// Load a PEM-encoded root.
let mut file = File::open("my_root.pem").unwrap();
let mut root_store = RootCertStore::empty();
root_store.add_parsable_certificates(
certs(&mut file).unwrap().into_iter().map(|c| c.into()),
);
// Build a CaTlsConfig that trusts only this root.
let ca_cfg = CaTlsConfig::custom_roots(root_store.roots.clone());
// Convert to a rustls::ClientConfig (uses the default Ring provider).
let client_cfg = ca_cfg.client_config(iroh_relay::tls::default_provider())?;
Disabling Verification for Testing
For development environments, you can disable certificate verification entirely using CaTlsConfig::insecure_skip_verify(). Never use this in production. This configuration is available at the endpoint level as shown in the high-level endpoint example above.
How TLS is Applied at Connection Time
When a connection is established, the configuration flows through to MaybeTlsStreamBuilder::connect in iroh-relay/src/client/tls.rs. This method clones the stored ClientConfig, creates a tokio_rustls::TlsConnector, and performs the actual TLS handshake with the remote relay server.
The high-level client in iroh/src/client.rs coordinates this by retrieving the custom tls_config and feeding it to MaybeTlsStreamBuilder, ensuring your custom settings apply to all outgoing connections.
Summary
- Iroh uses rustls as its underlying TLS implementation, with configuration centralized in
iroh-relay/src/tls.rsthrough theCaTlsConfigstructure. - Create custom configurations by building a
rustls::ClientConfigwith your chosenCryptoProvider(Ring or AWS-LC-RS) and security parameters. - Apply settings to components using
ClientBuilder::tls_client_configfor relay clients orEndpointBuilder::tls_client_configfor the main Iroh endpoint. - Manage root certificates through
CaTlsConfig::custom_roots()or disable verification for testing withCaTlsConfig::insecure_skip_verify(). - Connection establishment occurs in
MaybeTlsStreamBuilder::connect, which uses the supplied configuration to create thetokio_rustls::TlsConnector.
Frequently Asked Questions
Can I use AWS-LC-RS instead of Ring for the cryptographic provider?
Yes. While Ring is the default provider, you can instantiate the AWS-LC-RS provider and pass it to ClientConfig::builder_with_provider(). The CaTlsConfig::client_config method accepts any Arc<CryptoProvider>, allowing you to swap cryptographic backends based on your performance or compliance requirements.
How do I completely disable TLS certificate verification for local testing?
Use CaTlsConfig::insecure_skip_verify() when building your endpoint or client. This disables all certificate verification and should only be used in development or test environments. In production, use CaTlsConfig::custom_roots() to specify your trusted certificate authorities.
Where does the actual TLS handshake occur in the codebase?
The handshake is performed in iroh-relay/src/client/tls.rs within the MaybeTlsStreamBuilder::connect method. This function clones the ClientConfig you provided, creates a tokio_rustls::TlsConnector, and initiates the TLS handshake with the remote server using your custom configuration.
Can I configure TLS settings for the DNS resolver used by Iroh?
Yes. The DNS-over-HTTPS client supports custom TLS configuration via DnsBuilder::tls_client_config, which accepts a rustls::ClientConfig just like the relay client builder. This allows you to customize TLS settings for DNS resolution independently of your peer-to-peer connection settings.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →