Architecting a HIPAA-Compliant Ambient Scribe on AWS: A Well-Architected Walkthrough

26 min read
ArchitectureAWSHealthcare

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.

Architecture diagram of a HIPAA-compliant ambient clinical scribe on AWS, showing the exam room and clinician app streaming audio over TLS into AWS HealthScribe in us-east-1, with a customer-managed KMS key and an encrypted S3 bucket inside the us-east-1 PHI processing and storage boundary, a human-in-the-loop review step feeding the EHR, and a tamper-evident CloudTrail audit layer (log file integrity validation plus WORM-locked storage) over a non-negotiable foundation of a signed BAA, HIPAA-eligible services, and the shared responsibility model

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.
  • BucketKeyEnabled on 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.

Comments

Loading comments…

Leave a comment

50 characters remaining

1000 characters remaining