Configure mTLS between client and API7 Gateway
Mutual TLS (mTLS) is an enhanced form of Transport Layer Security (TLS), a method for mutual authentication between the client and server. It is achieved through a process known as a handshake, where both parties exchange and validate certificates to verify each other's identities.
This guide will show you how to configure mTLS between client and API7 Gateway, preventing unauthorized access and hardening security.
Prerequisite(s)
- Install API7 Enterprise.
- Launch Your First API, and make sure your service has a hostname
test.com
.
Generate Certificates and Keys
-
Generate the Certificate Authority (CA) key and certificate:
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 36500 -sha256 \
-key ca.key \
-out ca.crt \
-subj "/CN=MyTestCA" \
-extensions v3_ca \
-config <(printf "[req]\ndistinguished_name=req\n[ v3_ca ]\nbasicConstraints=critical,CA:TRUE\nkeyUsage=critical,keyCertSign,cRLSign\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid:always,issuer") -
Generate the key and certificate signing request (CSR):
openssl genrsa -out server.key 2048
openssl req -new -sha256 \
-key server.key \
-out server.csr \
-subj "/CN=test.com" -
Sign the server CSR with the CA certificate to generate the server certificate:
openssl x509 -req -days 36500 -sha256 \
-in server.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt \
-extensions v3_req \
-extfile <(printf "[v3_req]\nbasicConstraints=CA:FALSE\nkeyUsage=digitalSignature,keyEncipherment\nextendedKeyUsage=serverAuth") -
Generate the key and certificate signing request (CSR) for the client:
openssl genrsa -out client.key 2048
openssl req -new -sha256 \
-key client.key \
-out client.csr \
-subj "/CN=CLIENT" -
Sign the client CSR with the CA certificate to generate the client certificate:
openssl x509 -req -days 36500 -sha256 \
-in client.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out client.crt \
-extensions v3_req \
-extfile <(printf "[v3_req]\nbasicConstraints=CA:FALSE\nkeyUsage=digitalSignature,keyEncipherment\nextendedKeyUsage=clientAuth")
Upload Certificates
If you would like to reference SSL certificate from secret provider, see Reference Secrets in HashiCorp Vault, Reference Secrets in AWS Secrets Manager, or Reference Secrets in Kubernetes Secret.
- Dashboard
- Ingress Controller
Create Certificates
- Select Certificates of your gateway group from the side navigation bar, enter the SSL Certificates tab.
- Click Add SSL Certificate.
- From the dialog box, do the following:
- In the Name field, enter
Test SSL Certificate
. - In the Certificate field, upload the
server.crt
file. - In the Private Key field, upload the
server.key
file. - Click Add.
- Select Certificates of your gateway group from the side navigation bar, then click CA Certificates tab.
- Click Add CA Certificate.
- From the dialog box, do the following:
- In the Name field, enter
Test CA Certificate
. - In the Certificate field, upload the
ca.crt
file. - Click Add.
Create SNI
- Select SNIs of your gateway group from the side navigation bar.
- Click Add SNI.
- From the dialog box, do the following:
- In the Name field, enter
Test SNI
. - In the Domain field, enter
test.com
. - In the SSL Protocol field, select
TLS 1.2
andTLS 1.3
. - In the SSL Certificate field, select the
Test SSL Certificate
you created previously. - Open the mTLS switch.
- In the CA Certificate field, select the
Test CA Certificate
you created previously. - Click Add.
- In the Usage field, you should see a matched published service with the hostname
test.com
. Then you are ready for validation.
- Gateway API
- APISIX CRD
Gateway API currently does not support downstream mTLS.
Generate a Kubernetes TLS secret named test-tls-secret
using the provided certificate and private key files, and outputs the manifest to secret.yaml
in the api7
namespace:
kubectl create secret tls test-mtls-secret \
--cert=server.crt \
--key=server.key \
--namespace=api7 \
--dry-run=client -o yaml > secret.yaml
Create a generic Kubernetes secret named test-ca-secret
from the ca.crt
file and outputs the manifest to ca-secret.yaml
in the api7
namespace:
kubectl create secret generic test-ca-secret \
--from-file=cert=ca.crt \
--namespace=api7 \
--dry-run=client -o yaml > ca-secret.yaml
Apply these secret configuration to your cluster:
kubectl apply -f secret.yaml -f ca-secret.yaml
Generate another Kubernetes manifest file to configure these secrets on the gateway for mTLS:
apiVersion: apisix.apache.org/v2
kind: ApisixTls
metadata:
name: test-mtls
spec:
ingressClassName: apisix
hosts:
- test.com
secret:
name: test-mtls-secret
namespace: api7
client:
caSecret:
name: test-ca-secret
namespace: api7
depth: 1
Apply the configuration to your cluster:
kubectl apply -f client-mtls.yaml
Verify mTLS between Client and API7 Gateway
With Client Certificate
- Docker
- Kubernetes
First, expose the service port to your local machine by port forwarding:
kubectl port-forward svc/apisix-gateway 9443:443 &
Send a request to https://test.com:9443/ip
with the 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 like the following verifies that the mTLS connection between the client and API7 Gateway is successfully established:
* 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
* ALPN: curl offers h2,http/1.1
Handling connection for 9443
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Request CERT (13):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Certificate (11):
* (304) (OUT), TLS handshake, CERT verify (15):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384 / [blank] / UNDEF
* ALPN: server accepted h2
* Server certificate:
* subject: CN=test.com
* start date: Jul 30 07:40:58 2025 GMT
* expire date: Jul 6 07:40:58 2125 GMT
* issuer: CN=MyTestCA
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://test.com:9443/ip
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: test.com:9443]
* [HTTP/2] [1] [:path: /ip]
* [HTTP/2] [1] [user-agent: curl/8.6.0]
* [HTTP/2] [1] [accept: */*]
> GET /ip HTTP/2
> Host: test.com:9443
> User-Agent: curl/8.6.0
> Accept: */*
>
< HTTP/2 200
HTTP/2 200
...
{
"origin": "127.0.0.1, 101.44.80.31"
}
Note that API7 Gateway 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 a client certificate.
curl -ikv --resolve "test.com:9443:127.0.0.1" "https://test.com:9443/ip"
The mTLS handshake should fail due to the lack of a client certificate.
Additional Resources
- Key Concepts
- Getting Started
- API Security