By default, you must attach policies to resources that are in the same namespace. However, you might have policies that you want to reuse across teams, such as to standardize security protections across your organization.

To do so, you can create policies in a “global” namespace. Then, the policies can attach to resources in any namespace in your cluster through label selectors.

Before you begin

  1. Follow the Get started guide to install Gloo Gateway.

  2. Follow the Sample app guide to create a gateway proxy with an HTTP listener and deploy the httpbin sample app.

  3. Get the external address of the gateway and save it in an environment variable.

Step 1: Review default policy behavior

By default, policies are attached to resources in the same namespace. This way, each team manages their own apps, routing resources, and policies.

  1. Send a request to the httpbin service on the /anything path and note the expected 200 response.

    Example output:

      HTTP/1.1 200 OK
    access-control-allow-credentials: true
    access-control-allow-origin: *
    content-type: application/json; encoding=utf-8
    date: Tue, 29 Jul 2025 20:08:21 GMT
    content-length: 587
    x-envoy-upstream-service-time: 1
    server: envoy
      
      {
      "args": {},
      "headers": {
        "Accept": [
          "*/*"
        ],
        "Host": [
          "www.example.com"
        ],
        "User-Agent": [
          "curl/8.7.1"
        ],
        "X-Envoy-Expected-Rq-Timeout-Ms": [
          "15000"
        ],
        "X-Envoy-External-Address": [
          "127.0.0.1"
        ],
        "X-Forwarded-For": [
          "10.244.0.7"
        ],
        "X-Forwarded-Proto": [
          "http"
        ],
        "X-Request-Id": [
          "7ec1f5f7-72b7-4053-b2e4-0117a2438d4c"
        ]
      },
      "origin": "10.244.0.7",
      "url": "http://www.example.com/anything",
      "data": "",
      "files": null,
      "form": null,
      "json": null
    }
      
  2. Create a GlooTrafficPolicy that rewrites the path to /status/418 if it has the transform:status header. Note that the policy is in the same namespace as the HTTPRoute.

      kubectl apply -f- <<EOF  
    apiVersion: gloo.solo.io/v1alpha1
    kind: GlooTrafficPolicy
    metadata:
      name: transformation
      namespace: httpbin
    spec:
      targetRefs:
      - group: gateway.networking.k8s.io
        kind: HTTPRoute
        name: httpbin
      transformation:
        request:
          set:
          - name: ":path"
            value: '{% if request_header("transform") == "status" %}/status/418{% else %}{{ header(":path") }}{% endif %}'
    EOF
      
  3. Repeat the request with the transform:status header. The request is now transformed from the /anything path to the /status/418 path.

    Example output: Notice that the response is now 418 I'm a teapot! instead of the initial 200 response.

      HTTP/1.1 418 Unknown
    access-control-allow-credentials: true
    access-control-allow-origin: *
    x-more-info: http://tools.ietf.org/html/rfc2324
    date: Wed, 30 Jul 2025 15:45:07 GMT
    content-length: 13
    content-type: text/plain; charset=utf-8
    x-envoy-upstream-service-time: 1
    server: envoy
    
    I'm a teapot!
      
  4. Delete the GlooTrafficPolicy.

      kubectl delete GlooTrafficPolicy -n httpbin transformation
      
  5. Create the same GlooTrafficPolicy but in a different namespace, such as the gloo-system namespace.

      kubectl apply -f- <<EOF  
    apiVersion: gloo.solo.io/v1alpha1
    kind: GlooTrafficPolicy
    metadata:
      name: transformation
      namespace: gloo-system
    spec:
      targetRefs:
      - group: gateway.networking.k8s.io
        kind: HTTPRoute
        name: httpbin
      transformation:
        request:
          set:
          - name: ":path"
            value: '{% if request_header("transform") == "status" %}/status/418{% else %}{{ header(":path") }}{% endif %}'
    EOF
      
  6. Repeat the request. This time, the request is not transformed. The policy cannot be attached because the resource is in a different namespace. Instead, you get the initial 200 response.

    Example output:

      HTTP/1.1 200 OK
    access-control-allow-credentials: true
    access-control-allow-origin: *
    content-type: application/json; encoding=utf-8
    date: Tue, 29 Jul 2025 20:08:21 GMT
    content-length: 587
    x-envoy-upstream-service-time: 1
    server: envoy
      
      {
      "args": {},
      "headers": {
        "Accept": [
          "*/*"
        ],
        "Host": [
          "www.example.com"
        ],
        "User-Agent": [
          "curl/8.7.1"
        ],
        "X-Envoy-Expected-Rq-Timeout-Ms": [
          "15000"
        ],
        "X-Envoy-External-Address": [
          "127.0.0.1"
        ],
        "X-Forwarded-For": [
          "10.244.0.7"
        ],
        "X-Forwarded-Proto": [
          "http"
        ],
        "X-Request-Id": [
          "7ec1f5f7-72b7-4053-b2e4-0117a2438d4c"
        ]
      },
      "origin": "10.244.0.7",
      "url": "http://www.example.com/anything",
      "data": "",
      "files": null,
      "form": null,
      "json": null
    }
      

