diff --git a/content/includes/nap-waf/config/common/forward-proxy-conf.md b/content/includes/nap-waf/config/common/forward-proxy-conf.md new file mode 100644 index 000000000..eca8f09bc --- /dev/null +++ b/content/includes/nap-waf/config/common/forward-proxy-conf.md @@ -0,0 +1,20 @@ +Enable Forward Proxy Settings for IP Intelligence Client. + +To configure proxy settings, edit the client configuration file: +Path: +```shell +/etc/app_protect/tools/iprepd.cfg +``` +Example configuration: +```shell +EnableProxy=True +ProxyHost=5.1.2.4 +ProxyPort=8080 +ProxyUsername=admin # Optional +ProxyPassword=admin # Optional +CACertPath=/etc/ssl/certs/ca-certificates.crt # Optional +``` +After saving the changes, restart the client to apply the new settings. +```shell +/opt/app_protect/bin/iprepd /etc/app_protect/tools/iprepd.cfg > ipi.log 2>&1 & +``` diff --git a/content/includes/nap-waf/config/common/ip-groups-override-rules.md b/content/includes/nap-waf/config/common/ip-groups-override-rules.md new file mode 100644 index 000000000..e9c2ff0f5 --- /dev/null +++ b/content/includes/nap-waf/config/common/ip-groups-override-rules.md @@ -0,0 +1,62 @@ +#### IP-Address-Lists feature as part of Override Rules feature. + +The Override Rules feature allows you to override original or parent policy settings. + +Rules are defined using specific conditions, which can include an IP Address Lists based on the declarative policy JSON schema. + +When triggered, the rule is applied to the _clientIp_ attribute using the _matches_ function. + +'clientIp.matches(ipAddressLists["standalone"])' + +Here is a policy example: + +```json +{ + "policy": { + "name": "ip_group_override_rule", + "template": { + "name": "POLICY_TEMPLATE_NGINX_BASE" + }, + "applicationLanguage": "utf-8", + "caseInsensitive": false, + "enforcementMode": "blocking", + "ip-address-lists": [ + { + "name": "standalone", + "ipAddresses": [ + { + "ipAddress": "1.1.1.1/32" + } + ] + } + ], + "override-rules": [ + { + "name": "myRule1", + "condition": "clientIp.matches(ipAddressLists['standalone'])", + "actionType": "extend-policy", + "override": { + "policy": { + "enforcementMode": "transparent" + } + } + } + ] + } +} +``` + +The previous example policy contains an IP address lists with the name "standalone", used for the override rule condition "clientIp.matches(ipAddressLists['standalone'])". +The condition means that the rule enforcement is applied and override base policy enforcement when clientIp is matched to one of ipAddresses in ipAddressList with name "standalone". +The value used for the override condition must exist and exactly match the name in "ip-address-lists". + +#### Possible errors + +| Error text | Input | Explanation | +| -----------| ------------- | ------------ | +| _Invalid field invalidList_ | _clientIp.matches(invalidList['standalone']);_ | An incorrect keyword was used instead of _ipAddressLists_ | +| _Invalid value empty string_ | _clientIp.matches(ipAddressLists['']_ | An empty name was provided | +| _Failed to compile policy - 'ipGroupOverridePolicy'_ | _uri.matches(ipAddressLists['standalone']);_ | Used _ipAddressLists_ without the _clientIP_ attribute | + + + diff --git a/content/includes/nap-waf/config/common/ip-groups-overview.md b/content/includes/nap-waf/config/common/ip-groups-overview.md new file mode 100644 index 000000000..d1729a7d0 --- /dev/null +++ b/content/includes/nap-waf/config/common/ip-groups-overview.md @@ -0,0 +1,81 @@ +IP address lists is a feature to organize lists of allowed and forbidden IP addresses across several lists with common attributes. + +This allows you to control unique policy settings for incoming requests based on specific IP addresses. + +Each IP address list contains a unique name, enforcement type (_always_, _never_ and _policy-default_), and list of IP addresses. + + +An example of a declarative policy using IP address lists configuration: + +```json +{ + "policy": { + "name": "IpGroups_policy", + "template": { + "name": "POLICY_TEMPLATE_NGINX_BASE" + }, + "applicationLanguage": "utf-8", + "caseInsensitive": false, + "enforcementMode": "blocking", + "ip-address-lists": [ + { + "name": "Standalone", + "description": "Optional Description", + "blockRequests": "policy-default", + "setGeolocation": "IN", + "ipAddresses": [ + { + "ipAddress": "1.2.3.4/32" + }, + { + "ipAddress": "1111:fc00:0:112::2" + } + ] + } + ] + } +} + +``` +The example with IP-Group definition in external file external_ip_groups.json: + +```json +{ + "policy": { + "name": "IpGroups_policy2", + "template": { + "name": "POLICY_TEMPLATE_NGINX_BASE" + }, + "applicationLanguage": "utf-8", + "caseInsensitive": false, + "enforcementMode": "blocking", + "ip-address-lists": [ + { + "name": "external_ip_groups", + "description": "Optional Description", + "blockRequests": "always", + "setGeolocation": "IL", + "$ref": "file:///tmp/policy/external_ip_groups.json" + } + ] + } +} +``` +Example of the file external_ip_groups.json + +```json +{ + "name": "External IP address lists", + "description": "Optional Description", + "blockRequests": "always", + "setGeolocation": "IR", + "ipAddresses": [ + { + "ipAddress": "66.51.41.21" + }, + { + "ipAddress": "66.52.42.22" + } + ] +} +``` diff --git a/content/includes/nap-waf/config/common/ip-intelligence-conf.md b/content/includes/nap-waf/config/common/ip-intelligence-conf.md new file mode 100644 index 000000000..094b42cb6 --- /dev/null +++ b/content/includes/nap-waf/config/common/ip-intelligence-conf.md @@ -0,0 +1,121 @@ + + +NGINX App Protect WAF provides an IP Intelligence feature, which allows customizing the enforcement based on the source IP of the request to limit access from IP addresses with questionable reputation. Please note that: +- The IP intelligence feature is **disabled** by default and needs to be installed, enabled, and configured within the policy. +- To review the installation steps, please refer to the administration guide: [App Protect v4]({{< ref "/nap-waf/v4/admin-guide/install.md#Prerequisites" >}}) / [App Protect v5]({{< ref "/nap-waf/v5/admin-guide/install.md#Prerequisites" >}}) +- The system must have an active Internet connection and a working DNS. +- If NGINX App Protect is behind a firewall, ensure external access to vector.brightcloud.com over port 443 - this is the IP Intelligence server used for data retrieval. +- If NGINX App Protect accesses the Internet through a forward proxy server, ensure that it is configured correctly [App Protect v4]({{< ref "/nap-waf/v4/configuration-guide/configuration.md#ip-intelligence-forward-proxy-configuration" >}}) / [App Protect v5]({{< ref "/nap-waf/v5/configuration-guide/configuration.md##ip-intelligence-forward-proxy-configuration" >}}). + +Once installed, make sure to enable the feature in the two relevant sections of the policy: +1. By enabling the corresponding violation in the violation list: `"name": "VIOL_MALICIOUS_IP"` and assigning the appropriate `block` and `alarm` values to the violation. + +2. By enabling the feature in the corresponding IP Intelligence JSON section: `"ip-intelligence": {"enabled": true}` and defining actions for the IP Intelligence categories listed below. + +An example policy where both elements are enabled, and all the IP intelligence categories are configured to `block` and `alarm` can be found here: + +```json +{ + "policy": { + "name": "ip_intelligency_policy", + "template": { + "name": "POLICY_TEMPLATE_NGINX_BASE" + }, + "applicationLanguage": "utf-8", + "caseInsensitive": false, + "enforcementMode": "blocking", + "blocking-settings": { + "violations": [ + { + "name": "VIOL_MALICIOUS_IP", + "alarm": true, + "block": true + } + ] + }, + "ip-intelligence": { + "enabled": true, + "ipIntelligenceCategories": [ + { + "category": "Anonymous Proxy", + "alarm": true, + "block": true + }, + { + "category": "BotNets", + "alarm": true, + "block": true + }, + { + "category": "Cloud-based Services", + "alarm": true, + "block": true + }, + { + "category": "Denial of Service", + "alarm": true, + "block": true + }, + { + "category": "Infected Sources", + "alarm": true, + "block": true + }, + { + "category": "Mobile Threats", + "alarm": true, + "block": true + }, + { + "category": "Phishing Proxies", + "alarm": true, + "block": true + }, + { + "category": "Scanners", + "alarm": true, + "block": true + }, + { + "category": "Spam Sources", + "alarm": true, + "block": true + }, + { + "category": "Tor Proxies", + "alarm": true, + "block": true + }, + { + "category": "Web Attacks", + "alarm": true, + "block": true + }, + { + "category": "Windows Exploits", + "alarm": true, + "block": true + } + ] + } + } +} +``` + +This policy will basically block `"block": true` all IP addresses that are part of any threat category and add a log entry `"alarm": true` for the transaction. + +The IP address database is managed by an external provider and is constantly updated (every 1 minute by default). The database also categorizes IP addresses into one or more threat categories. These are the same categories that can be configured individually in the IP intelligence section: +- Anonymous Proxy +- BotNets +- Cloud-based Services +- Denial of Service +- Infected Sources +- Mobile Threats +- Phishing Proxies +- Scanners +- Spam Sources +- Tor Proxies +- Web Attacks +- Windows Exploits + +Note that since the IP address database is constantly updated, IP address enforcement is also expected to change. IP Addresses may be added, removed, or moved from one category to another based on the reported activity of the IP address. diff --git a/content/includes/nap-waf/config/v5/build-nginx-image-oss/build-rocky.md b/content/includes/nap-waf/config/v5/build-nginx-image-oss/build-rocky.md new file mode 100644 index 000000000..00f2fcd65 --- /dev/null +++ b/content/includes/nap-waf/config/v5/build-nginx-image-oss/build-rocky.md @@ -0,0 +1,41 @@ +```dockerfile +# syntax=docker/dockerfile:1 + +# Base Image +FROM rockylinux:9 + +# Install NGINX OSS and NGINX App Protect WAF v5 module +RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ + --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ + dnf -y install wget ca-certificates yum-utils \ + && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ + && echo "[nginx-mainline]" > /etc/yum.repos.d/nginx.repo \ + && echo "name=nginx mainline repo" >> /etc/yum.repos.d/nginx.repo \ + && echo "baseurl=http://nginx.org/packages/mainline/centos/\$releasever/\$basearch/" >> /etc/yum.repos.d/nginx.repo \ + && echo "gpgcheck=1" >> /etc/yum.repos.d/nginx.repo \ + && echo "enabled=1" >> /etc/yum.repos.d/nginx.repo \ + && echo "gpgkey=https://nginx.org/keys/nginx_signing.key" >> /etc/yum.repos.d/nginx.repo \ + && echo "module_hotfixes=true" >> /etc/yum.repos.d/nginx.repo \ + && echo "[app-protect-x-oss]" > /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ + && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ + && echo "baseurl=https://pkgs.nginx.com/app-protect-x-oss/centos/${UBI_VERSION}/\$basearch/" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ + && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ + && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ + && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ + && echo "enabled=1" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ + && dnf clean all \ + && dnf install -y app-protect-module-oss \ + && dnf clean all \ + && rm -rf /var/cache/dnf \ + && ln -sf /dev/stdout /var/log/nginx/access.log \ + && ln -sf /dev/stderr /var/log/nginx/error.log + +# Expose port +EXPOSE 80 + +# Define stop signal +STOPSIGNAL SIGQUIT + +# Set default command +CMD ["nginx", "-g", "daemon off;"] +``` diff --git a/content/includes/nap-waf/config/v5/build-nginx-image-plus/build-rocky.md b/content/includes/nap-waf/config/v5/build-nginx-image-plus/build-rocky.md new file mode 100644 index 000000000..e0362cd74 --- /dev/null +++ b/content/includes/nap-waf/config/v5/build-nginx-image-plus/build-rocky.md @@ -0,0 +1,35 @@ +```dockerfile +# syntax=docker/dockerfile:1 + +# Base Image +FROM rockylinux:9 + +# Install NGINX Plus and NGINX App Protect WAF v5 module +RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ + --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ + dnf -y install wget ca-certificates \ + && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ + && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/${NGINX_PLUS_REPO} \ + && echo "[app-protect-x-plus]" > /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ + && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ + && echo "baseurl=https://pkgs.nginx.com/app-protect-x-plus/centos/${UBI_VERSION}/\$basearch/" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ + && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ + && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ + && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ + && echo "enabled=1" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ + && dnf clean all \ + && dnf install -y app-protect-module-plus \ + && dnf clean all \ + && rm -rf /var/cache/dnf \ + && ln -sf /dev/stdout /var/log/nginx/access.log \ + && ln -sf /dev/stderr /var/log/nginx/error.log + +# Expose port +EXPOSE 80 + +# Define stop signal +STOPSIGNAL SIGQUIT + +# Set default command +CMD ["nginx", "-g", "daemon off;"] +``` diff --git a/content/includes/nap-waf/ip-intelligence.md b/content/includes/nap-waf/ip-intelligence.md new file mode 100644 index 000000000..31f173479 --- /dev/null +++ b/content/includes/nap-waf/ip-intelligence.md @@ -0,0 +1,67 @@ +If the deployment intends to use the IP intelligence Feature (available from version 5.7.0), then the IP intelligence container needs to be added to the deployment in the docker compose file. + +Modify the original `docker-compose.yml` file to include the additional IP Intelligence container: + +```yaml +services: + waf-enforcer: + container_name: waf-enforcer + image: private-registry.nginx.com/nap/waf-enforcer:5.7.0 + environment: + - ENFORCER_PORT=50000 + ports: + - "50000:50000" + volumes: + - /opt/app_protect/bd_config:/opt/app_protect/bd_config + - /var/IpRep:/var/IpRep + networks: + - waf_network + restart: always + user: "101:101" + depends_on: + - waf-ip-intelligence + + waf-config-mgr: + container_name: waf-config-mgr + image: private-registry.nginx.com/nap/waf-config-mgr:5.7.0 + volumes: + - /opt/app_protect/bd_config:/opt/app_protect/bd_config + - /opt/app_protect/config:/opt/app_protect/config + - /etc/app_protect/conf:/etc/app_protect/conf + restart: always + user: "101:101" + network_mode: none + depends_on: + waf-enforcer: + condition: service_started + + waf-ip-intelligence: + container_name: waf-ip-intelligence + image: private-registry.nginx.com/nap/waf-ip-intelligence:5.7.0 + volumes: + - /var/IpRep:/var/IpRep + networks: + - waf_network + restart: always + user: "101:101" + +networks: + waf_network: + driver: bridge +``` + +Notes: +- Replace `waf-config-mgr`, `waf-enforcer` and `waf-ip-intelligence` tags with the actual release version tag you are deploying. We are using version 5.7.0 for this example deployment. +- By default, the containers `waf-config-mgr`, `waf-enforcer` and `waf-ip-intelligence` operate with the user and group IDs set to 101:101. Ensure that the folders and files are accessible to these IDs. + +Before creating the deployment in docker compose, create the required directories: + +```shell +sudo mkdir -p /opt/app_protect/config /opt/app_protect/bd_config /var/IpRep +``` + +Then set correct ownership: + +```shell +sudo chown -R 101:101 /opt/app_protect/ /var/IpRep +``` diff --git a/content/includes/nap-waf/policy.html b/content/includes/nap-waf/policy.html index de530f555..0d84e0c67 100644 --- a/content/includes/nap-waf/policy.html +++ b/content/includes/nap-waf/policy.html @@ -270,153 +270,160 @@

