All Products
Search
Document Center

Alibaba Cloud Service Mesh:Configure mTLS on the ASM ingress gateway and restrict client access

Last Updated:Mar 11, 2026

Mutual TLS (mTLS) on the Service Mesh (ASM) ingress gateway requires every client to present a valid certificate before establishing a connection. Each client certificate carries identity information that you can match in an authorization policy to deny specific clients access to certain paths -- giving you fine-grained, identity-based access control at the gateway level.

This guide walks through three tasks:

  1. Generate root CA, server, and client certificates for mTLS.

  2. Configure an mTLS listener on port 443 of the ASM ingress gateway.

  3. Deploy an authorization policy that denies a specific client identity access to a path.

Prerequisites

Before you begin, make sure that you have:

Step 1: Generate mTLS certificates

This step produces three certificate pairs -- root CA, server, and client -- all signed by the same root CA.

Note

When prompted for certificate fields during generation, accept the default values. The configuration files below pre-set all required fields.

  1. Create a file named ca.cnf with the following content.

    Expand to view ca.cnf

    HOME = .
    RANDFILE = $ENV::HOME/.rnd
    ####################################################################
    [ ca ]
    default_ca = CA_default # The default ca section
    [ CA_default ]
    default_days = 1000 # how long to certify for
    default_crl_days = 30 # how long before next CRL
    default_md = sha256 # use public key default MD
    preserve = no # keep passed DN ordering
    x509_extensions = ca_extensions # The extensions to add to the cert
    email_in_dn = no # Don't concat the email in the DN
    copy_extensions = copy # Required to copy SANs from CSR to cert
    
    #====Following 7 lines are for signing other certificates, not for making the CA certificate.====
    base_dir = .
    certificate = $base_dir/cacert.pem # The CA certifcate
    private_key = $base_dir/cakey.pem # The CA private key
    new_certs_dir = $base_dir # Location for new certs after signing
    database = $base_dir/index.txt # Database index file
    serial = $base_dir/serial.txt # The current serial number
    unique_subject = no # Set to 'no' to allow creation of several certificates with same subject.
    
    ####################################################################
    [ req ]
    default_bits = 4096
    default_keyfile = cakey.pem
    distinguished_name = ca_distinguished_name
    x509_extensions = ca_extensions
    string_mask = utf8only
    ####################################################################
    [ ca_distinguished_name ]
    countryName = Country Name (2 letter code)
    countryName_default = CN
    stateOrProvinceName = State or Province Name (full name)
    stateOrProvinceName_default = bj
    localityName = Locality Name (eg, city)
    localityName_default = bj
    organizationName = Organization Name (eg, company)
    organizationName_default = test-asm
    organizationalUnitName = Organizational Unit (eg, division)
    organizationalUnitName_default = R&D
    commonName = Common Name (e.g. server FQDN or YOUR name)
    commonName_default = Test CA
    emailAddress = Email Address
    emailAddress_default = test@example.com
    ####################################################################
    [ ca_extensions ]
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid:always, issuer
    basicConstraints = critical, CA:true
    keyUsage = keyCertSign, cRLSign
    
    
    #====All lines below are for signing other certs, not for making the CA cert.======
    
    ####################################################################
    [ signing_policy ]
    countryName = optional
    stateOrProvinceName = optional
    localityName = optional
    organizationName = optional
    organizationalUnitName = optional
    commonName = supplied
    emailAddress = optional
    ####################################################################
    [ signing_req ]
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid,issuer
    basicConstraints = CA:FALSE
    keyUsage = digitalSignature, keyEncipherment
  2. Generate the root certificate.

    openssl req -x509 -config ca.cnf -newkey rsa:4096 -sha256 -nodes -out cacert.pem -outform PEM

    This produces cacert.pem (the CA certificate) and cakey.pem (the CA private key).

  3. Create a file named server.cnf with the following content.

    HOME = .
    RANDFILE = $ENV::HOME/.rnd
    ####################################################################
    [ req ]
    default_bits = 2048
    default_keyfile = serverkey.pem
    distinguished_name = server_distinguished_name
    req_extensions = server_req_extensions
    string_mask = utf8only
    ####################################################################
    [ server_distinguished_name ]
    countryName = Country Name (2 letter code)
    countryName_default = CN
    stateOrProvinceName = State or Province Name (full name)
    stateOrProvinceName_default = bj
    localityName = Locality Name (eg, city)
    localityName_default = bj
    organizationName = Organization Name (eg, company)
    organizationName_default = test
    commonName = Common Name (e.g. server FQDN or YOUR name)
    commonName_default = test.com
    emailAddress = Email Address
    emailAddress_default = test@example.com
    ####################################################################
    [ server_req_extensions ]
    subjectKeyIdentifier = hash
    basicConstraints = CA:FALSE
    keyUsage = digitalSignature, keyEncipherment
    subjectAltName = @alternate_names
    nsComment = "OpenSSL Generated Certificate"
    ####################################################################
    [ alternate_names ]
    DNS.1 = test.com
  4. Generate and sign the server certificate.

    openssl req -config server.cnf -newkey rsa:2048 -sha256 -nodes -out server.csr -outform PEM
    touch index.txt
    echo '01' > serial.txt
    openssl ca -config ca.cnf -policy signing_policy -extensions signing_req -out servercert.pem -infiles server.csr

    This produces servercert.pem (the server certificate) and serverkey.pem (the server private key).

  5. Create a file named client.cnf with the following content.

    HOME = .
    RANDFILE = $ENV::HOME/.rnd
    ####################################################################
    [ req ]
    default_bits = 2048
    default_keyfile = client.key.pem
    distinguished_name = server_distinguished_name
    req_extensions = server_req_extensions
    string_mask = utf8only
    ####################################################################
    [ server_distinguished_name ]
    countryName = Country Name (2 letter code)
    countryName_default = CN
    stateOrProvinceName = State or Province Name (full name)
    stateOrProvinceName_default = bj
    localityName = Locality Name (eg, city)
    localityName_default = bj
    organizationName = Organization Name (eg, company)
    organizationName_default = test.client
    commonName = Common Name (e.g. server FQDN or YOUR name)
    commonName_default = test.client
    emailAddress = Email Address
    emailAddress_default = test.client@example.com
    ####################################################################
    [ server_req_extensions ]
    subjectKeyIdentifier = hash
    basicConstraints = CA:FALSE
    keyUsage = digitalSignature, keyEncipherment
    subjectAltName = @alternate_names
    nsComment = "OpenSSL Generated Certificate"
    ####################################################################
    [ alternate_names ]
    URI.1 = spiffe://test.client

    The client certificate's CommonName is test.client. The Subject Alternative Name (SAN) includes URI.1 = spiffe://test.client. The spiffe:// prefix is required because the principals field in an ASM authorization policy matches the portion after spiffe://.

  6. Generate and sign the client certificate.

    openssl req -config client.cnf -newkey rsa:2048 -sha256 -nodes -out clientcert.csr -outform PEM
    openssl ca -config ca.cnf -policy signing_policy -extensions signing_req -out clientcert.pem -infiles clientcert.csr

    This produces clientcert.pem (the client certificate) and client.key.pem (the client private key).

  7. Import the mTLS certificate into ASM. Set the certificate name to test.com. For details, see Use the certificate management feature of ASM.

    Alternatively, create a Kubernetes Secret directly with kubectl. Run this command with the kubeconfig of your data plane cluster:

    kubectl create -n istio-system secret generic test.com \
      --from-file=tls.key=serverkey.pem \
      --from-file=tls.crt=servercert.pem \
      --from-file=ca.crt=cacert.pem

