After six quarters of escalating PingIdentity licensing costs, our platform team completed a full migration of our internal application access layer to Cloudflare Access. The primary driver was financial: we've reduced our annual ZTNA/IdP expenditure by approximately 73%. However, this operational efficiency came with a tangible trade-off in granularity and depth of audit reporting, which has complicated certain compliance workflows.
Our architecture involves ~150 microservices across three Kubernetes clusters, with Access protecting internal admin panels, monitoring dashboards (Grafana, Prometheus), and CI/CD systems. The migration itself was straightforward. Defining policies as code using Terraform proved effective for version control and drift prevention.
```hcl
resource "cloudflare_access_application" "grafana_internal" {
zone_id = var.cf_zone_id
name = "Internal Grafana"
domain = "grafana.internal.example.com"
type = "self_hosted"
session_duration = "24h"
cors_headers {
allow_all_headers = true
allow_all_methods = true
allow_all_origins = false
allowed_origins = ["https://internal.example.com"]
}
}
resource "cloudflare_access_policy" "grafana_devs" {
application_id = cloudflare_access_application.grafana_internal.id
zone_id = var.cf_zone_id
name = "Engineering Team"
precedence = 1
decision = "allow"
include {
email_domain = ["ourcompany.com"]
}
require {
geo = ["US", "CA", "DE", "GB"]
}
}
```
**Where Access excels:**
* **Performance:** The global network adds negligible latency. Our benchmarks show a median increase of 12ms for end-to-end authentication versus our previous on-prem PingFederate nodes.
* **User Experience:** The SSO flow is seamless, especially with the WARP connector for managed devices. No more VPN for internal tools.
* **Cost Structure:** The per-user pricing model is predictable and scales linearly, unlike the punitive "connector-based" licensing we were subjected to before.
* **Integration Simplicity:** The `cloudflared` daemon is trivial to deploy as a sidecar in our Kubernetes pods, abstracting away the complexity of the tunnel.
**Where reporting and observability regressed:**
* **Audit Log Detail:** PingIdentity provided exhaustive field-level data (e.g., specific SAML assertion attributes used, detailed policy evaluation trees). Cloudflare's audit logs are high-level, confirming "Allowed/Denied" and the applied policy, but lack the forensic depth.
* **Custom Reporting:** Generating a report to prove, for instance, which users accessed a specific application *and* from which IDP group attribute they were derived is now a multi-step process of joining logs from Cloudflare with our HRIS system, whereas Ping exported this as a single view.
* **Real-time Alerting:** We had built fine-grained alerts in Ping for anomalous sequences of access attempts. Cloudflare's alerting is primarily focused on security events (like block actions) and does not allow for custom, log-based alerting on user access patterns natively. We now must ship logs to a SIEM and rebuild that logic.
The financial justification was overwhelming, and the core ZTNA functionality is robust. However, teams with stringent compliance requirements (SOX, FedRAMP) or those needing deep, self-service user access analytics should factor in the additional overhead of reconstructing those insights externally. We are compensating by piping Access logs to BigQuery and building custom dashboards, but this reintroduces complexity and cost we had hoped to eliminate.
Has anyone else navigated this specific trade-off? I'm particularly interested in how other organizations are augmenting Cloudflare Access logs for granular compliance reporting without resorting to a full third-party IAM analytics platform.
—chris
—chris
Platform engineer at a mid-sized fintech. We run ~200 services across four k8s clusters. Our SSO/Zscaler combo covers internal apps, similar to OP's stack.
1. **Annual contract costs** - Ping's enterprise pricing started at $12/user/month for us, ballooned with "premium" modules. Cloudflare Access is effectively free under our $5k/mo Enterprise plan, since it's bundled with our CDN/WAF spend. The real hidden cost is internal dev time to rebuild reports.
2. **Audit log depth** - Ping logs every attribute check, session detail, policy decision tree. Cloudflare logs show `allowed/denied`, timestamp, user email, app name. That's it. You can't reconstruct *why* a policy fired after the fact. This broke our SOX traceability until we built a sidecar logger.
3. **On-prem integration** - If you have legacy on-prem apps (we had two), Ping's agents install on any VM. Cloudflare Access requires a publicly routable endpoint, even if you use Tunnel. That meant re-architecting two old .NET apps to sit behind a k8s ingress controller first.
4. **Policy granularity** - Ping policies can use LDAP groups, custom attributes, device posture, and time-of-day. Cloudflare Access policies are basically `include {email domain, group, IP}` and `require {2FA, service token}`. If you need "allow this AD group except on Tuesdays from untrusted networks," you're writing custom code.
I'd stick with Ping if your auditors demand attribute-level audit trails. If you're cloud-native and compliance just needs basic access logs, Cloudflare cuts the check. Tell us: what compliance framework caused the reporting headache, and do you have any non-http services to protect?
If it ain't broke, don't 'upgrade' it.
Interesting trade-off. I'm pretty new to this space, but I've been reading about how Cloudflare Access logs are basically a black box compared to something like Ping. You mentioned the sidecar logger for SOX - did you build that from scratch or is there an open source tool you based it on? Also curious if you looked at any middle ground options before going all-in on Access, like keeping Ping for audit logs and just using Cloudflare for the proxy layer.
That's a good question about a hybrid approach. We had the same thought initially, but our security team shot it down. They said managing two separate policy engines - one in Ping for logging and one in Cloudflare for actual access - would create a nightmare for keeping permissions in sync and double the maintenance.
For the logging sidecar, I know user286 mentioned building one. I've seen some teams use Fluentd or Vector to try and capture more context from the apps themselves before the request hits Access, but it seems really messy. Did anyone else here try something like that and get it to work?