Deny requests to routes

For a more secure setup, you can enable a feature gate to deny requests to your HTTP routes by default.

About the feature gate

You can enable the gatewayDefaultDenyAllHTTPRequests feature gate in your Gloo Mesh Gateway installation to automatically deny all requests to your HTTP routes if no ExtAuthPolicy or JwtPolicy is applied to the route.

To deny all requests for a route, you add the gateway.gloo.solo.io/require_auth: "true" to the route that you want to protect. You have the option to protect individual routes, or apply this label to all routes in a route table or delegated route table. Access to the route is granted only if an auth policy is applied to the route, such as an ExtAuthPolicy or JwtPolicy, and the client request can be authenticated successfully.

Without the gateway.gloo.solo.io/require_auth: "true" label, requests to your routes are allowed by default. You can still apply auth policies to protect routes. However, if your auth policies are deleted, misconfigured, or otherwise not persisted in the Envoy proxy, then the route becomes exposed again. By using the gatewayDefaultDenyAllHTTPRequests feature gate, you can safeguard against such accidental exposure.

Feature considerations

Before using this feature, keep in mind the following considerations.

Deny requests to your routes by default

To deny requests to your routes by default, you enable the gatewayDefaultDenyAllHTTPRequests feature gate in your Gloo Mesh Gateway installation. Then, when you set up routing for your app, add the gateway.gloo.solo.io/require_auth: "true" label to the route that you want to deny requests for. Note that Gloo Mesh Gateway only respects this label when the gatewayDefaultDenyAllHTTPRequests feature gate is enabled.

  1. Install or upgrade Gloo Platform with the gatewayDefaultDenyAllHTTPRequests feature gate enabled. In multicluster setups, this feature gate is enabled in the management cluster installation. For more information, see the Feature gate and Helm reference docs.

    featureGates:
      gatewayDefaultDenyAllHTTPRequests: true
    
    --set featureGates.gatewayDefaultDenyAllHTTPRequests=true
    

    The following example command uses the gloo-gateway-demo installation profile.

    meshctl install --profiles gloo-gateway-demo \
      --set common.cluster=$CLUSTER_NAME \
      --set licensing.glooGatewayLicenseKey=$GLOO_GATEWAY_LICENSE_KEY \
      --set featureGates.gatewayDefaultDenyAllHTTPRequests=true
    
  2. Deploy the httpbin sample app.

  3. Configure a virtual gateway with an HTTP or HTTPS listener. The following example creates a sample HTTP listener for the ingress gateway.

    kubectl apply -f- <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: VirtualGateway
    metadata:
      name: istio-ingressgateway
      namespace: httpbin
    spec:
      listeners:
      - http: {}
        port:
          number: 80
      workloads:
      - selector:
          labels:
            istio: ingressgateway
    EOF
    
  4. Create a route table for the sample httpbin app. Include the gateway.gloo.solo.io/require_auth: "true" label to each route that you want to deny requests to by default. You can apply the label to an entire route table, delegated routes, or individual routes, such as in the following examples.

    Deny requests to all routes in the route table by applying the label to the route table. Note that if you also specify a label at the individual route level, the individual route label takes precedence. For example, you might explicitly set the label to false to allow a more permissive route. The route table in the following example:

    • Has the gateway.gloo.solo.io/require_auth: "true" label in the route table metadata so that all routes in the route table inherit this label by default.
    • Sets up two routes, httpbin-insecure and httpbin-secure. All routes inherit the gateway.gloo.solo.io/require_auth: "true" label from the metadata of the route table. Each route must have an accepted auth policy, or else requests are denied by default.
    • The httpbin-insecure route includes the gateway.gloo.solo.io/require_auth: "false" label. This way, the value inherited from the route table is overridden and the gateway does not deny requests to this individual route by default. You might have an insecure route for quick testing or for use cases where you want to allow a missing or failed JWT.
    kubectl apply -f- <<EOF
    kind: RouteTable
    apiVersion: networking.gloo.solo.io/v2
    metadata:
      name: httpbin
      namespace: httpbin
      labels:
        app: httpbin
        gateway.gloo.solo.io/require_auth: "true"
    spec:
      hosts:
        - '*'
      virtualGateways:
        - name: istio-ingressgateway
          namespace: httpbin
      http:
      - name: httpbin-insecure
        labels:
          route: httpbin
          gateway.gloo.solo.io/require_auth: "false"
        matchers:
        - uri:
            prefix: /insecure
        forwardTo:
          destinations:
          - ref:
              name: httpbin
              namespace: httpbin
            port:
              number: 8000
          pathRewrite: /headers
      - name: httpbin-secure
        labels:
          route: httpbin
        matchers:
        - uri:
            prefix: /secure
        forwardTo:
          destinations:
          - ref:
              name: httpbin
              namespace: httpbin
            port:
              number: 8000
          pathRewrite: /headers
    EOF
    

    Deny requests to all routes in a delegated route table. This way, you do not have to include the label in the delegated child route table. The delegated child route table inherits its parent route table label. Note that if you specify a label in the delegated child route table, that label takes precedence. For example, you might explicitly set the label to false to allow a more permissive route. For more information about delegation, see Delegate requests to sub-tables.

    The following parent route table:

    • Selects the virtual gateway that you previously created.
    • Delegates the httpbin route to the route table with the app: httpbin label.
    • Includes the gateway.gloo.solo.io/require_auth: "true" label for the delegated httpbin route so that all routes in the delegated child route table inherit the label. This way, the feature to deny all HTTP traffic by default is enabled for all of the routes in the delegated child route table.
    kubectl apply -f- <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
    metadata:
      name: gateway
      namespace: gloo-mesh-gateways
    spec:
      hosts:
        - '*'
      virtualGateways:
        - name: istio-ingressgateway
          namespace: httpbin
      http:
        - name: httpbin
          labels:
            gateway.gloo.solo.io/require_auth: "true"
        - delegate:
            routeTables:
            - labels:
                app: httpbin
    EOF
    



    The following delegated child route table:

    • Has the app: httpbin label so that it is selected by the parent route table to get delegated traffic.
    • Sets up two routes, httpbin-insecure and httpbin-secure.
    • The httpbin-insecure route includes the gateway.gloo.solo.io/require_auth: "false" label. This way, it overrides the parent route table setting so that the httpbin-insecure route can get traffic that is not protected by an auth policy. You might have an insecure route for quick testing or for use cases where you want to allow a missing or failed JWT.
    • The httpbin-secure route inherits the gateway.gloo.solo.io/require_auth: "true" label from the parent route table. The route must have an accepted external auth or JWT policy, or else requests are denied by default.
    kubectl apply -f- <<EOF
    kind: RouteTable
    apiVersion: networking.gloo.solo.io/v2
    metadata:
      name: httpbin
      namespace: httpbin
      labels:
        app: httpbin
    spec:
      http:
      - name: httpbin-insecure
        labels:
          route: httpbin
          gateway.gloo.solo.io/require_auth: "false"
        matchers:
        - uri:
            prefix: /insecure
        forwardTo:
          destinations:
          - ref:
              name: httpbin
              namespace: httpbin
            port:
              number: 8000
          pathRewrite: /headers
      - name: httpbin-secure
        labels:
          route: httpbin
        matchers:
        - uri:
            prefix: /secure
        forwardTo:
          destinations:
          - ref:
              name: httpbin
              namespace: httpbin
            port:
              number: 8000
          pathRewrite: /headers
    EOF
    

    Deny requests for specific routes by applying the label to an individual route in a route table. The route table in the following example:

    • Sets up two routes, httpbin-insecure and httpbin-secure.
    • The httpbin-insecure route includes the gateway.gloo.solo.io/require_auth: "false" label. You might have an insecure route for quick testing or for use cases where you want to allow a missing or failed JWT.
    • The httpbin-secure route includes the gateway.gloo.solo.io/require_auth: "true" label. The route must have an accepted auth policy, or else requests are denied by default.

    Note that individual route labels take precedence over any parent route tables or the label of the route table itself.

    kubectl apply -f- <<EOF
    kind: RouteTable
    apiVersion: networking.gloo.solo.io/v2
    metadata:
      name: httpbin
      namespace: httpbin
      labels:
        app: httpbin
    spec:
      hosts:
        - '*'
      virtualGateways:
        - name: istio-ingressgateway
          namespace: httpbin
      http:
      - name: httpbin-insecure
        labels:
          route: httpbin
          gateway.gloo.solo.io/require_auth: "false"
        matchers:
        - uri:
            prefix: /insecure
        forwardTo:
          destinations:
          - ref:
              name: httpbin
              namespace: httpbin
            port:
              number: 8000
          pathRewrite: /headers
      - name: httpbin-secure
        labels:
          route: httpbin
          gateway.gloo.solo.io/require_auth: "true"
        matchers:
        - uri:
            prefix: /secure
        forwardTo:
          destinations:
          - ref:
              name: httpbin
              namespace: httpbin
            port:
              number: 8000
          pathRewrite: /headers
    EOF
    