The following table summarizes the certificate files generated in this step.

CertificateFileKey size
Root CA certificatecacert.pemRSA 4096-bit
Root CA private keycakey.pemRSA 4096-bit
Server certificateservercert.pemRSA 2048-bit
Server private keyserverkey.pemRSA 2048-bit
Client certificateclientcert.pemRSA 2048-bit
Client private keyclient.key.pemRSA 2048-bit

Step 2: Configure an mTLS listener on port 443

Add an mTLS listener on port 443 of the ASM ingress gateway so that external clients can access the HTTPBin service over mutual TLS.

  1. Update the Gateway resource with the following configuration.

    apiVersion: networking.istio.io/v1beta1
    kind: Gateway
    metadata:
      name: httpbin
      namespace: default
    spec:
      selector:
        istio: ingressgateway
      servers:
        - hosts:
            - '*'
          port:
            name: test
            number: 80
            protocol: HTTP
        - hosts:
          - test.com
          port:
            number: 443
            name: https
            protocol: HTTPS
          tls:
            mode: MUTUAL
            credentialName: test.com

    Key fields:

    FieldValueDescription
    tls.modeMUTUALRequires clients to present a valid certificate signed by the CA in the Secret
    credentialNametest.comReferences the Secret created in Step 1, which contains the server certificate, private key, and CA certificate
  2. Verify the mTLS connection by accessing the HTTPBin service with the client certificate.

    curl --header "host:test.com" \
         --resolve "test.com:443:${ASM gateway IP}" \
         --cacert cacert.pem \
         --cert clientcert.pem \
         --key client.key.pem \
         https://test.com/status/200 -I

    Expected output:

    HTTP/2 200
    server: istio-envoy
    date: Sun, 28 Jul 2024 7:30:30 GMT
    content-type: text/html; charset=utf-8
    access-control-allow-origin: *
    access-control-allow-credentials: true
    content-length: 0
    x-envoy-upstream-service-time: 6

    An HTTP/2 200 response confirms that the mTLS listener is working and the client certificate is accepted.

