About ambient mesh

Solo collaborated with Google to develop ambient mesh, a new “sidecarless” architecture for the Istio service mesh. Ambient mesh uses node-level ztunnels to route and secure Layer 4 traffic between pods with mutual TLS (mTLS). Waypoint proxies enforce Layer 7 traffic policies whenever needed. To onboard apps into the ambient mesh, you simply label the namespace the app belongs to. Because no sidecars need to be injected in to your apps, ambient mesh significantly reduces the complexity of adopting a service mesh.

To learn more about ambient, see the ambient mesh documentation.

About this guide

In this guide, you learn how to set up Gloo Gateway as a waypoint proxy for multiple apps in your ambient mesh. To demonstrate the Layer 7 capabilities of the waypoint proxy, you deploy the three sample apps client, httpbin2, and httpbin3 to your cluster. The client app sends in-mesh traffic to httpbin2 and httpbin3. To apply Layer 7 policies, you create HTTPRoute resources for the httpbin2 and httpbin3 apps that define the policies that you want to apply to each app. Because the HTTPRoute is scoped to a particular service, when the client app sends a request to that service, only the policies that are defined for that service are enforced by the waypoint proxy.

Gloo Gateway as a waypoint proxy in your ambient mesh
Gloo Gateway as a waypoint proxy in your ambient mesh

Set up an ambient mesh

Set up an ambient mesh in your cluster to secure service-to-service communication with mutual TLS. You can use Solo.io’s Gloo Operator to install a managed ambient mesh, or manually install and manage your own ambient mesh installation.

  • Managed ambient mesh with Gloo Operator: Follow the Install Gloo-managed ambient meshes guide in the Gloo Mesh Core docs to quickly install a managed Solo distribution of Istio by using the Gloo Operator.
  • Manual ambient mesh installation:
    • Manually install a Solo distribution of Istio. The Solo distribution of Istio is a hardened Istio enterprise image, which maintains n-4 support for CVEs and other security fixes. Note that the Solo distribution of Istio is required for a multicluster ambient mesh setup.
    • Install the community version of ambient mesh by following the ambient mesh quickstart tutorial. This tutorial uses a script to quickly set up an ambient mesh in your cluster. You do not need to create an Istio ingress gateway as you configure Gloo Gateway as the ingress gateway for your ambient mesh.

Deploy sample apps

Install the httpbin2, httpbin3, and curl client sample apps into the httpbin namespace. You use these sample apps to demonstrate the Layer 7 capabilities of the waypoint proxy.

  1. Create the httpbin namespace.

      kubectl create ns httpbin
      
  2. Deploy the httpbin2, httpbin3, and client sample apps.

  3. Verify that all apps are deployed successfully.

      kubectl get pods -n httpbin
      

    Example output:

      NAME                                        READY   STATUS    RESTARTS   AGE
    client-87678cb44-dclfs                      1/1     Running   0          87m
    httpbin2-58dcc755ff-ngq2f                   1/1     Running   0          92m
    httpbin3-77bbdd9b6b-8d8hq                   1/1     Running   0          70m
      
  4. Label the httpbin namespace to add the httpbin2, httpbin3, and client apps to the ambient mesh.

      kubectl label ns httpbin istio.io/dataplane-mode=ambient
      

Enable the Gloo Gateway ambient integration

To create a waypoint proxy that uses Gloo Gateway, you must first enable the ambient integration in Gloo Gateway.

Create a waypoint proxy

