security
18227 TopicsUnderstanding The TikTok Ban, Salt Typhoon and More | AppSec Monthly January Ep.27
In this episode of AppSec Monthly, our host MegaZone is joined by m_heath, Merlyn Albery-Speyer, and AubreyKingF5, as they dive into the latest cybersecurity news. We explore the complexities of the TikTok ban, the impact of geopolitical decisions on internet freedom, and the nuances of data sovereignty. Our experts also discuss the implications of recent breaches by Chinese state actors and the importance of using end-to-end encrypted apps to protect your data. Additionally, we shed light on the fascinating history of internet control and how it continues to evolve with emerging technologies. Stay tuned until the end for insights on the upcoming VulnCon 2025 and how you can participate. Don’t forget to subscribe for more AppSec insights!213Views1like3CommentsStop Registering AI Agents and Apps by Hand - Explore Dynamic Client Registration BIG-IP ZTA
Introduction Managing OAuth client registrations manually at scale is tedious. Every new application needs an admin to log in, configure a client entry, hand off credentials, and hope nothing drifts out of sync. It works fine when you have five clients. It doesn't work when you have fifty or when AI Agents and Apps need to onboard programmatically as part of an automated pipeline. That's the problem Dynamic Client Registration (DCR) solves. BIG-IP ZTA's DCR support lets OAuth client applications register with BIG-IP ZTA’s authorization server dynamically, at runtime, without manual admin intervention for each one. The authorization server exposes a registration endpoint, a client sends its metadata, and APM creates the client entry and returns credentials on the spot. The client is automatically tied to the OAuth profile it registered against. Clean, automated, and auditable. I see it too, exposing the registration endpoint and it's an intentional move. You can't just hit the registration endpoint and create clients freely. Every registration request requires a valid Initial Access Token (IAT). That token comes from a specially designated client application, one that exists solely to issue IATs and can't be used for anything else. No authorization code flows, no resource owner password grants just IAT issuance. This separation keeps the registration endpoint controlled even as client onboarding scales out. The result is a model that works well for Zero Trust architecture, where you want programmatic, policy-controlled access rather than static configurations that age poorly. DCR gives you the automation; the IAT mechanism gives you the guardrails. How it looks in production Thanks to Matt_Dierick for building this lab up Starting with the end in mind, let’s see how this looks in production. In our setup we have an MCP client communicating with MCP server protected by BIG-IP ZTA. MCP Client Run Bruno to start API request for MCP client registration Request an IAT token to ZTA in order to register a new client Register the new client with the previous IAT token, and the output are a Client_ID and Client_Secret Request The JWT token that will be use to call the MCP Server Now, let’s send a valid request to MCP server through BIG-IP ZTA Now we have a clear picture of how the flow starts from client point of view to obtain the JWT token that allows further calls to the protected OAuth resource Let’s build it from BIG-IP ZTA BIG-IP ZTA Dynamic Client Registration flow In this flow the client uses the initial access token to start the process of automatic registration. As observed in the flow diagram below, The client initiates a POST to /register OAuth endpoint with the IAT access token BIG-IP ZTA responds back with the client_id and client secret. The client uses the client_id and client secret to request the JWT Access token Once Authenticated the client is now registered and able to perform future operations. Considerations for Dynamic Client Registration Dynamically registered clients are automatically associated with the OAuth profile Only authorized client applications can perform dynamic registration Clients can be identified as static or dynamic in the UI, similar to the below Below are the steps to build that flow Create Token configurations, Key configurations and JWT provider and provider list 2. Create the OAuth scope 3. Configure Oauth Claim Setting up OAuth profile 1. Navigate to: Main tab → Access → Federation → OAuth Authorization Server → OAuth Profiles 2. Select an OAuth profile. 3. Enable Dynamic Client Registration. 4. Configure the following settings: - IAT Client Applications, It specifies the client applications that can obtain an Initial Access Token (IAT) required to register dynamic clients. Only applications selected here can generate the token used during dynamic registration. - Allowed Grant Types , Supported Scopes, Client Authentication Method, Client Secret Location and Dynamic Client Registration Flow BIG-IP ZTA Dynamic OAuth client access With the client automatically registered, it’s time to see how the client access the protected resource through BIG-IP ZTA. The flow diagram below shows the traffic flow after client obtaining the JWT Access token. - The client uses the JWT Access token to access the protected resources. - BIG-IP ZTA validates the JWT signature, claim and scope and enforce the configured policy. Let’s explore the API protection profile settings below, 1- Create an API protection profile that makes use of both BIG-IP ZTA and BIG-IP Advanced WAF. 2- Let’s explore the API profiles Access settings Add OAuth Scope check subroutine. Define OAuth scope Add the subroutine to the main path in the per-request policy. 3- The scope validation step Optionally part of the API protection profile, you can enable BIG-IP Advanced WAF to protect the API requests. Conclusion If you're running any kind of modern application environment whether AI agents calling protected APIs, microservices spinning up on demand, or third-party integrations that can't wait for a manual provisioning ticket, static client registration is already a bottleneck. BIG-IP ZTA's DCR implementation gives you a clean answer to that problem. Clients register themselves. The IAT-gated endpoint keeps that process from becoming a free-for-all. And because every dynamically registered client is tied to an OAuth profile from the moment it's created, your policy enforcement travels with it automatically. Related content Using APM as an OAuth 2.0 Authorization Server23Views1like0CommentsA 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.104Views1like0CommentsPQC: a blindspot (logging) on BIG-IP - RFE
On BIG-IP it's currently not possible to log information such as proposed and negotiated Key Exchange Algorithm. No available iRule commands for that. On the other hand, NGINX do offer the possible to log it ($ssl_curve/$ssl_curves variables). I've got a RFE created for the following: Provide new iRule commands in events CLIENTSSL_CLIENTHELLO and CLIENTSSL_HANDSHAKE that outputs the Key Exchange Algorithm: - list of proposed (by the SSL client) Key Exchange Algorithms in CLIENTSSL_CLIENTHELLO - negotiated Key Exchange Algorithms in CLIENTSSL_HANDSHAKE => RFE ID2347153 — "iRule command equivalent to NGINX's $ssl_curve for logging the negotiated KEM/DH group" Don't hesitate to open a support case to bind it to that RFE, the more we are the higher priority will be assigned to implement it (hopefully). 😀 Alexandre47Views1like2CommentsAPM Portal access and ECMAScript compatibility
I notice that ECMAScript (ES13) is supported as stated in version 21.1 release note https://techdocs.f5.com/en-us/bigip-21-1-0/big-ip-release-notes/big-ip-new-features.html#portal-access-ecmascript-es13-support-for-modern-javascript-applications As I know, latest version in 17.1 can also use the latest cache-fm-Modern.js file. Does it imply that latest version in 17.1, say 17.1.3.2, also support ECMAScript (ES13)? https://my.f5.com/manage/s/article/K00014878665Views0likes2CommentsAutomating 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.67Views2likes0CommentsAPM OIDC debug logging is somehow verbose but not where it should - RFE
While I was configuring and testing an APM Access policy for an OIDC integration with Entra ID, I was seeing some backchannel errors logged (debug level) some HTTP error 400. The whole logging is quite verbose, but here, not very useful: [...] OAuth Client: failed for server '/Common/entraid_test' using 'authorization_code' grant type (client_id=xxxxxxxxxxxxxx), error: HTTP error 400, Session variable 'session.oauth.client./Common/entra_front_act_oauth_client_ag.errMsg' set to 'HTTP error 400, ' Session variable 'session.oauth.client./Common/entraid_test.errMsg' set to 'HTTP error 400, ' Session variable 'session.oauth.client.last.errMsg' set to 'HTTP error 400, ' So, tcpdump was required to see what exactly the error was in the returned JSON payload from Entra ID. I've got a new RFE from F5 support => (Bug alias 2229965) [RFE] Add extra verbosity for the debug-level logging for OIDC backchannel connection Don't hesitate to open a support case to get it bound to that RFE, the more we are the higher priority will be assigned to implement it (hopefully). 😀 Alexandre40Views0likes3CommentsAWAF Access Profile, missing a configurable JWKS URL - RFE
The AWAF Access Profile functionality (introduced in 17.5) is potentially a great feature, but IMHO it (still) lacks an essential function in the "Verify Digital Signature" part: an automatic refresh/rotation interval to periodically fetch and update the JWKS from a specified URL. Currently, it only supports the upload of a file containing the key. Not enough for a mature solution, which supports enterprise deployments (OIDC integrations with such as Entra ID, Okta, etc.) Note: I do know that some experts here builded some automation to work around this lacking feature. Great stuff. Anyway, as I though the effort for the F5 devs should not be huge (they have already some code doing that in their APM OIDC auto-discovery function), I've opened a support case/RFE and got one back => RFE ID2294753: AWAF Access profile Verify Digital Signature to support dynamic JWKS retrieval via a configurable URL endpoint Don't hesitate to open a support case to get it bound to that RFE, the more we are the higher priority will be assigned to implement it (hopefully). 😀 Alexandre31Views0likes0Comments