$ contact --now

WAF + CDN rollout across a multi-brand, multi-country domain portfolio

Migrating every public-facing brand domain across four countries onto CloudFront + AWS WAF — geo-fencing, OWASP managed rules, and centralized logging — as a scheduled, reversible cut-over that never touched how internal traffic reached the same backends.

CloudFrontAWS WAFTerraformRoute 53ACM

Overview

Goal: put AWS WAF in front of every public web and API endpoint across the brand portfolio to protect against OWASP Top-10 threats, geo-block traffic from high-risk jurisdictions, and centralize logging and monitoring through CloudWatch — without disturbing how internal users and services already reach the same backends via an internal load balancer.

[ External users / bots ] ──► [ Amazon CloudFront ]  ◄── ACM wildcard certs per brand
                                        │                   (*.brand1.com, *.brand2.se, ...)
                                 [ AWS WAF ]  ──► [ OpenSearch — logging ]
                                        │
                              [ Internal load balancer ]  ◄── internal users, unchanged path
                                        │
                          [ Ingress / EKS workloads ]

Infrastructure is managed as a single reusable Terraform module, so every brand domain gets the same WAF ruleset, logging configuration, and certificate handling rather than a hand-rolled one-off per domain.

1. Geo-fencing policy

Traffic is blocked from a list of countries aligned with EU sanctions guidance and the EU's published list of jurisdictions of concern — a mix of comprehensively sanctioned states and countries flagged for elevated fraud/AML risk in the financial sector specifically. This is public policy guidance, not company-specific data, and is reviewed periodically rather than hard-coded permanently, since sanctions guidance changes:

Afghanistan, Belarus, Bosnia & Herzegovina, Burundi, Central African Republic, China, DPRK (North Korea), DR Congo, Guatemala, Guinea, Guinea-Bissau, Haiti, Iran, Iraq, Lebanon, Libya, Mali, Moldova, Montenegro, Myanmar (Burma), Nicaragua, Niger, Russia, Serbia, Somalia, South Sudan, Sudan, Syria, Tunisia, Türkiye, Ukraine (limited regions), United States (for certain EU crypto rules), Venezuela, Yemen, Zimbabwe.
Geo-blocking is a risk-reduction control, not a compliance guarantee on its own — treat the country list as one input to a broader fraud/AML program, and keep it under change control so updates are reviewable rather than a silent edit no one remembers making.

2. Domain scope

Every public brand domain across the portfolio was brought into scope, each with its own ACM wildcard certificate in us-east-1 (a CloudFront requirement) and its own set of subdomains routed through CloudFront + WAF. The full domain-by-domain scope for this rollout — domain names below are illustrative brand placeholders, not the real portfolio:

brand1.com — primary consumer brand

Subdomains routed through CloudFront + WAF
agreementanetapieid
idinvoiceminesider-altminasidor
myportalprod-cmsprovenir
loanappssocore-dev.partnercore.partner
*.core.partner*.core.test-partnerwww

brand2.se — domestic brand + internal tooling

Subdomains routed through CloudFront + WAF
apiconfluencedev-gatedev-sftp
invoicesgategitgrafana
loanappnugetrepooctopuspmm-flow
dev-filetransfersonarqubesrvtest-confluence
test-gatewww

Remaining brand domains — international markets

Brand domainSubdomains routed through CloudFront
brand3.fiwww, *.brand3.fi
brand4.nowww, *.brand4.no
brand5.nowww, *.brand5.no
brand6.nowww, www.nettbank, *.brand6.no
brand7.nowww, flexicredit

Seven brand domains across four countries, roughly fifty individual and wildcard subdomains in total — every one of them backed by the same reusable Terraform module, the same WAF ruleset, and the same CloudWatch logging target, so onboarding domain fifty felt identical to onboarding domain one.

Internal DNS remains unchanged throughout and continues to resolve directly to the internal load balancer — only public DNS records move to CloudFront. Keeping these two resolution paths genuinely independent is what makes the cut-over reversible.

3. DEV/TEST as a dress rehearsal

