All Products
Search
Document Center

Alibaba Cloud Service Mesh:Control egress traffic to an external database with an authorization policy

Last Updated:Mar 11, 2026

In a production environment, a compromised or misconfigured service can reach databases it should never access. For example, a service in a development namespace could connect to a production database, exposing sensitive data.

Service Mesh (ASM) solves this with its zero-trust security model. By routing egress traffic through a dedicated egress gateway and applying an AuthorizationPolicy, you enforce namespace-level access control for outbound database connections. Only services in approved namespaces can reach the external database -- all others are denied.

This topic walks through a complete example: routing traffic from the demo-server namespace through an egress gateway to an external ApsaraDB RDS for MySQL database, then using an authorization policy to allow or deny that traffic.

How it works

The solution uses three layers of control:

  1. Outbound traffic policy -- Set to REGISTRY_ONLY so that only explicitly registered external services (ServiceEntries) are reachable from the mesh.

  2. Egress gateway routing -- A Gateway, DestinationRule, and VirtualService route database traffic from the sidecar proxy through the egress gateway to the external database. Mutual TLS (mTLS) secures the connection between the sidecar and the gateway.

  3. Authorization policy -- An AuthorizationPolicy on the egress gateway controls which namespaces are allowed or denied access.

+-----------------+       mTLS        +-----------------+              +--------------+
|  demo-server    | ----------------> |  Egress gateway | -----------> |  External    |
|  (sidecar)      |    port 13306     |  (authz policy) |  port 3306   |  RDS MySQL   |
+-----------------+                   +-----------------+              +--------------+

Prerequisites

Before you begin, make sure that you have:

Step 1: Enable automatic sidecar injection

Create a namespace named demo-server and enable automatic sidecar proxy injection for it. Once enabled, every pod deployed in this namespace receives a sidecar proxy that intercepts all inbound and outbound traffic, bringing it under mesh control.

For detailed instructions, see Manage global namespaces.

Step 2: Deploy a MySQL client

Deploy a MySQL client in the demo-server namespace. This workload serves as the test client for verifying authorization policy behavior later.

  1. Encode the database connection password in Base64:

       echo <database-connection-password> | base64
  2. Create a file named k8s-mysql.yaml with the following content: Replace {yourPasswordBase64} with the Base64-encoded value from the previous step.

       apiVersion: v1
       data:
         password: {yourPasswordBase64}  # The Base64-encoded database password.
       kind: Secret
       metadata:
         name: mysql-pass
       type: Opaque
       ---
    
       apiVersion: apps/v1
       kind: Deployment
       metadata:
         labels:
           name: lbl-k8s-mysql
         name: k8s-mysql
       spec:
         progressDeadlineSeconds: 600
         replicas: 1
         revisionHistoryLimit: 10
         selector:
           matchLabels:
             name: lbl-k8s-mysql
         strategy:
           rollingUpdate:
             maxSurge: 25%
             maxUnavailable: 25%
           type: RollingUpdate
         template:
           metadata:
             labels:
               name: lbl-k8s-mysql
           spec:
             containers:
               - env:
                   - name: MYSQL_ROOT_PASSWORD
                     valueFrom:
                       secretKeyRef:
                         key: password
                         name: mysql-pass
                 image: 'mysql:latest'
                 imagePullPolicy: Always
                 name: mysql
                 ports:
                   - containerPort: 3306
                     name: mysql
                     protocol: TCP
                 resources:
                   limits:
                     cpu: 500m
                 terminationMessagePath: /dev/termination-log
                 terminationMessagePolicy: File
                 volumeMounts:
                   - mountPath: /var/lib/mysql
                     name: k8s-mysql-storage
             dnsPolicy: ClusterFirst
             restartPolicy: Always
             schedulerName: default-scheduler
             securityContext: {}
             terminationGracePeriodSeconds: 30
             volumes:
               - emptyDir: {}
                 name: k8s-mysql-storage
  3. Deploy the Secret and Deployment to the demo-server namespace:

       kubectl apply -f k8s-mysql.yaml -n demo-server
  4. Confirm that a sidecar proxy was injected into the MySQL client pod: On the Container tab, a container named istio-proxy confirms that sidecar proxy injection succeeded.

    1. Log on to the ACK console. In the left-side navigation pane, click Clusters.

    2. On the Clusters page, click the name of your cluster and choose Workloads > Pods in the left-side navigation pane.

    3. On the Pods page, click the pod name of the MySQL client.

