When workloads in a service mesh need controlled access to external services, manually creating and linking ServiceEntry, VirtualService, Gateway, and Destination resources is complex and error-prone. Service Mesh (ASM) 1.16.4 and later provides the ASMEgressTrafficPolicy custom resource definition (CRD), which consolidates these resources into a single definition. With one ASMEgressTrafficPolicy resource, you specify which workloads can reach which external services, over which protocols, and through which egress gateway.
Use cases
Security compliance: Route all outbound traffic through dedicated egress gateway nodes for policy enforcement and auditing. This suits environments where compliance rules require every external connection to be logged and inspectable.
Fine-grained access control: Combine egress traffic policies with AuthorizationPolicy resources to allow or deny specific HTTP methods, paths, or source namespaces at the egress gateway.
How it works
When you apply an ASMEgressTrafficPolicy, ASM automatically generates the ServiceEntry, VirtualService, Gateway, and Destination configurations that redirect traffic from the sidecar proxy to the egress gateway, which then forwards it to the external service.

Traffic between mesh components follows these communication patterns:
| Segment | Protocol | Details |
|---|---|---|
| Sidecar-to-sidecar, sidecar-to-gateway | mutual TLS (mTLS) | Enabled by default. ASM manages the certificates. |
| Application-to-sidecar | Plaintext (recommended) | Plaintext lets the sidecar inspect Layer 7 traffic and support routing and observability. If the application sends HTTPS directly, only Layer 4 (TCP-level) capabilities are available. |
| Gateway-to-external service | Plaintext or HTTPS | Configurable per egress rule. The gateway can also upgrade HTTP to HTTPS before forwarding. |
ASMEgressTrafficPolicy does not support HTTP plaintext communication between the sidecar proxy and the egress gateway. mTLS is always used on this segment.
Limitations
ASMEgressTrafficPolicy does not support:
Proportional (weighted) routing of egress traffic
Initiating mTLS from the egress gateway to external services
Other advanced configurations available through native Istio resources
For these capabilities, configure the egress gateway manually. See Configure an egress gateway to route all outbound traffic in ASM.
Prerequisites
An ASM instance of a commercial edition (Enterprise Edition or Ultimate Edition), version 1.16.4 or later. To create an instance, see Create an ASM instance. To upgrade, see Upgrade an ASM instance.
Automatic sidecar injection enabled for the default namespace. See Enable automatic sidecar proxy injection.
Set up the environment
Complete these one-time setup steps before creating egress traffic policies.
Set the outbound traffic policy to REGISTRY_ONLY
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 Data Plane Component Management > Sidecar Proxy Setting.
On the global tab, set External Access Policy to REGISTRY_ONLY, and then click Update Settings.
With this setting, workloads can only access external services explicitly defined in the mesh registry.
Create the istio-egress namespace
Create the
istio-egressnamespace. See Manage global namespaces.On the Global namespace page, click Sync Automatic Sidecar Injection to Kubernetes Cluster to sync the namespace to the ACK cluster.
Create an egress gateway
Create an egress gateway named egressgateway-a with the following port mappings:
| Protocol | Port |
|---|---|
| HTTP | 80 |
| HTTPS | 443 |
| HTTPS | 444 |
Enable Support two-way TLS authentication. For steps, see Create an egress gateway.
After creation, verify that the generated YAML contains the following spec field. Add it if missing:
spec:
podLabels:
security.istio.io/tlsMode: istioDeploy test workloads
Deploy two services to test egress policies: sleep-a in the mytest namespace (with sidecar injection) and nginx in the default namespace.
Create the
mytestnamespace and enable automatic sidecar proxy injection. See Manage global namespaces.Save the following YAML to
test.yaml:Deploy both services:
kubectl apply -f test.yamlVerify that external access is blocked: Both commands return
502, confirming that theREGISTRY_ONLYpolicy blocks outbound traffic.kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.org kubectl -n default exec deployment/nginx -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.org
Route HTTP traffic through the egress gateway
ASMEgressTrafficPolicy supports only mTLS for communication between the sidecar proxy and the egress gateway. HTTP plaintext communication to the egress gateway is not supported because:
Traffic management is implemented in sidecar proxies on the client side and does not require egress gateways.
Observability does not rely on egress gateways.
Security capabilities depend on egress gateways. However, without mTLS, all authorization capabilities based on client identities are unavailable. In this case, egress gateways can only deny all requests indiscriminately.
The following steps configure sleep-a in the mytest namespace to access http://www.httpbin.org through the egress gateway using mTLS.
Create the egress traffic policy
ASM console
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 > Egress Gateway.
Click the gateway name to open the Gateway overview page. Click Outbound Traffic Policy on the left. Configure parameters as shown in the following figure.

