Mutual TLS (mTLS) on an ingress gateway enforces two-way certificate verification: only clients that present a valid certificate can reach your backend services. This prevents unauthorized access, eavesdropping, and data tampering for gRPC traffic without requiring TLS configuration on individual applications.
How mTLS works with gRPC on an ingress gateway
gRPC runs on HTTP/2. Ingress gateways support gRPC with TLS or mTLS. When a request reaches the ingress gateway, TLS termination happens at the gateway: it decrypts the incoming TCP stream, validates the client certificate against a trusted CA, and forwards plaintext traffic to the backend service inside the mesh. Individual applications do not need their own TLS configuration.
The following diagram shows the traffic flow:
Client (with cert) --[mTLS]--> Ingress Gateway --[plaintext]--> gRPC Service
|
TLS termination +
client cert validationPrerequisites
Before you begin, make sure you have:
A Service Mesh (ASM) Enterprise Edition instance. See Create an ASM instance
A Container Service for Kubernetes (ACK) managed cluster. See Create an ACK managed cluster
The ACK cluster added to the ASM instance. See Add a cluster to an ASM instance
An ingress gateway deployed in the ASM instance. See Create an ingress gateway
An application deployed in the ACK cluster. See Deploy an application in an ASM instance
Step 1: Deploy a sample gRPC server
Deploy a gRPC server Deployment and its corresponding Service to the ACK cluster.
Log on to the ACK console. In the left-side navigation pane, click Clusters.
On the Clusters page, click the name of the cluster that you want to manage and choose Workloads > Deployments in the left-side navigation pane.
In the upper part of the Deployments page, select a namespace from the Namespace drop-down list and click Create from YAML.
On the Create page, copy the following YAML code to the code editor and click Create.
ImportantThe
namefield underportsin the Service definition must start withhttp2-orgrpc-. Istio uses this prefix to identify the protocol. If the name does not follow this convention, Istio treats the traffic as plain TCP and routing may not work as expected.
Step 2: Create an ingress gateway
Use the default port 443 to expose the gRPC service externally. For detailed steps, see Create an ingress gateway.
Step 3: Configure a Gateway and a VirtualService
Create an Istio Gateway and a VirtualService to route HTTPS/gRPC traffic on port 443 to the backend gRPC server.
Create the Gateway
Log on to the ASM console. In the left-side navigation pane, choose .
On the Mesh Management page, find the ASM instance that you want to configure, and click the instance name or click Manage in the Actions column.
Create an Istio gateway.
In the left-side navigation pane, choose .
On the Gateway page, click Create from YAML.
Select default from the Namespace drop-down list, copy the following YAML code to the code editor, and click Create.
apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: gw-grpc-443 namespace: default spec: selector: istio: ingressgateway servers: - hosts: - '*' port: name: https number: 443 protocol: HTTPS tls: credentialName: example-credential mode: MUTUAL
Key fields:
Field Value Description tls.modeMUTUALEnables mTLS. The gateway requires a valid client certificate for every connection. tls.credentialNameexample-credentialReferences the Kubernetes Secret that stores the server certificate and the CA certificate for client verification. You create this Secret in Step 4.
Create the VirtualService
In the left-side navigation pane of the ASM instance, choose .
On the VirtualService page, click Create from YAML.
Select default from the Namespace drop-down list, copy the following YAML code to the code editor, and click Create.
This VirtualService routes all traffic arriving on port 443 through the
gw-grpc-443Gateway to theistio-grpc-serverbackend.apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: grpc-vs spec: hosts: - "*" gateways: - gw-grpc-443 http: - match: - port: 443 route: - destination: host: istio-grpc-server
Step 4: Mount TLS certificates
The ingress gateway needs a server certificate for TLS termination and a CA certificate to verify client certificates. A gRPC client typically requires a Subject Alternative Name (SAN) certificate.
The Secret name must match the credentialName value configured in the Gateway resource. In this example, both use example-credential.
Generate test certificates
For testing, generate a self-signed CA and the required server and client certificates. Run the following commands:
# Create a directory for the certificates
mkdir -p example_certs && cd example_certs
# Generate a self-signed CA certificate
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 \
-subj '/O=example Inc./CN=example.com' \
-keyout ca.key -out ca.crt
# Generate a server certificate signed by the CA
openssl req -newkey rsa:2048 -nodes \
-subj '/CN=x.test.example.com/O=server' \
-keyout server_key.pem -out server.csr
openssl x509 -req -sha256 -days 365 \
-CA ca.crt -CAkey ca.key -set_serial 0 \
-in server.csr -out server_cert.pem
# Generate a client certificate signed by the same CA
openssl req -newkey rsa:2048 -nodes \
-subj '/CN=x.test.example.com/O=client' \
-keyout client_key.pem -out client.csr
openssl x509 -req -sha256 -days 365 \
-CA ca.crt -CAkey ca.key -set_serial 1 \
-in client.csr -out client_cert.pemAlternatively, use the sample certificates from the grpc-go examples.
Mount certificates for ASM versions earlier than 1.17
Run the following kubectl command to create a Secret in the istio-system namespace, where the ingress gateway runs:
kubectl create -n istio-system secret generic example-credential \
--from-file=tls.key=server_key.pem \
--from-file=tls.crt=server_cert.pem \
--from-file=ca.crt=client_ca_cert.pemIf you generated certificates by using the commands in Generate test certificates, replace client_ca_cert.pem with ca.crt in the preceding command.
The following table describes the Secret keys:
| Key | File | Description |
|---|---|---|
tls.key | server_key.pem | Server private key |
tls.crt | server_cert.pem | Server certificate |
ca.crt | client_ca_cert.pem | CA certificate used to verify client certificates. Use ca.crt if you generated your own certificates. |
Mount certificates for ASM version 1.17 or later
Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.
On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose ASM Gateways > Certificate Management.
On the Certificate Management page, click Create. In the Certificate Information panel, configure the required parameters and click OK.
Step 5: Test the gRPC client with mTLS
With the Gateway, VirtualService, and certificates in place, verify the setup by running a gRPC client that presents a client certificate.
Install dependencies
Set up the Go gRPC development environment. See Quick start of gRPC in Go.
Clone the sample repository
Clone the grpc-go repository, which includes sample certificates and the helloworld example:
git clone https://github.com/grpc/grpc-go.gitThe sample certificates are located at grpc-go/examples/data/x509/.
Update the client code
Replace the content of grpc-go/examples/helloworld/greeter_client/main.go with the following code. Set the addr flag to <ingress-gateway-ip>:443.
Replace the following placeholder with your actual value:
| Placeholder | Description | Example |
|---|---|---|
<ingress-gateway-ip> | Public IP address of the ingress gateway | 47.95.XX.XX |
Run the client
Navigate to the grpc-go/examples directory and run:
go run helloworld/greeter_client/main.go -addr <ingress-gateway-ip>:443Expected output:
Greeting: Hello WorldVerify that mTLS blocks unauthenticated clients
To confirm that mTLS is enforced, connect without a client certificate. The connection should fail with a TLS handshake error.
Negative test with curl
Run the following command without a client certificate. Replace <ingress-gateway-ip> with the public IP address of your ingress gateway:
curl -v --cacert ca.crt \
https://<ingress-gateway-ip>:443Expected result: The TLS handshake fails with an error similar to certificate required or tlsv13 alert certificate required. This confirms the gateway rejects unauthenticated clients.
Positive test with curl
Run the following command with a valid client certificate:
curl -v --cacert ca.crt \
--cert client_cert.pem --key client_key.pem \
https://<ingress-gateway-ip>:443Expected result: The TLS handshake succeeds and the gateway accepts the connection.
Troubleshooting
| Symptom | Possible cause | Solution |
|---|---|---|
| TLS handshake error on the client | The server certificate in the Secret is invalid or expired. | Recreate the Secret with valid certificate files. Make sure the Secret name matches the credentialName in the Gateway resource. |
connection refused on port 443 | The ingress gateway is not listening on port 443, or the Gateway resource is not applied. | Verify the Gateway resource exists: kubectl get gateway -n default. Check that the ingress gateway pod is running in the istio-system namespace. |
certificate required error | The client is not sending a certificate. | Make sure the client code loads both the client certificate and key. Check the file paths passed to the -cert and -key flags. |
| Traffic reaches the gateway but times out | The VirtualService does not route traffic to the correct backend. | Verify the VirtualService destination host matches the Service name (istio-grpc-server). Check that the Service port name starts with grpc- or http2-. |
| Secret exists but gateway returns TLS errors | The Secret may not be in the correct namespace or the key names are wrong. | Verify the Secret is in the istio-system namespace: kubectl -n istio-system get secrets. Check that the Secret contains tls.key, tls.crt, and ca.crt keys. |
Gateway pod logs show no certificate | The ingress gateway cannot find the credential. | Check the gateway pod logs: kubectl logs -n istio-system <gateway-pod-name>. Verify that credentialName in the Gateway YAML matches the Secret name. |
What's next
ASM traffic management -- Explore routing capabilities such as traffic splitting and fault injection.
Create an ingress gateway -- Configure additional gateway settings for production use.