generated from nginx/template-repository
-
Notifications
You must be signed in to change notification settings - Fork 120
PLM Overview and Installation #1060
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
Merged
ADubhlaoich
merged 4 commits into
nginx:nap-release-plm
from
zahava-brown:plm-overview-and-installation
Sep 8, 2025
Merged
Changes from 2 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
367 changes: 367 additions & 0 deletions
367
content/nap-waf/v5/admin-guide/policy-lifecycle-management.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,367 @@ | ||
--- | ||
title: Policy Lifecycle Management | ||
weight: 200 | ||
toc: true | ||
type: how-to | ||
product: NAP-WAF | ||
--- | ||
|
||
## Overview | ||
|
||
Policy Lifecycle Management (PLM) provides a comprehensive solution for automating the management, compilation, and deployment of security policies within Kubernetes environments. PLM extends the WAF compiler capabilities by providing a native Kubernetes operator-based approach to policy orchestration. | ||
|
||
The Policy Lifecycle Management system is architected around a **Policy Controller** that implements the Kubernetes operator pattern to manage the complete lifecycle of WAF security artifacts. The system addresses the fundamental challenge of policy distribution at scale by eliminating manual intervention points and providing a declarative configuration model through Custom Resource Definitions (CRDs) for policies, logging profiles, signatures, and user-defined signatures. | ||
|
||
## Prerequisites | ||
|
||
Before deploying Policy Lifecycle Management, ensure you have the following prerequisites: | ||
|
||
### System Requirements | ||
|
||
- Kubernetes cluster (tested with k3s) | ||
- Helm 3 installed | ||
- Docker installed and configured | ||
- NGINX Docker Image | ||
- NGINX JWT License | ||
- Docker registry credentials for private-registry.nginx.com | ||
|
||
### Custom Resource Definitions (CRDs) | ||
|
||
Policy Lifecycle Management requires specific Custom Resource Definitions to be applied before deployment. These CRDs define the resources that the Policy Controller manages: | ||
|
||
**Required CRDs:** | ||
- `appolicies.appprotect.f5.com` - Defines WAF security policies | ||
- `aplogconfs.appprotect.f5.com` - Manages logging profiles and configurations | ||
- `apusersigs.appprotect.f5.com` - Handles user-defined signatures | ||
- `apsignatures.appprotect.f5.com` - Manages signature updates and collections | ||
|
||
Apply the CRDs using the following command: | ||
```bash | ||
kubectl apply -f crds/ | ||
``` | ||
|
||
### NGINX Configuration | ||
|
||
Policy Lifecycle Management requires specific NGINX configuration to integrate with the Policy Controller. The key directive `app_protect_default_config_source` must be set to `"custom-resource"` to enable PLM integration. | ||
|
||
**Required NGINX Configuration:** | ||
|
||
```nginx | ||
user nginx; | ||
worker_processes auto; | ||
|
||
load_module modules/ngx_http_app_protect_module.so; | ||
|
||
error_log /var/log/nginx/error.log notice; | ||
pid /var/run/nginx.pid; | ||
|
||
events { | ||
worker_connections 1024; | ||
} | ||
|
||
http { | ||
include /etc/nginx/mime.types; | ||
default_type application/octet-stream; | ||
|
||
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' | ||
'$status $body_bytes_sent "$http_referer" ' | ||
'"$http_user_agent" "$http_x_forwarded_for"'; | ||
|
||
access_log stdout main; | ||
sendfile on; | ||
keepalive_timeout 65; | ||
|
||
app_protect_enforcer_address 127.0.0.1:50000; | ||
|
||
# Enable Policy Lifecycle Management | ||
app_protect_default_config_source "custom-resource"; | ||
|
||
app_protect_security_log_enable on; | ||
app_protect_security_log my-logging-cr /opt/app_protect/bd_config/s.log; | ||
|
||
server { | ||
listen 80; | ||
server_name localhost; | ||
proxy_http_version 1.1; | ||
|
||
location / { | ||
app_protect_enable on; | ||
|
||
# Reference to Custom Resource policy name | ||
app_protect_policy_file my-policy-cr; | ||
|
||
client_max_body_size 0; | ||
default_type text/html; | ||
proxy_pass http://127.0.0.1/proxy$request_uri; | ||
} | ||
|
||
location /proxy { | ||
app_protect_enable off; | ||
client_max_body_size 0; | ||
default_type text/html; | ||
return 200 "Hello! I got your URI request - $request_uri\n"; | ||
} | ||
} | ||
} | ||
``` | ||
|
||
**Key PLM-specific directives:** | ||
- `app_protect_default_config_source "custom-resource"` - Enables Policy Controller integration | ||
- `app_protect_policy_file my-policy-cr` - References the Custom Resource policy name instead of bundle file paths | ||
- `app_protect_security_log my-logging-cr` - References the Custom Resource logging configuration name | ||
|
||
## Helm Chart Configuration | ||
|
||
Policy Lifecycle Management is deployed as part of the NGINX App Protect Helm chart. To enable PLM, you must configure the Policy Controller settings in your `values.yaml` file. | ||
|
||
### Enabling Policy Controller | ||
|
||
Set the following configuration in your `values.yaml`: | ||
|
||
```yaml | ||
appprotect: | ||
policyController: | ||
enable: true | ||
replicas: 1 | ||
image: | ||
repository: private-registry.nginx.com/nap/waf-policy-controller | ||
tag: 5.8.0 | ||
imagePullPolicy: IfNotPresent | ||
wafCompiler: | ||
image: | ||
repository: private-registry.nginx.com/nap/waf-compiler | ||
tag: 5.8.0 | ||
enableJobLogSaving: false | ||
resources: | ||
requests: | ||
cpu: 100m | ||
memory: 128Mi | ||
``` | ||
|
||
### NGINX Repository Configuration | ||
|
||
To enable signature updates with the APSignatures CRD, configure the NGINX repository credentials: | ||
|
||
```yaml | ||
appprotect: | ||
nginxRepo: | ||
nginxCrt: <base64-encoded-cert> | ||
nginxKey: <base64-encoded-key> | ||
``` | ||
|
||
## Installation Flow | ||
|
||
### Step-by-Step Installation Process | ||
|
||
1. **Prepare Environment Variables** | ||
|
||
Set the required environment variables: | ||
```bash | ||
export JWT=<your-nginx-jwt-token> | ||
export NGINX_REGISTRY_TOKEN=<base64-encoded-docker-credentials> | ||
export NGINX_CERT=<base64-encoded-nginx-cert> | ||
export NGINX_KEY=<base64-encoded-nginx-key> | ||
``` | ||
|
||
2. **Pull the Helm Chart** | ||
|
||
Login to the registry and pull the chart: | ||
```bash | ||
helm registry login private-registry.nginx.com | ||
helm pull oci://private-registry.nginx.com/nap/nginx-app-protect --version <release-version> --untar | ||
cd nginx-app-protect | ||
``` | ||
|
||
3. **Apply Custom Resource Definitions** | ||
|
||
Apply the required CRDs before deploying the chart: | ||
```bash | ||
kubectl apply -f crds/ | ||
``` | ||
|
||
4. **Create Storage** | ||
|
||
Create the directory and persistent volume for policy bundles: | ||
```bash | ||
mkdir -p /mnt/nap5_bundles_pv_data | ||
chown -R 101:101 /mnt/nap5_bundles_pv_data | ||
kubectl apply -f <your-pv-yaml-file> | ||
``` | ||
|
||
{{< call-out "note" >}} | ||
The PV must have the name `<release-name>-bundles-pv` to be properly recognized by the Helm chart. | ||
{{< /call-out >}} | ||
|
||
5. **Configure Docker Registry Credentials** | ||
|
||
Create the Docker registry secret or configure in values.yaml: | ||
```bash | ||
kubectl create secret docker-registry regcred -n <namespace> \ | ||
--docker-server=private-registry.nginx.com \ | ||
--docker-username=<JWT-Token> \ | ||
--docker-password=none | ||
``` | ||
|
||
6. **Deploy the Helm Chart with Policy Controller** | ||
|
||
Install the chart with Policy Controller enabled: | ||
```bash | ||
helm install <release-name> . \ | ||
--namespace <namespace> \ | ||
--create-namespace \ | ||
--set appprotect.policyController.enable=true \ | ||
--set dockerConfigJson=$NGINX_REGISTRY_TOKEN \ | ||
--set appprotect.config.nginxJWT=$JWT \ | ||
--set appprotect.nginxRepo.nginxCert=$NGINX_CERT \ | ||
--set appprotect.nginxRepo.nginxKey=$NGINX_KEY | ||
``` | ||
|
||
7. **Verify Installation** | ||
|
||
Check that all components are deployed successfully: | ||
```bash | ||
kubectl get pods -n <namespace> | ||
kubectl get crds | grep appprotect.f5.com | ||
kubectl get all -n <namespace> | ||
``` | ||
|
||
## Using Policy Lifecycle Management | ||
|
||
### Creating Policy Resources | ||
|
||
Once PLM is deployed, you can create policy resources using Kubernetes manifests: | ||
|
||
**Sample APPolicy Resource:** | ||
```bash | ||
kubectl apply -f config/policy-manager/samples/appprotect_v1_appolicy.yaml | ||
zahava-brown marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
``` | ||
|
||
**Sample APUserSig Resource:** | ||
```bash | ||
kubectl apply -f config/policy-manager/samples/appprotect_v1_apusersigs.yaml | ||
zahava-brown marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
``` | ||
|
||
### Monitoring Policy Status | ||
|
||
Check the status of your policy resources: | ||
|
||
```bash | ||
kubectl get appolicy -n <namespace> | ||
kubectl describe appolicy <policy-name> -n <namespace> | ||
``` | ||
|
||
The Policy Controller will show status information including: | ||
- Bundle location | ||
- Compilation status | ||
- Signature update timestamps | ||
|
||
## Confirming Setup is Functioning | ||
|
||
### 1. Test Policy Compilation | ||
|
||
Apply the sample policy Custom Resource to verify PLM is working correctly: | ||
|
||
```bash | ||
kubectl apply -f config/policy-manager/samples/appprotect_v1_appolicy.yaml | ||
zahava-brown marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
``` | ||
|
||
### 2. Check Policy Compilation Status | ||
|
||
Verify that the policy has been compiled successfully by checking the Custom Resource status: | ||
|
||
```bash | ||
kubectl get appolicy <custom-resource-name> -n <namespace> -o yaml | ||
``` | ||
|
||
You should see output similar to this, with `state: ready` and no errors: | ||
|
||
```yaml | ||
status: | ||
bundle: | ||
compilerVersion: 11.553.0 | ||
location: /etc/app_protect/bundles/dataguard-blocking-policy/dataguard-blocking_policy20250904100458.tgz | ||
signatures: | ||
attackSignatures: "2025-08-28T01:16:06Z" | ||
botSignatures: "2025-08-27T11:35:31Z" | ||
threatCampaigns: "2025-08-25T09:57:39Z" | ||
state: ready | ||
processing: | ||
datetime: "2025-09-04T10:05:52Z" | ||
isCompiled: true | ||
``` | ||
|
||
### 3. Verify Policy Controller Logs | ||
|
||
Check the Policy Controller logs for expected compilation messages: | ||
|
||
```bash | ||
kubectl logs <policy-controller-pod> -n <namespace> | ||
``` | ||
|
||
Look for successful compilation messages like: | ||
|
||
``` | ||
2025-09-04T10:05:52Z INFO Job is completed {"controller": "appolicy", "controllerGroup": "appprotect.f5.com", "controllerKind": "APPolicy", "APPolicy": {"name":"dataguard-blocking","namespace":"localenv-plm"}, "namespace": "localenv-plm", "name": "dataguard-blocking", "reconcileID": "6bab7054-8a8a-411f-8ecc-01399a308ef6", "job": "dataguard-blocking-appolicy-compile"} | ||
|
||
2025-09-04T10:05:52Z INFO job state is {"controller": "appolicy", "controllerGroup": "appprotect.f5.com", "controllerKind": "APPolicy", "APPolicy": {"name":"dataguard-blocking","namespace":"localenv-plm"}, "namespace": "localenv-plm", "name": "dataguard-blocking", "reconcileID": "6bab7054-8a8a-411f-8ecc-01399a308ef6", "job": "dataguard-blocking-appolicy-compile", "state": "ready"} | ||
|
||
2025-09-04T10:05:52Z INFO bundle state was changed {"controller": "appolicy", "controllerGroup": "appprotect.f5.com", "controllerKind": "APPolicy", "APPolicy": {"name":"dataguard-blocking","namespace":"localenv-plm"}, "namespace": "localenv-plm", "name": "dataguard-blocking", "reconcileID": "6bab7054-8a8a-411f-8ecc-01399a308ef6", "job": "dataguard-blocking-appolicy-compile", "from": "processing", "to": "ready"} | ||
``` | ||
|
||
### 4. Verify Bundle Creation | ||
|
||
Check that the policy bundle has been created in the shared volume directory: | ||
|
||
```bash | ||
ls -la /mnt/nap5_bundles_pv_data/dataguard-blocking-policy/ | ||
``` | ||
|
||
You should see the compiled policy bundle file in the directory structure. | ||
|
||
### 5. Test Policy Enforcement | ||
|
||
To verify that the policy bundles are being deployed and enforced correctly: | ||
|
||
1. **Update NGINX Configuration** | ||
|
||
Use the Custom Resource name in your NGINX configuration: | ||
```nginx | ||
app_protect_policy_file dataguard-blocking; | ||
``` | ||
|
||
2. **Reload NGINX** | ||
|
||
Reload NGINX to apply the new policy: | ||
```bash | ||
nginx -s reload | ||
``` | ||
|
||
3. **Test Policy Enforcement** | ||
|
||
Send a request that should be blocked by the dataguard policy to verify it's working: | ||
```bash | ||
curl "http://[CLUSTER-IP]:80/?a=<script>" | ||
``` | ||
|
||
The request should be blocked, confirming that PLM has successfully compiled and deployed the policy. | ||
|
||
## Troubleshooting | ||
|
||
### Common Issues | ||
|
||
**Policy Controller Not Starting** | ||
- Verify CRDs are installed: `kubectl get crds | grep appprotect.f5.com` | ||
- Check pod logs: `kubectl logs <policy-controller-pod> -n <namespace>` | ||
- Ensure proper RBAC permissions are configured | ||
|
||
**Policy Compilation Failures** | ||
- Check Policy Controller logs for compilation errors | ||
- Verify WAF compiler image is accessible | ||
- Ensure policy syntax is valid | ||
|
||
**Bundle Storage Issues** | ||
- Verify persistent volume is properly mounted | ||
- Check storage permissions (should be 101:101) | ||
- Confirm PVC is bound to the correct PV | ||
|
||
For additional troubleshooting information, see the [Troubleshooting Guide]({{< ref "/nap-waf/v5/troubleshooting-guide/troubleshooting.md#nginx-app-protect-5" >}}). |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.