Skip to main content

Version: 3.11.0

Configure mTLS Between Client and APISIX

Mutual TLS (mTLS) is a two-way TLS where client and the server authenticate each other. It is typically implemented to prevent unauthorized access and harden security.

This guide will show you how to configure mTLS between downstream client applications and APISIX.


mTLS between Client and APISIX

Prerequisite(s)

Create a Route

Create a route that forwards all requests to /ip to the upstream httpbin.org:

curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
"id": "quickstart-ip",
"uri": "/ip",
"upstream": {
"nodes": {
"httpbin.org:80":1
},
"type": "roundrobin"
}
}'

An HTTP/1.1 200 OK response verifies that the route is created successfully.

Generate Certificates and Keys

Generate the certificate authority (CA) key and certificate:

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.crt

Generate the key and certificate with the common name test.com for APISIX, and sign with the CA certificate:

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.crt -CAkey ca.key -CAserial ca.srl -CAcreateserial \
-in server.csr -out server.crt

Generate the key and certificate with the common name CLIENT for a client, and sign with the CA certificate:

openssl genrsa -out client.key 2048 && \
openssl req -new -sha256 -key client.key -out client.csr -subj "/CN=CLIENT" && \
openssl x509 -req -days 36500 -sha256 -extensions v3_req \
-CA ca.crt -CAkey ca.key -CAserial ca.srl -CAcreateserial \
-in client.csr -out client.crt

Configure mTLS for APISIX

Load the content stored in server.crt, server.key, and ca.crt into environment variables:

server_cert=$(cat server.crt)
server_key=$(cat server.key)
ca_cert=$(cat ca.crt)

Create an SSL certificate object to save the server certificate, server certificate key, and CA certificate:

curl -i "http://127.0.0.1:9180/apisix/admin/ssls" -X PUT -d '
{
"id": "quickstart-mtls-client-ssl",
"sni": "test.com",
"cert": "'"${server_cert}"'",
"key": "'"${server_key}"'",
"client": {
"ca": "'"${ca_cert}"'"
}
}'

sni: test.com, the same as server certificate CN value

cert: server certificate server.crt

key: server certificate key server.key

client.ca: CA certificate ca.crt

Verify mTLS between Client and APISIX

With Client Certificate

As the certificate is only valid for the CN test.com, you should use test.com as the domain name where APISIX is hosted.

Send a request to https://test.com:9443/ip with client certificate and resolve test.com to 127.0.0.1:

curl -ikv --resolve "test.com:9443:127.0.0.1" "https://test.com:9443/ip" \
--cert client.crt --key client.key

An mTLS handshake similar to the following verifies the mTLS between client and APISIX is enabled:

* Added test.com:9443:127.0.0.1 to DNS cache
* Hostname test.com was found in DNS cache
* Trying 127.0.0.1:9443...
* Connected to test.com (127.0.0.1) port 9443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Request CERT (13):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Certificate (11):
* TLSv1.3 (OUT), TLS handshake, CERT verify (15):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=test.com
* start date: Apr 21 07:47:54 2023 GMT
* expire date: Mar 28 07:47:54 2123 GMT
* issuer: CN=ROOTCA
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x5625339a72e0)
> GET /ip HTTP/2
> Host: test.com:9443
> user-agent: curl/7.74.0
> accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200
HTTP/2 200
...

Note that APISIX and the client successfully verified each other's certificate during the handshake and established a connection.

Without Client Certificate

Send a request to https://test.com:9443/ip but without client certificate:

curl -ikv --resolve "test.com:9443:127.0.0.1" "https://test.com:9443/ip"

A failed mTLS handshake is similar to the following:

* Added test.com:9443:127.0.0.1 to DNS cache
* Hostname test.com was found in DNS cache
* Trying 127.0.0.1:9443...
* Connected to test.com (127.0.0.1) port 9443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Request CERT (13):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Certificate (11):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=test.com
* start date: Apr 21 07:47:54 2023 GMT
* expire date: Mar 28 07:47:54 2123 GMT
* issuer: CN=ROOTCA
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55f791e252e0)
> GET /ip HTTP/2
> Host: test.com:9443
> user-agent: curl/7.74.0
> accept: */*
>
* TLSv1.3 (IN), TLS alert, unknown (628):
* OpenSSL SSL_read: error:1409445C:SSL routines:ssl3_read_bytes:tlsv13 alert certificate required, errno 0
* Failed receiving HTTP2 data
* OpenSSL SSL_write: SSL_ERROR_ZERO_RETURN, errno 0
* Failed sending HTTP2 data
* Connection #0 to host test.com left intact

the handshake failed due to the lack of client certificate.

Next Steps

You can learn more about mTLS and APISIX SSL object in SSL Certificates.

APISIX also supports TLS connection between clients and APISIX. See Configure HTTPS between client and APISIX for more details.


API7.ai Logo

API Management for Modern Architectures with Edge, API Gateway, Kubernetes, and Service Mesh.

Product

API7 Cloud

SOC2 Type IIISO 27001HIPAAGDPRRed Herring

Copyright © APISEVEN Ltd. 2019 – 2024. Apache, Apache APISIX, APISIX, and associated open source project names are trademarks of the

Apache Software Foundation