I try to setup mTLS with an Azure Application Gateway. Unfortunately I always get an error
<html><head><title>400 The SSL certificate error</title></head><body><center><h1>400 Bad Request</h1></center><center>The SSL certificate error</center><hr><center>Microsoft-Azure-Application-Gateway/v2</center></body></html>
In the gateway logs, I can see the connection attempts, but without any errors. curl or the browsers also don't provide any useful logs. I also checked with openssl verify -CAfile ca.pem client.pem
, that the certificate signature matches the CA (result OK
).
I set it up via Terraform:
Root CA
resource "tls_private_key" "gateway_mtls_root_ca_private_key" { algorithm = "RSA" rsa_bits = 4096}resource "tls_self_signed_cert" "gateway_mtls_root_ca" { private_key_pem = tls_private_key.gateway_mtls_root_ca_private_key.private_key_pem subject { common_name = "root-ca" organization = "test" } validity_period_hours = 24 * 90 # 3 months for testing phase is_ca_certificate = true allowed_uses = ["cert_signing","crl_signing","digital_signature" ]}
Client Certificate
resource "tls_private_key" "gateway_mtls_client_cert_private_key" { algorithm = "RSA" rsa_bits = 4096}resource "tls_cert_request" "gateway_mtls_client_cert_request" { private_key_pem = tls_private_key.gateway_mtls_client_cert_private_key.private_key_pem subject { common_name = "client" organization = "test" }}resource "tls_locally_signed_cert" "gateway_mtls_client_cert" { cert_request_pem = tls_cert_request.gateway_mtls_client_cert_request.cert_request_pem ca_private_key_pem = tls_private_key.gateway_mtls_root_ca_private_key.private_key_pem ca_cert_pem = tls_self_signed_cert.gateway_mtls_root_ca.cert_pem validity_period_hours = 24 * 30 # 1 month for testing allowed_uses = ["client_auth","key_encipherment","digital_signature", ]}
Application Gateway
resource "azurerm_application_gateway" "container_gateway" { name = "test-gateway" location = var.resource_group_region resource_group_name = var.resource_group_name sku { name = "Standard_v2" tier = "Standard_v2" capacity = 2 } identity { type = "UserAssigned" identity_ids = [ azurerm_user_assigned_identity.gateway_identity.id ] } gateway_ip_configuration { name = local.gateway_ip_config_name subnet_id = var.gateway_subnet_ids[0] } backend_address_pool { name = local.gateway_backend_pool_name ip_addresses = var.container_group_ip_addresses } backend_http_settings { name = local.gateway_backend_settings cookie_based_affinity = "Disabled" port = 80 protocol = "Http" request_timeout = 20 } frontend_ip_configuration { name = local.gateway_ip_config_name public_ip_address_id = azurerm_public_ip.container_pip.id } frontend_port { name = local.gateway_frontend_https_port_name port = 443 } http_listener { name = local.gateway_https_listener_name frontend_ip_configuration_name = local.gateway_ip_config_name frontend_port_name = local.gateway_frontend_https_port_name protocol = "Https" ssl_certificate_name = local.gateway_ssl_certificate_name ssl_profile_name = local.gateway_ssl_profile_name } request_routing_rule { name = local.gateway_https_path_based_rules_name rule_type = "PathBasedRouting" http_listener_name = local.gateway_https_listener_name url_path_map_name = local.gateway_url_path_map_name priority = 1000 } url_path_map { name = local.gateway_url_path_map_name default_backend_address_pool_name = local.gateway_backend_pool_name default_backend_http_settings_name = local.gateway_backend_settings path_rule { name = "test" paths = ["/*"] backend_address_pool_name = local.gateway_backend_pool_name backend_http_settings_name = local.gateway_backend_settings } } ssl_certificate { name = local.gateway_ssl_certificate_name key_vault_secret_id = azurerm_key_vault_certificate.gateway_server_certificate.secret_id } ssl_policy { policy_type = "Predefined" policy_name = "AppGwSslPolicy20220101" } trusted_client_certificate { name = local.gateway_trusted_client_certificate_name data = tls_self_signed_cert.gateway_mtls_root_ca.cert_pem } ssl_profile { name = local.gateway_ssl_profile_name trusted_client_certificate_names = [local.gateway_trusted_client_certificate_name] verify_client_certificate_revocation = "OCSP" ssl_policy { policy_type = "Predefined" policy_name = "AppGwSslPolicy20220101" } }}
Do you have an idea, what could be wrong in this setup? Or where I can find more useful logs to analyze it? Thank you!