policy

+ip-intelligence +Yes +object + + + + json-profiles Yes array of objects - + json-validation-files Yes array of objects - + login-enforcement Yes object - + login-pages Yes array of objects A login page is a URL in a web application that requests must pass through to get to the authenticated URLs. Use login pages, for example, to prevent forceful browsing of restricted parts of the web application, by defining access permissions for users. Login pages also allow session tracking of user sessions. - + methods Yes array of objects - + name No string The unique user-given name of the policy. Policy names cannot contain spaces or special characters. Allowed characters are a-z, A-Z, 0-9, dot, dash (-), colon (:) and underscore (_). - + open-api-files Yes array of objects - + override-rules Yes array of objects This section defines policy override rules. - + parameters Yes array of objects This section defines parameters that the security policy permits in requests. - + performStaging No boolean Determines staging handling for all applicable entities in the policy, such as signatures, URLs, parameters, and cookies. If disabled, all entities will be enforced and any violations triggered will be considered illegal. - + response-pages Yes array of objects The Security Policy has a default blocking response page that it returns to the client when the client request, or the web server response, is blocked by the security policy. You can change the way the system responds to blocked requests. All default response pages contain a variable, <%TS.request.ID()%>, that the system replaces with a support ID number when it issues the page. - + sensitive-parameters Yes array of objects This section defines sensitive parameters. The contents of these parameters are not visible in logs nor in the user interfaces. Instead of actual values a string of asterisks is shown for these parameters. Use these parameters to protect sensitive user input, such as a password or a credit card number, in a validated request. A parameter name of "password" is always defined as sensitive by default. - + server-technologies Yes array of objects The server technology is a server-side application, framework, web server or operating system type that is configured in the policy in order to adapt the policy to the checks needed for the respective technology. - + signature-requirements Yes array of objects - + signature-sets Yes array of objects Defines behavior when signatures found within a signature-set are detected in a request. Settings are culmulative, so if a signature is found in any set with block enabled, that signature will have block enabled. - + signature-settings Yes object - + signatures Yes array of objects This section defines the properties of a signature on the policy. - + template Yes object Specifies the template to populate the default attributes of a new policy. - + threat-campaigns Yes array of objects This section defines the enforcement state for the threat campaigns in the security policy. - + urls Yes array of objects In a security policy, you can manually specify the HTTP URLs that are allowed (or disallowed) in traffic to the web application being protected. When you create a security policy, wildcard URLs of * (representing all HTTP URLs) are added to the Allowed HTTP URLs lists. - + wafEngineVersion No string - + xml-profiles Yes array of objects @@ -2849,13 +2856,13 @@

ip-address-lists

Specifies how the system responds to blocking requests sent from this IP address list.
-

Optional

+

Optional, if absent Policy Default is used.