Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WAF policy #1378

Merged
merged 2 commits into from
Feb 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions deployments/common/crds-v1beta1/k8s.nginx.org_policies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,24 @@ spec:
type: integer
zoneSize:
type: string
waf:
description: 'WAF defines an WAF policy. policy status: preview'
type: object
properties:
apPolicy:
type: string
enable:
type: boolean
securityLog:
description: SecurityLog defines the security log of a WAF policy.
type: object
properties:
apLogConf:
type: string
enable:
type: boolean
logDest:
type: string
status:
description: PolicyStatus is the status of the policy resource
type: object
Expand Down
18 changes: 18 additions & 0 deletions deployments/common/crds/k8s.nginx.org_policies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,24 @@ spec:
type: integer
zoneSize:
type: string
waf:
description: 'WAF defines an WAF policy. policy status: preview'
type: object
properties:
apPolicy:
type: string
enable:
type: boolean
securityLog:
description: SecurityLog defines the security log of a WAF policy.
type: object
properties:
apLogConf:
type: string
enable:
type: boolean
logDest:
type: string
status:
description: PolicyStatus is the status of the policy resource
type: object
Expand Down
18 changes: 18 additions & 0 deletions deployments/helm-chart/crds/k8s.nginx.org_policies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,24 @@ spec:
type: integer
zoneSize:
type: string
waf:
description: 'WAF defines an WAF policy. policy status: preview'
type: object
properties:
apPolicy:
type: string
enable:
type: boolean
securityLog:
description: SecurityLog defines the security log of a WAF policy.
type: object
properties:
apLogConf:
type: string
enable:
type: boolean
logDest:
type: string
status:
description: PolicyStatus is the status of the policy resource
type: object
Expand Down
67 changes: 67 additions & 0 deletions docs-web/configuration/policy-resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ This document is the reference documentation for the Policy resource. An example
- [EgressMTLS Merging Behavior](#egressmtls-merging-behavior)
- [OIDC](#oidc)
- [OIDC Merging Behavior](#oidc-merging-behavior)
- [WAF](#waf)
- [WAF Merging Behavior](#waf-merging-behavior)
- [Using Policy](#using-policy)
- [Applying Policies](#applying-policies)
- [Invalid Policies](#invalid-policies)
Expand Down Expand Up @@ -77,6 +79,10 @@ spec:
- The EgressMTLS policy configures upstreams authentication and certificate verification.
- `egressMTLS <#egressmtls>`_
- No*
* - ``waf``
- The WAF policy configures WAF and log configuration policies for `NGINX AppProtect </nginx-ingress-controller/app-protect/installation/>`_
- `WAF <#waf>`_
- No*
```

\* A policy must include exactly one policy.
Expand Down Expand Up @@ -521,6 +527,67 @@ webapp-policy 27m

For `kubectl get` and similar commands, you can also use the short name `pol` instead of `policy`.

### WAF

> **Feature Status**: WAF is available as a preview feature: it is suitable for experimenting and testing; however, it must be used with caution in production environments. Additionally, while the feature is in preview status, we might introduce some backward-incompatible changes to the resource specification in the next releases. The feature is disabled by default. To enable it, set the [enable-preview-policies](/nginx-ingress-controller/configuration/global-configuration/command-line-arguments/#cmdoption-enable-preview-policies) command-line argument of the Ingress Controller.

> Note: This feature is only available in NGINX Plus with AppProtect.

The WAF policy configures NGINX Plus to secure client requests using App Protect policies.

For example, the following policy will enable the referenced APPolicy and APLogConf with the configured log destination:
```yaml
waf:
enable: true
apPolicy: "default/dataguard-alarm"
securityLog:
enable: true
apLogConf: "default/logconf"
logDest: "syslog:server=127.0.0.1:514"
```

> Note: The feature is implemented using the NGINX Plus [NGINX App Protect Module](https://docs.nginx.com/nginx-app-protect/configuration/).

```eval_rst
.. list-table::
:header-rows: 1

* - Field
- Description
- Type
- Required
* - ``enable``
- Enables NGINX App Protect.
- ``bool``
- Yes
* - ``apPolicy``
- The `App Protect policy </nginx-ingress-controller/app-protect/configuration/#app-protect-policies/>`_ of the WAF. Accepts an optional namespace.
- ``string``
- No
* - ``securityLog.enable``
- Enables security log.
- ``bool``
- No
* - ``securityLog.apLogConf``
- The `App Protect log conf </nginx-ingress-controller/app-protect/configuration/#app-protect-logs>`_ resource. Accepts an optional namespace.
- ``string``
- No
* - ``securityLog.logDest``
- The log destination for the security log. Accepted variables are ``syslog:server=<ip-address | localhost>:<port>``, ``stderr``, ``<absolute path to file>``. Default is ``"syslog:server=127.0.0.1:514"``.
- ``string``
- No
```

#### WAF Merging Behavior

A VirtualServer/VirtualServerRoute can reference multiple WAF policies. However, only one can be applied. Every subsequent reference will be ignored. For example, here we reference two policies:
```yaml
policies:
- name: waf-policy-one
- name: waf-policy-two
```
In this example the Ingress Controller will use the configuration from the first policy reference `waf-policy-one`, and ignores `waf-policy-two`.

### Applying Policies

You can apply policies to both VirtualServer and VirtualServerRoute resources. For example:
Expand Down
82 changes: 82 additions & 0 deletions examples-of-custom-resources/waf/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# WAF

In this example we deploy the NGINX Plus Ingress controller with [NGINX App Protect](https://www.nginx.com/products/nginx-app-protect/), a simple web application and then configure load balancing and WAF protection for that application using the VirtualServer resource.

## Prerequisites

1. Follow the installation [instructions](../../docs/installation.md) to deploy the Ingress controller with NGINX App Protect.
1. Save the public IP address of the Ingress controller into a shell variable:
```
$ IC_IP=XXX.YYY.ZZZ.III
```
1. Save the HTTPS port of the Ingress controller into a shell variable:
```
$ IC_HTTPS_PORT=<port number>
```

## Step 1. Deploy a Web Application

Create the application deployment and service:
```
$ kubectl apply -f webapp.yaml
```

## Step 2 - Deploy the AP Policy

1. Create the syslog service and pod for the App Protect security logs:
```
$ kubectl apply -f syslog.yaml
```
1. Create the App Protect policy, log configuration and user defined signature:
```
$ kubectl apply -f ap-dataguard-alarm-policy.yaml
$ kubectl apply -f ap-logconf.yaml
$ kubectl apply -f ap-apple-uds.yaml
```

## Step 3 - Configure Load Balancing

Update the `logDest` field from `virtualserver.yaml` with the ClusterIP of the syslog service. For example, if the IP is `10.101.21.110`:
```yaml
waf:
...
logDest: "syslog:server=10.101.21.110:514"
```

Create the VirtualServer Resource:
```
$ kubectl apply -f virtualserver.yaml
```
Note the App Protect configuration settings in the Policy resource. They enable WAF protection by configuring App Protect with the policy and log configuration created in the previous step.

## Step 4 - Test the Application

1. To access the application, curl the coffee and the tea services. We'll use `curl`'s `--insecure` option to turn off certificate verification of our self-signed
certificate and the --resolve option to set the Host header of a request with `webapp.example.com`

Send a request to the application:
```
$ curl --resolve webapp.example.com:$IC_HTTPS_PORT:$IC_IP https://webapp.example.com:$IC_HTTPS_PORT/ --insecure
Server address: 10.12.0.18:80
Server name: webapp-7586895968-r26zn
...
```

Now, let's try to send a request with a suspicious URL:
```
$ curl --resolve webapp.example.com:$IC_HTTPS_PORT:$IC_IP "https://webapp.example.com:$IC_HTTPS_PORT/<script>" --insecure
<html><head><title>Request Rejected</title></head><body>
...
```
Lastly, let's try to send some suspicious data that matches the user defined signature.
```
$ curl --resolve webapp.example.com:$IC_HTTPS_PORT:$IC_IP -X POST -d "apple" "https://webapp.example.com:$IC_HTTPS_PORT/" --insecure
<html><head><title>Request Rejected</title></head><body>
...
```
As you can see, the suspicious requests were blocked by App Protect

1. To check the security logs in the syslog pod:
```
$ kubectl exec -it <SYSLOG_POD> -- cat /var/log/messages
```
18 changes: 18 additions & 0 deletions examples-of-custom-resources/waf/ap-apple-uds.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: appprotect.f5.com/v1beta1
kind: APUserSig
metadata:
name: apple
spec:
signatures:
- accuracy: medium
attackType:
name: Brute Force Attack
description: Medium accuracy user defined signature with tag (Fruits)
name: Apple_medium_acc
risk: medium
rule: content:"apple"; nocase;
signatureType: request
systems:
- name: Microsoft Windows
- name: Unix/Linux
tag: Fruits
34 changes: 34 additions & 0 deletions examples-of-custom-resources/waf/ap-dataguard-alarm-policy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
apiVersion: appprotect.f5.com/v1beta1
kind: APPolicy
metadata:
name: dataguard-alarm
spec:
policy:
signature-requirements:
- tag: Fruits
signature-sets:
- name: apple_sigs
block: true
signatureSet:
filter:
tagValue: Fruits
tagFilter: eq
applicationLanguage: utf-8
blocking-settings:
violations:
- alarm: true
block: false
name: VIOL_DATA_GUARD
data-guard:
creditCardNumbers: true
enabled: true
enforcementMode: ignore-urls-in-list
enforcementUrls: []
lastCcnDigitsToExpose: 4
lastSsnDigitsToExpose: 4
maskData: true
usSocialSecurityNumbers: true
enforcementMode: blocking
name: dataguard-alarm
template:
name: POLICY_TEMPLATE_NGINX_BASE
11 changes: 11 additions & 0 deletions examples-of-custom-resources/waf/ap-logconf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: appprotect.f5.com/v1beta1
kind: APLogConf
metadata:
name: logconf
spec:
content:
format: default
max_message_size: 64k
max_request_size: any
filter:
request_type: all
32 changes: 32 additions & 0 deletions examples-of-custom-resources/waf/syslog.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: syslog
spec:
replicas: 1
selector:
matchLabels:
app: syslog
template:
metadata:
labels:
app: syslog
spec:
containers:
- name: syslog
image: balabit/syslog-ng:3.28.1
ports:
- containerPort: 514
- containerPort: 601
---
apiVersion: v1
kind: Service
metadata:
name: syslog-svc
spec:
ports:
- port: 514
targetPort: 514
protocol: TCP
selector:
app: syslog
18 changes: 18 additions & 0 deletions examples-of-custom-resources/waf/virtual-server.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: webapp
spec:
host: webapp.example.com
policies:
- name: waf-policy
upstreams:
- name: webapp
service: webapp-svc
port: 80
routes:
- path: /
action:
pass: webapp
policies:
- name: waf-policy
12 changes: 12 additions & 0 deletions examples-of-custom-resources/waf/waf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
name: waf-policy
spec:
waf:
enable: true
apPolicy: "default/dataguard-alarm"
securityLog:
enable: true
apLogConf: "default/logconf"
logDest: "syslog:server=127.0.0.1:514"
Loading