What this use case demonstrates
This use case deploys NGINX Ingress Controller (NIC) running NGINX Plus with NGINX App Protect V5 (NAP V5) as the in-cluster data plane on GKE. WAF runs on two layers: NAP V5 enforcing inside the cluster, F5 Distributed Cloud (XC) enforcing at the edge. XC also provides API discovery and protection driven by an OpenAPI spec.
It covers all four ADSP areas: Delivery, Security, Deployment, and xOps.
- Delivery: F5 Distributed Cloud HTTPS load balancer at the edge, NGINX Ingress Controller handling in-cluster delivery through the NIC VirtualServer CRD.
- Security: Two layers of WAF. NAP V5 runs as NIC sidecars (waf-enforcer and waf-config-mgr) and enforces the WAF policy attached to the VirtualServer. XC WAF runs at the edge in blocking mode. XC API protection is driven by an OpenAPI spec.
- Deployment: XC consumed as SaaS, GKE Standard with private nodes, NIC and NAP installed via OCI Helm chart, the application installed via a separate OCI Helm chart.
- xOps: NAP policy lives in config/uc2/nap/policy.json. The workflow compiles it with the NAP waf-compiler container, uploads the compiled bundle to GCS, and NIC mounts the bundle read-only via the GCS Fuse CSI driver. The waf-config-mgr sidecar watches the mount and pushes updates to the waf-enforcer. Change the policy, push, and NAP follows.
Architecture
What gets deployed:
- A GCP VPC with a dedicated k8s subnet (with secondary ranges for pods and services), management subnet, and NAT for private nodes
- A GKE Standard zonal cluster with private nodes and a control plane locked down by authorized networks
- NGINX Ingress Controller running NGINX Plus, with NAP V5 enforcer and config-mgr sidecars
- Comfy Capybara deployed via an OCI Helm chart, exposed through a NIC VirtualServer that references the waf-policy CRD in the nginx-ingress namespace
- An F5 Distributed Cloud HTTP load balancer with WAF and API protection. The origin pool is resolved from the NIC LoadBalancer IP via Terraform remote state.
The VirtualServer attaches waf-policy both server-wide and on the /api route by default, so the policy enforces everywhere as a baseline.
DevSecOps in practice for UC2
The lead-in covers the approach. For UC2, that means:
- Terraform handles infrastructure, the GKE cluster, NIC and NAP, the application Helm release, and all F5 Distributed Cloud objects. No click-ops.
- State lives in a GCS bucket the workflow creates on the first run, with a separate state file per module. The same bucket carries the compiled NAP policy bundle that NIC mounts via the GCS Fuse CSI driver. The XC origin pool reads the NIC LoadBalancer IP from state/uc2/nic, so no IP is pasted between configs.
- GitHub Actions runs the pipeline.
- Branch names trigger deployments, so git history shows what was meant to happen.
- GCP Workload Identity Federation replaces static service account keys for the runner. NIC pods also use Workload Identity to impersonate the runtime service account when mounting the NAP bundle from GCS.
- The XC API certificate, NGINX Plus JWT, and NGINX registry credentials live in GitHub Actions secrets, not the repo.
- The OpenAPI spec at config/uc2/app/oas/openapi.json is base64-encoded by the workflow and referenced inline by the XC API definition. Change the spec, push, and API protection follows.
The pipeline
Pushing to a branch runs the workflow. There is no manual terraform apply or helm install.
| Action | Branch |
|---|---|
| Validate, plan, and apply | deploy-adsp-uc2 |
| Validate only (no apply) | test-adsp-uc2 |
| Destroy all resources | destroy-adsp-uc2 |
Modules deploy sequentially: state bucket - infra - GKE - compile NAP policy - NIC and NAP - app - XC. Destroy runs in reverse.
What’s in the repo
f5devcentral/F5-ADSP-Automation:
| Directory | Purpose |
|---|---|
| infra/gcp/ | VPC, subnets with pod and service secondary ranges, NAT, firewall |
| k8s/gcp/ | GKE Standard cluster and node pool |
| f5/nic/gcp/ | NGINX Ingress Controller and NAP V5 Helm release |
| f5/xc/ | F5 Distributed Cloud HTTP LB, WAF, API definition (shared with other XC use cases) |
| app/gcp/ | Comfy Capybara Helm release and VirtualServer |
| config/uc2/gcp/env.json | GCP, GKE, and NIC config |
| config/uc2/nap/policy.json | NAP policy source, compiled in the workflow |
| config/uc2/app/env.json | Application chart and VirtualServer config |
| config/uc2/app/oas/openapi.json | OpenAPI spec the XC API definition is built from |
| config/uc2/xc/env.json | XC tenant, LoadBalancer, WAF and API feature flags |
| .github/workflows/ | CI/CD workflows |
Prerequisites, secrets, and troubleshooting are in the UC2 deployment guide.
Demo
Try it
Fork f5devcentral/F5-ADSP-Automation, set the secrets and tfvars from the deployment guide, and push to deploy-adsp-uc2. Push to destroy-adsp-uc2 to tear it down.
Contribute
Issues and PRs welcome at f5devcentral/F5-ADSP-Automation.
Resources:
F5 Application Delivery and Security Platform GitHub Repo and Automation Guide
ADSP Architecture Article Series:
Automating F5 ADSP Deployments (Intro)
Automating F5 ADSP Deployments (Part 1 - F5 XC WAF and BIG-IP Adv. WAF)
Automating F5 ADSP Deployments (Part 2 - F5 XC API Security and NGINX Ingress & App Protect)
Automating F5 ADSP Deployments (Part 3 - F5 XC API Protection and NGINX Ingress)
Automating F5 ADSP Deployments (Part 4 - F5 XC API Security and NGINX Gateway Fabric)
Automating F5 ADSP Deployments (Part 5 - F5 XC, BIG-IP APM, CIS, and NGINX Ingress)
Minimizing Security Complexity: Managing Distributed WAF Policies