You use the gloo-waypoint GatewayClass to deploy Gloo Gateway as a waypoint proxy in your cluster.

  1. Create a waypoint proxy in the httpbin namespace. Note that creating a waypoint proxy does not automatically enforce Layer 7 policies for the apps in your cluster. To assign a waypoint, you must label your apps. You learn how to label your apps in a later step.

      kubectl apply -f - <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: gloo-waypoint
      namespace: httpbin
    spec:
      gatewayClassName: gloo-waypoint
      listeners:
      - name: proxy
        port: 15088
        protocol: istio.io/PROXY
    EOF
      
  2. Wait for the waypoint proxy to deploy successfully.

      kubectl -n httpbin rollout status deploy gloo-proxy-gloo-waypoint
      

    Example output:

      deployment "gloo-proxy-gloo-waypoint" successfully rolled out
      
  3. Label the httpbin2 and httpbin3 apps to use the waypoint proxy that you created.

      kubectl -n httpbin label svc httpbin2 istio.io/use-waypoint=gloo-waypoint
    kubectl -n httpbin label svc httpbin3 istio.io/use-waypoint=gloo-waypoint
      
  4. Send a request from the client app to httpbin2 and httpbin3. Verify that the request succeeds.

       kubectl -n httpbin exec deploy/client -- curl -s http://httpbin2:8000/get
     kubectl -n httpbin exec deploy/client -- curl -s http://httpbin3:8000/get
      

    Example output for httpbin2:

      {
     "args": {},
     "headers": {
       "Accept": [
         "*/*"
       ],
       "Host": [
         "httpbin2:8000"
       ],
       "User-Agent": [
         "curl/8.7.1"
       ],
       "X-Envoy-Expected-Rq-Timeout-Ms": [
         "15000"
       ],
       "X-Forwarded-Proto": [
         "http"
      ],
       "X-Request-Id": [
         "590a6a48-60f8-4ec0-92d1-fcb629b97e0d"
       ]
     },
     "method": "GET",
     "origin": "10.XX.X.XX:34059",
     "url": "http://httpbin2:8000/get"
    }
      

Enforce L7 policies with the waypoint

In this step, you explore how to apply header modification, external auth, and rate limit Layer 7 policies to your sample apps. These policies are enforced by the Gloo Gateway waypoint proxy that you created earlier. You can add other Layer 7 policies to the waypoint proxy. For more information, see the traffic management, security, and resiliency guides.

Header control

Use the Kubernetes Gateway API to define header manipulation rules that you apply to the httpbin apps, including adding, setting, and removing request headers.

  1. Create an HttpRoute resource for the httpbin2 app with the following request header modifications rules:

    • Add the App: httpbin2 header to all requests.
    • Set the User-Agent header to custom. If the User-Agent header is not present, it is added to the request.
    • Remove the X-Remove header from the request.

    Note that the HTTPRoute specifies the httpbin2 service in the parentRefs section. This setting instructs the waypoint proxy to enforce these policies for the httpbin2 app only.

      kubectl apply -f - <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin2
      namespace: httpbin
    spec:
      parentRefs:
      - name: httpbin2
        kind: Service
        group: ""
      rules:
        - matches:
          - path:
              type: PathPrefix
              value: /
          backendRefs:
           - name: httpbin2
             port: 8000
          filters:
            - type: RequestHeaderModifier
              requestHeaderModifier:
                add:
                  - name: App
                    value: httpbin2
                set:
                  - name: User-Agent
                    value: custom
                remove:
                  - X-Remove
    EOF
      
  2. Create an HTTPRoute for the httpbin3 app with the following request header modifications rules:

    • Add the App: httpbin3 header to all requests.
      kubectl apply -f - <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin3
      namespace: httpbin
    spec:
      parentRefs:
      - name: httpbin3
        kind: Service
        group: ""
      rules:
        - matches:
          - path:
              type: PathPrefix
              value: /
          backendRefs:
           - name: httpbin3
             port: 8000
          filters:
            - type: RequestHeaderModifier
              requestHeaderModifier:
                add:
                  - name: App
                    value: httpbin3
    EOF
      
  3. Use the client sample app to send a request to the httpbin2 app. Verify that you see the App: httpbin2 and User-Agent: custom headers, and that the X-Remove was not added to the respones.

      kubectl -n httpbin exec deploy/client -- curl -s http://httpbin2:8000/get \
     -H "X-Remove: this header"
      

    Example output:

       {
         "args": {},
         "headers": {
           "Accept": [
             "*/*"
           ],
           "App": [
             "httpbin2"
           ],
           "Host": [
             "httpbin2:8000"
           ],
           "User-Agent": [
             "custom"
           ],
           "X-Client": [
             "curl"
           ],
           "X-Envoy-Expected-Rq-Timeout-Ms": [
             "15000"
           ],
           "X-Forwarded-Proto": [
             "http"
           ],
           "X-Request-Id": [
             "4ef6b82d-6388-4be9-bb2c-b3077beafee8"
           ]
         },
         "method": "GET",
         "origin": "10.XX.X.XX:33737",
         "url": "http://httpbin2:8000/get"
       }
    
       

  4. Send the same request to the httpbin3 app. Verify that you see the App: httpbin3 header and X-Remove headers, and that the User-Agent header is not changed to custom.

      kubectl -n httpbin exec deploy/client -- curl -s http://httpbin3:8000/get \
     -H "X-Remove: this header"
      

    Example output:

       {
         "args": {},
         "headers": {
           "Accept": [
             "*/*"
           ],
           "Host": [
             "httpbin3:8000"
           ],
           "App": [
             "httpbin3"
           ],
           "User-Agent": [
             "curl/8.7.1"
           ],
           "X-Envoy-Expected-Rq-Timeout-Ms": [
             "15000"
           ],
           "X-Forwarded-Proto": [
             "http"
           ],
           "X-Remove": [
             "this header"
           ],
           "X-Request-Id": [
             "8a32f44f-55ab-4ff7-8b77-16d18739ae02"
           ]
         },
         "method": "GET",
         "origin": "10.XX.X.XX:53569",
         "url": "http://httpbin3:8000/get"
       }
    
       

  5. Optional: Remove the HTTPRoutes for the httpbin2 and httpbin3 apps.

      kubectl delete httproutes httpbin2 httpbin3 -n httpbin
      

