WSO2 API Manager 4.2搭配AWS ALB的mTLS认证配置异常排查
问题:AWS ALB透传mTLS证书到WSO2 APIM 4.2解析失败
场景与配置
在前端部署AWS Application Load Balancer(ALB)的WSO2 API Manager 4.2平台中,为特定API配置Mutual TLS(mTLS)认证:
- ALB采用透传模式配置mTLS
- WSO2端将目标API设置为要求mTLS,并更新
deployment.toml配置:[apimgt.mutual_ssl] certificate_header = "X-Amzn-Mtls-Clientcert" enable_client_validation = false client_certificate_encode = true
问题现象
调用API时WSO2返回认证失败错误:
curl -v https://WSO2-GW-ALB.env.dev/my-api/1.0.0/test --key client-v3.key --cert client-v3.crt < content-type: application/json; charset=UTF-8 < set-cookie: AWSALBTG=xxxxxxxxxx...; Expires=Tue, 06 Aug GMT; Path=/ < set-cookie: AWSALBTGCORS=xxxxxxxxxx...; Expires=Tue, 06 Aug 2024 14:03:35 GMT; Path=/; SameSite=None; Secure < activityid: e18b453b-f9ff-4dec-8aaa-0e9ea316312e < access-control-expose-headers: < access-control-allow-origin: * < access-control-allow-methods: GET < x-forwarded-proto: https < x-forwarded-for: 10.XX.XX.XX < x-forwarded-port: 443 < access-control-allow-headers: authorization,Access-Control-Allow-Origin,Content-Type,SOAPAction,apikey,Internal-Key,Authorization < x-amzn-trace-id: Root=1-6ccccf2b7-4c1026ccccc83630554457e0 < x-amzn-mtls-clientcert: -----BEGIN%20CERTIFICATE-----%0AMIIFJDCCAwxxxxxxxxxxxxxxxxxxxxxxxxygAwxAgI0Aw6<reduced>%0A-----END%20CERTIFICATE-----%0A < * TLSv1.2 (IN), TLS header, Supplemental data (23): * Connection #0 to host WSO2-GW-ALB.env.dev left intact {"code":"900900","message":"Unclassified Authentication Failure","description":"Error while validating into Certificate Existence"}
WSO2日志显示证书解析失败:
TID: [] [] [2024-07-30 13:32:12,953] ERROR {org.wso2.carbon.apimgt.gateway.handlers.Utils} - Error while validating into Certificate Existence org.wso2.carbon.apimgt.api.APIManagementException: Error while converting into X509Certificate at org.wso2.carbon.apimgt.gateway.handlers.Utils.getClientCertificateFromHeader_aroundBody34(Utils.java:491) at org.wso2.carbon.apimgt.gateway.handlers.Utils.getClientCertificateFromHeader(Utils.java:1) at org.wso2.carbon.apimgt.gateway.handlers.Utils.getClientCertificate_aroundBody32(Utils.java:448) at org.wso2.carbon.apimgt.gateway.handlers.Utils.getClientCertificate(Utils.java:1) at org.wso2.carbon.apimgt.gateway.handlers.security.authenticator.MutualSSLAuthenticator.authenticate_aroundBody4(MutualSSLAuthenticator.java:105) at org.wso2.carbon.apimgt.gateway.handlers.security.authenticator.MutualSSLAuthenticator.authenticate(MutualSSLAuthenticator.java:1) at org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler.isAuthenticate_aroundBody56(APIAuthenticationHandler.java:546) ... Caused by: java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: Incomplete BER/DER data at java.base/sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:115) at java.base/java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:355) at org.wso2.carbon.apimgt.gateway.handlers.Utils.getClientCertificateFromHeader_aroundBody34(Utils.java:488)
关键排查结论:ALB发送的X-Amzn-Mtls-Clientcert头仅对空格、换行做了URL编码,但未处理+、/、=这些字符,而WSO2期望接收完全URL编码的证书头,导致解码后证书格式损坏无法解析。
解决方案
1. 使用Lambda@Edge补全证书头编码
创建Lambda函数在ALB的请求阶段拦截并处理证书头,对未编码的字符进行补全编码:
exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; const headers = request.headers; if (headers['x-amzn-mtls-clientcert']) { let certHeader = headers['x-amzn-mtls-clientcert'][0].value; // 对+、/、=进行URL编码 certHeader = certHeader.replace(/\+/g, '%2B') .replace(/\//g, '%2F') .replace(/=/g, '%3D'); headers['x-amzn-mtls-clientcert'][0].value = certHeader; } callback(null, request); };
将该Lambda关联到ALB的对应监听器,确保请求到达WSO2网关前完成编码处理。
2. 修改WSO2证书解析逻辑(自定义扩展)
修改WSO2网关的证书解析代码,在解码前先补全未编码的字符:
找到org.wso2.carbon.apimgt.gateway.handlers.Utils类的getClientCertificateFromHeader方法,添加以下代码:
// 在URL解码前补全字符编码 certHeader = certHeader.replace("+", "%2B") .replace("/", "%2F") .replace("=", "%3D"); // 执行原有解码逻辑 String decodedCert = URLDecoder.decode(certHeader, StandardCharsets.UTF_8.name());
重新打包APIM网关组件,替换原有jar包后重启网关。
3. 引入NGINX中间层转码
在ALB与WSO2网关之间部署NGINX,配置NGINX处理证书头编码后转发:
location / { proxy_pass http://wso2-gateway-group; # 处理证书头的未编码字符 set $encoded_cert $http_x_amzn_mtls_clientcert; set $encoded_cert "${encoded_cert//+/%2B}"; set $encoded_cert "${encoded_cert//\//%2F}"; set $encoded_cert "${encoded_cert//=/%3D}"; proxy_set_header X-Amzn-Mtls-Clientcert $encoded_cert; # 转发其他必要头信息 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
这种方式无需修改WSO2代码,适合快速落地。
内容的提问来源于stack exchange,提问作者Soufiane
相关产品推荐
相关产品推荐