Step 3: Restrict client access with an authorization policy

Deploy an AuthorizationPolicy that denies the test.client identity access to a specific path on the HTTPBin application.

  1. Apply the following AuthorizationPolicy. This policy denies requests from test.client to the /status/418 path on the ingress gateway. For more information, see Configure authorization policies for HTTP requests.

    apiVersion: security.istio.io/v1beta1
    kind: AuthorizationPolicy
    metadata:
      name: test
      namespace: istio-system
    spec:
      action: DENY
      rules:
        - from:
            - source:
                principals:
                  - test.client
          to:
            - operation:
                paths:
                  - /status/418
      selector:
        matchLabels:
          istio: ingressgateway

    Key fields:

    FieldValueDescription
    source.principalstest.clientMatches the identity extracted from the client certificate's SAN (spiffe://test.client). ASM strips the spiffe:// prefix before matching.
    operation.paths/status/418The path to deny
    actionDENYRejects matching requests. All other requests are still allowed.

Verify the authorization policy

  1. Access /status/200 with the client certificate. This path is not restricted, so the request succeeds.

    curl --header "host:test.com" \
         --resolve "test.com:443:${ASM gateway IP}" \
         --cacert cacert.pem \
         --cert clientcert.pem \
         --key client.key.pem \
         https://test.com/status/200 -I

    Expected output:

    HTTP/2 200
    server: istio-envoy
    date: Sun, 28 Jul 2024 7:33:30 GMT
    content-type: text/html; charset=utf-8
    access-control-allow-origin: *
    access-control-allow-credentials: true
    content-length: 0
    x-envoy-upstream-service-time: 6
  2. Access /status/418 with the client certificate. The authorization policy blocks this request.

    curl --header "host:test.com" \
         --resolve "test.com:443:${ASM gateway IP}" \
         --cacert cacert.pem \
         --cert clientcert.pem \
         --key client.key.pem \
         https://test.com/status/418

    Expected output:

    RBAC: access denied%

    The RBAC: access denied response confirms that the test.client identity is blocked from accessing /status/418.

  3. Access /status/418 with the server certificate to confirm that only test.client is denied.

    curl --header "host:test.com" \
         --resolve "test.com:443:${ASM gateway IP}" \
         --cacert cacert.pem \
         --cert servercert.pem \
         --key serverkey.pem \
         https://test.com/status/418

    Expected output:

        -=[ teapot ]=-
    
           _...._
         .'  _ _ `.
        | ."` ^ `". _,
        \_;`"---"`|//
          |       ;/
          \_     _/
            `"""`

    A successful response confirms that the DENY policy applies only to the test.client identity, not to other certificate holders.