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.
- Response behavior change: When you enable the feature gate, the gateway denies unauthorized requests with a 403 HTTP response code, even if the route is not found which typically returns a 404 HTTP response code. As such, this response behavior change might affect automation that you have in place, such as to monitor or troubleshoot logs.
- Ingress gateway only: You can use this feature with an Istio ingress gateway for north-south traffic within the service mesh. This feature does not support east-west gateways or egress gateways for traffic that leaves the service mesh.
- HTTP routes only: You can use this feature to set up the ingress gateway to deny all requests for HTTP/HTTPS routes only. This feature does not support other types of routes, such as TLS or TCP.
- Gloo external auth service only: You must use the Gloo external auth service to enforce the auth policies to the routes. You cannot use your own custom external auth service. You can add the
gateway.gloo.solo.io/require_auth: "false"
label to these routes so that you know that the routes are not protected by thegatewayDefaultDenyAllHTTPRequests
feature gate. - JwtPolicy cannot allow missing or failed JWT: Your JwtPolicies cannot set the
allowMissingOrFailed
field or thevalidationPolicy
field toALLOW_MISSING
orALLOW_MISSING_OR_FAILED
JWTs. For the deny all feature gate to work, the gateway needs a valid JWT. Because JwtPolicies with those fields might allow a missing or invalid JWT, the gateway denies requests to the route. Instead, consider these options:- You can apply an additional ExtAuthPolicy, so that some type of auth is enforced on the route. This way, you can configure
ALLOW_MISSING
orALLOW_MISSING_OR_FAILED
JWTs because the request can successfully authenticate via external auth. - You can disable this feature for the route that you want to allow a missing or failed JWT by applying the
gateway.gloo.solo.io/require_auth: "false"
label on that route.
- You can apply an additional ExtAuthPolicy, so that some type of auth is enforced on the route. This way, you can configure
- JWT must have
iss
claim: For thegatewayDefaultDenyAllHTTPRequests
feature gate to work, JWT claims must include aniss
claim. If not, the gateway denies the request. Note that this behavior differs from the regular gateway behavior, which can authenticate JWTs that do not to have theiss
claim. - Version requirements: To enable this feature, your setup must meet the following requirements:
- Gloo Platform version 2.5 or later
- Solo distribution of Istio (not community Istio)
- Istio version 1.18.6, 1.19.5, 1.20.1, or later
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.
-
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
-
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
-
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
andhttpbin-secure
. All routes inherit thegateway.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 thegateway.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 theapp: 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
andhttpbin-secure
. - The
httpbin-insecure
route includes thegateway.gloo.solo.io/require_auth: "false"
label. This way, it overrides the parent route table setting so that thehttpbin-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 thegateway.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
andhttpbin-secure
. - The
httpbin-insecure
route includes thegateway.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 thegateway.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
- Has the
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.
-
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
-
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
-
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 thegateway.gloo.solo.io/require_auth: "false"
label to allow a more permissive routecurl -vik http://$INGRESS_GW_IP:80/insecure
curl -vik localhost:8080/insecure
Example output:
HTTP/2 200
-
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
-
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%
-
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
-
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.-
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
-
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