All Products
Search
Document Center

Alibaba Cloud Service Mesh:Use ASM egress gateway to access external mTLS services

Last Updated:Oct 23, 2024

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.

Important

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

  1. 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.

  2. 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.

  3. 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 for test.com is sent to the actual test.com ServiceEntry.

  4. 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 ]=-
    
           _...._
         .'  _ _ `.
        | ."` ^ `". _,
        \_;`"---"`|//
          |       ;/
          \_     _/
            `"""`
  5. 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

  1. 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.

  2. 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
  3. 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
  4. 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.

  5. 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.

  6. 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.

  1. 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 of test.com through the egress gateway.

  2. 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.