Build and use the compiler tool
This document describes how to use the F5 WAF for NGINX compiler, a tool for converting security policies and logging profiles from JSON to a bundle file that F5 WAF can process and apply.
You can use it to get the latest security updates for Attack signatures, Threat campaigns and Bot signatures.
The compiler is packaged as a Docker image and can executed using the Docker CLI or as part of a continuous integration/continuous delivery (CI/CD) pipeline.
If you are using a virtual machine/bare-metal installation, read the Update F5 WAF for NGINX signatures topic.
If you are using a Helm-based Kubernetes deployment, read the Kubernetes operations improvements (Early access) topic.
One or more bundle files can be referenced in the NGINX configuration file, and you can configure global settings such as the cookie seed and user-defined signatures.
For more information about policies, read the Configure policies topic.
To complete this guide, you will need the following prerequisites:
- An active F5 WAF for NGINX subscription (Purchased or trial)
- Credentials to the MyF5 Customer Portal, provided by email from F5, Inc.
- Docker
- Log in to MyF5.
- Go to My Products & Plans > Subscriptions to see your active subscriptions.
- Find your NGINX subscription, and select the Subscription ID for details.
- Download the SSL Certificate and Private Key files from the subscription page.
Create a directory and copy your certificate and key to this directory:
mkdir -p /etc/docker/certs.d/private-registry.nginx.com
cp <path-to-your-nginx-repo.crt> /etc/docker/certs.d/private-registry.nginx.com/client.cert
cp <path-to-your-nginx-repo.key> /etc/docker/certs.d/private-registry.nginx.com/client.key
Log in to the Docker registry:
docker login private-registry.nginx.com
This example Dockerfile is based on a Debian image.
# syntax=docker/dockerfile:1
ARG BASE_IMAGE=private-registry.nginx.com/nap/waf-compiler:<version-tag>
FROM ${BASE_IMAGE}
# Installing packages as root
USER root
ENV DEBIAN_FRONTEND="noninteractive"
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 \
apt-get update \
&& apt-get install -y \
apt-transport-https \
lsb-release \
ca-certificates \
wget \
gnupg2 \
ubuntu-keyring \
&& wget -qO - https://cs.nginx.com/static/keys/app-protect-security-updates.key | gpg --dearmor | \
tee /usr/share/keyrings/app-protect-security-updates.gpg >/dev/null \
&& printf "deb [signed-by=/usr/share/keyrings/app-protect-security-updates.gpg] \
https://pkgs.nginx.com/app-protect-security-updates/ubuntu `lsb_release -cs` nginx-plus\n" | \
tee /etc/apt/sources.list.d/nginx-app-protect.list \
&& wget -P /etc/apt/apt.conf.d https://cs.nginx.com/static/files/90pkgs-nginx \
&& apt-get update \
&& apt-get install -y \
app-protect-attack-signatures \
app-protect-bot-signatures \
app-protect-threat-campaigns \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# non-root default user (UID 101)
USER nginx
You can can upgrade or downgrade one of the Signatures by specifying a specific version, such as app-protect-attack-signatures-2020.04.30.
You can use the Docker registry API to list the available image tags.
Replace <path-to-your-nginx-repo.key>
with the location of your client key and <path-to-your-nginx-repo.crt>
with the location of your client certificate.
curl -s https://private-registry.nginx.com/v2/nap/waf-compiler/tags/list --key <path-to-your-nginx-repo.key> --cert <path-to-your-nginx-repo.crt>
{
"name": "nap/waf-compiler",
"tags": [
"1.0.0",
"5.1.0",
"5.2.0"
]
}
The jq command was used to format the example output.
Run the following command to build your image, where waf-compiler-<version-tag>:custom
is an example of the image tag:
sudo docker build --no-cache --platform linux/amd64 \
--secret id=nginx-crt,src=nginx-repo.crt \
--secret id=nginx-key,src=nginx-repo.key \
-t waf-compiler-<version-tag>:custom .
Never upload your F5 WAF for NGINX images to a public container registry such as Docker Hub. Doing so violates your license agreement.
This section uses version-tag
as a placeholder in its examples, following the previous section. Ensure that all input files are accessible to UID 101.
To compile a security policy from a JSON file and create a policy bundle, run the following command:
docker run --rm \
-v $(pwd):$(pwd) \
waf-compiler-<version-tag>:custom \
-p $(pwd)/policy.json -o $(pwd)/compiled_policy.tgz
Ensure that the output directory is writable, otherwise you may encounter a permission denied error.
To use multiple policy bundles within a single NGINX configuration, you must supply a global settings JSON file.
This ensures that all bundles have a common foundation such as cookie seed and user-defined signatures.
An example global_settings.json
might look as follows:
{
"waf-settings": {
"cookie-protection": {
"seed": "<seed value>"
}
}
}
To compile a policy with global settings, add the -g
parameter:
docker run --rm \
-v $(pwd):$(pwd) \
waf-compiler-1.0.0:custom \
-g $(pwd)/global_settings.json -p $(pwd)/policy.json -o $(pwd)/compiled_policy.tgz
You can incorporate the source of the policy (as policy.json
) or logging profile (as logging_profile.json
) into the final bundle using the -include-source
parameter.
docker run --rm \
-v $(pwd):$(pwd) \
waf-compiler-1.0.0:custom \
-include-source -full-export -g $(pwd)/global_settings.json -p $(pwd)/policy.json -o $(pwd)/compiled_policy.tgz
This will transform any configuration that relies on external references into an inline configuration within the bundled source.
Additionally, when -include-source
is combined with -full-export
, the policy.json within the bundle will contain the entire source policy, including any default settings from the base template.
To compile a logging profile, execute the command below:
docker run \
-v $(pwd):$(pwd) \
waf-compiler-<version-tag>:custom \
-l $(pwd)/log_01.json -o $(pwd)/log01.tgz
To view information about a bundle file, such as attack signatures versions, use the following command:
docker run \
-v $(pwd):$(pwd) \
waf-compiler-<version-tag>:custom \
-dump -bundle $(pwd)/compiled_policy.tgz
When configuring policies, you may run into problems.
There are ways to remediate them based on the context:
Description | Solution |
---|---|
Expected declarative policy | Ensure the JSON of the policy is well-formed |
Policy Bundles version is older than the local version | You must recompile all your bundles from scratch when installing security updates. |
Policy Bundles version is newer than the local version | You must recompile all your bundles from scratch when installing security updates. |
Found mixed content of compiled and raw configuration | Only pre-compiled bundles can be used in NGINX configuration: compile JSON to bundles first. |
Compiler is required, but not installed: Missing /opt/app_protect/bin/config_set_compiler | Only pre-compiled bundles can be used in NGINX configuration: compile JSON to bundles first. |
Policy Bundles have differing global states | Recompile all of your bundles from scratch with your custom compiler. Bundles must be compiled with the same compiler: you cannot mix default and custom bundles. |
Policy Bundles have differing cookie seeds | Recompile all of your bundles from scratch with your custom compiler. Bundles must be compiled with the same compiler: you cannot mix default and custom bundles. |
Duplicate policy name found | Don’t compile multiple policies with the same name, or one policy to multiple bundles. Each policy can be compiled once but a bundle can be re-used. |
_Duplicate logging profile name found | Don’t compile the same logging profile to multiple bundles. Each profile can be compiled once but a bundle can be re-used. |
Timeout waiting for enforcer | Likely an internal issue: contact Support |
The global settings allows configuration of the following items:
Name | Type | Description |
---|---|---|
seed | string | The seed value is used by F5 WAF for NGINX to generate the encryption key for the cookies it creates. These cookies are used for various purposes such as validating the integrity of the cookies generated by the application. Use a random alphanumeric string of at least 20 characters length (but not more than 1000 characters). |
Name | Reference | Type | Description |
---|---|---|---|
$ref | Yes | string | Path to the file that contains the user defined signatures. |
{
"waf-settings": {
"cookie-protection": {
"seed": "80miIOiSeXfvNBiDJV4t"
},
"user-defined-signatures": [
{
"$ref": "file:///policies/uds.json"
}
]
}
}
When deploying multiple scalability instances (Such as Kubernetes deployment replicas), ensure that all policy bundles are compiled with the same global settings and security updates.
When executing commands inside the compiler container, ensure that you use /opt/app_protect/bin/apcompile
as the compiler binary.
This is particularly important if you’re overriding the default entry point as part of a CI/CD process.
/opt/app_protect/bin/apcompile -g /path/to/global_settings.json -p /path/to/policy.json -o /path/to/compiled_policy.tgz