Step 3: Create an egress gateway

An egress gateway centralizes outbound traffic from the mesh, giving you a single enforcement point for authorization policies. Without it, traffic leaves the mesh directly from each sidecar, making namespace-level access control impractical.

  1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  2. On the Mesh Management page, click the name of your ASM instance. In the left-side navigation pane, choose ASM Gateways > Egress Gateway.

  3. On the Egress Gateway page, click Create.

  4. Configure the following parameters, then click Create:

    ParameterValue
    Nameegressgateway
    ClusterSelect your cluster
    Protocol (Port Mapping)TCP
    Service Port (Port Mapping)13306

For a full description of each parameter, see Create an egress gateway.

Step 4: Restrict outbound traffic and register the external database

By default, services in an ASM instance can access all external services. To enforce access control, restrict outbound traffic to registered services only, then register the external database as a ServiceEntry.

Set the outbound traffic policy

  1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  2. On the Mesh Management page, click the name of your ASM instance. In the left-side navigation pane, choose Dataplane Component Management > Sidecar Proxy Setting.

  3. On the global tab, click Outbound Traffic Policy, set it to REGISTRY_ONLY, and click Update Settings.

After this change, only external services registered as ServiceEntries are reachable from the mesh.

Register the external database as a ServiceEntry

  1. On the details page of your ASM instance, choose Cluster & Workload Management > External Service(ServiceEntry) in the left-side navigation pane, then click Create from YAML.

  2. Select istio-system from the Namespace drop-down list and paste the following YAML:

       apiVersion: networking.istio.io/v1beta1
       kind: ServiceEntry
       metadata:
         name: demo-server-rds
         namespace: demo-server
       spec:
         endpoints:
           - address: rm-xxxxxxx.mysql.xxxx.rds.aliyuncs.com   # Replace with your RDS endpoint.
             ports:
               tcp: 3306
         hosts:
           - rm-xxxxxxx.mysql.xxxx.rds.aliyuncs.com
         location: MESH_EXTERNAL
         ports:
           - name: tcp
             number: 3306    # The port of the external database.
             protocol: TCP    # The protocol used by the external database.
         resolution: DNS
  3. Click Create.

Step 5: Route traffic through the egress gateway

Create three Istio resources -- a Gateway, a DestinationRule, and a VirtualService -- that define the TCP routing path: sidecar (port 3306) --> egress gateway (port 13306) --> external database (port 3306). mTLS secures traffic between the sidecar and the egress gateway.

Create the Gateway

The Gateway resource configures the egress gateway to accept inbound mTLS connections on port 13306. Services must present a valid Istio-issued certificate before traffic is forwarded.

  1. On the details page of your ASM instance, choose ASM Gateways > Gateway in the left-side navigation pane, then click Create from YAML.

  2. Select istio-system from the Namespace drop-down list and paste the following YAML: The ISTIO_MUTUAL TLS mode enables mTLS authentication between the sidecar and the egress gateway.

       apiVersion: networking.istio.io/v1beta1
       kind: Gateway
       metadata:
         name: istio-egressgateway
         namespace: istio-system
       spec:
         selector:
           istio: egressgateway
         servers:
           - hosts:
               - '*'
             port:
               name: http-0
               number: 13306
               protocol: TLS
             tls:
               mode: ISTIO_MUTUAL
  3. Click Create.

Create the DestinationRule

The DestinationRule configures the sidecar to use mTLS when connecting to the egress gateway, and sets the Server Name Indication (SNI) to the external database host for correct TLS routing.

  1. On the details page of your ASM instance, choose Traffic Management Center > DestinationRule in the left-side navigation pane, then click Create from YAML.

  2. Select demo-server from the Namespace drop-down list and paste the following YAML: The sni field must match the host of the external database so that TLS routing works correctly.

       apiVersion: networking.istio.io/v1beta1
       kind: DestinationRule
       metadata:
         name: demo-server-egress-gateway
         namespace: demo-server
       spec:
         host: istio-egressgateway.istio-system.svc.cluster.local
         subsets:
           - name: mysql-gateway-mTLS
             trafficPolicy:
               loadBalancer:
                 simple: ROUND_ROBIN
               portLevelSettings:
                 - port:
                     number: 13306   # The egress gateway port.
                   tls:
                     mode: ISTIO_MUTUAL
                     sni: rm-xxxxxxx.mysql.xxxx.rds.aliyuncs.com   # Replace with your RDS endpoint.
  3. Click Create.

