借助应用网关互认证服务变量实现APIM客户端证书验证
APIM通过Application Gateway传递的证书变量实现客户端证书验证方案
核心前提
你的APIM部署在VNet内部模式,前端Application Gateway(AGW)完成了客户端证书互认证,证书无法直接传递到APIM,因此无法直接使用APIM内置的context.Request.Certificate.Verify()或<validate-client-certificate>策略。但可以通过AGW的互认证服务变量转发证书相关信息到APIM,再在APIM策略中完成验证。
第一步:AGW端配置(转发证书相关信息)
- 确保AGW已启用客户端证书互认证。
- 在AGW的请求头重写规则中,添加自定义请求头,将AGW的互认证服务变量映射到这些头中传递给APIM:
- 示例映射:
X-Client-Cert->client_certificate(Base64编码的完整证书内容)X-Cert-Issuer->client_certificate_issuer(证书颁发者DN)X-Cert-Subject->client_certificate_subject(证书主题DN)X-Cert-Expiry->client_certificate_expiry(证书过期时间,UTC格式字符串)
- 示例映射:
第二步:APIM端验证实现
由于无法直接赋值context.Request.Certificate对象,提供两种验证方案:
方案一:直接验证转发的证书字段(简单高效)
直接通过AGW转发的自定义头完成四项验证,无需重建证书对象:
<policies> <inbound> <base /> <!-- 检查证书是否存在 --> <choose> <when condition="@(!context.Request.Headers.ContainsKey("X-Client-Cert"))"> <return-response> <set-status code="403" reason="Forbidden" /> <set-body>未提供客户端证书</set-body> </return-response> </when> </choose> <!-- 验证证书过期时间 --> <choose> <when condition="@(DateTime.Parse(context.Request.Headers.GetValueOrDefault("X-Cert-Expiry", "")) < DateTime.UtcNow)"> <return-response> <set-status code="403" reason="Forbidden" /> <set-body>客户端证书已过期</set-body> </return-response> </when> </choose> <!-- 验证指定颁发者 --> <choose> <when condition="@(!context.Request.Headers.GetValueOrDefault("X-Cert-Issuer", "").Equals("CN=你的指定颁发者", StringComparison.OrdinalIgnoreCase))"> <return-response> <set-status code="403" reason="Forbidden" /> <set-body>无效的证书颁发者</set-body> </return-response> </when> </choose> <!-- 验证指定主题 --> <choose> <when condition="@(!context.Request.Headers.GetValueOrDefault("X-Cert-Subject", "").Equals("CN=你的指定主题", StringComparison.OrdinalIgnoreCase))"> <return-response> <set-status code="403" reason="Forbidden" /> <set-body>无效的证书主题</set-body> </return-response> </when> </choose> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error> </policies>
方案二:重建证书对象进行验证(支持复杂场景)
如果需要使用X509Certificate2的原生方法(如Verify()),可以通过AGW转发的Base64证书内容重建证书对象:
<policies> <inbound> <base /> <!-- 检查证书是否存在 --> <choose> <when condition="@(!context.Request.Headers.ContainsKey("X-Client-Cert"))"> <return-response> <set-status code="403" reason="Forbidden" /> <set-body>未提供客户端证书</set-body> </return-response> </when> </choose> <!-- 从Base64内容重建证书对象 --> <set-variable name="clientCert" value="@(new System.Security.Cryptography.X509Certificates.X509Certificate2(Convert.FromBase64String(context.Request.Headers.GetValueOrDefault("X-Client-Cert", ""))))" /> <!-- 验证证书有效性(含过期检查) --> <choose> <when condition="@(!((System.Security.Cryptography.X509Certificates.X509Certificate2)context.Variables["clientCert"]).Verify())"> <return-response> <set-status code="403" reason="Forbidden" /> <set-body>无效的客户端证书</set-body> </return-response> </when> </choose> <!-- 验证指定颁发者 --> <choose> <when condition="@(!((System.Security.Cryptography.X509Certificates.X509Certificate2)context.Variables["clientCert"]).Issuer.Equals("CN=你的指定颁发者", StringComparison.OrdinalIgnoreCase))"> <return-response> <set-status code="403" reason="Forbidden" /> <set-body>无效的证书颁发者</set-body> </return-response> </when> </choose> <!-- 验证指定主题 --> <choose> <when condition="@(!((System.Security.Cryptography.X509Certificates.X509Certificate2)context.Variables["clientCert"]).Subject.Equals("CN=你的指定主题", StringComparison.OrdinalIgnoreCase))"> <return-response> <set-status code="403" reason="Forbidden" /> <set-body>无效的证书主题</set-body> </return-response> </when> </choose> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error> </policies>
关于证书吊销状态验证
AGW默认不启用证书吊销检查,需要手动开启:
- 进入AGW的SSL设置,找到“客户端证书验证”部分。
- 开启“验证客户端证书吊销状态”,选择CRL或OCSP验证方式。
- 开启后,AGW会自动拦截已吊销的证书,不会转发请求到APIM,因此APIM无需额外处理吊销验证。
内容的提问来源于stack exchange,提问作者Vishal Mamidi
相关产品推荐
相关产品推荐

