Key Takeaways
- HIPAA-compliant LLM deployment requires four technical controls: a BAA with every vendor processing PHI, VPC-private or private-endpoint inference, a PHI de-identification pipeline before prompts reach the LLM, and immutable audit logging for every ePHI access event
- A signed BAA with OpenAI, Anthropic, or Azure OpenAI covers the inference endpoint — it does not cover your prompt logs, your observability tool, your vector store, or your fine-tuning jobs unless those are also under BAA
- Microsoft Presidio (open-source) handles clinical text de-identification via NER; AWS Comprehend Medical handles structured clinical entities — use both in a layered pipeline before any PHI reaches the model
- Prodinit has built HIPAA-compliant LLM infrastructure for multi-site mental health clinical trial research — VPC-private inference, Presidio de-identification, and zero PHI in observability traces
Most healthcare teams discover their HIPAA compliance gaps only after their LLM system is already running. The prompt logs contain PHI. The observability tool sends traces to a third-party cloud that has no BAA. A fine-tuning job ingested clinical notes before anyone asked whether the training infrastructure was covered. By the time the gap is visible, the system is in production and the remediation is expensive.
HIPAA-compliant LLM deployment is not a single control — it is a set of architectural decisions made across the inference path, the data handling pipeline, the logging stack, and the access control layer. Each decision point is a potential compliance failure.
HIPAA-compliant LLM deployment requires four technical controls under the Security Rule: a signed BAA with every vendor that processes PHI, VPC-private or private-endpoint inference to prevent uncontrolled data egress, a PHI de-identification pipeline before prompts enter the LLM, and immutable audit logging for every ePHI access event.
What HIPAA Actually Requires for LLM Systems
The HIPAA Security Rule (45 CFR § 164.300–164.318) applies to electronic Protected Health Information (ePHI) — any individually identifiable health information transmitted or maintained electronically. When your LLM system processes clinical notes, trial enrollment records, or any health data that can be linked to an individual, it is handling ePHI and the Security Rule applies.
The Security Rule mandates four categories of technical safeguards:
Access control (§ 164.312(a)). Unique user identification, emergency access procedures, automatic logoff, and encryption of stored ePHI. For LLM systems: role-based API keys (not shared credentials), MFA on every interface that touches ePHI, and encryption at rest for vector stores and prompt logs containing PHI.
Audit controls (§ 164.312(b)). Hardware, software, and procedural mechanisms to record and examine activity in systems that contain ePHI. For LLM systems: every query that touches PHI must generate an audit event with user identity, timestamp, resource accessed, and action performed. Logs must be retained for at least six years and protected from modification.
Integrity (§ 164.312(c)). ePHI must be protected from improper alteration or destruction. For LLM systems: immutable log storage (S3 Object Lock, CloudWatch with log group protection), versioned prompt templates, and pipeline controls that prevent ad-hoc modification of PHI-containing records.
Transmission security (§ 164.312(e)). Encryption in transit for ePHI. For LLM systems: TLS 1.2 minimum on all API calls, end-to-end encryption for PHI moving between your application layer and the LLM endpoint, and encrypted channels for any PHI stored in a vector database.
Beyond the Security Rule, the Business Associate Agreement (BAA) requirement under the Privacy Rule means every vendor that receives, maintains, or transmits PHI on your behalf must sign a BAA before they handle that data. "Every vendor" means the LLM inference provider, the observability tool, the vector store service, the logging platform, and the CI/CD system if it runs prompt tests against PHI.
Two Architecture Patterns for HIPAA-Compliant LLM Deployment
Production healthcare AI systems use one of two patterns, or a hybrid depending on PHI sensitivity and volume.
Pattern A — Cloud LLM API with BAA
OpenAI, Anthropic, Azure OpenAI Service, and AWS Bedrock all offer HIPAA-eligible configurations with a signed BAA. This pattern keeps model management off your plate and deploys fastest.
How it works: your application layer de-identifies PHI before the API call (see the next section), calls the LLM API over TLS within a VPC that routes through a PrivateLink or VPC endpoint (no public internet path for API traffic), and logs traces to a self-hosted Langfuse instance within the same VPC.
Application Layer (VPC)
→ PHI de-identification (Presidio)
→ De-identified prompt
→ LLM API via VPC PrivateLink (OpenAI/Anthropic/Azure/Bedrock)
→ Response
→ Audit log → CloudWatch Logs (encrypted, retained 6 years)
→ Trace → Self-hosted Langfuse (no PHI in trace payloads)
What the BAA covers: the inference endpoint and any data stored by the provider for that service tier. Azure OpenAI and AWS Bedrock typically offer zero data retention on inputs/outputs for HIPAA configurations — verify this explicitly in the BAA before signing.
What the BAA does not cover: your Langfuse Cloud account (unless they have a HIPAA BAA — verify), your GitHub Actions logs if they contain PHI, your local development environment, or any third-party analytics tool that receives request metadata.
When to use Pattern A: natural language to SQL over clinical data (de-identification removes identifiers before the query), document summarization for administrative PHI (billing codes, encounter notes with identifiers stripped), and any use case where de-identification preserves enough clinical signal for the LLM task.
Pattern B — VPC-Private Model Deployment
PHI never leaves your VPC. Run open-weight models (Llama 3, Mistral, BioMedLM for clinical NLP) on AWS EKS with GPU node groups, served via vLLM or NVIDIA NIM, accessible only within the VPC.
Application Layer (VPC)
→ PHI (can remain partially identified — within VPC boundary)
→ Private model endpoint (vLLM on EKS, no internet)
→ Response
→ Audit log → CloudWatch Logs (encrypted)
→ Trace → Self-hosted Langfuse (same VPC)
When to use Pattern B: substance abuse treatment records (42 CFR Part 2 requires stricter controls than standard HIPAA), mental health records in jurisdictions with enhanced state privacy laws, fine-tuning on PHI where the training job must stay within your infrastructure, and very high-volume scenarios where API pricing makes private deployment cheaper.
Prodinit built Pattern B for a digital health research company conducting multi-site mental health clinical trials in New York — PHI-containing clinical trial records stayed within a dedicated AWS VPC, with LLM inference running on EKS GPU nodes accessible only via internal service discovery. The full architecture is detailed in the clinical trial dashboard case study. For the air-gapped variant of this pattern with zero internet egress, the air-gapped LLM deployment guide covers the infrastructure specifics.
Decision framework:
| Factor | Pattern A (Cloud API + BAA) | Pattern B (VPC-Private) |
|---|---|---|
| PHI de-identification required | Yes — before API call | Optional — within VPC boundary |
| Time to production | 2–4 weeks | 6–10 weeks |
| Model quality | GPT-4o, Claude Sonnet (state of the art) | Open-weight (Llama 3, Mistral) |
| 42 CFR Part 2 workloads | Not recommended | Recommended |
| GPU infrastructure required | No | Yes ($8K–$40K/month on EKS) |
| Data residency requirements | Depends on provider region | Fully controlled |
PHI De-identification Before the LLM
De-identification is the control that makes Pattern A viable and reduces risk in Pattern B. HIPAA defines two acceptable methods under 45 CFR § 164.514:
Safe Harbor method: remove all 18 specific identifiers: names, geographic subdivisions smaller than a state, dates (other than year) for individuals over 89, phone numbers, fax numbers, email addresses, SSNs, medical record numbers, health plan beneficiary numbers, account numbers, certificate and license numbers, vehicle identifiers, device identifiers, URLs, IP addresses, biometric identifiers, full-face photographs, and any unique identifying number.
Expert Determination method: a qualified statistician determines that the risk of re-identification is very small. Requires documentation and ongoing verification.
For LLM systems processing clinical text (encounter notes, trial records, discharge summaries), Presidio is the production-standard open-source tool for automated PHI detection and redaction:
from presidio_analyzer import AnalyzerEngine
from presidio_anonymizer import AnonymizerEngine
from presidio_anonymizer.entities import OperatorConfig
analyzer = AnalyzerEngine()
anonymizer = AnonymizerEngine()
def deidentify_clinical_text(text: str) -> tuple[str, list]:
results = analyzer.analyze(
text=text,
entities=[
"PERSON", "DATE_TIME", "PHONE_NUMBER", "EMAIL_ADDRESS",
"US_SSN", "MEDICAL_LICENSE", "URL", "IP_ADDRESS", "LOCATION"
],
language="en",
)
# Pseudonymize rather than redact where clinical context matters
anonymized = anonymizer.anonymize(
text=text,
analyzer_results=results,
operators={
"PERSON": OperatorConfig("replace", {"new_value": "<PATIENT>"}),
"DATE_TIME": OperatorConfig("replace", {"new_value": "<DATE>"}),
"LOCATION": OperatorConfig("replace", {"new_value": "<SITE>"}),
}
)
return anonymized.text, results # return entity map for audit log
de_identified_prompt, phi_entities = deidentify_clinical_text(raw_clinical_note)
# Only de_identified_prompt goes to the LLM
# phi_entities go to the audit log, not the trace
For structured clinical data (enrollment tables, lab values), complement Presidio with AWS Comprehend Medical, which is purpose-built for clinical entities: medications, diagnoses, anatomy, test results, and treatment. Run Comprehend Medical first for clinical NER, then Presidio for general PII.
The exception case: some clinical AI tasks lose utility after de-identification. A model computing differential diagnoses from encounter notes needs patient age, specific dates, and geographic context that Safe Harbor would strip. For these cases, Pattern B (within-VPC inference on identifiable data) is the appropriate path — combined with access controls that restrict which roles can invoke the model on identified records.
Audit Logging and Access Control for ePHI
HIPAA does not specify an exact audit log format, but requires that audit controls produce records sufficient to reconstruct who accessed what ePHI and when. For LLM systems, that means logging at two layers:
Infrastructure layer: AWS CloudTrail records all API calls to EKS, Bedrock, S3, and RDS. Enable CloudTrail for all regions, store logs in an S3 bucket with Object Lock (WORM mode, six-year retention), and set up CloudWatch alarms for unusual access patterns.
Application layer: log every LLM query that touches PHI at the application level. The audit record must include user identity (not just a service account), timestamp, the de-identified prompt hash (not the raw PHI), the model and version used, and the disposition (whether the response was shown, flagged, or suppressed). Do not log raw PHI-containing prompts in your application audit log — store those in encrypted, access-controlled storage with a separate retrieval path for legal hold.
import hashlib
import json
import boto3
def audit_log_llm_query(
user_id: str,
session_id: str,
prompt_hash: str, # SHA-256 of de-identified prompt
model: str,
phi_entity_count: int,
response_hash: str,
) -> None:
log_entry = {
"event_type": "llm_phi_query",
"user_id": user_id,
"session_id": session_id,
"timestamp": datetime.utcnow().isoformat() + "Z",
"model": model,
"prompt_hash": prompt_hash,
"phi_entities_detected": phi_entity_count,
"response_hash": response_hash,
}
# Write to CloudWatch Logs group with 6-year retention and protection
cloudwatch.put_log_events(
logGroupName="/hipaa/llm-audit",
logStreamName=session_id,
logEvents=[{"timestamp": int(time.time() * 1000), "message": json.dumps(log_entry)}],
)
RBAC for LLM access: apply the minimum necessary standard — users should access only the ePHI required for their role. For LLM-powered clinical tools: clinical staff query against their patient panel only, research analysts query de-identified aggregate data, and admin roles have no direct LLM access to PHI. Implement this via role-tagged API keys, not shared credentials, and rotate keys quarterly.
What Most HIPAA LLM Deployments Get Wrong
Five gaps appear in nearly every initial HIPAA LLM architecture review:
1. Prompt logs contain raw PHI. The observability tool (Langfuse Cloud, LangSmith, Datadog) receives full prompt payloads with patient names and dates that were never de-identified before logging. Fix: hash or redact PHI fields before sending any payload to a third-party trace collector, or self-host the observability tool within the VPC.
2. The BAA chain is incomplete. The team signs a BAA with OpenAI but not with their vector store provider (Pinecone, Weaviate Cloud) where RAG embeddings over clinical notes are stored. Any vendor that stores or processes PHI needs a BAA — not just the inference provider.
3. Fine-tuning on PHI without covered infrastructure. Fine-tuning a model on clinical notes where the training job runs in a provider's shared infrastructure (OpenAI fine-tuning API, Hugging Face AutoTrain) without confirming the fine-tuning infrastructure is covered by the BAA. If fine-tuning PHI, use Azure OpenAI's fine-tuning (which extends the BAA), AWS Bedrock fine-tuning, or a fully private training infrastructure.
4. De-identification treated as an output step. Teams run de-identification after the LLM response rather than before the LLM input. The PHI was already transmitted to the inference endpoint and potentially logged in the provider's request logs.
5. No access revocation process. Staff who leave or change roles retain LLM access until someone notices. HIPAA requires timely access revocation. Automate this via SSO-linked API key issuance where key validity mirrors the user's active directory status.
Get Prodinit's AI engineering guides in your inbox
Deep-dives on production LLMs, voice AI, and MLOps — published weekly. No sales emails.
Frequently Asked Questions
A BAA with OpenAI or Anthropic covers the inference endpoint under their HIPAA-eligible service tier — it means the provider has agreed to handle PHI as a business associate with the required safeguards. It does not automatically make your entire system HIPAA-compliant. Your application layer, prompt logging, vector store, observability tool, and any other system touching PHI must each be separately covered by BAA or configured to receive only de-identified data.
Yes, with two approaches: de-identify clinical documents before embedding and storing them in the vector store (PHI is removed before it leaves your controlled environment), or deploy the vector store and embedding service within your VPC under a BAA with the vector store provider. Pinecone and Weaviate Cloud offer HIPAA BAAs on enterprise plans. For maximum control, run pgvector on PostgreSQL within your VPC.
Yes. AWS Bedrock is listed on AWS's HIPAA-eligible services list, and AWS will include Bedrock in the AWS BAA. Key configuration requirement: enable the no-data-retention setting (AWS calls this "model invocation logging disabled") so that prompt inputs and model outputs are not stored by AWS after the API call completes. Verify this setting is active for your specific Bedrock endpoint before processing PHI.
For general clinical text tasks, Llama 3.1 8B or 70B (Meta) running via vLLM on GPU nodes in a VPC is the standard starting point — strong instruction following, good clinical language comprehension, and actively maintained. For clinical NLP specifically (entity extraction from EHR notes), BioMedLM (Stanford) and ClinicalBERT variants are purpose-fine-tuned on clinical text. For mental health or psychiatric use cases, MedAlpaca is a starting point but requires domain-specific fine-tuning for production reliability.
An MVP HIPAA-compliant system using Pattern A (cloud LLM API with BAA) typically takes 4–6 weeks: BAA execution with providers, PHI de-identification pipeline build and validation, VPC routing via PrivateLink, self-hosted observability setup, and audit logging infrastructure. Pattern B (private VPC deployment) adds 4–6 weeks for GPU infrastructure, model serving setup, and access control implementation. Prodinit builds both patterns — the LLMOps consulting services post covers what a typical engagement looks like end to end.