deekshith-hadil opened a new issue, #12783: URL: https://github.com/apache/apisix/issues/12783
### Current Behavior When APISIX is configured as a TCP (stream) proxy and the upstream is configured with `tls.verify = true` and a client certificate, APISIX successfully establishes a connection to the upstream even if the configured CA for verifying the upstream certificate is invalid. In other words, APISIX is not verifying the upstream server's TLS certificate for L4 (stream) routes and allows the connection to proceed regardless of verification failure. ### Expected Behavior When `upstream.tls.verify` is `true`, APISIX should validate the upstream server certificate against the configured CA (`client.ca` referenced by `client_cert_id`) and abort/close the connection if verification fails (e.g., if the CA does not match). ## Actual behavior - APISIX does not reject the upstream TLS connection when an invalid CA is provided; data is successfully proxied to the upstream despite the CA mismatch. ### Error Logs No Error logs ### Steps to Reproduce 1. Install APISIX using the Helm chart: ```sh helm repo add apisix https://apache.github.io/apisix-helm-chart helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update kubectl create ns apisix helm install apisix apisix/apisix \ --set etcd.enabled=true \ --set apisix.enableIPv6=false \ --set ingress-controller.enabled=false \ --set apisix.admin.allow.ipList="" \ --set service.type=LoadBalancer \ --set apisix.admin.type=LoadBalancer \ --set service.stream.enabled=true \ --set 'service.stream.tcp[0]=5443' \ -n apisix ``` 2. Generate certificates: ```sh # Root CA1 (used to sign upstream server) openssl genrsa -out ca.key 2048 openssl req -new -sha256 -key ca.key -out ca.csr -subj "/CN=ROOTCA" openssl x509 -req -days 36500 -sha256 -extensions v3_ca -signkey ca.key -in ca.csr -out ca.cer # Client certificate (self signed) openssl req -x509 -newkey rsa:2048 -sha256 -days 36500 -nodes -keyout mtls-client.key -out client.cer -subj "/CN=MTLSCLIENT" -addext "extendedKeyUsage = clientAuth" ``` 3. Create a client SSL object in APISIX referencing CA1 (initially correct CA): ```sh curl -X PUT 'http://127.0.0.1:9180/apisix/admin/ssls/5443' \ -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' \ -H 'Content-Type: application/json' \ -d '{ "sni": "test.com", "cert": "'"$(cat mtls-client.cer)"'", "key": "'"$(cat mtls-client.key)"'", "type": "client", "client": { "ca": "'"$(cat ca.cer)"'" } }' ``` 4. Create a stream_route with upstream.tls.verify = true and `client_cert_id` pointing to the SSL object: ```sh curl -X PUT http://127.0.0.1:9180/apisix/admin/stream_routes/5443 \ -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" \ -H "Content-Type: application/json" \ -d '{ "name": "mtlstest", "server_port": 5443, "upstream": { "name": "mtlsupstream", "desc": "Upstream for the example service", "scheme": "tls", "nodes": [ { "host": "10.12.130.244", "port": 5000, "weight": 100, "priority": 0 } ], "tls": { "verify": true, "client_cert_id": 5443 } } }' ``` 5. Start an upstream TLS server (no client-cert verification on upstream for this test because of known issue https://github.com/apache/apisix/issues/12472): ```sh # Create server certificates # Server certificate (CN=test.com), signed by CA1 openssl genrsa -out server.key 2048 openssl req -new -sha256 -key server.key -out server.csr -subj "/CN=test.com" openssl x509 -req -days 36500 -sha256 -extensions v3_req -CA ca.cer -CAkey ca.key -CAserial ca.srl -CAcreateserial -in server.csr -out server.cer # Run server openssl s_server -accept 5000 -cert server.cer -key server.key ``` 6. Send raw TCP data to APISIX (APISIX should proxy via TLS to upstream): ```sh echo 'test' | nc 127.0.0.1 5443 ``` - At this point, data is received by the upstream server (expected). 7. Now patch the client SSL in APISIX to use the wrong CA (CA2) that does not match the upstream certificate: ```sh # Generate new CA certificate # Root CA2 (different CA, NOT used to sign client/server certs) openssl genrsa -out ca2.key 2048 openssl req -new -sha256 -key ca2.key -out ca2.csr -subj "/CN=ROOTCA" openssl x509 -req -days 36500 -sha256 -extensions v3_ca -signkey ca2.key -in ca2.csr -out ca2.cer openssl genrsa -out ca2.key 2048 openssl req -new -sha256 -key ca2.key -out ca2.csr -subj "/CN=ROOTCA" openssl x509 -req -days 36500 -sha256 -extensions v3_ca -signkey ca2.key -in ca2.csr -out ca2.cer curl -X PUT 'http://127.0.0.1:9180/apisix/admin/ssls/5443' \ -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' \ -H 'Content-Type: application/json' \ -d '{ "sni": "test.com", "cert": "'"$(cat client.cer)"'", "key": "'"$(cat client.key)"'", "type": "client", "client": { "ca": "'"$(cat ca2.cer)"'" } }' ``` 8. Repeat sending TCP data: ```sh echo 'test' | nc 127.0.0.1 5443 ``` - Actual result: Data is still successfully received by the upstream. APISIX did not terminate the connection even though the CA used to verify the upstream certificate is incorrect. ### Environment - APISIX version (run `apisix version`): 3.14.1 - APISIX helm chart version: 2.12.4 - Kubernetes server version: v1.31.5+k3s1 - Operating system (run `uname -a`): Linux 212801065-522 5.15.0-161-generic #171-Ubuntu SMP Sat Oct 11 08:17:01 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux - OpenResty / Nginx version (run `openresty -V` or `nginx -V`): NA - etcd version, if relevant (run `curl http://127.0.0.1:9090/v1/server_info`): NA - APISIX Dashboard version, if relevant: NA - Plugin runner version, for issues related to plugin runners: NA - LuaRocks version, for installation issues (run `luarocks --version`): NA -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
