Deploy a web application firewall with Calico Ingress Gateway
This guide shows you how to deploy and configure a web application firewall (WAF) with the Calico Ingress Gateway. By deploying the WAF in this way, you can protect publicly exposed services from a variety of application-layer attacks.
This feature is tech preview. Tech preview features may be subject to significant changes before they become GA.
Prerequisites
- Calico Ingress Gateway is set up for your cluster.
- You have the value of
metadata.namefor theGatewayresource you want to use with WAF.
Deploy WAF on Calico Ingress Gateway
Calico Ingress Gateway uses Envoy's implementation of the Kubernetes Gateway API. To direct ingress gateway traffic through the WAF, you need to configure Envoy to use the WAF HTTP filter.
To enable WAF on a Calico Ingress Gateway:
-
Create a
Backendresource to allow Envoy to find the WAF HTTP filter:kubectl apply -f - <<EOF
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
name: tigera-waf-backend
spec:
endpoints:
- unix:
path: "/var/run/waf-http-filter/extproc.sock"
EOF -
Create an
EnvoyExtensionPolicyresource to direct Envoy to use thetigera-waf-backendbackend for the WAF HTTP filter:kubectl apply -f - <<EOF
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
name: tigera-waf-envoy-extension-policy
spec:
extProc:
- backendRefs:
- name: tigera-waf-backend
kind: Backend
processingMode:
request:
body: Streamed
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: <gateway-name>
EOFReplace
<gateway-name>with the value ofmetadata.namein yourGatewayresource.The WAF now processes all HTTP requests that pass through the specified
Gatewayresource.To deploy a WAF on multiple gateways, you must create a separate
EnvoyExtensionPolicyresource for eachGatewayresource. EachEnvoyExtensionPolicymust reference the sametigera-waf-backendbackend. -
To verify that the WAF is enabled for your gateway, you can simulate an SQL injection attack through your gateway and see whether it triggers a security event.
noteThe query string in this example has some SQL syntax embedded in the text. This is harmless and for demo purposes, but WAF will detect this pattern and create an WAF log for this HTTP request.
-
Get the service IP of your gateway:
export GATEWAY_HOST=$(kubectl get gateway/<gateway-name> -o jsonpath='{.status.addresses[0].value}') -
Trigger a security event by simulating an SQL injection attack on that service IP:
curl --verbose --header "Host: www.example.com" http://$GATEWAY_HOST/?artist=0+div+1+union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A1%2C2%2Ccurrent_user -
From the web console, go to Threat > Security Events and check for a security event with corresponds with this simulated SQL injection attack.
-
Customizing your WAF configuration for an ingress gateway
The default WAF configuration uses the OWASP Core Rule Set v4.7.0 in detection-only mode with early blocking enabled.
To customize a WAF configuration for an ingress gateway, you can include custom directives in an EnvoyPatchPolicy resource.
For information on how to create custom directives, see WAF customization options.
For example, to enable the OWASP Core Rule Set in blocking mode, you can apply an EnvoyPatchPolicy resource like this:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyPatchPolicy
metadata:
name: tigera-waf-http-filter-metadata
namespace: <gateway-namespace>
spec:
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: <gateway-name>
type: JSONPatch
jsonPatches:
- type: "type.googleapis.com/envoy.config.listener.v3.Listener"
name: <gateway-namespace>/<gateway-name>/http
operation:
op: add
jsonPath: "default_filter_chain.filters[0].typed_config.http_filters[?match(@.name, '.*tigera-waf-http-filter/.*')]"
path: typed_config/grpc_service/initial_metadata
value:
- key: directivesJson
value: "[\"SecRuleEngine On\"]"
You can add additional directives to the directivesJson array to further customize the WAF behavior.
Make sure that combine the directives as an inlined JSON list with proper escaping.
The array in the following snippet is an example of how to set the WAF to detection-only mode, remove a specific rule, and set a sampling percentage:
- key: directivesJson
value: "[\"SecRuleEngine DetectionOnly\", \"SecRuleRemoveById 920420\", \"SecAction \\\""id:900400,phase:1,pass,nolog,setvar:tx.sampling_percentage=50\\\"\]"