A few years ago, I got a call from a mid-sized e-commerce company that was panicking. Their legal team had just realized they'd been deleting CDN access logs after 30 days to save money, but their new payment processor contract required 12 months of retention for fraud investigations. They weren't just out of compliance — they'd already lost the data. That one gap cost them a six-figure audit finding, and it’s a story I’ve seen play out more than once.
Why Keeping Everything Forever Will Bankrupt You (And Still Fail Compliance)
When you're new to managing CDN logs, the safest feeling approach is to keep everything. Every request, every header, every edge status code, forever. I get it. Disk is cheap, right? Except at CDN scale, it really isn't. A moderately busy site pushing 50 million requests a day can generate 80-120 GB of raw log data daily. Keep that uncompressed for a year and you’re looking at 30+ terabytes for a single property. Multiply that across a few domains and your S3 bill starts to look scarier than any audit letter.
But the bigger problem isn't just cost — it's that keeping everything forever can actually hurt your CDN Log Aggregation Architecture: Collecting Billions of Events Without Dropping Data and your legal standing. Privacy laws like GDPR and CCPA don’t just tell you how long to keep data, they tell you how long you’re *allowed* to keep it. If you’re holding onto IP addresses and user-agent strings with no defined data retention purpose, you’re not being thorough, you’re creating liability. A solid compliance policy is about keeping the right data for the right amount of time, not hoarding it all.
I learned this lesson early on when I was consulting for a media client. We’d built them a beautiful, centralized logging pipeline that dumped every edge log into a single bucket with no expiry. Six months later, their DPO asked us how we were handling data minimization and we didn’t have an answer. We had to scramble to add lifecycle rules and retroactively purge old PII. Don’t make that mistake — define your rules up front.
# Example: S3 Lifecycle policy for tiered log retention
# This enforces your compliance policy automatically
{
"Rules": [
{
"ID": "cdn-access-logs-retention",
"Filter": { "Prefix": "cdn-logs/access/" },
"Status": "Enabled",
"Transitions": [
{ "Days": 30, "StorageClass": "STANDARD_IA" },
{ "Days": 90, "StorageClass": "GLACIER" }
],
"Expiration": { "Days": 365 },
"AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
}
]
}
Creating a Data Retention Policy Auditors Will Actually Accept
A lot of teams think a compliance policy is just a document legal writes and engineering ignores. In practice, your CDN legal requirements live or die by how you implement them. Auditors don’t want to see a PDF that says “we retain logs for one year.” They want to see *how* you enforce it. They’ll ask for proof that logs can’t be tampered with, that access is logged, and that deletion actually happens on schedule. If your log retention plan is “we’ll delete it manually when we remember,” you’ll fail.
The simplest way to satisfy this as a beginner is to split your logs by purpose and apply different rules. You don’t need the full, verbose log with every request header for a year. What you need is a layered approach, and it ties directly into how you handle CDN Real-Time Log Streaming Architecture: From Edge Events to Analytics in Seconds. Raw, detailed logs with IPs and cookies are useful for 30-45 days for debugging and security triage. After that, you can strip or hash PII and roll them up into aggregated, anonymized summaries for long-term trends. That keeps you compliant without paying to store high-cardinality PII in hot storage for 12 months.
We usually document this in a simple, version-controlled config file that both engineering and legal can read. It removes ambiguity and, as the HTTP Working Group Specifications point out for traceability, having clear, auditable handling of request metadata is part of good HTTP stewardship. The web.dev Articles on privacy also stress this same principle: collect and keep only what you need. Your policy should name the log type, the reason for keeping it, and the exact expiry.
# retention-policy.yaml - A simple, auditable log retention policy
# Reviewed by: Legal & Engineering | Version: 1.2
policies:
- name: "raw_edge_access_logs"
description: "Full logs with IP, User-Agent for WAF debugging"
retention_days: 45
pii_fields: ["client_ip", "user_agent", "cookie"]
action_after_retention: "anonymize_and_aggregate"
storage: "s3-standard"
- name: "anonymized_monthly_summary"
description: "Aggregated traffic & error rates, no PII"
retention_days: 400 # ~13 months for annual audits
pii_fields: []
action_after_retention: "delete"
storage: "glacier-deep-archive"
- name: "security_waf_events"
description: "Flagged malicious requests for legal hold"
retention_days: 730 # 2 years for potential litigation
pii_fields: ["client_ip"]
action_after_retention: "review"
storage: "s3-object-lock"
What to Keep, How Long, and What It’ll Cost You
So what numbers should you actually use? There’s no single global law for log retention, but most CDN legal requirements fall into predictable buckets. Payment data (PCI-DSS adjacent logs) often pushes you toward a year. General privacy laws want you to justify every month you keep personal data. And your own security team will want at least a few weeks of raw data to investigate an incident. The trick is mapping each need to a storage tier.
Don’t pay for instant access to data you’ll only need if you get sued. This is where cost control really happens. For example, CDN Log Sampling Strategies: Reducing Storage Costs Without Losing Signal can cut your raw volume by 80% before it even hits your compliance bucket, but even without sampling, tiering saves a fortune. Keep those first 30 days in Standard for quick queries, then shift to Infrequent Access, then to Glacier. I’ve seen teams cut their yearly storage bill from $18k to under $3k just by adding two transition rules — with the exact same retention period.
| Log Category | Typical Compliance Need | Recommended Retention | Storage Tier Strategy | Est. Cost per TB / Month |
|---|---|---|---|---|
| Raw Access Logs (with IP/PII) | Security & debugging (GDPR: minimize) | 30-45 days | Standard (30d) → Delete or Anonymize | $23.00 |
| Anonymized / Aggregated Logs | Capacity planning & analytics | 13 months | Standard-IA (90d) → Glacier Instant | $4.50 - $12.50 |
| WAF / Bot / Security Events | PCI-DSS, fraud investigation | 12-24 months | Glacier Flexible (90d+) + Object Lock | $3.60 |
| Billing / Cache Purge Audit Logs | Contract & change audit | 7 years | Glacier Deep Archive | $0.99 |
Putting Tiered Retention Into Practice Without Killing Your Pipeline
Your policy's approved, now you've got to actually build it. Don't try to force every log type through the same pipeline — that's how you end up over-retaining PII and overpaying for storage you don't need. We've learned to split our CDN logs into three tiers on ingest: security/WAF events, access/compliance logs, and analytics/clickstream. Security logs get the longest hot retention because you'll need them for incident response, while raw access logs with full IPs can be aggressively anonymized after 30-45 days.
The math gets real fast. A mid-sized e-commerce property doing 2,000 RPS per POP across 40 POPs will generate roughly 6-8 TB of raw logs per day. Keep that in hot ClickHouse or BigQuery at $0.023 per GB and you're looking at $5,200+ per month just for 30 days of retention. Our standard pattern now is 30 days hot (ClickHouse/BigQuery for fast queries), 90 days warm as gzipped Parquet in S3 Standard-IA ($0.0125/GB), then 1-7 years cold in S3 Glacier Instant or GCS Archive ($0.004/GB). That tiering alone cuts our log storage bill by 68-72% while keeping us compliant for PCI DSS (1 year) and most SOC 2 requirements.
Automate the anonymization and deletion — don't rely on a cron job someone has to remember. Hash or truncate IPs after your hot window expires, and let lifecycle policies handle the rest. If you're doing any kind of Clickstream Analysis at CDN Edge: Understanding User Navigation Patterns, you’ll want to fork a pseudonymized stream *before* the hot window closes. That way your product team keeps their behavioral data, but your compliance team can prove the raw PII is gone. Here's the Terraform we use for almost every customer bucket:
# Tiered CDN log retention with PII auto-expiry and legal hold support
resource "aws_s3_bucket_lifecycle_configuration" "cdn_logs" {
bucket = aws_s3_bucket.cdn_logs.id
rule {
id = "access-logs-tiered-retention"
status = "Enabled"
filter { prefix = "access/" }
transition {
days = 30
storage_class = "STANDARD_IA"
}
transition {
days = 90
storage_class = "GLACIER"
}
expiration {
days = 365 # Adjust to 2555 for 7-year PCI/SOC2
}
noncurrent_version_expiration {
noncurrent_days = 30
}
}
rule {
id = "security-logs-extended"
status = "Enabled"
filter { prefix = "waf-security/" }
transition {
days = 90
storage_class = "GLACIER"
}
expiration { days = 1095 }
}
}
# Anonymize after 30 days with Athena + S3 Object Lambda
# SELECT regexp_replace(client_ip, '\\.\\d+$', '.0') as anon_ip
Advanced Patterns and Troubleshooting When Auditors Come Knocking
Policies look great on paper until legal says "hold everything related to that incident" or an auditor asks you to prove a log was actually deleted. For legal holds, don't try to pause your lifecycle rules — you'll forget to turn them back on and suddenly you're retaining everything forever. Instead, we use S3 Object Lock in Governance mode and copy the relevant objects (filtered by time, POP, or Ray ID) to a separate `legal-hold/` prefix with its own retention. It's immutable, auditable, and it doesn't contaminate your main retention timeline. We've had a hold last 18 months for a payment fraud investigation; the main pipeline kept churning and deleting on schedule without a single manual intervention.
The most common troubleshooting call we get isn't missing logs, it's "why don't these logs match?" Clock skew across 50+ edge POPs, plus deferred log shipping during peak, means your timestamps will be out of order by 2-5 seconds — sometimes 30+ seconds if a POP had a brief partition. If you're trying to stitch together a User Journey Analytics from CDN Logs: Mapping the Path to Conversion or build Conversion Attribution from CDN Edge: First-Party Tracking Without Client-Side Scripts, you must normalize on `edge_timestamp` not `received_timestamp`, and buffer your ETL by at least 5 minutes. And for GDPR's "proof of deletion" requirement, enable S3 Inventory and CloudTrail data events on your log buckets. When an auditor asks for deletion evidence, you can show the lifecycle transition and the 403 on attempted rehydration — "trust us, we deleted it" won't cut it.
Finally, watch your cross-region replication. If you're replicating logs from EU POPs to a US bucket for analysis, you've just created a data residency violation. We've fixed this by keeping raw logs in-region (eu-central-1 for EU traffic) and only replicating the anonymized Parquet dataset globally. It adds about $0.02 per GB in replication costs, but it's a hell of a lot cheaper than a GDPR fine. And always test your rehydration — we run a monthly restore of a random Glacier archive to ensure we can actually produce 13-month-old logs within the 24-hour SLA auditors expect.
Frequently Asked Questions
How long do we *actually* need to keep CDN logs for GDPR vs. PCI DSS?
They're different clocks. GDPR doesn't mandate a specific retention period — it mandates you keep personal data (like IPs) no longer than necessary, which for most of our clients means 30-45 days for raw IPs, then anonymized. PCI DSS 4.0 is explicit: 90 days immediately available (hot/warm) and 1 year total retention for audit logs. If you handle card data at the edge, keep your WAF/security logs for 1 year, but you can still anonymize access logs after 30 days and stay compliant with both.
Can we just anonymize IPs immediately and keep logs forever for cheap?
You can, but you'll break your own incident response. If you truncate IPs to /24 on ingest, you can't trace a DDoS or credential stuffing attack back to a single actor. The pattern that passes audits is delayed anonymization: keep full IPs for 30 days in hot storage for security, then run a batch job to hash/truncate and move to warm/cold. You keep the long-term trends for capacity planning without the PII liability. Storage cost for anonymized Parquet in Glacier is about $4 per TB/month, so keeping 7 years is genuinely cheap.
What do we show an auditor when they ask for logs we've already deleted?
You show proof of policy enforcement, not the logs. Auditors want three things: 1) Your documented retention schedule with business justification, 2) S3 lifecycle/bucket policy JSON showing automated deletion, and 3) S3 Server Access Logs or CloudTrail showing the DELETE operations plus an S3 Inventory report proving the objects are gone. We've never had an auditor penalize a company for deleting on schedule — we *have* seen findings for keeping logs 2 years past policy without justification.
How do we handle conflicting retention laws for US vs. EU traffic?
Don't use a single global bucket. Tag logs at the edge by jurisdiction (we use a `x-cdn-geo: eu/us` header added at the POP) and route to region-specific buckets with different lifecycles — eu-central-1 might be 30 days raw + 1 year anonymized, while us-east-1 is 90 days raw + 7 years anonymized for a US litigious hold requirement. The edge routing adds <5ms of log shipping latency and keeps you from having to apply the strictest rule everywhere, which would've cost one of our SaaS clients an extra $11,000/month in unnecessary hot storage.