Database — HIPAA Configuration (Cloud SQL)
Overview
Cloud SQL (MySQL and PostgreSQL) is a HIPAA-eligible service under Google's BAA. This document covers encryption, network isolation, access controls, backups, and audit logging for a HIPAA-compliant database deployment.
1. Instance Configuration
1.1 Create a HIPAA-Ready Cloud SQL Instance
gcloud sql instances create phi-db-instance \
--database-version=POSTGRES_15 \
--tier=db-custom-2-7680 \
--region=us-central1 \
--no-assign-ip \ # Private IP only — no public IP
--network=projects/YOUR_PROJECT_ID/global/networks/phi-vpc \
--availability-type=REGIONAL \ # High availability (multi-zone)
--backup-start-time=02:00 \
--retained-backups-count=30 \
--retained-transaction-log-days=7 \
--database-flags=log_connections=on,log_disconnections=on,log_checkpoints=on,log_lock_waits=on \
--deletion-protection \
--project=YOUR_PHI_PROJECT_ID
1.2 Verify No Public IP
gcloud sql instances describe phi-db-instance \
--format="value(settings.ipConfiguration.ipv4Enabled)"
# Must return: False
2. Encryption
2.1 Customer-Managed Encryption Keys (CMEK)
# Create a KMS key ring and key
gcloud kms keyrings create phi-keyring \
--location=us-central1 --project=YOUR_PHI_PROJECT_ID
gcloud kms keys create phi-db-key \
--keyring=phi-keyring \
--location=us-central1 \
--purpose=encryption \
--rotation-period=7776000s \ # 90-day rotation
--project=YOUR_PHI_PROJECT_ID
# Grant Cloud SQL service account access to the key
gcloud kms keys add-iam-policy-binding phi-db-key \
--keyring=phi-keyring --location=us-central1 \
--member="serviceAccount:[email protected]" \
--role="roles/cloudkms.cryptoKeyEncrypterDecrypter" \
--project=YOUR_PHI_PROJECT_ID
2.2 Enforce SSL/TLS
gcloud sql instances patch phi-db-instance \
--require-ssl --project=YOUR_PHI_PROJECT_ID
# Verify
gcloud sql instances describe phi-db-instance \
--format="value(settings.ipConfiguration.requireSsl)"
# Must return: True
3. Cloud SQL Auth Proxy
The Cloud SQL Auth Proxy handles IAM authentication and TLS automatically. It is the required method for connecting to Cloud SQL in a HIPAA environment.
Cloud Run → [IAM Auth] → Cloud SQL Auth Proxy → [Encrypted tunnel] → Cloud SQL
Cloud Run includes built-in proxy support via the --add-cloudsql-instances flag.
Python Connection
import sqlalchemy
from google.cloud import secretmanager
def create_engine():
instance_connection_name = "YOUR_PROJECT_ID:us-central1:phi-db-instance"
pool = sqlalchemy.create_engine(
sqlalchemy.engine.url.URL.create(
drivername="postgresql+pg8000",
username="phi_app_user",
password=get_secret("db-password"),
database="phi_db",
query={"unix_sock": f"/cloudsql/{instance_connection_name}/.s.PGSQL.5432"}
),
pool_size=5, max_overflow=2, pool_timeout=30, pool_recycle=1800,
)
return pool
4. Database User Management
-- PostgreSQL: application user with minimal permissions
CREATE USER phi_app_user WITH PASSWORD 'use-secret-manager-not-this';
GRANT CONNECT ON DATABASE phi_db TO phi_app_user;
GRANT USAGE ON SCHEMA public TO phi_app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO phi_app_user;
REVOKE DELETE ON audit_log FROM phi_app_user; -- App cannot delete its own audit trail
-- Read-only user for reporting
CREATE USER phi_readonly_user WITH PASSWORD 'use-secret-manager-not-this';
GRANT SELECT ON ALL TABLES IN SCHEMA public TO phi_readonly_user;
5. Backups and Point-in-Time Recovery
# On-demand backup before major changes
gcloud sql backups create \
--instance=phi-db-instance \
--description="Pre-deployment backup $(date +%Y-%m-%d)" \
--project=YOUR_PHI_PROJECT_ID
# Point-in-time restore
gcloud sql instances clone phi-db-instance phi-db-restore \
--point-in-time=2026-02-20T10:00:00.000Z \
--project=YOUR_PHI_PROJECT_ID
| Backup Type | Retention | Test Frequency |
|---|---|---|
| Automated daily | 30 days | Quarterly |
| Transaction logs (PITR) | 7 days | Quarterly |
| Pre-change snapshot | Indefinite | N/A |
6. Database Audit Logging
# Enable pgAudit for detailed query logging
gcloud sql instances patch phi-db-instance \
--database-flags=cloudsql.enable_pgaudit=on,pgaudit.log=all \
--project=YOUR_PHI_PROJECT_ID
Application-Level Audit Table
CREATE TABLE audit_log (
id BIGSERIAL PRIMARY KEY,
event_time TIMESTAMPTZ NOT NULL DEFAULT NOW(),
user_id VARCHAR(255) NOT NULL,
action VARCHAR(50) NOT NULL,
resource_type VARCHAR(100) NOT NULL,
resource_id VARCHAR(255) NOT NULL,
ip_address INET,
request_id UUID,
outcome VARCHAR(10) NOT NULL
);
REVOKE UPDATE, DELETE ON audit_log FROM phi_app_user;
7. Column-Level Encryption
For especially sensitive PHI fields (SSN, diagnosis codes):
from cryptography.fernet import Fernet
from google.cloud import secretmanager
def encrypt_phi_field(value: str) -> str:
key = get_field_encryption_key()
return Fernet(key).encrypt(value.encode()).decode()
def decrypt_phi_field(encrypted_value: str) -> str:
key = get_field_encryption_key()
return Fernet(key).decrypt(encrypted_value.encode()).decode()
8. Compliance Verification
#!/bin/bash
INSTANCE="phi-db-instance"
PROJECT="YOUR_PHI_PROJECT_ID"
echo "=== Public IP (must be False) ===" && \
gcloud sql instances describe $INSTANCE --project=$PROJECT \
--format="value(settings.ipConfiguration.ipv4Enabled)"
echo "=== SSL Required (must be True) ===" && \
gcloud sql instances describe $INSTANCE --project=$PROJECT \
--format="value(settings.ipConfiguration.requireSsl)"
echo "=== CMEK Key ===" && \
gcloud sql instances describe $INSTANCE --project=$PROJECT \
--format="value(diskEncryptionConfiguration.kmsKeyName)"
Next: Redis (Memorystore) →