kubectl
Save the following YAML to
egress-by-egressgateway.yaml: For a complete field reference, see ASMEgressTrafficPolicy CRD.apiVersion: istio.alibabacloud.com/v1 kind: ASMEgressTrafficPolicy metadata: name: egress-by-egressgateway # Format: egress-by-{egress gateway name} namespace: istio-egress # Fixed value spec: byEgressGateway: name: egressgateway egressRules: - from: - namespace: mytest workloadSelector: app: sleep-a to: - name: httpbin-service-http hosts: - www.httpbin.org # Multiple hosts must resolve to the same IP addresses - httpbin.org port: name: http number: 80 protocol: HTTP byEgressGateway: port: 80 # Sidecar -> port 80 -> Gateway -> port 80 -> httpbin.orgApply the policy:
kubectl apply -f egress-by-egressgateway.yaml
Verify the policy
Confirm that
nginxin thedefaultnamespace is still blocked: Expected output:502kubectl -n default exec deployment/nginx -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.orgConfirm that
sleep-ain themytestnamespace can access the external service: Expected output:200kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.orgDelete the policy and confirm that access is revoked: Expected output:
502. This confirms the egress traffic policy was controlling the access.kubectl -n istio-egress delete ASMEgressTrafficPolicy egress-by-egressgateway kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.org
Route HTTPS traffic through the egress gateway
Two solutions are available for routing HTTPS egress traffic. Choose based on where TLS is handled:
| Solution | Sidecar-to-gateway | Gateway-to-external | Port flow | When to use |
|---|---|---|---|---|
| Solution 1: mTLS + HTTPS upgrade (recommended) | mTLS | HTTPS (upgraded from HTTP at gateway) | Sidecar -> 80 -> Gateway -> 443 -> External | Applications send HTTP. The gateway handles TLS. Simpler application code. |
| Solution 2: HTTPS passthrough | mTLS | HTTPS (passthrough) | Sidecar -> 444 -> Gateway -> 443 -> External | Applications send HTTPS directly. |
Solution 1: mTLS with HTTPS upgrade (recommended)
The egress gateway upgrades HTTP requests to HTTPS before forwarding them to the external service. Applications send plaintext HTTP, keeping TLS management at the gateway level.
Create the egress traffic policy
ASM console
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 > Egress Gateway.
Click the gateway name to open the Gateway overview page, and then click Outbound Traffic Policy on the left. Configure parameters as shown in the following figure.

kubectl
Save the following YAML to
egress-by-egressgateway.yaml. This configuration includes thehttpsUpgradefield, which tells the gateway to upgrade HTTP to HTTPS: For a complete field reference, see ASMEgressTrafficPolicy CRD.apiVersion: istio.alibabacloud.com/v1 kind: ASMEgressTrafficPolicy metadata: name: egress-by-egressgateway # Format: egress-by-{egress gateway name} namespace: istio-egress # Fixed value spec: byEgressGateway: name: egressgateway egressRules: - from: - namespace: mytest workloadSelector: app: sleep-a to: - name: httpbin-service-http hosts: - www.httpbin.org # Multiple hosts must resolve to the same IP addresses - httpbin.org port: name: http number: 80 protocol: HTTP byEgressGateway: port: 80 # Sidecar -> port 80 -> Gateway -> port 80 -> httpbin.org (HTTP) httpsUpgrade: enabled: true # Enable HTTPS upgrade at the gateway port: 443 # Sidecar -> port 80 -> Gateway -> port 443 -> httpbin.org (HTTPS)Apply the policy:
kubectl apply -f egress-by-egressgateway.yaml
Verify the policy
Confirm HTTP access from
sleep-a: Expected output:200kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" http://httpbin.orgVerify the HTTPS upgrade. Request the
/anythingendpoint, which echoes the request URL: Expected output: Theurlfield starts withhttps, confirming that the gateway upgraded the request to HTTPS before forwarding.kubectl -n mytest exec deployment/sleep-a -- sh -c "curl -s http://httpbin.org/anything | grep url""url": "https://httpbin.org/anything"Confirm HTTPS access from
sleep-a: Expected output:200kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" https://www.httpbin.orgConfirm that
nginxin thedefaultnamespace is still blocked: HTTP returns502. HTTPS returns a connection refused error. To see why, check the sidecar proxy logs: The log shows"upstream_cluster":"BlackHoleCluster", meaning the request was routed to a cluster that drops all traffic -- confirming the policy blocks access for unauthorized workloads.# HTTP access kubectl -n default exec deployment/nginx -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.org # HTTPS access kubectl -n default exec deployment/nginx -- curl -s -o /dev/null -w "%{http_code}\n" https://www.httpbin.orgkubectl -n default logs -f deployment/nginx -c istio-proxy --tail=1Delete the policy and confirm that access is revoked for
sleep-a: HTTP returns502. HTTPS returns a connection refused error.kubectl -n istio-egress delete ASMEgressTrafficPolicy egress-by-egressgateway kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.org kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" https://www.httpbin.org
Solution 2: HTTPS passthrough
The sidecar proxy forwards HTTPS traffic to the egress gateway through mTLS, and the gateway passes the HTTPS connection through to the external service without terminating TLS.
Create the egress traffic policy
ASM console
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 > Egress Gateway.
Click the gateway name to open the Gateway overview page, and then click Outbound Traffic Policy on the left. Configure parameters as shown in the following figure.

