Terraform配置Azure应用网关mTLS时出现400 SSL证书错误排查
问题现象
请求应用网关时返回400错误:
<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>
- 网关日志仅显示连接尝试记录,无具体错误详情
- 已通过
openssl verify -CAfile ca.pem client.pem验证客户端证书与CA签名匹配,结果为OK
现有Terraform配置
根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" ] }
客户端证书配置
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", ] }
应用网关配置
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" } } }
一、配置可能存在的问题
OCSP验证配置冲突
SSL profile中开启了verify_client_certificate_revocation = "OCSP",但测试用自签CA和客户端证书未配置OCSP端点,网关无法获取吊销状态会直接拒绝请求。建议暂时关闭OCSP验证,修改为:ssl_profile { name = local.gateway_ssl_profile_name trusted_client_certificate_names = [local.gateway_trusted_client_certificate_name] verify_client_certificate_revocation = "None" ssl_policy { policy_type = "Predefined" policy_name = "AppGwSslPolicy20220101" } }根CA证书格式问题
检查传入trusted_client_certificate的CA证书是否为纯PEM格式公钥证书,无多余内容(如私钥)。可通过openssl x509 -in ca.pem -text -noout确认格式正确性。客户端证书扩展用法检查
用openssl x509 -in client.pem -text -noout查看X509v3 Extended Key Usage字段,确认是否明确包含TLS Web Client Authentication。SSL策略兼容性
AppGwSslPolicy20220101可能与客户端证书加密套件不兼容,可尝试切换为AppGwSslPolicy20170401S等兼容策略,或自定义策略包含客户端支持的套件。前端IP配置重名
gateway_ip_configuration和frontend_ip_configuration使用了相同的local.gateway_ip_config_name,可能导致网关内部配置冲突,建议给两者设置不同名称。
二、获取更详细的日志
启用应用网关诊断日志
在Azure门户开启ApplicationGatewayAccessLog和ApplicationGatewayFirewallLog,发送至Log Analytics工作区,运行以下Kusto查询获取详细错误:AzureDiagnostics | where ResourceType == "APPLICATIONGATEWAYS" and OperationName == "ApplicationGatewayAccess" | where HttpStatus == 400 | project TimeGenerated, ClientIP, RequestUri, SslErrorMessage, ServerRoutedIPSslErrorMessage字段会包含具体证书错误原因。用openssl调试客户端请求
执行以下命令获取SSL握手阶段详细信息:openssl s_client -connect <gateway-ip>:443 -cert client.pem -key client-key.pem -CAfile ca.pem -state -debug重点关注
Verify return code及握手过程中的错误提示。
内容的提问来源于stack exchange,提问作者UoS