External auth with API keys

Create an AuthConfig to secure traffic to the httpbin2 app with an API key.

  1. Create AuthConfig and Kubernetes secret resources to set up API key authentication for the httpbin2 app. The AuthConfig allows requests with the mykey API key that is stored in the secret. In addition, it extracts the organization field from the Kubernetes secret and adds the value as the X-Organiztion request header.

      kubectl apply -f - <<EOF 
    apiVersion: v1
    kind: Secret
    type: extauth.solo.io/apikey
    metadata:
      name: apikey
      namespace: gloo-system
      labels: 
        team: infrastructure
    stringData:
      api-key: mykey
      organization: solo.io
    ---
    apiVersion: enterprise.gloo.solo.io/v1
    kind: AuthConfig
    metadata:
      name: apikeys
      namespace: httpbin
    spec:
      configs:
      - apiKeyAuth:
          headerName: api-key
          labelSelector:
            team: infrastructure
          headersFromMetadataEntry:
            X-Organization:
              name: organization
    EOF
      
  2. Create a RouteOption resource that references the AuthConfig that you created.

      kubectl apply -f - <<EOF
    apiVersion: gateway.solo.io/v1
    kind: RouteOption
    metadata:
      name: httpbin2
      namespace: httpbin
    spec:
      targetRefs:
      - group: gateway.networking.k8s.io
        kind: HTTPRoute
        name: httpbin2
      options:
        extauth:
          configRef:
            name: apikeys
            namespace: httpbin
    EOF
      
  3. Create an HTTPRoute resource that routes traffic to the httpbin2 app. This resource is required for the waypoint proxy to enforce the external auth policies that you defined in your RouteOption.

      kubectl apply -f - <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin2
      namespace: httpbin
    spec:
      parentRefs:
      - name: httpbin2
        kind: Service
        group: ""
      rules:
        - matches:
          - path:
              type: PathPrefix
              value: /
          backendRefs:
           - name: httpbin2
             port: 8000
    EOF
      
  4. Send a request to the httpbin2 app without an API key. Note that the request is denied and you get back a 401 HTTP response code.

      kubectl -n httpbin exec deploy/client -- curl -vik http://httpbin2:8000/get 
      

    Example output:

      * Request completely sent off
    HTTP/1.1 401 Unauthorized
    www-authenticate: API key is missing or invalid
    date: Mon, 13 Jan 2025 20:40:30 GMT
    server: envoy
    content-length: 0
      
  5. Send another request. This time, you include the API key that you stored in the secret. Verify that you get back a 200 HTTP response code and that you see the Api-Key and X-Organization headers in your CLI output.

      kubectl -n httpbin exec deploy/client -- curl -vik http://httpbin2:8000/get \
    -H "api-key: mykey"
      

    Example output:

       {
         "args": {},
         "headers": {
           "Accept": [
             "*/*"
           ],
           "Api-Key": [
             "mykey"
           ],
           "Host": [
             "httpbin2:8000"
           ],
           "X-Envoy-Expected-Rq-Timeout-Ms": [
             "15000"
           ],
           "X-Forwarded-Proto": [
             "http"
          ],
           "X-Organization": [
             "solo.io"
           ],
           "X-Request-Id": [
             "bb5e646e-43f3-4044-809c-4241a644d72b"
           ],
           "X-User-Id": [
             "apikey"
           ]
         },
         "method": "GET",
         "origin": "10.XX.X.XX:35791",
         "url": "http://httpbin2:8000/get"
       }
       

  6. Send a request to the httpbin3 app without any API key. Verify that no external authentication is required for that app.

      kubectl -n httpbin exec deploy/client -- curl -s http://httpbin3:8000/get 
      

    Example output:

      {
      "args": {},
      "headers": {
        "Accept": [
          "*/*"
        ],
        "Host": [
          "httpbin3:8000"
        ],
        "User-Agent": [
          "curl/8.7.1"
        ],
        "X-Envoy-Expected-Rq-Timeout-Ms": [
         "15000"
        ],
        "X-Forwarded-Proto": [
          "http"
        ],
       "X-Request-Id": [
          "23454ca7-4d40-42d3-a15b-22f7e6c26383"
        ]
      },
      "method": "GET",
      "origin": "10.XX.X.XX:59357",
      "url": "http://httpbin3:8000/get"
    }
      
  7. Optional: Delete the external auth resources.

      kubectl delete secret apikey -n gloo-system
    kubectl delete routeoption httpbin2 -n httpbin
    kubectl delete authconfig apikeys -n httpbin
    kubectl delete httproute httpbin2 -n httpbin
      

