Skip to content

Instantly share code, notes, and snippets.

Created September 17, 2022 06:11
Show Gist options
  • Save bzp2010/6ce0bf7c15c191029ed54724547195b4 to your computer and use it in GitHub Desktop.
Save bzp2010/6ce0bf7c15c191029ed54724547195b4 to your computer and use it in GitHub Desktop.
APISIX mTLS for client to APISIX

APISIX mTLS for client to APISIX


This gist provides a complete example of client-side authentication for Apache APISIX.

It includes the process of:

  • generating a certificate
  • configuring the certificate in APISIX
  • configuring the route in APISIX
  • testing

It also demonstrates how to pass some information about the client certificate upstream, which includes serial, fingerprint, and common name.


Generate certificates

Just follow these commands, it will generate certificates by OpenSSL.

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

# For server certificate
openssl genrsa -out server.key 2048
openssl req -new -sha256 -key server.key -out server.csr -subj "/"
openssl x509 -req -days 36500 -sha256 -extensions v3_req  -CA  ca.cer -CAkey ca.key  -CAserial  -CAcreateserial -in server.csr -out server.cer

# For client 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.cer -CAkey ca.key  -CAserial  -CAcreateserial -in client.csr -out client.cer

# Convert client certificate to pkcs12 for Windows usage
openssl pkcs12 -export -clcerts -in client.cer -inkey client.key -out client.p12

Configure the certificate in APISIX

Use curl to request APISIX Admin API to setting up SSL for specify SNI. Note that line feeds in the certificate need to be replaced with \n.

curl -XPUT '' \
--header 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' \
--header 'Content-Type: application/json' \
--data-raw '{
    "sni": "",
    "cert": "<content of server.cer>",
    "key": "<content of server.key>",
    "client": {
        "ca": "<content of ca.cer>"

The sni field specifies the domain name (CN) of the certificate, when the client tries to handshake with APISIX via TLS, APISIX will match the SNI data in ClientHello with this field to find the corresponding server certificate for handshake.

The cert and the key fields are the public and private keys of the server certificate.

The is the CA public key of the client certification certificate, which in theory can use a different public key from the server certificate, and this example uses the same CA for the convenience of demonstration purposes.

Configure the root in APISIX

Next, let's create a route.

curl -XPUT '' \
--header 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' \
--header 'Content-Type: application/json' \
--data-raw '{
    "uri": "/anything",
    "plugins": {
        "proxy-rewrite": {
            "headers": {
                "X-Ssl-Client-Fingerprint": "$ssl_client_fingerprint",
                "X-Ssl-Client-Serial": "$ssl_client_serial",
                "X-Ssl-Client-S-DN": "$ssl_client_s_dn"
    "upstream": {
        "nodes": {

As you can see, we don't need to specify the hostname in the route (you can of course set it if you need to), APISIX will automatically handle the TLS handshake based on the SNI and the ssl resource created in the previous step.

In addition to this, you will see that we have set up the proxy-rewrite plugin, which will dynamically set the headers for the request, and the source of their values are Nginx variables, which you can see here, We will see the effect of this plugin later.


If you are using Windows, and try it in broswer, you will first need to install the client certificate into the system keyring. Double click on the client.p12 file to install it.

If you use curl, then you need to specify the location of the client certificate and key at request time.

Windows and broswer

Since we will be using as the domain name for testing, you will have to add them to your DNS or local hosts file.

When everything is done, let's open a Chromium-like (it prefers to use system certificates keyring) browser and try to access

Firstly, you will see this, just click Advanced and Proceed to (unsafe) to continue.


Then, if you have just installed the certificate correctly, you will see this. You need to check the certificate and confirm it.


Finally, you will see these things, the API return JSON data from (we have just configured the upstream).


The response contains the three request headers we just configured via the proxy-rewrite plugin. Where we can determine from the last two images that the serial value of the client certificate was indeed received correctly upstream.


Use this command:

curl -k --cert ./client.cer --key ./client.key

Then, you will recieve response:

  "args": {},
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Host": "",
    "User-Agent": "curl/7.81.0",
    "X-Amzn-Trace-Id": "Root=1-63256343-17e870ca1d8f72dc40b2c5a9",
    "X-Forwarded-Host": "",
    "X-Ssl-Client-Fingerprint": "c1626ce3bca723f187d04e3757f1d000ca62d651",
    "X-Ssl-Client-S-Dn": "CN=CLIENT",
    "X-Ssl-Client-Serial": "5141CC6F5E2B4BA31746D7DBFE9BA81F069CF970"
  "json": null,
  "method": "GET",
  "origin": "",
  "url": ""

As you can see, the response body also contains the request body received upstream, which contains the correct data.


Apache APISIX does a good job of mTLS for clients to APISIX and sends key information from the certificate to the upstream service.

Also, implementing APISIX with mTLS for upstream services is very simple, and I will describe it later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment