Reference architecture for a HIPAA healthcare master
The end-to-end flow from source systems to consumers, every service's role, the multi-account boundaries, and the stated scale the rest of this set is sized against.
markdownexamplev1Y4DQ-4KEHstage: designtrust: officialservice: s3service: glueservice: entity-resolutionservice: healthlakeservice: auroraservice: step-functionsservice: eventbridgeservice: athenainterface: architectureend-to-end healthcare MDM architecturemulti-account landing zone Control Towerzone model raw curated masterEntity Resolution and HealthLake placementStep Functions orchestrationpublish to consumers EventBridgeaccount boundaries for PHIstated scale assumptions
The scale this set is sized against
Every estimate in this set assumes one stated scale, named here so that the arithmetic elsewhere is checkable. Substitute your own figures before reusing any total.
| Dimension | Assumed value |
|---|---|
| Source systems | 6 — two EHRs, registration, claims, provider roster, patient portal |
| Patient source records | 12 million, resolving to roughly 8 million distinct patients |
| Provider records | 400,000, resolving to roughly 300,000 distinct providers |
| Organisations and locations | 15,000 and 25,000 |
| Monthly changed records | 2 million across all entity types |
| Synchronous lookups | 200,000 per month from registration screens |
| Region | US East (N. Virginia), single Region, DR to a second Region |
| Clinical data volume in FHIR | 2 TB growing 100 GB per month |
These are assumptions, not measurements. They exist so the cost model in document 07 has something to multiply.
The zone model
Four zones, each with a different retention and access posture. The zone model is what makes the architecture auditable: every master value can be traced back to an immutable object.
| Zone | Store | Purpose | Mutability |
|---|---|---|---|
| Raw | S3 with Object Lock | Every inbound payload, exactly as received | Immutable |
| Curated | S3, Glue Data Catalog | Standardised, quality-checked, matchable | Rewritable |
| Master | Aurora PostgreSQL | Golden records, crosswalk, steward decisions | Versioned |
| Interoperability | HealthLake | FHIR R4 clinical and demographic view | Transactional |
Raw uses S3 Object Lock, which "uses a write-once-read-many (WORM) model to store objects" and
"works only in buckets that have S3 Versioning enabled". Governance mode is the right default for
raw: it protects objects "against being deleted by most users" while allowing a holder of
s3:BypassGovernanceRetention to act, and that bypass requires an explicit
x-amz-bypass-governance-retention:true header. Compliance mode is stronger — an object "can't be
overwritten or deleted by any user, including the root user in your AWS account", and "the only way
to delete an object under the compliance mode before its retention date expires is to delete the
associated AWS account". Reserve it for the audit log, and understand the irreversibility before
choosing it.
End-to-end flow
SOURCES INGEST / LAND CURATE + MEASURE
------- ------------- ----------------
EHR (HL7v2, FHIR) --\ API Gateway + Lambda Glue ETL (Spark)
Registration -------+-> Kinesis Data Streams --> - standardise, flatten
Claims / payer -----+ or Amazon MSK - Glue Data Quality (DQDL)
Provider roster ----+ | - quarantine failing rows
Portal / CRM -------/ v |
S3 RAW (Object Lock, v
versioned, KMS CMK) S3 CURATED + Glue Data Catalog
| (Lake Formation governed)
| |
| v
| MATCH (Step Functions, serialised)
| +--------------------------------+
| | AWS Entity Resolution |
| | rule-based workflow (primary) |
| | ML workflow (second pass) |
| | GenerateMatchId (synchronous) |
| +--------------------------------+
| | match groups + match IDs (S3)
| v
| RESOLVE (CUSTOM CODE)
| +--------------------------------+
+-------------------->| crosswalk: matchId -> master id|
lineage back to | survivorship rule evaluation |
the raw object | steward override replay |
| version + provenance per attr |
+--------------------------------+
|
+------------------+------------------+
v v
MASTER (Aurora PostgreSQL) HealthLake (FHIR R4)
golden records, crosswalk, resource matching ->
steward decisions, audit Linkage (preview)
| |
v v
PUBLISH (IDs only) FHIR R4 APIs,
outbox -> EventBridge Bulk Data export,
-> SNS / SQS per consumer SMART on FHIR
-> S3 extract for analytics |
| v
+-----------> CONSUMERS <-------------+
Athena, Redshift, OpenSearch,
downstream apps, steward console
Every service's role
| Service | Role in this architecture |
|---|---|
| Amazon S3 | Raw and curated zones; match output; extracts. Object Lock for immutability |
| AWS KMS | Customer managed keys per zone; key policy is the second access control |
| AWS Glue (ETL) | Standardise, flatten FHIR-shaped data, write curated tables |
| AWS Glue Data Catalog | The table definitions Entity Resolution reads from |
| AWS Glue Data Quality | DQDL rulesets, scores, and quarantine of failing rows |
| AWS Lake Formation | Column, row and cell-level permissions over curated data |
| AWS Entity Resolution | Matching; produces match groups and match IDs |
| AWS HealthLake | FHIR R4 store, FHIR APIs, Bulk Data export, integrated NLP |
| Amazon Aurora PostgreSQL | The master: golden records, crosswalk, steward decisions |
| Aurora reader, second AZ | Failover target for the synchronous registration path |
| AWS Step Functions | Orchestrates the pipeline and serialises matching jobs |
| AWS Lambda | Transformations, survivorship evaluation, synchronous lookups |
| Amazon Kinesis / MSK | Streaming ingestion of ADT and registration events |
| Amazon EventBridge | Publishes master-change events; also a HealthLake event target |
| Amazon SNS / SQS | Per-consumer fan-out with retry and a dead-letter queue |
| Amazon Athena | SQL over curated data and over HealthLake data |
| Amazon Redshift | Analytical consumption where a warehouse already exists |
| Amazon OpenSearch Service | Steward search over candidate matches |
| Amazon Comprehend Medical | PHI and clinical entity detection in free text |
| Amazon Macie | Sensitive-data discovery over the S3 zones |
| AWS CloudTrail | API audit, including data events on the PHI buckets |
| AWS Config | Conformance pack Operational-Best-Practices-for-HIPAA-Security |
| AWS Security Hub CSPM | Aggregated findings across accounts |
| IAM Identity Center | Human access; Cognito where patients or partners authenticate |
| Amazon VPC and PrivateLink | Private connectivity; no PHI path over the public internet |
| AWS Backup | Backup and Vault Lock for Aurora, S3, DynamoDB |
| AWS Control Tower | Landing zone, organisational units, guardrails |
HealthLake's own documentation names IAM, S3, CloudTrail, CloudWatch, CloudFormation, AWS PrivateLink, EventBridge, AWS Lake Formation and Amazon Athena among its related services, so the integration points above are documented rather than inferred.
Account boundaries
A single account is the wrong answer. Use AWS Control Tower to establish organisational units, and separate accounts by blast radius and by whether PHI is present.
Organization (AWS Organizations, Control Tower landing zone)
|
+-- Security OU
| +-- Log archive CloudTrail org trail, Config history. No PHI. Object Lock.
| +-- Security tooling Security Hub CSPM, Macie delegated admin, GuardDuty
|
+-- Infrastructure OU
| +-- Network Transit gateway, egress, PrivateLink endpoints
| +-- Shared services CI/CD, artefact store. No PHI.
|
+-- Data OU (PHI present; every account covered by the BAA)
| +-- Ingest Raw S3 zone, Kinesis/MSK, API Gateway
| +-- Resolve Glue, Entity Resolution, Step Functions, curated S3
| +-- Master Aurora, the crosswalk, the steward console backend
| +-- Interop HealthLake data store
|
+-- Consumption OU
+-- Analytics Athena, Redshift. Lake Formation grants. PSEUDONYMISED PHI unless
| the linking code is removed; de-identified extracts are a
| separate product. Athena results bucket is its own PHI sink.
+-- Non-production Synthetic data only. Never production PHI. The labelled
match-evaluation set is real patient data and so lives in the
Data OU, not here.
Three reasons this split earns its complexity. First, the Entity Resolution quota "Concurrent matching jobs — Each supported Region: 1 — Adjustable: No" is per account and Region, so separating the resolve account from everything else preserves the option of adding a second account to lift effective concurrency. Second, the log archive account is the only durable integrity story for audit: logs written to an account whose operators cannot delete them. Third, the non-production boundary is the single most effective PHI control available, because the cheapest way to avoid disclosing PHI in a lower environment is for it never to be there.
Cross-account data sharing uses Lake Formation, which "simplif[ies] securing and managing distributed data lakes across multiple AWS accounts through a centralized approach, providing fine-grained access control to the Data Catalog and Amazon S3 locations", with permissions "enforced using granular controls at the column, row, and cell-levels" across Athena, Redshift Spectrum, EMR and Glue.
Two paths through the same pipeline
Batch, for the bulk of the work. Step Functions runs on a schedule: crawl and standardise, evaluate data quality, start the Entity Resolution matching job, wait for completion, apply survivorship and overrides, upsert the master, publish changes. Serialised by entity type because of the concurrency quota.
The master is on a clinical path, so it needs a high-availability posture rather than a single
instance: an Aurora writer with a reader in a second Availability Zone and automatic failover.
Document 07 carries the cost of that reader. State the degraded mode too — if the master is
unreachable, registration falls back to GenerateMatchId alone and the golden-record update is
reconciled afterwards, rather than the screen blocking.
Three places PHI accumulates outside the four zones, each needing its own key, retention and scanning: Step Functions execution history, CloudWatch log groups, and the Athena query-results bucket. Documents 04 and 06 cover the controls; the point here is that they are part of the architecture, not incidental.
Synchronous, for registration. A registration screen calls GenerateMatchId, which "processes
your records against the workflow's matching rules to identify potential matches. For existing
records, it retrieves their Match IDs and associated rules. For records without matches, it
generates new Match IDs." It is rule-based only, takes a "Fixed number of 1 item" per call, defaults
to 10 requests per second, and "Additional charges apply for each API call". Its default
CONSISTENT mode "provides highest accuracy but slower response time" — the right trade for a
clinical registration.
Document 06 covers idempotency, reprocessing and recovery across both paths.