Skip to main content

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 TypeRetentionTest Frequency
Automated daily30 daysQuarterly
Transaction logs (PITR)7 daysQuarterly
Pre-change snapshotIndefiniteN/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) →