Create the VirtualService

The VirtualService defines two TCP routing rules that chain the traffic path from sidecar to egress gateway to external database.

  1. On the details page of your ASM instance, choose Traffic Management Center > VirtualService in the left-side navigation pane, then click Create from YAML.

  2. Select demo-server from the Namespace drop-down list and paste the following YAML: This VirtualService defines two TCP routing rules:

    RuleGateway matchBehavior
    Rule 1meshCaptures outbound traffic from sidecars on port 3306 and redirects it to port 13306 on the egress gateway
    Rule 2istio-system/istio-egressgatewayCaptures traffic arriving at the egress gateway on port 13306 and forwards it to port 3306 on the external database
       apiVersion: networking.istio.io/v1beta1
       kind: VirtualService
       metadata:
         name: demo-server-through-egress-gateway
         namespace: demo-server
       spec:
         exportTo:
           - istio-system
           - demo-server
         gateways:
           - mesh
           - istio-system/istio-egressgateway
         hosts:
           - rm-xxxxxxx.mysql.xxxx.rds.aliyuncs.com
         tcp:
           - match:
               - gateways:
                   - mesh
                 port: 3306
             route:
               - destination:
                   host: istio-egressgateway.istio-system.svc.cluster.local
                   port:
                     number: 13306
                   subset: mysql-gateway-mTLS
                 weight: 100
           - match:
               - gateways:
                   - istio-system/istio-egressgateway
                 port: 13306
             route:
               - destination:
                   host: rm-xxxxxxx.mysql.xxxx.rds.aliyuncs.com
                   port:
                     number: 3306
                 weight: 100
  3. Click Create.

Step 6: Test the authorization policy

With all routing in place, create an authorization policy on the egress gateway to verify namespace-level access control. First deny traffic, then allow it.

Deny access

  1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  2. On the Mesh Management page, click the name of your ASM instance. In the left-side navigation pane, choose Mesh Security Center > AuthorizationPolicy, then click Create.

  3. Configure the following parameters, then click Create:

    ParameterValue
    NameEnter a name for the policy
    Policy TypeDENY
    ASM Gateway (Gateway Scope tab)egressgateway (the Match Label auto-fills to istio:egressgateway)
    Namespaces (Request Matching Rules)Turn on Namespaces and set it to demo-frontend

    Create authorization policy

  4. Verify that access is denied: Expected result: The ERROR 2013 error is returned, confirming that the DENY policy blocks traffic from the demo-server namespace to the external database.

    1. Log on to the ACK console. In the left-side navigation pane, click Clusters.

    2. On the Clusters page, click the name of your cluster and choose Workloads > Pods in the left-side navigation pane.

    3. On the Pods page, find the k8s-mysql pod and click Terminal in the Actions column. Then click Container: MySQL.

    4. Run the following command to connect to the external database:

      mysql --user=root --password=$MYSQL_ROOT_PASSWORD --host rm-xxxxxxx.mysql.xxxx.rds.aliyuncs.com

Allow access

  1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  2. On the Mesh Management page, click the name of your ASM instance. In the left-side navigation pane, choose Mesh Security Center > AuthorizationPolicy.

  3. Find the authorization policy and click YAML in the Actions column.

  4. In the Edit dialog box, change the value of the action parameter to ALLOW, then click OK.

  5. Run the same command on the terminal of the k8s-mysql container: Expected result: The Welcome to the MySQL monitor message is returned, confirming that the ALLOW policy permits traffic from the demo-server namespace to the external database.

       mysql --user=root --password=$MYSQL_ROOT_PASSWORD --host rm-xxxxxxx.mysql.xxxx.rds.aliyuncs.com

These results confirm that an authorization policy on the egress gateway effectively controls which namespaces can reach an external database.

Cleanup

To remove the resources created in this topic, run the following commands:

# Delete the MySQL client
kubectl delete -f k8s-mysql.yaml -n demo-server

# Delete Istio resources (run from the ASM console or with kubectl against the ASM API server)
kubectl delete virtualservice demo-server-through-egress-gateway -n demo-server
kubectl delete destinationrule demo-server-egress-gateway -n demo-server
kubectl delete gateway istio-egressgateway -n istio-system
kubectl delete serviceentry demo-server-rds -n demo-server

Also remove the egress gateway and authorization policy from the ASM console.

See also