Logging Monitoring Failures in Actix with Mutual Tls
Logging, Monitoring, and Failures in Actix with Mutual TLS
Mutual Transport Layer Security (mTLS) in Actix requires both the server and the client to present and validate certificates. This strict authentication model changes how logs are generated and monitored, and it can expose logging and monitoring failures when certificate validation happens before structured logging is initialized.
In an Actix-web service, if TLS termination occurs at the reverse proxy or load balancer and the application only sees plaintext HTTP, the runtime context lacks certificate metadata. Without passing client certificate details into the request extensions or structured logs, audit trails become incomplete. Failures occur when access logs record only an IP and path, but do not include the client certificate subject or serial number. This makes it difficult to trace which identity performed an action, especially during incident response or compliance audits.
Additionally, if certificate validation errors (such as expired or untrusted certs) are handled silently by middleware and not surfaced in logs or metrics, monitoring gaps appear. You may see 200 OK responses in application logs while mTLS failures are suppressed at the edge. This disconnect between transport-layer success and application-layer observability means critical security events go unrecorded. Actix middleware that runs early can skip structured logging setup, so errors from certificate verification may never reach your logging pipeline, creating blind spots for automated alerting.
To detect these issues, monitor for patterns such as missing certificate fields in structured logs, spikes in TLS handshake failures without corresponding alerts, and inconsistent status codes between the proxy and application. Ensure your Actix middleware captures peer identity into request extensions and propagates it into log fields like peer_cert_subject and peer_cert_serial. Correlating mTLS events with application logs and metrics gives a complete picture of who is accessing what and under which identity.
Mutual TLS-Specific Remediation in Actix
Remediation focuses on ensuring client certificate details are captured, validated, and included in logs and metrics. Configure Actix to extract certificate information from the TLS connection and propagate it into structured logs. Below are concrete code examples that demonstrate how to set up mTLS in Actix and log certificate details.
First, enable client certificate verification in your Actix server configuration. Use the openssl feature of actix-web along with native TLS via rustls or openssl to request and validate client certs. The server must be configured to require client authentication, and middleware should extract certificate fields and insert them into request extensions for downstream handlers and logging.
use actix_web::{web, App, HttpServer, HttpRequest};
use actix_web::dev::ServiceRequest;
use actix_web::middleware::Next;
use actix_web::error::ErrorUnauthorized;
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
use std::sync::Arc;
async fn require_mtls(req: ServiceRequest, next: Next) -> Result {
// Extract peer certificate from the request extensions (populated by TLS acceptor)
let cert = req.extensions().get::>()
.and_then(|certs| certs.first())
.ok_or_else(|| ErrorUnauthorized("client certificate required"))?;
let subject = cert.subject_name().to_string();
let serial = cert.serial_number().to_string();
// Insert certificate metadata into request extensions for handlers and loggers
req.extensions_mut().insert(subject.clone());
req.extensions_mut().insert(serial.clone());
// Structured logging: include certificate identifiers
tracing::info!(
method = %req.method(),
path = %req.path(),
peer_cert_subject = %subject,
peer_cert_serial = %serial,
"mTLS request received"
);
next.call(req).await
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// Configure OpenSSL acceptor with client verification
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder.set_private_key_file("key.pem", SslFiletype::PEM).unwrap();
builder.set_certificate_chain_file("cert.pem").unwrap();
builder.set_client_ca_list_from_file("ca.pem").unwrap();
builder.set_verify(openssl::ssl::SslVerifyMode::PEER | openssl::ssl::SslVerifyMode::FAIL_IF_NO_PEER_CERT);
HttpServer::new(move || {
App::new()
.wrap_fn(|req, srv| {
// TLS handshake happens before this wrapper; extensions are populated by the server
require_mtls(req, srv)
})
.route("/api/values", web::get().to(|| async { "ok" }))
})
.bind_openssl("127.0.0.1:8443", builder)?
.run()
.await
}
In this example, the OpenSSL acceptor requires a client certificate and validates it against a CA. The middleware extracts the subject and serial, inserts them into request extensions, and includes them in structured logs via tracing. This ensures that every log line tied to an mTLS-authenticated request contains the identity of the client, enabling precise monitoring and alerting.
For monitoring, expose metrics that track mTLS-specific events: number of requests with valid client certs, number of rejected handshakes due to missing or invalid certs, and certificate expiry times. Combine these with your existing application metrics to detect anomalies such as sudden drops in mTLS success rates or unexpected certificate serial numbers appearing in logs. The combination of precise logging and metric collection closes the visibility gap introduced by mTLS and reduces the risk of undetected access by unauthorized identities.