# Proposed AWS Component Diagram v0.3 ![AWS Component Architecture](../diagrams/aws_components.svg) --- ## Components ### 1. Application Layer **AWS Application Load Balancer (ALB)** - Terminates TLS (HTTPS) for incoming webhooks from Healthie (lightweight pointer POST — worker fetches full data via GraphQL) - Routes traffic to Fargate tasks via target group - Access logging enabled **AWS Fargate (ECS Tasks)** - Runs the Django application container - Auto-scaled based on CPU in **production only**; staging and dev run a fixed fleet (`infra/environments/*/main.tf`) - Tasks run in private subnet (no public IP) - IAM task role grants least-privilege access to S3, Secrets Manager, SQS, KMS, RDS - Workers consume SQS: perform GraphQL fetch for Healthie pointer events to retrieve full resource data before normalization (**worker task code pending** — dev runs the same flow synchronously in the webhook view) ### 2. Data Layer **Amazon RDS (PostgreSQL)** - Primary database for all structured data - Deployed in private subnet - Encrypted at rest with KMS - Automated backups with point-in-time recovery (retention per env: dev 1 day, staging 7 days, prod 14 days) - Multi-AZ for production (HA); storage encryption on in staging/prod (dev stores synthetic data only, unencrypted by design) - Connections via VPC security group (only Fargate tasks can connect) **Amazon S3** - Stores clinical documents: lab PDFs, imaging reports, PROM screenshots, consent forms - Server-Side Encryption with KMS (staging/prod); AES256 in dev — bucket key enabled - S3 Block Public Access enabled (all four settings) - Versioning enabled (staging/prod), lifecycle rule expires noncurrent versions after 90 days - Object access logging: planned, not yet configured - Access via the Fargate task role's IAM policy; a restrictive bucket policy is planned ### 3. Messaging Layer **Amazon SQS** - Standard queue for webhook event processing (Healthie pointer-only events requiring follow-up GraphQL fetch) - Decouples webhook receipt from application processing - Dead-letter queue (DLQ) for failed messages after N retries; both queues KMS-encrypted with redrive policy - **Dev note:** queues exist in dev but private subnets have no SQS route (no interface endpoint/NAT by design) — task role SQS grants are inert until a consumer lands and `"sqs"` is added to the endpoints list ### 4. Security & Secrets **AWS Secrets Manager** - Stores today: database password (auto-generated), Django secret key (`-app-secrets`) - To add before go-live: Healthie API key + webhook secret, CMS client ID/secret — see `infra/README.md` pre-go-live checklist - Fargate tasks retrieve secrets at runtime via IAM-authorized API calls - Access logged via CloudTrail **AWS KMS** - Master key for PHI field encryption (application-level AES-256-GCM, `enc:v1` envelopes) + separate pseudonymization key (HMAC case IDs — service pending) - Master key for RDS encryption at rest and S3 SSE-KMS - Automatic key rotation (annual) - Key policy: Fargate task role (via `app_principal_arns`) + admin principal; the PHI field key additionally grants the RDS service principal (grant-based access only — it cannot decrypt) **Amazon CloudTrail** - Logs all API calls across the AWS account (**proposed / account-level — not part of this repo's Terraform**) - Enables compliance auditing and security monitoring ### 5. Monitoring & Logging **Amazon CloudWatch** - Application logs from Fargate tasks (structured JSON logs) - Custom metrics: queue depth, webhook delivery rate, processing latency, error rate - Alarms: queue depth threshold, deployment failure, RDS CPU/memory thresholds - Log retention: configurable per compliance requirements ### 6. Network & Access **Amazon VPC** - Public subnet: ALB only - Private subnet: Fargate tasks, RDS - No full NAT gateway; staging/prod add an egress-only internet gateway (single-AZ) so private tasks can reach non-AWS destinations (CMS ACCESS API, Healthie). Dev has no such route. - VPC endpoints for S3, Secrets Manager, KMS, SQS (private connectivity for AWS APIs — more specific routes than the NAT default) - Security groups enforce least-privilege inter-service communication ### 7. CI/CD (proposed — not yet built) **AWS CodePipeline + CodeBuild** - Triggered on push to `main` - Stages: test → security scan → build container → deploy staging → approve → deploy production - Container image built with CodeBuild, stored in Amazon ECR - Same artifact promoted from staging → production (immutable container image) - IAM roles for pipeline execution (least-privilege) > **Current state:** CI runs on GitHub Actions (`.github/workflows/ci.yml` — lint + test suite). Container deployment to ECS is manual `docker build`/push until the pipeline lands. --- ## Environment Separation | Environment | VPC | RDS | S3 | Fargate | Secrets Manager | |---|---|---|---|---|---| | Development | Dedicated (synthetic data only) | Single-AZ, unencrypted by design, 1-day backup retention | AES256, no versioning | 1 task, fixed fleet, no SQS route | Dev secrets | | Staging | Dedicated VPC | Single-AZ, KMS encrypted, 7-day retention | SSE-KMS, versioned | Fixed fleet (default 2 tasks), no auto-scale | Staging secrets | | Production | Separate VPC | Multi-AZ, KMS encrypted, 14-day retention | SSE-KMS, versioning, lifecycle | CPU auto-scaled, health checks (gunicorn) | Production secrets | All three environments are defined in `infra/` (Terraform): see `infra/README.md` for state bootstrap and per-env plan/apply.