Service Mesh (ASM) egress gateway serves as the unified exit for traffic within ASM, which is capable of initiating TLS/mTLS requests to achieve end-to-end encrypted communication. Additionally, the egress gateway can implement comprehensive security policies for more granular access control. In ASM, the egress gateway is the ideal choice for managing outbound traffic. This topic describes how to use the ASM egress gateway to manage outbound traffic and initiate mTLS communication.
Ensure that you have completed all the steps listed in Configure mTLS service on ASM ingress gateway and restrict specific client access. This topic uses the applications deployed in the ASM and Container Service for Kubernetes (ACK) environment as external mTLS servers. Therefore, when performing the steps in this topic, you need to create another ASM and ACK environment as the primary environment. To clarify, the ${ASM gateway IP}
in this topic represents the ingress gateway IP address used in Configure mTLS service on ASM ingress gateway and restrict specific client access, and "ACK cluster" and "ASM instance" refer to the primary environment resources.
Prerequisites
Automatic sidecar injection is enabled. For more information, see Configure sidecar proxy injection policies.
Step 1: Deploy the test application sleep
Deploy the sleep application. For more information, see Related operations.
Use the kubeconfig of the ACK cluster to run the following command to test access to the HTTPBin service deployed in another ASM and ACK environment.
kubectl exec deploy/sleep -- curl --header "host:test.com" ${ASM gateway IP}/status/418
Expected output:
-=[ teapot ]=-
_...._
.' _ _ `.
| ."` ^ `". _,
\_;`"---"`|//
| ;/
\_ _/
`"""`
Step 2: Enable REGISTRY_ONLY and create ServiceEntry
Sidecar supports configuring external access policies as REGISTRY_ONLY
. After REGISTRY_ONLY
is enabled, pods can only access services registered through ServiceEntry. You can choose whether to enable this feature. For more information, see Step 2: Enable REGISTRY_ONLY. After the feature is enabled, accessing unregistered services results in a 502 Bad Gateway
error.
Use the following content to configure ServiceEntry for test.com. For more information, see Create an external service.
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: test-com
namespace: default
spec:
endpoints:
- address: ${IP address of the ingress gateway}
hosts:
- test.com
location: MESH_EXTERNAL
ports:
- name: http
number: 80
protocol: HTTP
- name: https
number: 443
protocol: HTTPS
resolution: STATIC
After completing the configuration, you can access the HTTPBin service from the sleep pod.
Step 3: Create ASM egress gateway and route HTTP requests through the egress gateway
Create an egress gateway, configure it for HTTP traffic on port 80, and enable the mutual TLS authentication switch. After the switch is enabled, other workloads in ASM automatically use mTLS when sending traffic to the gateway, with the mTLS certificates managed uniformly by ASM. For more information, see Create an egress gateway.
Use the following content to create gateway rules. For more information, see Create gateway rules.
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: egress-gateway namespace: default spec: selector: istio: egressgateway servers: - hosts: - '*' port: name: http number: 80 protocol: HTTPS tls: mode: ISTIO_MUTUAL
The gateway rules declare that the egress gateway listens on port 80 with mTLS enabled, using certificates provided by ASM.
Use the following content to create a virtual service.
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: egressgateway-vs spec: hosts: - test.com gateways: - egress-gateway # Name of the gateway rule created in the previous step. - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local port: number: 80 weight: 100 - match: - gateways: - egress-gateway port: 80 route: - destination: host: test.com port: number: 80 weight: 100
After creating the virtual service, the traffic for
test.com
in the sidecar is sent to the egress gateway, and the traffic received by the egress gateway fortest.com
is sent to the actualtest.com
ServiceEntry.Run the following command to access
test.com
from the sleep application's pod.kubectl exec deploy/sleep -- curl --header "host:test.com" ${ASM gateway IP}/status/418
Expected output:
-=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
Use the kubeconfig of the ASM instance to run the following command.
kubectl -n istio-system logs ${egress gateway pod name}| tail -1
Expected output:
{"authority_for":"test.com","bytes_received":"0","bytes_sent":"135","downstream_local_address":"192.168.36.32:80","downstream_remote_address":"192.168.36.29:58146","duration":"8","istio_policy_status":"-","method":"GET","path":"/status/418","protocol":"HTTP/1.1","request_id":"9f7b5475-6e45-4700-a85a-e00835b6b6c0","requested_server_name":"outbound_.80_._.istio-egressgateway.istio-system.svc.cluster.local","response_code":"418","response_flags":"-","route_name":"-","start_time":"2024-07-29T03:05:58.421Z","trace_id":"-","upstream_cluster":"outbound|80||test.com","upstream_host":"${ASM gateway IP}:80","upstream_local_address":"192.168.36.32:52838","upstream_response_time":"7","upstream_service_time":"7","upstream_transport_failure_reason":"-","user_agent":"curl/8.1.2","x_forwarded_for":"192.168.36.29"}
The above log confirms that the service passed through the ASM egress gateway.
The request path in this example is: sleep pod --> istio-egressgateway --> istio-ingressgateway --> httpbin
. Among them:
sleep pod --> istio-egressgateway
is mTLS traffic.istio-egressgateway --> istio-ingressgateway
is plaintext traffic.istio-ingressgateway --> httpbin
is mTLS traffic.
Interaction between the two gateways over plaintext is clearly insecure. As the server-side gateway supports mTLS, you only need to configure the client-side egress gateway to initiate mTLS requests.
Step 4: Upgrade HTTP requests to mTLS traffic in the egress gateway
Use the following content to update the virtual service.
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: egressgateway-vs spec: hosts: - test.com gateways: - egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local port: number: 80 weight: 100 - match: - gateways: - egress-gateway port: 80 route: - destination: host: test.com port: number: 443 # Only this line is modified weight: 100
The update here only changes the traffic sent to the
test.com
ServiceEntry from port 80 to port 443.Import the mTLS certificate used in Configure mTLS service on ASM ingress gateway and restrict specific client access. Ensure that the certificate imported is named
test.client
. For more information, see Use the certificate management feature of ASM. You can also use kubectl to create a secret to import the certificate. Use the kubeconfig of the ACK cluster to run the following command.kubectl create -n istio-system secret generic test.client \ --from-file=tls.key=client.key.pem \ --from-file=tls.crt=clientcert.pem \ --from-file=ca.crt=cacert.pem
Use the following content to create a destination rule.
apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: originate-mtls-for-test-com spec: host: test.com trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: MUTUAL credentialName: test.client sni: test.com
Run the following command to test access again.
kubectl exec deployment/sleep -it -- curl --header "host:test.com" ${ASM gateway IP}/status/418
Expected output:
RBAC: access denied%
The request is denied. This is because the client certificate used here is reused from Configure mTLS service on ASM ingress gateway and restrict specific client access, which is configured to prohibit test.client from accessing the
status/418
path.Run the following command to access the
status/200
path.kubectl exec deploy/sleep -it -- curl --header "host:test.com" ${ASM gateway IP}/status/200 -I
Expected output:
HTTP/1.1 200 OK server: envoy date: Mon, 29 Jul 2024 03:33:50 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: 5
The access is successful.
Run the following command to view the egress gateway access log.
kubectl -n istio-system logs ${egress gateway pod name}| tail -1
Expected output:
{"authority_for":"test.com","bytes_received":"0","bytes_sent":"19","downstream_local_address":"192.168.36.32:80","downstream_remote_address":"192.168.36.29:58146","duration":"3","istio_policy_status":"-","method":"GET","path":"/status/418","protocol":"HTTP/1.1","request_id":"82394ec4-cf13-45cb-ae4c-cb1873fbccda","requested_server_name":"outbound_.80_._.istio-egressgateway.istio-system.svc.cluster.local","response_code":"403","response_flags":"-","route_name":"-","start_time":"2024-07-29T03:34:36.647Z","trace_id":"-","upstream_cluster":"outbound|443||test.com","upstream_host":"${ASM gateway IP}:443","upstream_local_address":"192.168.36.32:42214","upstream_response_time":"2","upstream_service_time":"2","upstream_transport_failure_reason":"-","user_agent":"curl/8.1.2","x_forwarded_for":"192.168.36.29"}
This request accessed the ingress gateway's port 443, which only provides mTLS services.
Step 5: Subsequent configuration
The sleep pod initiates HTTP requests. After passing through the sidecar and egress gateway, the entire connection is secured with mTLS encryption, which forms the basis for client identity authentication. In this request flow, authorization policies can be configured in two places to restrict client behavior.
Use the following content to configure an authorization policy on the egress gateway. This can restrict which services within the cluster can access the
test.com
service.apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: labels: gateway: egressgateway name: test namespace: istio-system spec: action: DENY rules: - from: - source: principals: - cluster.local/ns/default/sa/sleep to: - operation: hosts: - test.com paths: - /headers selector: matchLabels: istio: egressgateway
This configuration restricts the sleep pod from accessing the
/headers
path oftest.com
through the egress gateway.Configure an authorization policy on the ingress gateway to restrict the identity of clients directly accessing the ingress gateway. The authorization policy on the ingress gateway configured in Step 4 prevents the current egress gateway from accessing the
/status/418
path.