Step 2: Enable global policy attachment

To enable the global policy attachment feature, upgrade your Gloo Gateway Helm installation.

  1. Get the Helm values for your current Helm installation.

      helm get values gloo-gateway -n gloo-system -o yaml > gloo-gateway.yaml
    open gloo-gateway.yaml
      
  2. Add the following values to the Helm values file to enable the global policy namespace feature. The example uses the gloo-system namespace as the “global” namespace, but you can use any existing namespace that you want.

      
    controller:
      extraEnv:
        KGW_GLOBAL_POLICY_NAMESPACE: gloo-system
      
  3. Upgrade your Helm installation. Replace the --version 2.0.1 option to match your current version.

      helm upgrade -i --namespace gloo-system --version 2.0.1 gloo-gateway oci://us-docker.pkg.dev/solo-public/gloo-gateway/charts/gloo-gateway -f gloo-gateway.yaml
      

Step 3: Create a global policy

Create a global policy in the gloo-system namespace. Then, use a global-policy label selector to attach the policy to resources in any namespace.

  1. Update the HTTPRoute for the httpbin service to add a label selector. The label selector can be any value that you want, but it must match the label selector that you add in the GlooTrafficPolicy.

      kubectl apply -f- <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin
      namespace: httpbin
      labels:
        global-policy: transformation
    spec:
      parentRefs:
        - name: http
          namespace: gloo-system
      hostnames:
        - "www.example.com"
      rules:
        - backendRefs:
            - name: httpbin
              port: 8000
    EOF
      
  2. Update the GlooTrafficPolicy to target the HTTPRoute by using the global-policy label in the targetSelectors field (instead of the targetRefs field).

      kubectl apply -f- <<EOF  
    apiVersion: gloo.solo.io/v1alpha1
    kind: GlooTrafficPolicy
    metadata:
      name: transformation
      namespace: gloo-system
    spec:
      targetSelectors:
      - group: gateway.networking.k8s.io
        kind: HTTPRoute
        matchLabels:
          global-policy: transformation
      transformation:
        request:
          set:
          - name: ":path"
            value: '{% if request_header("transform") == "status" %}/status/418{% else %}{{ header(":path") }}{% endif %}'
    EOF
      
  3. Send a request with the transform:status header. This time, the request is transformed even though the HTTPRoute and transformation policy are in different namespaces.

    Example output:

      HTTP/1.1 418 Unknown
    access-control-allow-credentials: true
    access-control-allow-origin: *
    x-more-info: http://tools.ietf.org/html/rfc2324
    date: Wed, 30 Jul 2025 15:49:17 GMT
    content-length: 13
    content-type: text/plain; charset=utf-8
    x-envoy-upstream-service-time: 0
    server: envoy
    
    I'm a teapot!%
      

More resources

For more examples of attaching policies to different resources, review each policy’s docs.

Cleanup

You can remove the resources that you created in this guide.
  1. Delete the transformation policy.

      kubectl delete GlooTrafficPolicy -n gloo-system transformation
      
  2. Restore the sample httpbin HTTPRoute.

      kubectl apply -f- <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin
      namespace: httpbin
    spec:
      parentRefs:
        - name: http
          namespace: gloo-system
      hostnames:
        - "www.example.com"
      rules:
        - backendRefs:
            - name: httpbin
              port: 8000
    EOF