Mutual TLS Authentication
#
Protect Admin API#
Why use itMutual TLS authentication provides a better way to prevent unauthorized access to APISIX.
The clients will provide their certificates to the server and the server will check whether the cert is signed by the supplied CA and decide whether to serve the request.
#
How to configureGenerate self-signed key pairs, including ca, server, client key pairs.
Modify configuration items in
conf/config.yaml
:
port_admin: 9180 https_admin: true
admin_api_mtls: admin_ssl_ca_cert: "/data/certs/mtls_ca.crt" # Path of your self-signed ca cert. admin_ssl_cert: "/data/certs/mtls_server.crt" # Path of your self-signed server side cert. admin_ssl_cert_key: "/data/certs/mtls_server.key" # Path of your self-signed server side key.
- Run command:
apisix initapisix reload
#
How client callsPlease replace the following certificate paths and domain name with your real ones.
- Note: The same CA certificate as the server needs to be used *
curl --cacert /data/certs/mtls_ca.crt --key /data/certs/mtls_client.key --cert /data/certs/mtls_client.crt https://admin.apisix.dev:9180/apisix/admin/routes -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1'
#
etcd with mTLS#
How to configureYou need to build APISIX-Openresty and configure etcd.tls
section if you want APISIX to work on an etcd cluster with mTLS enabled.
etcd: tls: cert: /data/certs/etcd_client.pem # path of certificate used by the etcd client key: /data/certs/etcd_client.key # path of key used by the etcd client
#
Protect Route#
Why use itUsing mTLS is a way to verify clients cryptographically. It is useful and important in cases where you want to have encrypted and secure traffic in both directions.
#
How to configureWhen configuring ssl
, use parameter client.ca
and client.depth
to configure the root CA that signing client certificates and the max length of certificate chain. Please refer to Admin API for details.
Here is an example Python script to create SSL with mTLS (id is 1
, changes admin API url if needed):
#!/usr/bin/env python# coding: utf-8# save this file as ssl.pyimport sys# sudo pip install requestsimport requests
if len(sys.argv) <= 4: print("bad argument") sys.exit(1)with open(sys.argv[1]) as f: cert = f.read()with open(sys.argv[2]) as f: key = f.read()sni = sys.argv[3]api_key = "edd1c9f034335f136f87ad84b625c8f1" # Change it
reqParam = { "cert": cert, "key": key, "snis": [sni],}if len(sys.argv) >= 5: print("Setting mTLS") reqParam["client"] = {} with open(sys.argv[4]) as f: clientCert = f.read() reqParam["client"]["ca"] = clientCert if len(sys.argv) >= 6: reqParam["client"]["depth"] = int(sys.argv[5])resp = requests.put("http://127.0.0.1:9080/apisix/admin/ssl/1", json=reqParam, headers={ "X-API-KEY": api_key,})print(resp.status_code)print(resp.text)
Create SSL:
./ssl.py ./server.pem ./server.key 'mtls.test.com' ./client_ca.pem 10
# test itcurl --resolve 'mtls.test.com:<APISIX_HTTPS_PORT>:<APISIX_URL>' "https://<APISIX_URL>:<APISIX_HTTPS_PORT>/hello" -k --cert ./client.pem --key ./client.key
Please make sure that the SNI fits the certificate domain.
#
mTLS Between APISIX and Upstream#
Why use itSometimes the upstream requires mTLS. In this situation, the APISIX acts as the client, it needs to provide client certificate to communicate with upstream.
#
How to configureWhen configuring upstreams
, we could use parameter tls.client_cert
and tls.client_key
to configure the client certificate APISIX used to communicate with upstreams. Please refer to Admin API for details.
This feature requires APISIX to run on APISIX-OpenResty.
Here is a similar Python script to patch a existed upstream with mTLS (changes admin API url if needed):
#!/usr/bin/env python# coding: utf-8# save this file as patch_upstream_mtls.pyimport sys# sudo pip install requestsimport requests
if len(sys.argv) <= 4: print("bad argument") sys.exit(1)with open(sys.argv[2]) as f: cert = f.read()with open(sys.argv[3]) as f: key = f.read()id = sys.argv[1]api_key = "edd1c9f034335f136f87ad84b625c8f1" # Change it
reqParam = { "tls": { "client_cert": cert, "client_key": key, },}
resp = requests.patch("http://127.0.0.1:9080/apisix/admin/upstreams/"+id, json=reqParam, headers={ "X-API-KEY": api_key,})print(resp.status_code)print(resp.text)
Patch existed upstream with id testmtls
:
./patch_upstream_mtls.py testmtls ./client.pem ./client.key