Picture a routine appointment. The clinician greets the patient and taps a button, and from that moment the conversation itself becomes the documentation: transcribed, structured into the sections a clinical note actually needs, and handed back as a draft for the clinician to review — so they can look at the patient instead of a keyboard. That's the workload we're architecting: real, regulated by HIPAA, and handling some of the most sensitive data in existence.
This post isn't a pile of YAML — it's about how you reason when the Well-Architected Framework meets a workload where a misconfigured bucket isn't an incident but a reportable breach. I keep the resource footprint deliberately minimal, because in a regulated environment every resource is a control you have to justify, document, and defend.
The AWS Well-Architected Framework is built on six pillars — Operational Excellence, Security, Reliability, Performance Efficiency, Cost Optimization, and Sustainability — and AWS layers a Healthcare Industry Lens of domain-specific principles on top. We'll use both. But first, the part you don't get to skip.
The Foundation You Architect Before the Architecture
There's always the temptation to go to the whiteboard and start drawing boxes. In healthcare, three things come before any box exists.
1. The Business Associate Addendum (BAA). If you're a Covered Entity or Business Associate touching Protected Health Information, AWS requires a signed BAA before PHI touches any service. No BAA, no ePHI — it's the contract that makes everything downstream lawful.
2. HIPAA-Eligible Services only. AWS maintains a HIPAA Eligible Services Reference (last updated July 22, 2026 as I write this) listing which services may process ePHI. If a service isn't on it, PHI does not touch it. Period. The good news: our whole stack — AWS HealthScribe (part of Amazon Transcribe), S3, KMS, Cognito, CloudTrail, and CloudFormation — is eligible.
3. The Shared Responsibility Model. AWS secures the cloud; you secure what you put in it. HealthScribe operates under this model explicitly — AWS protects the infrastructure, you manage your data, keys, and access. The half that fails audits is almost always the customer's half.
The Healthcare Industry Lens design principles reinforce it: align with regulation early, encrypt all sensitive data (the BAA requires it), log everything with immutable retention, least privilege for all data. Mandates, not afterthoughts.
The Minimal Architecture
Here's the smallest set of resources that does the job and stands up to scrutiny:
| Resource | Why it exists (the WAF/Lens principle) |
|---|---|
| AWS HealthScribe (streaming) | The workload itself — a HIPAA-eligible service that transcribes the visit and generates structured, evidence-linked clinical notes |
| S3 bucket (PHI output) | Durable storage for HealthScribe output — encrypted, private, versioned |
| KMS customer-managed key (CMK) | Customer-controlled encryption + audit — encrypt all sensitive data |
IAM ResourceAccessRole (least privilege) |
HealthScribe's scoped access to S3 and KMS — least privilege for all data |
| CloudTrail | Records every API call for audit — log everything |
On "immutable": CloudTrail isn't tamper-proof by default — you earn that with log file integrity validation plus a WORM-locked S3 bucket (Object Lock). Otherwise it's a claim you can't defend in a review.
That's it. A Cognito-fronted clinician app and an EHR sit at the edges as integration points, not the thing we're securing here. Everything is defined in CloudFormation — itself a Well-Architected decision, and where we start.
Operational Excellence: Everything Is Code, or It Didn't Happen
In a regulated environment, "I clicked some things in the console" is not an audit story. Infrastructure as Code is the Healthcare Lens principle automation reduces operational risk made concrete: a control defined in CloudFormation is reviewable in a pull request, repeatable across accounts, and diffable over time. You can prove exactly when a bucket became encrypted, who approved it, and that it never regressed. So the rule is simple: if it touches PHI, it lives in a template.
Trade-off: IaC front-loads effort — templates are slower to write than clicks. In exchange you get provable, versioned controls, which in healthcare is the difference between passing and failing a review. Not close.
Security: The Pillar That Earns Its Top Billing
For a PHI workload, Security is where the architecture lives or dies. Two decisions carry most of the weight.
Encrypt at rest — with a key you control
By default, HealthScribe encrypts output at rest using AWS owned keys — a layer you can't view, manage, or even audit. That satisfies "encrypted" — not "and we control the key." HealthScribe lets you add a customer-managed key (CMK) as a documented second layer, and for PHI that's the correct choice: a CMK gives you what a compliance program demands — rotation, key policies, the ability to disable the key, and CloudTrail visibility into every encrypt/decrypt via the KMS encryption context.
Here's the core PHI-at-rest decision as one consolidated template — the CMK and the bucket that uses it:
AWSTemplateFormatVersion: "2010-09-09"
Description: PHI-at-rest core for the ambient scribe — CMK + encrypted S3 bucket
Parameters:
ResourceAccessRoleArn:
Type: String
Description: ARN of the IAM role HealthScribe assumes to write output
Resources:
PhiKey:
Type: AWS::KMS::Key
DeletionPolicy: Retain # never destroy key material on stack delete
UpdateReplacePolicy: Retain
Properties:
Description: Customer-managed key for ambient scribe PHI output
EnableKeyRotation: true # rotate cryptographic material annually
KeyPolicy:
Version: "2012-10-17"
Statement:
- Sid: AllowAccountAdmin
Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
Action: "kms:*"
Resource: "*"
- Sid: AllowHealthScribeCrypto
Effect: Allow
Principal:
AWS: !Ref ResourceAccessRoleArn
Action:
- kms:Encrypt
- kms:Decrypt
- kms:GenerateDataKey*
Resource: "*"
Condition:
# scope crypto ops to HealthScribe's own encryption context
ForAllValues:StringEquals:
kms:EncryptionContextKeys:
- aws:us-east-1:transcribe:medical-scribe:session-id
- Sid: AllowHealthScribeDescribeKey
Effect: Allow
Principal:
AWS: !Ref ResourceAccessRoleArn
# DescribeKey carries no encryption context — must stand alone
Action: kms:DescribeKey
Resource: "*"
PhiBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain # a stray stack delete can't take PHI with it
UpdateReplacePolicy: Retain
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: aws:kms
KMSMasterKeyID: !Ref PhiKey
BucketKeyEnabled: true # fewer KMS calls, lower cost
OwnershipControls:
Rules:
- ObjectOwnership: BucketOwnerEnforced # ACLs disabled outright
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
VersioningConfiguration:
Status: Enabled
# Reject anything that isn't TLS — no plaintext PHI in transit, ever
PhiBucketTlsOnly:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref PhiBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: DenyInsecureTransport
Effect: Deny
Principal: "*"
Action: "s3:*"
Resource:
- !GetAtt PhiBucket.Arn
- !Sub "${PhiBucket.Arn}/*"
Condition:
Bool:
aws:SecureTransport: "false"
Notice what the template asserts: encryption is the bucket's default (not something a later upload can forget), ACLs are disabled outright and public access is blocked at every level, every request must arrive over TLS, versioning is on so a bad write can't silently destroy prior state, and Retain policies mean a stray stack deletion can't take the PHI or its key down with it. Declarations, not hopes.
Least privilege, scoped to the service
HealthScribe reaches S3 and KMS through an IAM role you provide — the two AllowHealthScribe* statements above are the whole grant: encrypt, decrypt, and generate a data key, plus a separate DescribeKey grant, and nothing else. That split isn't cosmetic. HealthScribe stamps a service-generated encryption context onto every crypto call — for streaming, the aws:us-east-1:transcribe:medical-scribe:session-id key — so you can scope those operations with an encryption-context condition the way AWS documents. But DescribeKey carries no encryption context, so it has to stand on its own or that condition would lock it out. The context is plaintext by design and surfaces in CloudTrail (the calls appear under the transcribe.streaming.amazonaws.com principal), which is exactly how you get auditable visibility into every encrypt/decrypt — so never put secrets in it.
The audit trail earns "immutable" — on its own bucket
That "tamper-evident" claim from the resource table isn't free, and it's why the audit logs live in a separate bucket from the PHI. The two have opposite retention needs: PHI output must stay deletable (retention expiry, a patient's right to erasure), while audit logs must be undeletable for the whole retention window. You can't satisfy both on one bucket — a WORM lock forbids the very lifecycle expiration the PHI bucket depends on. So the audit trail gets Object Lock in COMPLIANCE mode, which not even the root account can shorten:
# CloudTrail's WORM target — separate from PHI so retention rules don't collide
AuditLogsBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Properties:
ObjectLockEnabled: true # can only be set at bucket creation
ObjectLockConfiguration:
ObjectLockEnabled: Enabled
Rule:
DefaultRetention:
Mode: COMPLIANCE # immutable — not even root can delete early
Years: 7 # match your audit-retention obligation
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: aws:kms
KMSMasterKeyID: !Ref PhiKey
BucketKeyEnabled: true
OwnershipControls:
Rules:
- ObjectOwnership: BucketOwnerEnforced
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
VersioningConfiguration:
Status: Enabled # required for Object Lock
Point CloudTrail at this bucket (with its standard delivery bucket policy for cloudtrail.amazonaws.com) and turn on log file integrity validation, and now the claim holds: the logs are cryptographically verifiable and physically immutable for seven years. One easy-to-miss wire: because the bucket is encrypted with the CMK, CloudTrail also needs kms:GenerateDataKey* on PhiKey — scope it with a kms:EncryptionContext:aws:cloudtrail:arn condition, or cleaner still, give the audit trail its own key so its blast radius never overlaps the PHI. That's the difference between "we log everything" and a sentence you can actually defend in a review.
Reliability: Designing Around a Hard Regional Constraint
Here's the constraint behind the biggest design decision: AWS HealthScribe is available only in US East (N. Virginia), us-east-1. One Region. That rules out an active-active, multi-Region scribe tier. So you design around it:
- Graceful degradation over false availability. The Lens principle is plan to recover from failures automatically — but the key recovery here is human: if HealthScribe is down, the visit still happens and the clinician documents the old-fashioned way. It's an assist, not a dependency for care — its availability KPI tracks clinician productivity, not patient safety.
- DR for the processing tier is backup-and-restore, not multi-Region failover. The processing tier accepts a Region-scoped RTO. Durable PHI in S3 already has versioning; cross-Region replication is an optional add-on if your RPO demands it — not part of the minimal footprint. State RTO/RPO explicitly and get sign-off — claiming multi-Region five-nines when the core service is single-Region is how you lie to yourself in a review.
Trade-off: you trade the fantasy of active-active for an honest, documented single-Region posture with a human fallback. In healthcare, honesty about failure modes is the reliability strategy.
Performance Efficiency: Pick the Right Ingestion Mode
HealthScribe offers two workflows: real-time streaming (an HTTP/2 bidirectional channel) and asynchronous transcription jobs that batch-process audio from S3. Streaming gives the clinician near-real-time notes at the cost of more moving parts; batch jobs are simpler and cheaper but lose the immediacy. For an ambient scribe whose entire value is freeing the clinician in the moment, streaming wins — provided you feed it audio it can use: the docs require US English, lossless audio (FLAC/WAV), and 16-bit PCM at 16 kHz or higher. Garbage in, garbage note out.
Cost Optimization: The Cheapest Control Is the One You Don't Duplicate
Minimalism is a cost strategy. Every resource you don't provision is spend you don't incur and a control you don't have to audit. Beyond that, two doc-grounded levers:
- S3 lifecycle policies. PHI has retention obligations, but week-old audio doesn't need standard-tier pricing. Transition older objects to colder classes and expire what your policy allows — retention and cost aren't enemies, lifecycle rules are where they negotiate.
BucketKeyEnabledon S3. That one line in the template lowers the number of KMS API calls S3 makes, cutting KMS cost — security and cost pulling the same direction for once.
Trade-off: the CMK carries a monthly cost and per-request charges the default key doesn't. For PHI, that's the price of control and auditability — a rounding error next to a breach.
Sustainability: Managed Services and Disciplined Data Lifecycle
The Sustainability pillar rewards using exactly the resources you need and no more. Our architecture leans in almost by accident: HealthScribe is fully managed, so AWS runs the underlying compute far more efficiently than a bespoke pipeline on always-on instances could. Add the S3 lifecycle discipline from the cost section and sustainability aligns with both cost and compliance — three pillars, one decision. That's what "well-architected" feels like when it clicks.
The Constraints and Trade-Offs, on One Page
Principal-level architecture is mostly the discipline of making trade-offs explicit instead of discovering them in production. Here they are:
| Decision | Constraint / Trade-off | Why we chose it |
|---|---|---|
| HealthScribe region | us-east-1 only — no active-active scribe tier |
Accept single-Region processing with graceful human fallback; care never depends on it |
| Customer-managed CMK | Adds KMS cost + key-policy operational overhead | Control, rotation, and CloudTrail auditability the BAA effectively demands |
| Streaming vs. batch | Streaming = better UX, more complexity + cost | The product's value is in-the-moment; UX wins |
| AI-drafted notes | Output is probabilistic and assistive only | Human-in-the-loop is non-negotiable — a clinician reviews before anything is filed |
| Minimal resource set | Less flexibility than a maximal platform | Fewer controls to justify, audit, and defend |
That fourth row is the one to internalize: HealthScribe's docs are explicit that its output is assistive and must be reviewed by a professional before use in care. So the review step isn't UX polish — it's a safety and liability control. You never auto-file an AI-generated note. Ever.
Running the Real Review
None of this is theoretical. AWS ships the Well-Architected Tool with the Healthcare Industry Lens built in — run this exact workload through its questions and get a prioritized list of risks, before the audit rather than during it.
The pattern worth internalizing: in a regulated workload, the pillars stop being separate checklists. A CMK is security and auditability. A lifecycle policy is cost and sustainability and compliance. A single-Region constraint reshapes reliability and your whole availability conversation. Good architecture here isn't optimizing one pillar — it's finding the decisions that pay down several at once, and being honest about the ones that don't.
Building something regulated on AWS, or wrestling with a single-Region constraint of your own? I'd love to hear how you framed the trade-offs — drop a comment.