Before touching a single production record, the same Terraform module was applied to dev-* and test-* subdomains and left running for a full test cycle:

  • AWS managed rule groups plus custom rules tested against real application traffic patterns to confirm nothing legitimate gets blocked
  • Geo-blocking confirmed with traffic simulated from both allowed and blocked regions
  • Rate-limiting and IP allow-listing verified against known internal and partner ranges
  • Application functionality tested end to end to confirm the WAF doesn't block legitimate traffic
  • CloudWatch log groups and alarms confirmed to be receiving and triggering correctly

Additional recommendations worked through before production cut-over: simulating realistic traffic patterns to validate allowed vs. blocked requests, cross-region/edge-case testing for geo-blocking, integration tests against production-like clients to verify headers and redirects, and a final CloudWatch monitoring pass to confirm logs and alarms trigger as expected. DEV/TEST was treated explicitly as a dress rehearsal for exactly this reason — every issue found there is one that never reaches a customer.

4. Prerequisites & preparations

ItemDetailEst. time
CertificatesACM wildcards requested and validated in us-east-1 for every brand domain — validation can take longer than expected, so this starts well ahead of cut-over10 min per domain (initiation)
Terraform backendS3 + DynamoDB state lock ready and accessible10 min
DNSRoute 53 zones confirmed to exist for every domain in scope; records verified with dig/nslookup20 min
IAM rolesTerraform role verified for least privilege — create/modify access limited to WAF, CloudFront, Route 53, ACM, CloudWatch only5 min
Load balancer backupCurrent internal load balancer configuration (in git) and public IP recorded5 min
DNS TTL adjustment (optional)Lower TTL on non-alias records to 300s a few hours ahead of cut-over to speed propagation — CloudFront alias records propagate on their own and don't need manual TTL tuning10 min

Preparations phase, end to end: roughly 1–2 hours, done well ahead of the actual cut-over window.

5. Cut-over steps

#ActionResponsibleEst. time
1Update Terraform configuration to include the module, all WAF rules, CloudFront distributions, logging, and wildcard certs for every domainInfra/App30 min
2Review and approve the Terraform plan (terraform plan -out=tfplan)Infra/App15 min
3Apply the plan (terraform apply tfplan) to deploy WAF, CloudFront, CloudWatch, and prepare DNS records — no traffic cut over yetInfra/App30 min
4Confirm internal DNS still points to the internal load balancer, unaffectedInfra/App5 min
5Update load balancer host-header routing if needed; remove any conflicting SNI/SSL termination ahead of the public cut-overInfra/App20 min
6Validate ACM wildcard certificates in both Terraform state and the AWS consoleInfra/App5 min
7DNS cut-over: update public Route 53 records to point to CloudFront, scheduled for the low-traffic windowInfra/App10 min
8Functional testing: verify every domain resolves and behaves correctly via its CloudFront endpointDev & NOCwithin the overnight window
9Security testing: verify WAF geo-blocking and rate-limiting rules fire against the live endpointDev/NOC30 min
10Logging validation: confirm the CloudWatch log group is receiving entries and alarms are functionalNOC30 min
11Remove the public IP from the internal load balancer once verified, so all public traffic flows through CloudFrontInfra/App10 min

6. Estimated timeline

PhaseDuration
Preparations1–2 hours (ahead of cut-over window)
Production deployment (Terraform + load balancer + DNS)~1 hour, scheduled overnight
DNS propagation & verificationOvernight through the following morning
Post-cutover monitoring~2 hours, final verification the next morning

7. Rollback plan

  • Revert to the previous Terraform configuration and re-apply
  • Restore the internal load balancer's public IP
  • Confirm both internal and public DNS resolve correctly back to the load balancer

8. Communication

The wider IT organization is notified ahead of the scheduled cut-over window, including the expected start/end time and who to contact if something looks wrong during the overnight monitoring period — a reversible plan is only as good as people knowing it's happening.

Pre-go-live checklist

  • Terraform plan reviewed and approved by a second engineer
  • ACM certificates issued and validated for every domain in scope
  • DNS records verified with dig/nslookup before and after cut-over
  • Load balancer configuration backed up
  • Terraform IAM role confirmed least-privilege
  • CloudWatch logging and alarms confirmed functional
  • Cut-over window and rollback plan communicated to the wider team in advance