kubectl
Save the following YAML to
egress-by-egressgateway.yaml: For a complete field reference, see ASMEgressTrafficPolicy CRD.apiVersion: istio.alibabacloud.com/v1 kind: ASMEgressTrafficPolicy metadata: name: egress-by-egressgateway # Format: egress-by-{egress gateway name} namespace: istio-egress # Fixed value spec: byEgressGateway: name: egressgateway egressRules: - from: - namespace: mytest workloadSelector: app: sleep-a to: - name: httpbin-service-https hosts: - www.httpbin.org - httpbin.org port: name: https number: 443 protocol: HTTPS byEgressGateway: port: 444 # Uses the HTTPS 444 port defined during gateway creationApply the policy:
kubectl apply -f egress-by-egressgateway.yaml
Verify the policy
Confirm HTTP access from
sleep-a: Expected output:200kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" http://httpbin.orgVerify that the request reaches the external service over HTTPS: Expected output: The
urlfield starts withhttps, confirming that the external service received an HTTPS request.kubectl -n mytest exec deployment/sleep-a -- sh -c "curl -s http://httpbin.org/anything | grep url""url": "https://httpbin.org/anything"Confirm direct HTTPS access from
sleep-a: Expected output:200kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" https://www.httpbin.orgConfirm that
nginxin thedefaultnamespace is still blocked: HTTP returns502. HTTPS returns a connection refused error.kubectl -n default exec deployment/nginx -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.org kubectl -n default exec deployment/nginx -- curl -s -o /dev/null -w "%{http_code}\n" https://www.httpbin.orgDelete the policy and confirm that access is revoked: HTTP returns
502. HTTPS returns a connection refused error.kubectl -n istio-egress delete ASMEgressTrafficPolicy egress-by-egressgateway kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.org kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" https://www.httpbin.org
Route TCP traffic through the egress gateway
When the application initiates TLS directly and the mesh only needs to route the encrypted stream, configure the egress traffic policy with the TCP protocol.
Create the egress traffic policy
ASM console
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 > Egress Gateway.
Click the gateway name to open the Gateway overview page, and then click Outbound Traffic Policy on the left. Configure parameters as shown in the following figure.

kubectl
Save the following YAML to
egress-by-egressgateway.yaml:apiVersion: istio.alibabacloud.com/v1 kind: ASMEgressTrafficPolicy metadata: name: egress-by-egressgateway namespace: istio-egress spec: byEgressGateway: name: egressgateway egressRules: - from: - namespace: mytest workloadSelector: app: sleep-a to: - byEgressGateway: {} hosts: - www.alibabacloud.com name: aliyun-service-tcp port: name: tcp number: 443 protocol: TCPApply the policy:
kubectl apply -f egress-by-egressgateway.yaml
Verify the policy
Confirm that HTTP access from
sleep-atowww.alibabacloud.comreturns an error. TCP mode routes raw TCP streams and does not handle HTTP protocol negotiation: Expected output:502kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" http://www.alibabacloud.comConfirm that HTTPS access from
sleep-asucceeds. The application initiates TLS, and the gateway passes the TCP stream through: Expected output:200kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" https://www.alibabacloud.comConfirm that
nginxin thedefaultnamespace is blocked: HTTP returns502. HTTPS returns a connection refused error. The sidecar proxy logs show"upstream_cluster":"BlackHoleCluster".kubectl -n default exec deployment/nginx -- curl -s -o /dev/null -w "%{http_code}\n" http://www.alibabacloud.com kubectl -n default exec deployment/nginx -- curl -s -o /dev/null -w "%{http_code}\n" https://www.alibabacloud.comDelete the policy and confirm that access is revoked: HTTP returns
502. HTTPS returns a connection refused error.kubectl -n istio-egress delete ASMEgressTrafficPolicy egress-by-egressgateway kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" http://www.alibabacloud.com kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" https://www.alibabacloud.com
Add fine-grained access control with an authorization policy
Combine an AuthorizationPolicy with the egress traffic policy to control access at the egress gateway. The following example denies POST requests from the mytest namespace to httpbin.org:
kind: AuthorizationPolicy
apiVersion: security.istio.io/v1beta1
metadata:
name: sleep-a-egress-www-httpbin-org
namespace: istio-system
spec:
action: DENY
rules:
- to:
- operation:
hosts:
- www.httpbin.org
- httpbin.org
methods:
- POST
from:
- source:
namespaces: ["mytest"]
selector:
matchLabels:
istio: egressgateway-aAfter applying this policy, POST requests from sleep-a to httpbin.org return RBAC: access. GET requests are unaffected.
For more examples, see Configure authorization policies for HTTP requests.