Logging Monitoring Failures in Axum with Mutual Tls
Logging, Monitoring, and Failures in Axum with Mutual TLS
When Axum services are configured for Mutual TLS (mTLS), logging and monitoring can expose gaps that undermine visibility and incident response. In mTLS, both client and server present certificates, and Axum can validate the client identity via request extensions or custom middleware. If certificate validation errors, handshake failures, or unauthorized client rejections are not explicitly logged, operators lose visibility into rejected connections and potential probing behavior. Without structured logs that capture peer certificate details (subject, issuer, SANs) and validation outcomes, monitoring tools cannot reliably correlate failed handshakes with intrusion patterns or compliance violations.
In practice, a common failure scenario is that Axum accepts a request only after successful mTLS verification, but the application-layer logging does not include the certificate identity. If an attacker supplies a valid-but-compromised certificate, the access logs show an authenticated user without indicating which certificate was used. This creates a blind spot: you can see that a request succeeded, but you cannot trace it back to a specific principal for audit or alerting. Conversely, noisy rejection logging without normalization can flood monitoring systems and mask genuine anomalies. Therefore, pairing mTLS with consistent, structured logging of certificate metadata and decision outcomes is essential to maintain an accurate security posture.
Additionally, operational failures can arise when certificate revocation checks (e.g., CRL or OCSP) are performed but their outcomes are not recorded. An expired or revoked certificate might be rejected, yet the rejection is treated as a generic TLS error without context. Monitoring systems that only track HTTP status codes may miss patterns of unauthorized access attempts hidden inside TLS-level rejects. To detect such issues, Axum integrations should emit metrics and logs for TLS handshake outcomes, certificate identifiers, and revocation statuses, enabling dashboards that highlight increases in client authentication failures or unusual certificate usage.
To address these concerns, ensure your Axum service logs key mTLS events with sufficient fidelity. This includes the result of client certificate verification, the certificate’s distinguished name or public key fingerprint, and any relevant error codes. When combined with request IDs that are propagated across service boundaries, these logs allow you to trace a single mTLS-authenticated flow through multiple components. Without this, even a correctly configured mTLS setup can leave you unable to reconstruct attack chains or verify that monitoring alerts are grounded in accurate identity context.
middleBrick can help surface logging and monitoring gaps by scanning your unauthenticated API surface and identifying missing security checks, including weaknesses around authentication and data exposure that often intersect with mTLS implementations. By correlating runtime findings with your logging strategy, you can prioritize remediation steps such as enriching logs with certificate metadata and adding metrics for TLS handshake outcomes.
Mutual TLS-Specific Remediation in Axum
Implementing robust logging and monitoring with Mutual TLS in Axum requires explicit handling of certificate validation and structured emission of security-relevant events. Below are concrete code examples that show how to inspect client certificates, emit structured logs, and expose metrics in an Axum service.
use axum::{
async_trait, body::Body, extract::FromRequest, http::request::Parts, middleware, Extension, Request,
response::IntoResponse, routing::get, Router,
};
use std::convert::Infallible;
use std::sync::Arc;
use tracing::{error, info};
// A simple struct to carry certificate metadata for logging/monitoring
#[derive(Clone, Debug)]
struct ClientCertInfo {
pub subject: String,
pub issuer: String,
pub fingerprint: String,
}
// A custom extractor that validates mTLS and enriches the request
pub struct Authenticated {
pub cert_info: ClientCertInfo,
pub inner: Arc,
}
#[async_trait]
impl FromRequest<S> for Authenticated
where
S: Send + Sync,
{
type Rejection = (http::StatusCode, String);
async fn from_request(req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> {
// Extract peer certificates from the request extensions (set by the TLS layer)
let certs = req.extensions().get<Vec<Vec<u8>>>()
.ok_or_else(|| (http::StatusCode::FORBIDDEN, "Missing client certificate".to_string()))?;
if certs.is_empty() {
return Err((http::StatusCode::FORBIDDEN, "No client certificate provided".to_string()));
}
// In a real implementation, you would parse the DER certificate using `openssl` or `webpki`
// Here we use placeholders to keep the example concise
let cert_der = &certs[0];
let subject = "CN=example-client,O=Test".to_string(); // Replace with parsed subject
let issuer = "CN=Test CA,O=Test".to_string(); // Replace with parsed issuer
let fingerprint = format!("{:x}", md5::compute(cert_der)); // Example hash
// Emit structured log with certificate metadata
info!(
client_cert = subject.as_str(),
cert_issuer = issuer.as_str(),
cert_fingerprint = fingerprint.as_str(),
event = "mtls_handshake_success"
);
// You can also emit a metric here (e.g., increment a counter for successful mTLS)
// metrics::counter!(