Good job! Now, routes with the gateway.gloo.solo.io/require_auth: "true" label are protected by default. Any traffic requests sent to these routes are automatically denied with a 403 response. To allow traffic, you must apply an auth policy, such as an ExtAuthPolicy or JwtPolicy. For an example, continue to the next step to verify your setup.

Verify your secured routes

To verify your secured routes, send a series of requests to the routes. For requests to succeed, the routes must have an external auth or JWT policy that is applied to the routes and in an Accepted state. The following example sets up various JWT policies to demonstrate the feature.

  1. Save the external address of the ingress gateway.

    export INGRESS_GW_IP=$(kubectl get svc -n gloo-mesh-gateways istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    echo $INGRESS_GW_IP
    
    export INGRESS_GW_IP=$(kubectl get svc -n gloo-mesh-gateways istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
    echo $INGRESS_GW_IP
    

    In another tab in your terminal, port-forward the istio-ingressgateway pod on port 8080. Note that if you are testing on a local network such as kind on macOS, you might have to configure a load balancer such as metallb.

    kubectl port-forward pod/$(kubectl get pod -l istio=ingressgateway -A -o jsonpath='{.items[0].metadata.name}') -n gloo-mesh-gateways 8080:8080
    
  2. Send a request to the httpbin-secure route. The request is denied with a 403 response because the route does not have an attached auth policy.

    curl -vik http://$INGRESS_GW_IP:80/secure
    
    curl -vik localhost:8080/secure
    

    Example output:

    HTTP/2 403
    
  3. Send a request to the httpbin-insecure route. The request succeeds with a 200 response even though the route does not have an attached auth policy. The gateway does not deny requests by default because you included the gateway.gloo.solo.io/require_auth: "false" label to allow a more permissive route

    curl -vik http://$INGRESS_GW_IP:80/insecure
    
    curl -vik localhost:8080/insecure
    

    Example output:

    HTTP/2 200
    
  4. Apply a JWT policy to the route. The following example uses sample keys and a dev-example JWT. For more details about the sample JWT, see the GitHub readme.

    kubectl apply -f https://gist.githubusercontent.com/artberger/674bab05350c9a048303cc7daaffe730/raw/daf7d9b64e5e9ecf309f17123e01f5a6cbb6c7eb/jwt-policy-basic.yaml
    
  5. Get a sample JWT that is preconfigured to meet the validation requirements that you set in the JWT policy for the dev-example provider.

    TOKEN=$(curl https://raw.githubusercontent.com/solo-io/gloo-mesh-use-cases/main/gloo-gateway/jwt/dev-example.jwt -s) && echo "$TOKEN" | cut -d '.' -f2 - | base64 --decode
    

    Example output:

    {"iss":"https://dev.example.com","exp":4804324736,"iat":1648651136,"org":"internal","email":"dev1@solo.io","group":"engineering","scope":"is:developer%
    
  6. Repeat the request to the httpbin-secure route, this time with your valid JWT. The request now succeeds with a 200 response because the route has an attached auth JWT policy and you included a valid JWT in your request.

    curl -vik -H "X-Auth: Bearer ${TOKEN}" http://$INGRESS_GW_IP:80/secure
    
    curl -vik -H "X-Auth: Bearer ${TOKEN}" localhost:8080/secure
    

    Example output with a valid JWT:

    HTTP/2 200
    

    Example output with an invalid JWT:

    HTTP/2 401
    
  7. Delete the JWT policy that secures the httpbin-secure route and repeat the request. Notice that the request is denied again because the feature gate denies requests to the route by default. This way, the route stays protected in cases where the policy is accidentally deleted or misconfigured.

    kubectl delete JwtPolicy -n httpbin jwt-policy
    
    curl -vik -H "X-Auth: Bearer ${TOKEN}" http://$INGRESS_GW_IP:80/secure
    
    curl -vik -H "X-Auth: Bearer ${TOKEN}" localhost:8080/secure
    

    Example output:

    HTTP/2 403
    

Cleanup

You can optionally remove the resources that you set up as part of this guide.
  1. Delete the routing and policy resources that you created.

    kubectl delete VirtualGateway -n httpbin istio-ingressgateway
    kubectl delete RouteTable -n httpbin httpbin
    kubectl delete RouteTable -n gloo-mesh-gateways gateway #for delegated example
    kubectl delete JwtPolicy -n httpbin jwt-policy
    
  2. If you do not want to use this feature anymore, you can disable the feature gate. Upgrade Gloo Mesh Gateway and disable the gatewayDefaultDenyAllHTTPRequests feature gate. In multicluster setups, you disable this feature gate in the management cluster. For more information, see the Feature gate and Helm reference docs.

    featureGates:
      gatewayDefaultDenyAllHTTPRequests: false
    
    --set featureGates.gatewayDefaultDenyAllHTTPRequests=false