Gloo Gateway as a waypoint proxy
Enforce Layer 7 policies for the apps in your ambient mesh by using Gloo Gateway as a waypoint proxy.
This feature is an Enterprise-only feature that requires a Gloo Gateway Enterprise license.
Using Gloo Gateway as a waypoint proxy requires ambient mesh to be installed with Istio version 1.23 or later.
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.
You can create an HTTPRoute and scope it to the waypoint proxy by referencing the waypoint proxy in the parentRef
section. This way, the policies that are defined in the HTTPRoute are automatically applied to all services in the waypoint proxy namespace.
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.
- Manually install a Solo distribution of Istio. The Solo distribution of Istio is a hardened Istio enterprise image, which maintains
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.
Create the httpbin namespace.
kubectl create ns httpbin
Deploy the httpbin2, httpbin3, and client sample apps.
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
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.
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
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
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
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.
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 tocustom
. 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
- Add the
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
- Add the
Use the client sample app to send a request to the httpbin2 app. Verify that you see the
App: httpbin2
andUser-Agent: custom
headers, and that theX-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" }
Send the same request to the httpbin3 app. Verify that you see the
App: httpbin3
header andX-Remove
headers, and that theUser-Agent
header is not changed tocustom
.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" }
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.
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 theorganization
field from the Kubernetes secret and adds the value as theX-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
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
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
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
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
andX-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" }
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" }
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.
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
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
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
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 ...
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
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
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
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 ...
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 ...
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