Rate limit

Create different RatelimitConfig resources to limit the number of requests that you can send to the httpbin2 and httpbin3 apps.

  1. Create a RatelimitConfig to set up your rate limiting rules for the httpbin2 app.

      kubectl apply -f - <<EOF
    apiVersion: ratelimit.solo.io/v1alpha1
    kind: RateLimitConfig
    metadata:
      name: ratelimit-httpbin2
      namespace: httpbin
    spec:
      raw:
        descriptors:
        - key: generic_key
          value: counter
          rateLimit:
            requestsPerUnit: 1
            unit: MINUTE
        rateLimits:
        - actions:
          - genericKey:
              descriptorValue: counter
    EOF
      
  2. Create a RouteOption configuration that references the RatelimitConfig that you created earlier.

      kubectl apply -f - <<EOF
    apiVersion: gateway.solo.io/v1
    kind: RouteOption
    metadata:
      name: httpbin2
      namespace: httpbin
    spec:
      targetRefs:
      - group: gateway.networking.k8s.io
        kind: HTTPRoute
        name: httpbin2
      options:
        rateLimitConfigs:
          refs:
          - name: ratelimit-httpbin2
            namespace: httpbin
    EOF
      
  3. Create an HTTPRoute resource for the httpbin2 app. This resource is required to enforce the Layer 7 rate limiting rules for only the httpbin2 app.

      kubectl apply -f - <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin2
      namespace: httpbin
    spec:
      parentRefs:
      - name: httpbin2
        kind: Service
        group: ""
      rules:
        - matches:
          - path:
              type: PathPrefix
              value: /
          backendRefs:
           - name: httpbin2
             port: 8000
    EOF
      
  4. Send multiple requests to the httpbin2 app. Verify that the first request comes back with a 200 HTTP response code and that any subsequent requests are denied with a 429 HTTP response code.

      for i in {1..3}; do kubectl -n httpbin exec deploy/client -- curl -vik http://httpbin2:8000/get ; done
      

    Example output:

      HTTP/1.1 200 OK
    access-control-allow-credentials: true
    access-control-allow-origin: *
    ...
    HTTP/1.1 429 Too Many Requests
    x-envoy-ratelimited: true
    ...
    HTTP/1.1 429 Too Many Requests
    x-envoy-ratelimited: true
    ...
      
  5. Create another RatelimitConfig for the httpbin3 app. This configuration rate limits requests if the X-Organization: myorg header is present on the request.

      kubectl apply -f - <<EOF
    apiVersion: ratelimit.solo.io/v1alpha1
    kind: RateLimitConfig
    metadata:
      name: ratelimit-httpbin3
      namespace: httpbin
    spec:
      raw:
        setDescriptors:
          - simpleDescriptors:
              - key: organization
                value: myorg
            rateLimit:
              requestsPerUnit: 1
              unit: MINUTE
        rateLimits:
        - setActions:
          - requestHeaders:
              descriptorKey: organization
              headerName: X-Organization
    EOF
      
  6. Create a RouteOption resource that references your RatelimitConfig.

      kubectl apply -f - <<EOF
    apiVersion: gateway.solo.io/v1
    kind: RouteOption
    metadata:
      name: httpbin3
      namespace: httpbin
    spec:
      targetRefs:
      - group: gateway.networking.k8s.io
        kind: HTTPRoute
        name: httpbin3
      options:
        rateLimitConfigs:
          refs:
          - name: ratelimit-httpbin3
            namespace: httpbin
    EOF
      
  7. Create an HTTPRoute resource for the httpbin3 app. This resource is required to enforce the Layer 7 rate limiting rules for only the httpbin3 app.

      kubectl apply -f - <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin3
      namespace: httpbin
    spec:
      parentRefs:
      - name: httpbin3
        kind: Service
        group: ""
      rules:
        - matches:
          - path:
              type: PathPrefix
              value: /
          backendRefs:
           - name: httpbin3
             port: 8000
    EOF
      
  8. Send multiple requests to the httpbin3 app without the X-Organization header. Verify that you are not rate limited after the first request.

      for i in {1..3}; do kubectl -n httpbin exec deploy/client -- curl -vik http://httpbin3:8000/get ; done
      

    Example output:

      HTTP/1.1 200 OK
    access-control-allow-credentials: true
    access-control-allow-origin: *
    content-type: application/json; charset=utf-8
    ...
    HTTP/1.1 200 OK
    access-control-allow-credentials: true
    access-control-allow-origin: *
    content-type: application/json; charset=utf-8
    ...
    HTTP/1.1 200 OK
    access-control-allow-credentials: true
    access-control-allow-origin: *
    content-type: application/json; charset=utf-8
    ...
      
  9. Repeat the requests. This time, you include the X-Organization: myorg header. Verify that the first request comes back with a 200 HTTP response code and that any subsequent requests are denied with a 429 HTTP response code.

      for i in {1..3}; do kubectl -n httpbin exec deploy/client -- curl -vik http://httpbin2:8000/get -H "X-Organization: myorg" ; done
      

    Example output:

      HTTP/1.1 200 OK
    access-control-allow-credentials: true
    access-control-allow-origin: *
    content-type: application/json; charset=utf-8
    ...
    HTTP/1.1 429 Too Many Requests
    x-envoy-ratelimited: true
    ...
    HTTP/1.1 429 Too Many Requests
    x-envoy-ratelimited: true
    ...
      
  10. Optional: Delete the ratelimit resources.

      kubectl delete ratelimitconfig ratelimit-httpbin2 ratelimit-httpbin3 -n httpbin
    kubectl delete routeoption httpbin2 httpbin3 -n httpbin
    kubectl delete httproutes httpbin2 httpbin3 -n httpbin