application delivery
43318 TopicsF5OS using Ansible Linux Shell with remote users as iCall replacement(works with banner as well).
(AI Made picture so don't take it as 100% truth) In F5OS 1.8.0 and up remote users can automatically enter the Linux Shell if they have the correct remote group parameters and if this is system level enabled as shown in https://clouddocs.f5.com/training/community/rseries-training/html/rseries_security.html#superuser-role The superuser role if enabled can still trigger F5OS commands with "f5sh" that is similar to "tmsh" in TMOS and described in https://my.f5.com/manage/s/article/K000148922 . Code version: The code was tested on F5OS 1.8.4 rSeries 5900 Ansible Example without banner: --- - name: Restart docker container hosts: f5os gather_facts: no vars: container_name: tcpdumpd_manager tasks: - name: Restart the specified docker container ansible.builtin.shell: | docker restart {{ container_name }} become: false args: executable: /bin/bash Cronjobs also can be edited through shell Ansible playbook for scheduling transferred scripts. - name: Add cron job ansible.builtin.shell: | (crontab -l 2>/dev/null | grep -Fv '/opt/check_service.sh'; \ echo '*/5 * * * * /opt/check_service.sh') | crontab - become: false args: executable: /bin/bash Great Ansible F5OS automation article with cool examples that even has file transfer for transferring script file to the F5OS: Five Ways to Automate F5OS with Ansible: A Practical Guide | DevCentral Ansible Example with banner: The F5OS ssh banner is inserted between the username and password and that breaks the shell module as I did found out. I suspect that Ansible uses the PEXPECT Python package that spans SSH session and it is similar to TCL EXPECT and most people dealing with iRules will find this interesting. You need to add sudo in-front of each command. - name: Restart container hosts: localhost gather_facts: false tasks: - name: Run docker command ansible.builtin.expect: command: >- ssh -tt -o StrictHostKeyChecking=no -o ConnectTimeout=10 -o ServerAliveInterval=5 -o ServerAliveCountMax=2 {{ ansible_user }}@{{ ansible_host }} responses: '(?i)password:': {{ ansible_pass }} '(?m)\$\s*$': "sudo docker restart {{ container_name }}\nexit\n" timeout: 20 echo: true delegate_to: localhost register: out Also SCP file transfer can be done through the EXPEC module. From Linux bash you can use f5sh to trigger F5OS commands. Examples are f5sh "show interface" and to chain commands f5sh "config; vlan 500; commit; exit" . If you just write f5sh, you will enter the F5os from the Linux. This is like tmsh for TMOS. Summary! This is great feature. TMOS also has cronjobs but after upgrade the cronjob is lost but not on F5OS, this is why icall scripts still are better for TMOS Tenants. iCall has the option to be triggered by logs and that in F5OS will be harder as it will need a bash script that is sitting as a background process as to monitor the logs and a cronjob can check if the script is still running as a device reboot will cause the script to stop running. The script can be transferred and started the way I have shown with RESTCONF REST-API with Ansible/AWX as the best option.120Views2likes1CommentAzure application gateway as backend pool of F5 VS
Hi All, I am facing an issue with the below setup and need some guidance. Architecture: Internet Client → F5 VIP → Azure Application Gateway (Internal IP) → Backend Application The requirement is to publish the application through F5, where the backend pool member is the internal IP address of an Azure Application Gateway. Issue: If I configure the F5 pool health monitor as TCP, the pool member becomes UP. If I configure the health monitor as HTTP or HTTPS, the pool member remains DOWN. Accessing the Azure Application Gateway directly (using its internal IP and required hostname) works successfully. The issue only happens when traffic passes through F5. SSL/TLS Configuration: SSL certificate is configured on F5 VIP. The same application certificate is also configured on Azure Application Gateway listener. Hostname used by the application We have already tried server SNI configuration on F5 and multiple SSL profile settings, but the issue is not resolved. Troubleshooting already performed: Verified Azure Application Gateway backend configuration. Confirmed Application Gateway listener and certificate are working when accessed directly. Tested F5 TCP health monitor successfully. Tested HTTP/HTTPS monitors from F5, but they fail. Raised a case with F5, and they advised checking from the Azure Application Gateway side. Appreciate your support.58Views0likes3CommentsA Method for the Madness: Meet HTTP QUERY
Note the to reader: I saw a headline on the new QUERY method and in a quick read didn't really understand the need, so I did a deep dive with Claude to understand the method itself, then followed with the larger infrastructure, security, and operational impacts for the implementation transitional period. This article is a summary of that session and co-authored by Claude. Every REST API grows a POST /search endpoint sooner or later — not because POST is the right tool for reading data, but because GET can't carry a body and your filter JSON stopped fitting in the URL years ago. The IETF closed that gap. On 15 June 2026 the RFC Editor published RFC 10008, "The HTTP QUERY Method" — a 24-page Proposed Standard on the IETF Standards Track. It's the first genuinely new HTTP method since PATCH landed as RFC 5789 in 2010, a 16-year gap. QUERY gives you the one thing GET and POST each refuse to provide: a safe, idempotent, cacheable request that carries a body. The TL;DR What it is: QUERY is a new, IANA-registered HTTP method that is safe and idempotent like GET, but carries a request body like POST. The body defines the query. Why it exists: GET is semantically correct for reads but forces the query into the URL (length limits, encoding pain, logging/bookmarking leakage). POST /search carries a body but lies to the infrastructure — nothing in the protocol signals the request is read-only, so caches, retry logic, and proxies can't treat it as one. QUERY is the missing middle. What's new on the wire: Nothing special. Any existing HTTP/1.1 or HTTP/2 connection carries it today. The friction is at every layer that has opinions about methods. The security headline: "Safe" is a promise about intent, not a guarantee about payloads. QUERY bodies need POST-level inspection, cache keys must include the full body (or you get cache poisoning), CSRF checks still apply to any endpoint with side effects, and method allowlists written before June 2026 don't know QUERY exists. Where support stands (mid-2026): Node.js has parsed QUERY since early 2024; OpenAPI 3.2 documents it; browsers can send it via fetch()/XHR but don't yet cache it; declarative HTML forms fall back to GET and drop the body; Spring hasn't shipped support. Treat it as production-ready for server-to-server, early-stage for browser-facing traffic. What to do: Don't rip out POST /search. QUERY sits alongside GET and POST — migrate gradually, and confirm every infrastructure layer handles it deliberately before real traffic arrives. The two-tool problem For as long as most of us have built APIs, reading data from a server meant choosing between two imperfect tools. GET has exactly the semantics you want for reads: safe (no state change expected), idempotent, and cacheable. The catch is that GET has no generally defined semantics for a request body — core HTTP semantics (RFC 9110 §9.3.1) even warn that a body on a GET can lead implementations to reject the request or treat it as a request-smuggling attempt. So the query has to go in the URL, and that runs into hard walls: URL length limits vary per proxy, load balancer, and server, and you discover the smallest one in the chain at runtime. RFC 9110 only recommends supporting URIs of at least ~8,000 octets, and that's a floor, not a promise. Some data is awkward to encode in a URI at all. Request URIs get logged, bookmarked, and dropped into Referer headers and analytics. And a nested filter object with arrays and boolean logic becomes an unreadable, fragile query string. POST fixes the body problem and creates a semantic one. A POST can create a record, update state, trigger a job, submit a form, or just run a search — and the HTTP layer can't tell which. Your application knows POST /search is read-only, but that's a private agreement between the server and the humans who wrote it. The caches, proxies, retry logic, CORS, gateways, and WAFs in the middle only see "POST," so they treat it as unsafe: not cacheable, not auto-retryable. Even a 200 OK doesn't tell them whether state changed. What QUERY actually does QUERY is the obvious hybrid: body support from POST, safe-and-idempotent semantics from GET. QUERY /users HTTP/1.1 Host: example.org Content-Type: application/json { "role": "admin", "status": "active", "sort": "name", "page": 1 } Because the method is declared safe and idempotent — and IANA-registered as such — the infrastructure can finally reason about it. A dropped QUERY can be automatically retried or restarted without worrying about partial state changes. Responses are cacheable. And the request finally tells the truth about what it's doing. A few spec details worth knowing: No new status codes, no new content types. QUERY reuses the existing vocabulary. A missing media type earns a 400; an unsupported one earns a 415; a syntactically valid query that can't be processed (say, correct SQL against a nonexistent table) earns a 422. Accept-Query for discovery. A response header a resource uses to advertise QUERY support and the media types it accepts, so clients can discover support instead of trial-and-erroring into a 405 Method Not Allowed. Cache key includes the body. This is the whole trick that makes a body-carrying request cacheable — and, as we'll see, the whole security footgun. A URI escape hatch. The server can respond to a QUERY with a Location / Content-Location header, assigning a stable URI to the query and its result, so clients can GET that URI afterward. This restores bookmarking and sharing, which you lose when the condition moves from the URL into the body. The name, for the curious: early drafts used SEARCH, borrowed from the WebDAV family (alongside PROPFIND and REPORT). The working group settled on QUERY because it maps cleanly to the URI's query component and describes a generic safe-read operation rather than implying one specific use case. The security implications most coverage skips Here's the part that matters more than the protocol itself. QUERY is well specified; the surrounding security assumptions are what need a second look. For nearly three decades, developers and security teams have built applications, APIs, WAFs, proxies, and tooling around a fixed set of verbs — GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS. A new one that behaves like a GET/POST hybrid breaks assumptions baked into all of those layers. 1. "Safe" describes intent, not payload This is the single most important thing to internalize. The safe designation means the client is not requesting a state change. It says nothing about whether the body is malicious. A QUERY body can carry SQL injection, XSS, command injection, or an oversized payload just as easily as a POST body can. Any WAF/IDS rule set that inspects POST bodies for these patterns must apply the same coverage to QUERY — SQLi, XSS, and command-injection inspection, plus request size limits. Give QUERY POST-level scrutiny at the body, even while trusting its read-only semantics for caching and retries. Treating "safe" as "harmless" is the mistake that turns a clean protocol upgrade into an open door. 2. Cache poisoning and cache deception QUERY is explicitly cacheable, and RFC 10008's cache model requires the cache key to incorporate the request body. That's non-negotiable, because otherwise two different queries to the same URL would collide. The risk: a cache that hashes or normalizes the body incorrectly — or normalizes it differently than the origin processes it — can return the wrong response on a false-positive key match. That's cache poisoning (an attacker plants a response that later gets served to victims) and cache deception (a victim's sensitive response gets cached under a key an attacker can retrieve) in one bug class. It's the same underlying failure as the GitHub Actions cache-poisoning attacks — the cache key doesn't capture the full request — just at a different layer of the stack. Any cache you enable for QUERY needs an explicit audit of how it derives keys from the body. Worth noting: as of mid-2026, current Chrome and Firefox send QUERY but don't cache repeated identical QUERYs yet. So browser-side caching is unimplemented rather than solved — the poisoning surface today lives in your CDN, reverse proxy, and API gateway. 3. The CSRF trap Because QUERY is labeled "safe," it's tempting to exclude it from CSRF protection the way you might exclude GET. Don't. The safe designation is a semantic promise, not an enforcement mechanism. If any endpoint accepts QUERY and has any side effect — logging that mutates state, a search that also writes an audit record, a "read" that lazily provisions something — it must remain covered by CSRF checks regardless of the method's designation. Middleware that method-matches on POST|PUT|DELETE|PATCH will silently skip QUERY. Extend it explicitly. 4. Method allowlists and request-smuggling flags Most WAFs, API gateways, and load balancers enforce method allowlists written as literal sets — and those written before June 2026 don't mention QUERY. Two failure modes result, and they pull in opposite directions: Reject: strict setups drop QUERY as an unknown verb, and your rollout silently fails at the edge. Pass through uninspected: looser setups forward QUERY but skip the body inspection they apply to POST — the worst outcome, an inspection blind spot. There's also a genuine request-smuggling dimension. Many enterprise WAFs flag non-standard verbs as protocol anomalies or smuggling vectors, precisely because inconsistent method handling across a proxy chain is how desync attacks start. If your CDN, WAF, and origin disagree about whether QUERY is valid — or one preserves the body while another strips it — you've created exactly the kind of parsing inconsistency smuggling exploits. On AWS, for example, CloudFront must be explicitly configured to forward QUERY with its body, and AWS WAF Core Rule Sets need QUERY deliberately whitelisted rather than caught by anomaly rules. The fix everywhere is the same: make QUERY a deliberate decision at every hop, not an accident. For penetration testers, the flip side is a fresh request type worth throwing at filters tuned for the usual suspects. Rules that catch a POST-body payload may not fire on the identical payload sent via QUERY. 5. Content-Type must be enforced, not sniffed RFC 10008 requires rejecting requests whose Content-Type is missing or inconsistent with the body, and explicitly forbids content sniffing — a server may not guess the media type and override a missing or wrong one. If you accept application/json, parse it as JSON; if you use a custom query DSL, define its media type and advertise it via Accept-Query. Leave this vague and you've simply carried the implicit, undocumented conventions of the POST /search era onto a shiny new method — with the added risk that a lenient parser and a strict one in your chain disagree about what the body means. 6. The logging trade-off is real but not free Moving search conditions out of the URL and into the body is a genuine privacy win: URIs persist in access logs, analytics, browser history, Referer headers, and bookmarks, and sensitive selectors don't belong there. But if your API gateway or application logs request bodies — many do, for debugging — those conditions end up recorded anyway, now in a place your log-redaction rules may not cover. You haven't eliminated the leak; you've relocated it. Audit body logging and redaction on QUERY endpoints as deliberately as you'd audit URL logging. 7. CORS preflight is mandatory QUERY is not on the CORS-safelisted method list, so browser JavaScript must send an OPTIONS preflight before any cross-origin QUERY. Test how your actual edge and application stack handles that preflight flow — a misconfigured CORS policy that reflexively allows a new method, or one that blocks the preflight, will either over-permit or silently break browser clients. 8. Observability blind spots Dashboards, log parsers, rate-limit buckets, and SIEM detection rules keyed on method names will bucket QUERY as "unknown" or drop it entirely. During the transition, flag QUERY traffic for visibility — a Sigma-style rule that surfaces QUERY requests so you can confirm they're expected — and tune it to your known-good clients as adoption grows. The goal is deliberate awareness during the transition, not a permanent alert. Where support actually stands A method this fundamental gets adopted layer by layer, and that's normal. The honest picture as of early July 2026: Node.js — parses QUERY at the HTTP layer, and has since early 2024, ahead of standardization. OpenAPI 3.2 — has a place to document QUERY operations. Browsers — fetch(url, { method: 'QUERY', body }) and XHR work (QUERY is neither forbidden nor normalized away), but neither Chrome nor Firefox caches QUERY responses yet, and declarative <form method="query"> falls back to GET and drops the body. Mozilla and WebKit standards positions are in progress. Spring — close, but hasn't shipped support. CDNs — Cloudflare and Akamai co-authored the RFC, so edge support may well arrive before framework integrations. Combined with the cache-key caveat, that means your edge may understand QUERY before your app does — plan accordingly. The practical read: solid for server-to-server APIs and backend services today; early-stage for public browser-facing traffic. A general adoption checklist QUERY is a semantically clean upgrade path, not a replacement. Existing POST /search endpoints keep working; migrate gradually. Before QUERY traffic shows up against your applications, confirm each layer treats it deliberately: Edge / CDN — Confirm your CDN is configured to recognize QUERY and forward it to the origin with its body intact, not discard the payload. WAF / API gateway — Add QUERY to method allowlists explicitly. Apply POST-level body inspection (SQLi, XSS, command injection) and size limits. Make sure anomaly/smuggling rules don't flag it by accident, and that no hop strips the body. Cache layer — Verify cache keys are built from the full request body, not just the URL and headers. Audit body normalization for false-positive collisions before enabling QUERY caching. CSRF middleware — Extend coverage to QUERY on any endpoint with side effects. Don't let a "safe" designation exclude it from protection. Content-Type handling — Enforce a required, consistent Content-Type; reject missing or mismatched types; never content-sniff. Advertise supported types via Accept-Query. Logging & redaction — Confirm request-body logging on QUERY endpoints is covered by the same redaction rules you'd apply to sensitive URL parameters. CORS — If browser clients are in scope, test the OPTIONS preflight flow end to end. Confirm your policy neither over-permits nor blocks the new method. Client tooling — Confirm the SDKs and HTTP libraries your consumers use support QUERY, and plan a POST-fallback path (or the Accept-Query discovery flow) for those that don't. Observability — Update method-keyed dashboards, rate limiters, and SIEM rules to recognize QUERY. Add a detection rule to surface QUERY traffic during rollout, tuned to known-good clients. Get those nine right and QUERY is exactly what the web has been missing for 16 years: a request that finally tells the truth about what it's doing. Skip them, and you've handed every layer of your stack a verb it doesn't understand.102Views1like0CommentsF5 Distributed Cloud (XC) - Origins & Health Checks
This article provides a platform-level overview of how F5 Distributed Cloud and the Application Aware Fabric handle origin discovery and health checking. It explains how these platform mechanics impact resiliency, scale, and application uptime, while also highlighting why proper health-check and origin configuration from day one is important for long-term operational stability.264Views5likes1CommentAutomating F5 ADSP — Part 1: F5 XC and BIG-IP for Delivery and Security
What this use case demonstrates This use case covers three of the four ADSP areas: Delivery, Security, and Deployment. Delivery — F5 Distributed Cloud (XC) load balancer at the edge, F5 BIG-IP LTM handling traffic management inside the VPC. Security — XC WAF at the edge, BIG-IP Advanced WAF (AWAF) applying in-path policy before traffic reaches the application servers. Deployment — XC consumed as SaaS, BIG-IP deployed as a Virtual Edition in GCP. Same article, two deployment models, both provisioned from code. You get two layers of delivery and two layers of WAF, across a SaaS edge and a self-managed VE. The whole stack, VPC through XC load balancer, comes up from a single git push. Architecture What gets deployed: A GCP VPC with management, external, internal, and application subnets BIG-IP with AWAF in a single-NIC configuration OWASP Juice Shop and crAPI as target applications F5 Distributed Cloud HTTP load balancer, origin pool, and WAF policy pointing at the BIG-IP The vulnerabilities in the apps are deliberate. They let you exercise the WAF stack against real attack signatures and API abuse patterns. Without them, you only know the controls deployed, not that they work. DevSecOps in practice The lead-in covers the approach. For UC1, that means: Terraform handles infrastructure, BIG-IP configuration, and 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 AS3 declaration BIG-IP pulls on boot, so the runner never needs network access to BIG-IP. 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. The F5 XC API certificate lives in GitHub Actions secrets, not the repo. The pipeline Pushing to a branch runs the workflow. There is no manual terraform to apply. Action Branch Validate, plan, and apply deploy-adsp-uc1 Validate only (no apply) test-adsp-uc1 Destroy all resources destroy-adsp-uc1 This keeps intent visible in git, makes destroy as easy as deploying, and gives reviewers a real PR to look at when something changes. What's in the repo f5devcentral/F5-ADSP-Automation: Directory Purpose infra/gcp/ VPC, subnets, firewall rules compute/gcp/ Juice Shop and crAPI f5/ BIG-IP base config and AWAF policy config/uc1/gcp/env.json GCP project, region, prefix config/uc1/xc/env.json F5 Distributed Cloud config .github/workflows/ CI/CD workflows Demo Try it Prerequisites, secrets, and troubleshooting are in the Use Case Deployment Guide. Contribute Issues and PRs welcome at f5devcentral/F5-ADSP-Automation/Issues. 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 WAF and NGINX App Protect) Automating F5 ADSP Deployments (Part 3 - F5 XC API Protection and NGINX Ingress) Automating F5 ADSP Deployments (Part 4 - F5 XC BOT Defense and BIG-IP AdvWAF) Automating F5 ADSP Deployments (Part 5 - F5 XC, BIG-IP APM, CIS, and NGINX Ingress) Minimizing Security Complexity: Managing Distributed WAF Policies
164Views1like0CommentsAutomating F5 Application Delivery and Security Platform Deployments
The F5 ADSP Architecture Automation Project The F5 Application Delivery and Security Platform (ADSP) reduces the complexity of modern applications by integrating operations, traffic management, performance optimization, and security controls into a single platform with multiple deployment options. This series outlines practical steps anyone can take to put these ideas into practice using the F5 ADSP Architectures GitHub repo and related projects. Each article in the series highlights a different deployment example. The examples can be run locally or integrated into CI/CD pipelines following DevSecOps practices. The repositories are community-supported and intended as reference code for demos, workshops, or as a stepping stone for your own F5 ADSP deployments. If you find any bugs or have any enhancement requests, open an issue, or better yet, contribute. The F5 Application Delivery and Security Platform (F5 ADSP) F5 ADSP addresses four core areas: how you operate day-to-day, how you deploy at scale, how you secure against evolving threats, and how you deliver reliably across environments. Each comes with its own challenges, but together they define the foundation for keeping systems fast, stable, and safe. xOps — day-to-day operations, observability, and lifecycle management Deployment — getting workloads where they need to go, at the scale they need Delivery — traffic management across hybrid and multi-cloud environments Security — protecting applications and APIs from current threats Each architecture deployment example in this series is designed to cover at least three of the four core areas. This ensures the examples demonstrate how multiple components of the platform work together in practice, rather than showcasing any single feature in isolation. DevSecOps: Integrating security into the software delivery lifecycle is a necessary part of building and maintaining secure applications. This project incorporates DevSecOps practices by using supported APIs and tooling, with each use case including a GitHub repository containing IaC code, CI/CD integration examples, and telemetry options. In practice across the series, that means Terraform for infrastructure and F5 configuration, GitHub Actions as the pipeline runner, federated cloud identity instead of long lived keys, secrets handled through the platform rather than committed, and vulnerable target applications so the security controls can be exercised end-to-end. Contribute The repos are community-supported. Open an issue, send a PR, or port a use case to another cloud. 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 WAF and NGINX App Protect) Automating F5 ADSP Deployments (Part 3 - F5 XC API Protection and NGINX Ingress) Automating F5 ADSP Deployments (Part 4 - F5 XC BOT Defense and BIG-IP AdvWAF) Automating F5 ADSP Deployments (Part 5 - F5 XC, BIG-IP APM, CIS, and NGINX Ingress) Minimizing Security Complexity: Managing Distributed WAF Policies762Views3likes0CommentsAutomating F5 ADSP — Part 2: F5 XC and NGINX for Delivery and Security
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 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.67Views2likes0CommentsF5 WAF on NGINX Gateway Fabric: Container-Native WAF for the Kubernetes Gateway API
The Kubernetes Gateway API is quickly becoming the standard for managing ingress and traffic routing — replacing the older Ingress resource with a more expressive, role-oriented model. But while the Gateway API provides platform teams with powerful traffic management, it comes with limited built-in application-layer security. It handles routing. Protection is not included. F5 WAF for NGINX Gateway Fabric closes that gap. It brings enterprise-grade WAF protection directly into the Kubernetes data plane — container-native, declaratively managed, and integrated with NGINX One Console for centralized policy management. In this article, I'll walk through the end-to-end workflow: creating a WAF policy in NGINX One Console, applying it to F5 NGINX Gateway Fabric, blocking a live XSS attack, and masking sensitive data with DataGuard — all without changing a single line of application code. Why WAF at the Gateway? Traditional WAF deployments were designed for monolithic architectures — sitting at the network perimeter, inspecting traffic before it reached a handful of servers. In Kubernetes, applications are distributed across dozens or hundreds of microservices, each with its own API surface. The perimeter model doesn't scale. F5 WAF for NGINX Gateway Fabric embeds security directly into the data plane. Every HTTPRoute behind the gateway gets WAF protection — declaratively, through the same Kubernetes-native workflows your platform team already uses. Key capabilities: Container-native — runs natively with NGINX Gateway Fabric, no sidecar required OWASP Top 10 protection with advanced attack signatures REST, GraphQL, and gRPC API protection DataGuard — automatic PII masking in API responses Centralized management through NGINX One Console NGINX One Console Integration The integration between NGINX Gateway Fabric and NGINX One Console is what makes this solution practical for real-world operations. It creates a clean separation between security policy ownership and application deployment. Policy Management SecOps teams create and manage WAF policies entirely within NGINX One Console — using the visual form editor or the JSON tab for advanced configurations. Policies are defined once and consumed by any number of gateways. There's no need for SecOps to touch Kubernetes resources or learn YAML. The console supports policy presets (like NGINX Strict for aggressive blocking), custom violation rules, attack signature set configuration, and application-specific exceptions. Once a policy is saved, it compiles instantly and generates an Object ID that platform teams reference from Kubernetes. Security Dashboard Every WAF event — blocked attacks, DataGuard alerts, policy violations — flows back to the Security Dashboard in real time. SecOps gets full visibility without leaving the console. The dashboard surfaces: Attack types, blocked requests, and violation counts per policy Top attack signatures — including XSS, SQLi, and bot patterns Attacker IP addresses and targeted endpoints Event drilldown with raw request payloads and signature match details For incident response, the Event Logs tab provides full forensic detail — the raw request, violation rating, matched signatures with accuracy and risk classification, and the support ID returned to the attacker. Log Profiles Security logging is configured as part of the WAF policy configuration. Logs are sent back to NGINX One Console using the secops_dashboard log profile, which feeds the Security Dashboard. This means every gateway running the policy contributes to the same centralized view — no separate log aggregation needed. Automatic Policy Updates When SecOps updates a policy — adding a new signature set, tightening a violation rule, or enabling DataGuard — NGINX Gateway Fabric detects the change automatically. The updated policy propagates to every gateway that references it. No pod restarts, no redeployments, no manual sync. This is the operating model: SecOps owns the security posture in the console. Platform teams consume it declaratively in Kubernetes. Both teams work independently without stepping on each other. How It Works — The WAFPolicy Resource The connection between NGINX One Console and NGINX Gateway Fabric is established via a WAFPolicy custom resource. This is the only Kubernetes resource the platform team needs to apply. The WAFPolicy does three things: Points the gateway to the specific policy created in NGINX One Console (by Object ID) Provides secure credentials to pull the policy (via a Kubernetes secret) Routes security events back to the console for the Security Dashboard apiVersion: gateway.nginx.org/v1alpha1 kind: WAFPolicy metadata: name: gateway-base-protection spec: targetRefs: - group: gateway.networking.k8s.io kind: Gateway name: gateway type: N1C policySource: n1cSource: url: https://your-console.example.com namespace: your-namespace policyObjectID: pol_xxxxxxxxxxxxx auth: secretRef: name: n1c-credentials securityLogs: - destination: type: syslog syslog: server: localhost:1514 logSource: n1cSource: url: https://your-console.example.com namespace: your-namespace profileName: "secops_dashboard" auth: secretRef: name: n1c-credentials Once applied, the gateway status confirms the policy is active: $ kubectl describe wafpolicy gateway-base-protection ... Status: Conditions: Message: The Policy is accepted Reason: Accepted Status: True Message: Policy is programmed in the data plane Reason: Programmed Status: True All traffic through the gateway is now inspected by F5 WAF. Demo Walkthrough The video below demonstrates the complete workflow — from policy creation to attack blocking to DataGuard masking. Here's a summary of what you'll see. Resources NGINX Gateway Fabric documentation — https://docs.nginx.com/nginx-gateway-fabric/ F5 WAF for NGINX Gateway Fabric Blog: https://blog.nginx.org/blog/nginx-gateway-fabric-2-6-f5-waf-for-nginx-comes-to-the-gateway-api NGINX One Console — https://docs.nginx.com/nginx-one/ GitHub — NGINX Gateway Fabric — https://github.com/nginx/nginx-gateway-fabric37Views1like0CommentsAPM Policy Migration Between Standalone TMOS 17.1.3 Systems
Hi everyone, We're migrating a single production APM policy from an i4600 to an r4600 appliance. Both systems are running TMOS 17.1.3, and the new appliance will not be part of the existing DSC cluster. We tried exporting/importing only the APM policy, but the import fails because referenced objects are missing on the target system. A full UCS restore would also migrate many unused objects that we don't want. Is there a supported way to: Analyze an APM policy and list all required dependencies before import? Export/import only the APM Customization GUI (HTML/CSS/JavaScript templates)? Migrate a single APM policy without restoring the entire APM configuration? Any recommended best practices for this scenario would be appreciated. Thanks in advanced!111Views0likes4CommentsDeploying F5 BIG-IP HA into AWS GovCloud
This guide provides a walk-through for deploying an active/standby F5 BIG-IP High Availability (HA) cluster within AWS GovCloud (US) using the AWS Console. Code Repository: F5GovSolutions/f5-aws-cloudformation-v2-govcloud While the repository's examples/failover/GOVCLOUD-GUIDE.md handles the exact AWS CLI workflows, this document serves as the web console companion. The Partition Problem The upstream commercial F5 templates (F5Networks/f5-aws-cloudformation-v2) assume a standard AWS commercial partition. Pointing those unmodified templates at GovCloud breaks deployment for three distinct reasons: Partition Isolation (aws-us-gov): GovCloud uses unique ARNs, regional endpoints, and an entirely separate AMI catalog. Furthermore, CloudFormation mandates that a parent stack's nested templates reside in an S3 bucket within the exact same region and partition. CloudFormation cannot fetch objects across partitions, meaning all templates must be pre-staged in a local GovCloud bucket. Air-Gapped Realities: In isolated enclaves with no internet egress, a booting BIG-IP cannot pull the runtime-init installer or Automation Toolchain RPMs from public GitHub repositories or F5 CDNs. Everything must be hosted locally inside an S3 bucket, accessible via VPC Gateway and Interface endpoints. The 17.x Clustering Bug: On the BIG-IP 17.x code train, a startup-timing condition occasionally prevents the local device-trust domain (/Common/Root) from initializing properly on first boot. When this occurs, Declarative Onboarding (DO) cannot establish the trust domain or failover group, leaving both nodes deadlocked. This modified template embeds an automated, non-blocking self-heal script to orchestrate the recovery process without manual intervention. What it deploys The root template (failover.yaml) orchestrates a series of nested module stacks (network, access, ingress, application, and individual BIG-IP nodes) to build: An active/standby pair of BIG-IP Virtual Editions (VE) deployed across two Availability Zones using a 3-NIC topology (Management, External, Internal). Cloud Failover Extension (CFE) integration to re-map floating application IPs and AWS routes during a failover event. Automated onboarding via F5 BIG-IP Runtime Init, executing Declarative Onboarding (DO) for core network clustering, Application Services 3 (AS3) for virtual servers/WAF policies, and CFE for AWS API integration. The architecture uses Pay-As-You-Go (PAYG) marketplace licensing and is fully validated on the 3nic-payg...-with-app runtime-init configuration. Core Architecture Differences vs. Commercial Staged-Bucket Deployment Mode Because of partition constraints, your local GovCloud S3 bucket serves as the single source of truth. It must hold two types of data: the nested CloudFormation templates cloned from the repository, and the target installation binaries (the runtime-init .run installer and the accompanying DO/AS3/CFE RPM packages). The Unauthenticated 403 Pitfall CloudFormation reads your deployment templates using your active IAM user/role credentials. However, during the bootstrap phase, the individual BIG-IP instances download their configuration files and RPM packages over an unauthenticated HTTPS request. They do not sign these requests with AWS credentials. If your S3 bucket permissions block public read access completely, the instances receive an HTTP 403 Forbidden response, initialization fails, and CloudFormation rolls back the stack. Because GovCloud blocks public access by default, you must apply a scoped bucket policy allowing s3:GetObject to Principal: "*" paired with a DenyInsecureTransport block. Single-Toggle VPC Endpoints Isolated enclaves require four distinct VPC endpoints to function: S3 (Gateway) for fetching installation packages and AS3 WAF policies, and Interface endpoints for EC2, Secrets Manager, and CloudFormation APIs. Missing even one endpoint causes silent automation failures. To simplify this, the template consolidates these requirements into a single parameter: setting provisionS3Endpoint=true automatically provisions all four regional endpoints with private DNS enabled. Note that your bucket, stack, and endpoints must reside within the same AWS region. Automated Clustering Self-Heal To bypass the 17.x initialization bug without manual operator access, the template installs a localized orchestration loop during the pre_onboard hook. The mechanism drops three files onto the file system: cluster-heal.sh: The main orchestrator script. cluster-heal-trust.py: A native Python script that securely pulls the admin password from Secrets Manager via a SigV4 request using the instance's IAM role, then invokes the local device trust commands. /etc/cron.d/cluster-heal: A cron job that triggers the orchestrator every 3 minutes. This loop checks the cluster status. If it detects a missing root domain, it triggers a single controlled reboot, reads the peer node's address from the runtime logs, pulls the password, and establishes device trust. Once synchronized, it issues the CloudFormation success signal and disables its own cron job. This preserves DO as the declarative source of truth without creating configuration drift. During this process, the CloudFormation stack will remain in CREATE_IN_PROGRESS for roughly 25 to 30 minutes, which is normal behavior. Elastic IP Allocation Constraints The default AWS regional quota is 5 Elastic IPs (EIPs). Depending on your topology, this architecture can request up to 7. To prevent deployment failures due to exhausted quotas, use the template toggles to limit public allocations: Default Configuration (Public Mgmt, Public VIP, Public Self IPs): 7 EIPs Standard Air-Gap Profile (Public Mgmt, Private VIP, Private Self IPs): 4 EIPs Strict Isolated Profile (Private Mgmt via Bastion, Private VIP, Private Self IPs): 3 EIPs Verify your regional limit under Service Quotas → EC2-VPC Elastic IPs (L-0263D0A3) before executing the template. Deployment Steps (AWS Console) Before You Begin Select a single target GovCloud region (us-gov-east-1 or us-gov-west-1). Your staging bucket, CloudFormation stack, EC2 Key Pair, and Secrets Manager secret must share this region to prevent cross-region routing failures in isolated enclaves. 1. Provision the staging S3 bucket S3 → Create bucket, in your Region. Give it a globally unique name. [S3 Create bucket, Region selector highlighted.] 2. Stage the templates and artifacts While file uploads can be handled via the S3 web GUI, staging is more reliably managed via the AWS CLI from a local workstation. Installing the AWS CLI is outside the scope of this article but it's easy and instructions can be Googled. Execute the following commands from the root of your cloned repository to sync the template architecture and upload your pre-downloaded F5 binaries: Download commands: # F5 BIG-IP Runtime Init installer (note: this repo's tag has NO "v" prefix) curl -fL -o f5-bigip-runtime-init-2.0.3-1.gz.run \ https://github.com/F5Networks/f5-bigip-runtime-init/releases/download/2.0.3/f5-bigip-runtime-init-2.0.3-1.gz.run # Declarative Onboarding (DO) curl -fL -o f5-declarative-onboarding-1.47.0-14.noarch.rpm \ https://github.com/F5Networks/f5-declarative-onboarding/releases/download/v1.47.0/f5-declarative-onboarding-1.47.0-14.noarch.rpm # Application Services (AS3) curl -fL -o f5-appsvcs-3.56.0-10.noarch.rpm \ https://github.com/F5Networks/f5-appsvcs-extension/releases/download/v3.56.0/f5-appsvcs-3.56.0-10.noarch.rpm # Cloud Failover Extension (CFE) curl -fL -o f5-cloud-failover-2.4.0-0.noarch.rpm \ https://github.com/F5Networks/f5-cloud-failover-extension/releases/download/v2.4.0/f5-cloud-failover-2.4.0-0.noarch.rpm Sync and upload commands (be sure to be at root of the cloned repo), set the variables accordingly: # Synchronize the nested CloudFormation infrastructure templates aws s3 sync ./examples/ "s3://$BUCKET/$PREFIX/" --region "$REGION" # Upload the core runtime engine and toolchain extensions aws s3 cp f5-bigip-runtime-init-2.0.3-1.gz.run "s3://$BUCKET/$PREFIX/" --region "$REGION" aws s3 cp f5-declarative-onboarding-1.47.0-14.noarch.rpm "s3://$BUCKET/$PREFIX/bigip-extensions/" --region "$REGION" aws s3 cp f5-appsvcs-3.56.0-10.noarch.rpm "s3://$BUCKET/$PREFIX/bigip-extensions/" --region "$REGION" aws s3 cp f5-cloud-failover-2.4.0-0.noarch.rpm "s3://$BUCKET/$PREFIX/bigip-extensions/" --region "$REGION" 3. Grant anonymous read on the artifacts In the S3 Console, select your staging bucket and navigate to Permissions. Under Block public access (bucket settings), disable the option to Block public access to buckets and objects granted through new public bucket policies (leave ACL blocks enabled). Next, apply the following bucket policy to allow the instances to pull down the bootstrap packages securely over HTTPS: { "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws-us-gov:s3:::YOUR-BUCKET-NAME-HERE/*" }, { "Sid": "DenyInsecureTransport", "Effect": "Deny", "Principal": "*", "Action": "s3:*", "Resource": [ "arn:aws-us-gov:s3:::YOUR-BUCKET-NAME-HERE", "arn:aws-us-gov:s3:::YOUR-BUCKET-NAME-HERE/*" ], "Condition": { "Bool": { "aws:SecureTransport": "false" } } } ] } Note: Ensure you replace YOUR-BUCKET-NAME-HERE with your actual bucket name. Do not include any trailing lines or comments in the JSON editor. [S3 Permissions — Block public access settings.] 4. Store the Admin Password Secret Navigate to AWS Secrets Manager → Store a new secret. Choose Other type of secret, select the Plaintext tab, clear the default JSON template, and type your raw password string. Name the secret (e.g., f5-bigip-admin) and save it using the default settings. Copy the resulting Secret ARN (arn:aws-us-gov:secretsmanager:...); both nodes query this specific object at startup. [Secrets Manager Store secret, plaintext tab.] [Secrets Manager: Name your secret.] 5. Create the SSH key pair EC2 → Key Pairs → Create key pair, download the .pem. The key pair is regional. This is optional but recommended you create one before template launch. [Screenshot: EC2 Create key pair.] (You can leave the parameter blank in the template and let the stack auto-create one, but then the private key only lives in SSM Parameter Store — pre-creating is simpler if you need to access the boxes vis SSH) 6. Confirm the BIG-IP AMI exists in your Region The deployment template discovers the target AMI using automated string matching. Ensure that your region has access to the target image by running the following lookup via your terminal, this can also be done via the GUI: aws ec2 describe-images --region "$REGION" --owners aws-marketplace \ --filters "Name=name,Values=*17.5*PAYG-Best Plus 25Mbps*" \ --query 'reverse(sort_by(Images,&CreationDate))[].[Name,ImageId,CreationDate]' --output table 7. Launch the stack (CloudFormation) Open CloudFormation, select your target region, and click Create stack (with new resources). Select Template is ready, choose Amazon S3 URL, and paste the direct object URL to your staged failover.yaml file. Configure the mandatory parameters: Stack Name: Define an environment-specific identifier. S3 Configurations: Populate s3BucketName and s3BucketRegion. Secrets Management: Paste your copied Secrets Manager ARN into bigIpSecretArn. Security Access: Set restrictedSrcAddressMgmt and restrictedSrcAddressApp to your administrative CIDR blocks to avoid exposing management interfaces. Air-Gap Toggles (For isolated VPCs): Change provisionS3Endpoint to true, and flip both provisionPublicIpExternalSelf and provisionPublicIpVip to false. In the options screen, consider setting Stack failure options to Preserve successfully provisioned resources during your initial test runs. This keeps instances alive for log inspection if a deployment fails. Acknowledge the CAPABILITY_NAMED_IAM prompt and click Submit. [CloudFormation Specify template — Amazon S3 URL field.] [Parameters page, air-gap toggles section.] [Review — Acknowledgement and Stack failure options.] 8. Wait it out Expect ~25–30 minutes in CREATE_IN_PROGRESS while the self-heal forms the cluster, then CREATE_COMPLETE. This is normal — it is not stuck. After 10 minutes, go ahead and admin SSH into the boxes, they should accept your admin secret by now, if not use your SSH key you created and referenced in the template. See the commands below or in the git repo guide. Validating the deployment From the stack Outputs, grab a management IP, then: Onboarding: grep -i 'All operations completed successfully' /var/log/cloud/bigIpRuntimeInit.log; the prompt should show failover01.local / failover02.local, not ip-x-x-x-x. Clustering: tmsh show cm sync-status → In Sync (green), Mode: high-availability, one node Active and one Standby. CFE: GET https://localhost/mgmt/shared/cloud-failover/inspect returns a populated object (instance, addresses, trafficGroup). The self-heal's own narration lives in /config/cluster-heal/log — the primary place to look if the stack runs long; you'll see the reboot → add-to-trust → creating failoverGroup → cluster In Sync → cfn-signal sent OK → disabling self-heal sequence. If clustering genuinely never forms (the rare case where the self-heal exhausts its attempts), the repo guide has a validated manual fallback that follows the same reboot → rebuild trust → reapply sequence. What's GovCloud-ready today — and what isn't Let's be clear about scope. The GovCloud template— staged-bucket defaults, the four VPC endpoints, the clustering self-heal, the bumped extensions — currently applies to one solution: the failover active/standby pair on the 3-NIC PAYG -with-app runtime-init config. The repo's autoscale, the quickstart standalone, and the other failover variants (2-NIC, BYOL, and the non--with-app configs) still carry upstream configuration and are not yet GovCloud-validated. Adapting them is planned work and would follow exactly the pattern documented here. And the self-heal is a workaround for an F5 platform bug, not a permanent fix. The right long-term resolution is the platform defect behind the KB; when a fixed build is in play, the self-heal simply stays inert. Where to go next The repo: F5GovSolutions/f5-aws-cloudformation-v2-govcloud Full CLI walkthrough (first-time operator): examples/failover/GOVCLOUD-GUIDE.md Parameter and architecture reference: examples/failover/README.md The self-heal sources: examples/failover/bigip-configurations/cluster-heal.sh and cluster-heal-trust.py If you're standing up BIG-IP HA in an enclave, start from the 4-EIP air-gap profile with provisionS3Endpoint=true, stage everything in one in-Region bucket, and let the self-heal do the clustering. File issues on the repo if you hit something the guide doesn't cover.58Views1like0Comments