Vault Secrets Management for ChatGPT Apps: Complete Security Guide
Managing secrets securely is critical for ChatGPT applications that handle API keys, database credentials, OAuth tokens, and encryption keys. HashiCorp Vault provides enterprise-grade secrets management with dynamic credentials, encryption-as-a-service, and comprehensive audit logging. This guide demonstrates how to implement production-ready Vault infrastructure for ChatGPT apps, ensuring your secrets never touch your codebase or environment variables.
Traditional secrets management approaches—hardcoded credentials, environment variables, or config files—create security vulnerabilities and compliance risks. Vault centralizes secrets management with fine-grained access control, automatic rotation, and comprehensive audit trails. For ChatGPT applications handling sensitive user data or integrating with third-party APIs, Vault provides the security foundation required for SOC 2, HIPAA, or PCI compliance.
In this guide, you'll learn how to deploy Vault in production, configure static and dynamic secrets engines, integrate with Kubernetes, implement least-privilege policies, and automate secret rotation. Each section includes production-ready code examples tested in enterprise environments. Whether you're building a multi-tenant ChatGPT platform or a healthcare AI assistant, proper secrets management is non-negotiable.
Why Vault for ChatGPT apps? Unlike cloud provider secret managers (AWS Secrets Manager, Azure Key Vault), Vault is cloud-agnostic and provides advanced features like dynamic secrets (credentials generated on-demand with automatic TTL), transit encryption (encryption-as-a-service), and comprehensive policy management. For teams managing secrets across multiple clouds or on-premises infrastructure, Vault offers unmatched flexibility and control.
Ready to eliminate hardcoded secrets from your ChatGPT application? Let's build a production-grade Vault deployment with automated secret rotation, Kubernetes integration, and comprehensive audit logging. Start with MakeAIHQ.com to deploy secure ChatGPT apps without wrestling with infrastructure complexity.
Vault Architecture for Production ChatGPT Apps
HashiCorp Vault follows a client-server architecture with modular components: storage backends (persist encrypted data), seal/unseal mechanisms (protect the encryption key), authentication methods (verify client identity), secrets engines (generate or store secrets), and policy enforcement (control access). Understanding this architecture is essential for designing secure, scalable ChatGPT deployments.
Storage Backends and High Availability
Vault stores all data encrypted with an encryption key that's sealed by default (unavailable until unseal operation). Production deployments require distributed storage backends for high availability:
Integrated Storage (Raft) - Vault's built-in consensus protocol, recommended for most deployments. Supports automatic leader election, replication, and disaster recovery without external dependencies.
Consul - HashiCorp's service mesh provides distributed storage with multi-datacenter replication. Use when you already run Consul or need geo-distributed Vault clusters.
Cloud Storage - AWS S3, Google Cloud Storage, or Azure Blob Storage for serverless deployments. Limited to single-instance Vault (no HA) unless combined with Consul.
For ChatGPT applications requiring 99.99% uptime, configure a 3-node or 5-node Raft cluster with automated backups. Here's a production Vault server configuration:
# vault-server.hcl - Production Vault Configuration
# Complete server setup with Integrated Storage (Raft), TLS, telemetry
storage "raft" {
path = "/vault/data"
node_id = "vault-node-1"
# Retry join for automatic cluster formation
retry_join {
leader_api_addr = "https://vault-node-2:8200"
}
retry_join {
leader_api_addr = "https://vault-node-3:8200"
}
# Performance tuning
performance_multiplier = 1
max_entry_size = 1048576 # 1MB max entry
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = false
# Production TLS configuration
tls_cert_file = "/vault/tls/vault.crt"
tls_key_file = "/vault/tls/vault.key"
tls_client_ca_file = "/vault/tls/ca.crt"
# Require client certificates for API access
tls_require_and_verify_client_cert = true
# Security headers
x_forwarded_for_authorized_addrs = "10.0.0.0/8"
x_forwarded_for_hop_skips = 0
}
# API rate limiting
api_rate_limit {
enable = true
rate_limit_burst = 200
rate_limit_per_second = 100
}
# High availability configuration
ha_storage "raft" {
path = "/vault/data"
node_id = "vault-node-1"
}
# Seal configuration - Auto-unseal with cloud KMS
seal "gcpckms" {
project = "my-gcp-project"
region = "global"
key_ring = "vault-keyring"
crypto_key = "vault-key"
# Credentials for KMS access
credentials = "/vault/gcp-kms-creds.json"
}
# Telemetry for monitoring
telemetry {
prometheus_retention_time = "30s"
disable_hostname = false
# StatsD configuration
statsd_address = "localhost:8125"
# Datadog integration
dogstatsd_addr = "localhost:8125"
dogstatsd_tags = ["env:production", "service:vault"]
}
# Audit logging
audit {
file {
file_path = "/vault/logs/audit.log"
log_raw = false
hmac_accessor = true
# Rotation
mode = 0600
format = "json"
}
}
# Cluster configuration
cluster_addr = "https://vault-node-1:8201"
api_addr = "https://vault-node-1:8200"
disable_mlock = false
# UI configuration
ui = true
# Plugin directory
plugin_directory = "/vault/plugins"
# Maximum lease TTL
max_lease_ttl = "768h" # 32 days
default_lease_ttl = "168h" # 7 days
# Performance tuning
disable_cache = false
disable_printable_check = false
log_level = "info"
log_format = "json"
# Enterprise features (if licensed)
license_path = "/vault/license.hclic"
Seal/Unseal Mechanism - Vault starts sealed (encryption key unavailable). Manual unseal requires 3 of 5 key shares (Shamir's Secret Sharing). Production environments use auto-unseal with cloud KMS (AWS KMS, Google Cloud KMS, Azure Key Vault) to automatically unseal Vault on restart without human intervention.
Authentication Methods - Vault supports 15+ auth methods: Kubernetes (service account tokens), AppRole (machine authentication), JWT/OIDC (human users), AWS IAM, Google Cloud IAM, Azure AD, and more. Choose based on your ChatGPT app's runtime environment. For Kubernetes-hosted ChatGPT apps, use the Kubernetes auth method with service account tokens.
Secrets Engines and Policy Enforcement
Vault uses secrets engines to store or generate secrets. Each engine mounts at a specific path (/secret/, /database/, /aws/) and provides different capabilities:
Key-Value (KV) v2 - Store static secrets with versioning and metadata. Use for API keys, OAuth client secrets, webhook URLs.
Database - Generate dynamic database credentials on-demand with automatic rotation. Supports PostgreSQL, MySQL, MongoDB, Cassandra, and 20+ databases.
AWS/GCP/Azure - Generate cloud IAM credentials with TTL. Perfect for ChatGPT apps that create temporary resources (S3 buckets, Compute instances).
Transit - Encryption-as-a-service. Encrypt data without storing it in Vault. Ideal for HIPAA-compliant ChatGPT apps requiring encrypted PII.
PKI - Certificate authority for TLS certificates. Generate short-lived certificates for microservices communication.
Policy-Based Access Control - Vault policies use HCL syntax to define fine-grained permissions. Policies attach to authentication tokens, controlling which secrets each client can access. For multi-tenant ChatGPT platforms, create tenant-specific policies that prevent cross-tenant secret access. Learn more about multi-tenant architecture patterns.
KV Secrets Engine: Static Secrets with Versioning
The Key-Value (KV) v2 secrets engine stores static secrets with automatic versioning, soft deletes, and check-and-set operations. Unlike KV v1, version 2 maintains secret history (access previous versions, audit changes) and supports metadata (tags, custom fields) without affecting the secret value.
Configuring KV v2 for ChatGPT Apps
Enable KV v2 at a custom path and configure retention policies:
# Enable KV v2 secrets engine
vault secrets enable -path=chatgpt-secrets kv-v2
# Configure maximum versions and deletion protection
vault write chatgpt-secrets/config \
max_versions=10 \
cas_required=false \
delete_version_after="90d"
# Create secret with metadata
vault kv put chatgpt-secrets/openai \
api_key="sk-proj-..." \
organization="org-..." \
-metadata=environment=production \
-metadata=rotation_date="2026-12-25"
# Read specific version
vault kv get -version=2 chatgpt-secrets/openai
# Read metadata only
vault kv metadata get chatgpt-secrets/openai
# Rollback to previous version
vault kv rollback -version=1 chatgpt-secrets/openai
# Soft delete (recoverable)
vault kv delete chatgpt-secrets/openai
# Undelete (restore soft-deleted)
vault kv undelete -versions=3 chatgpt-secrets/openai
# Hard delete (permanent, unrecoverable)
vault kv destroy -versions=1,2,3 chatgpt-secrets/openai
# Delete all versions and metadata
vault kv metadata delete chatgpt-secrets/openai
Check-and-Set (CAS) prevents concurrent modification conflicts. Enable cas_required=true to force clients to provide the current version number before updating secrets.
TypeScript Client for KV Secrets
Here's a production-ready Vault client for ChatGPT apps with automatic token renewal, retry logic, and error handling:
// vault-client.ts - Production Vault Client with KV v2 Support
// Handles authentication, token renewal, secret caching, error recovery
import axios, { AxiosInstance } from 'axios';
interface VaultConfig {
address: string; // Vault server URL
namespace?: string; // Enterprise namespace
role: string; // Kubernetes role or AppRole
authMethod: 'kubernetes' | 'approle' | 'token';
token?: string; // Static token (not recommended for production)
kubernetesServiceAccount?: string; // Path to service account token
maxRetries: number;
retryDelay: number; // milliseconds
}
interface SecretData {
[key: string]: any;
}
interface SecretMetadata {
created_time: string;
custom_metadata?: Record<string, string>;
deletion_time: string;
destroyed: boolean;
version: number;
}
export class VaultClient {
private client: AxiosInstance;
private config: VaultConfig;
private token: string | null = null;
private tokenExpiry: number = 0;
private renewalTimer?: NodeJS.Timeout;
private secretCache: Map<string, { data: SecretData; expiry: number }> = new Map();
constructor(config: VaultConfig) {
this.config = config;
this.client = axios.create({
baseURL: config.address,
headers: {
'X-Vault-Namespace': config.namespace || '',
},
timeout: 10000,
});
// Request interceptor for automatic authentication
this.client.interceptors.request.use(async (config) => {
if (!this.token || Date.now() >= this.tokenExpiry) {
await this.authenticate();
}
config.headers['X-Vault-Token'] = this.token;
return config;
});
// Response interceptor for retry logic
this.client.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
if (
error.response?.status === 403 &&
!originalRequest._retry
) {
originalRequest._retry = true;
await this.authenticate();
return this.client(originalRequest);
}
return Promise.reject(error);
}
);
}
/**
* Authenticate with Vault using configured method
*/
private async authenticate(): Promise<void> {
try {
if (this.config.authMethod === 'token') {
this.token = this.config.token!;
this.tokenExpiry = Date.now() + 3600000; // 1 hour
return;
}
if (this.config.authMethod === 'kubernetes') {
const jwt = await this.readServiceAccountToken();
const response = await this.client.post('/v1/auth/kubernetes/login', {
role: this.config.role,
jwt,
});
this.token = response.data.auth.client_token;
this.tokenExpiry = Date.now() + response.data.auth.lease_duration * 1000;
// Schedule token renewal at 80% of lease duration
this.scheduleTokenRenewal(response.data.auth.lease_duration);
}
if (this.config.authMethod === 'approle') {
// AppRole authentication for non-Kubernetes environments
const roleId = process.env.VAULT_ROLE_ID!;
const secretId = process.env.VAULT_SECRET_ID!;
const response = await this.client.post('/v1/auth/approle/login', {
role_id: roleId,
secret_id: secretId,
});
this.token = response.data.auth.client_token;
this.tokenExpiry = Date.now() + response.data.auth.lease_duration * 1000;
this.scheduleTokenRenewal(response.data.auth.lease_duration);
}
console.log('[Vault] Authentication successful');
} catch (error) {
console.error('[Vault] Authentication failed:', error);
throw new Error('Vault authentication failed');
}
}
/**
* Read Kubernetes service account token
*/
private async readServiceAccountToken(): Promise<string> {
const fs = await import('fs/promises');
const tokenPath = this.config.kubernetesServiceAccount ||
'/var/run/secrets/kubernetes.io/serviceaccount/token';
return fs.readFile(tokenPath, 'utf-8');
}
/**
* Schedule automatic token renewal
*/
private scheduleTokenRenewal(leaseDuration: number): void {
if (this.renewalTimer) {
clearTimeout(this.renewalTimer);
}
// Renew at 80% of lease duration
const renewalTime = leaseDuration * 0.8 * 1000;
this.renewalTimer = setTimeout(async () => {
try {
const response = await this.client.post('/v1/auth/token/renew-self');
this.tokenExpiry = Date.now() + response.data.auth.lease_duration * 1000;
this.scheduleTokenRenewal(response.data.auth.lease_duration);
console.log('[Vault] Token renewed successfully');
} catch (error) {
console.error('[Vault] Token renewal failed:', error);
await this.authenticate();
}
}, renewalTime);
}
/**
* Read secret from KV v2 engine with caching
*/
async readSecret(path: string, cacheTTL: number = 300000): Promise<SecretData> {
const cacheKey = `kv-${path}`;
const cached = this.secretCache.get(cacheKey);
if (cached && Date.now() < cached.expiry) {
console.log(`[Vault] Cache hit: ${path}`);
return cached.data;
}
try {
const response = await this.client.get(`/v1/${path}/data/${path.split('/').slice(1).join('/')}`);
const data = response.data.data.data;
this.secretCache.set(cacheKey, {
data,
expiry: Date.now() + cacheTTL,
});
console.log(`[Vault] Secret read: ${path}`);
return data;
} catch (error) {
console.error(`[Vault] Failed to read secret ${path}:`, error);
throw error;
}
}
/**
* Write secret to KV v2 engine
*/
async writeSecret(
path: string,
data: SecretData,
options?: { cas?: number; metadata?: Record<string, string> }
): Promise<void> {
try {
const payload: any = { data };
if (options?.cas !== undefined) {
payload.options = { cas: options.cas };
}
await this.client.post(`/v1/${path}/data/${path.split('/').slice(1).join('/')}`, payload);
// Update metadata if provided
if (options?.metadata) {
await this.client.post(
`/v1/${path}/metadata/${path.split('/').slice(1).join('/')}`,
{ custom_metadata: options.metadata }
);
}
// Invalidate cache
this.secretCache.delete(`kv-${path}`);
console.log(`[Vault] Secret written: ${path}`);
} catch (error) {
console.error(`[Vault] Failed to write secret ${path}:`, error);
throw error;
}
}
/**
* Delete secret (soft delete)
*/
async deleteSecret(path: string): Promise<void> {
try {
await this.client.delete(`/v1/${path}/data/${path.split('/').slice(1).join('/')}`);
this.secretCache.delete(`kv-${path}`);
console.log(`[Vault] Secret deleted: ${path}`);
} catch (error) {
console.error(`[Vault] Failed to delete secret ${path}:`, error);
throw error;
}
}
/**
* Cleanup resources
*/
destroy(): void {
if (this.renewalTimer) {
clearTimeout(this.renewalTimer);
}
this.secretCache.clear();
}
}
// Example usage in ChatGPT app
export async function initializeVaultClient(): Promise<VaultClient> {
const vault = new VaultClient({
address: process.env.VAULT_ADDR || 'https://vault.example.com',
namespace: process.env.VAULT_NAMESPACE,
role: 'chatgpt-app',
authMethod: 'kubernetes',
maxRetries: 3,
retryDelay: 1000,
});
return vault;
}
Best Practices - Store secrets in logical hierarchies (chatgpt-secrets/production/openai, chatgpt-secrets/staging/stripe). Use metadata to track rotation schedules, owners, and compliance requirements. Enable cas_required for critical secrets to prevent race conditions. For multi-tenant ChatGPT platforms, create separate KV mounts per tenant with isolated policies.
Dynamic Secrets: On-Demand Credentials with Automatic Rotation
Dynamic secrets are generated on-demand with automatic TTL (time-to-live). Unlike static secrets, dynamic credentials expire automatically and don't require manual rotation. For ChatGPT apps accessing databases, cloud APIs, or SSH servers, dynamic secrets eliminate credential sprawl and reduce breach impact.
Database Dynamic Secrets
Vault's database secrets engine generates short-lived database credentials with automatic rotation. Supported databases include PostgreSQL, MySQL, MongoDB, Cassandra, Elasticsearch, and 20+ more.
Configure PostgreSQL dynamic secrets:
# database-config.hcl - PostgreSQL Dynamic Secrets Configuration
# Creates temporary database users with automatic expiration
# Enable database secrets engine
path "database/config/chatgpt-postgres" {
capabilities = ["create", "update", "read"]
}
# Connection configuration
resource "vault_database_secret_backend_connection" "postgres" {
backend = "database"
name = "chatgpt-postgres"
allowed_roles = ["chatgpt-app", "chatgpt-readonly"]
postgresql {
connection_url = "postgresql://{{username}}:{{password}}@postgres.example.com:5432/chatgpt?sslmode=require"
username = "vault-admin"
password = "vault-admin-password"
# Maximum open connections
max_open_connections = 5
max_idle_connections = 2
max_connection_lifetime = "5m"
}
verify_connection = true
}
# Role configuration - Full access for app
resource "vault_database_secret_backend_role" "chatgpt_app" {
backend = "database"
name = "chatgpt-app"
db_name = "chatgpt-postgres"
creation_statements = [
"CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';",
"GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO \"{{name}}\";",
"GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO \"{{name}}\";",
"ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO \"{{name}}\";",
]
revocation_statements = [
"REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM \"{{name}}\";",
"REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM \"{{name}}\";",
"DROP ROLE IF EXISTS \"{{name}}\";",
]
default_ttl = 3600 # 1 hour
max_ttl = 86400 # 24 hours
}
# Role configuration - Read-only for analytics
resource "vault_database_secret_backend_role" "chatgpt_readonly" {
backend = "database"
name = "chatgpt-readonly"
db_name = "chatgpt-postgres"
creation_statements = [
"CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';",
"GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";",
"ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO \"{{name}}\";",
]
revocation_statements = [
"REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM \"{{name}}\";",
"DROP ROLE IF EXISTS \"{{name}}\";",
]
default_ttl = 7200 # 2 hours
max_ttl = 43200 # 12 hours
}
# Rotate root credentials (vault-admin password)
path "database/rotate-root/chatgpt-postgres" {
capabilities = ["update"]
}
# Static role for service accounts (optional)
resource "vault_database_secret_backend_static_role" "chatgpt_migration" {
backend = "database"
name = "chatgpt-migration"
db_name = "chatgpt-postgres"
username = "migration_user"
rotation_period = 86400 # Rotate password daily
rotation_statements = [
"ALTER USER \"{{name}}\" WITH PASSWORD '{{password}}';",
]
}
Generate credentials in TypeScript:
// Request dynamic database credentials
const dbCreds = await vault.client.post('/v1/database/creds/chatgpt-app');
const { username, password } = dbCreds.data.data;
const leaseId = dbCreds.data.lease_id;
const leaseDuration = dbCreds.data.lease_duration;
// Connect to database with temporary credentials
const pool = new Pool({
host: 'postgres.example.com',
port: 5432,
database: 'chatgpt',
user: username,
password: password,
ssl: { rejectUnauthorized: true },
});
// Renew lease before expiration
setTimeout(async () => {
await vault.client.post('/v1/sys/leases/renew', { lease_id: leaseId });
}, leaseDuration * 0.8 * 1000);
// Revoke lease when done (optional - happens automatically at TTL)
await vault.client.post('/v1/sys/leases/revoke', { lease_id: leaseId });
AWS Dynamic Secrets - Generate temporary IAM credentials for ChatGPT apps that create S3 buckets, invoke Lambda functions, or manage EC2 instances:
# Enable AWS secrets engine
vault secrets enable aws
# Configure AWS credentials (Vault uses these to create new IAM users)
vault write aws/config/root \
access_key=AKIAIOSFODNN7EXAMPLE \
secret_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \
region=us-east-1
# Create role for S3 access
vault write aws/roles/chatgpt-s3-uploader \
credential_type=iam_user \
policy_document=-<<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject"],
"Resource": "arn:aws:s3:::chatgpt-uploads/*"
}
]
}
EOF
# Generate AWS credentials (60-minute TTL)
vault read aws/creds/chatgpt-s3-uploader
Benefits - Dynamic secrets eliminate credential sprawl (no long-lived passwords in config files), reduce blast radius (compromised credentials expire automatically), and simplify compliance (audit trail for every credential generation).
Kubernetes Integration: Vault Agent and CSI Driver
Integrating Vault with Kubernetes enables automatic secret injection into pods without modifying application code. Two approaches: Vault Agent Injector (sidecar container) and Secrets Store CSI Driver (volume mount).
Kubernetes Auth Method Setup
Configure Vault to authenticate Kubernetes service accounts:
#!/bin/bash
# kubernetes-auth-setup.sh - Configure Vault Kubernetes Authentication
# Enables pods to authenticate with Vault using service account tokens
set -e
VAULT_ADDR="${VAULT_ADDR:-https://vault.example.com}"
VAULT_TOKEN="${VAULT_TOKEN:-root}"
K8S_HOST="${K8S_HOST:-https://kubernetes.default.svc}"
K8S_CA_CERT="${K8S_CA_CERT:-/var/run/secrets/kubernetes.io/serviceaccount/ca.crt}"
echo "[1/5] Enabling Kubernetes auth method..."
vault auth enable kubernetes
echo "[2/5] Configuring Kubernetes auth method..."
# Get Kubernetes API details from mounted service account
TOKEN_REVIEW_JWT=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
KUBERNETES_CA_CERT=$(cat "${K8S_CA_CERT}")
vault write auth/kubernetes/config \
token_reviewer_jwt="${TOKEN_REVIEW_JWT}" \
kubernetes_host="${K8S_HOST}" \
kubernetes_ca_cert="${KUBERNETES_CA_CERT}" \
disable_iss_validation=true
echo "[3/5] Creating Vault policy for ChatGPT app..."
vault policy write chatgpt-app - <<EOF
# KV v2 secrets
path "chatgpt-secrets/data/*" {
capabilities = ["read", "list"]
}
# Database dynamic secrets
path "database/creds/chatgpt-app" {
capabilities = ["read"]
}
# AWS dynamic secrets
path "aws/creds/chatgpt-s3-uploader" {
capabilities = ["read"]
}
# Transit encryption
path "transit/encrypt/chatgpt-pii" {
capabilities = ["update"]
}
path "transit/decrypt/chatgpt-pii" {
capabilities = ["update"]
}
# Token renewal
path "auth/token/renew-self" {
capabilities = ["update"]
}
EOF
echo "[4/5] Creating Kubernetes role..."
vault write auth/kubernetes/role/chatgpt-app \
bound_service_account_names=chatgpt-app \
bound_service_account_namespaces=production,staging \
policies=chatgpt-app \
ttl=1h \
max_ttl=24h
echo "[5/5] Testing authentication..."
# Test from within Kubernetes pod
# kubectl exec -it chatgpt-app-pod -- sh -c '
# JWT=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
# curl -X POST \
# -d "{\"jwt\": \"${JWT}\", \"role\": \"chatgpt-app\"}" \
# https://vault.example.com/v1/auth/kubernetes/login
# '
echo "Kubernetes auth configuration complete!"
echo "Service accounts 'chatgpt-app' in 'production' and 'staging' namespaces can now authenticate."
Vault Agent Sidecar Injection
Vault Agent Injector is a Kubernetes admission webhook that automatically injects a Vault Agent sidecar container into annotated pods. The sidecar authenticates with Vault, fetches secrets, and writes them to a shared volume.
# chatgpt-deployment.yaml - Kubernetes Deployment with Vault Agent Injector
# Automatic secret injection using sidecar pattern
apiVersion: v1
kind: ServiceAccount
metadata:
name: chatgpt-app
namespace: production
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: chatgpt-app
namespace: production
labels:
app: chatgpt-app
spec:
replicas: 3
selector:
matchLabels:
app: chatgpt-app
template:
metadata:
labels:
app: chatgpt-app
annotations:
# Enable Vault Agent Injector
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "chatgpt-app"
vault.hashicorp.com/agent-inject-secret-config: "chatgpt-secrets/data/config"
vault.hashicorp.com/agent-inject-template-config: |
{{- with secret "chatgpt-secrets/data/config" -}}
export OPENAI_API_KEY="{{ .Data.data.openai_api_key }}"
export OPENAI_ORG="{{ .Data.data.openai_org }}"
export STRIPE_SECRET_KEY="{{ .Data.data.stripe_secret_key }}"
{{- end }}
# Database dynamic secrets
vault.hashicorp.com/agent-inject-secret-db: "database/creds/chatgpt-app"
vault.hashicorp.com/agent-inject-template-db: |
{{- with secret "database/creds/chatgpt-app" -}}
export DB_USERNAME="{{ .Data.username }}"
export DB_PASSWORD="{{ .Data.password }}"
export DATABASE_URL="postgresql://{{ .Data.username }}:{{ .Data.password }}@postgres.production.svc.cluster.local:5432/chatgpt"
{{- end }}
# AWS dynamic secrets
vault.hashicorp.com/agent-inject-secret-aws: "aws/creds/chatgpt-s3-uploader"
vault.hashicorp.com/agent-inject-template-aws: |
{{- with secret "aws/creds/chatgpt-s3-uploader" -}}
export AWS_ACCESS_KEY_ID="{{ .Data.access_key }}"
export AWS_SECRET_ACCESS_KEY="{{ .Data.secret_key }}"
{{- end }}
# Agent configuration
vault.hashicorp.com/agent-limits-cpu: "250m"
vault.hashicorp.com/agent-limits-mem: "128Mi"
vault.hashicorp.com/agent-requests-cpu: "100m"
vault.hashicorp.com/agent-requests-mem: "64Mi"
# Preserve case for environment variables
vault.hashicorp.com/preserve-secret-case: "true"
# Log level
vault.hashicorp.com/log-level: "info"
spec:
serviceAccountName: chatgpt-app
containers:
- name: chatgpt-app
image: ghcr.io/makeaihq/chatgpt-app:latest
ports:
- containerPort: 3000
command:
- sh
- -c
- |
# Source secrets from Vault Agent
source /vault/secrets/config
source /vault/secrets/db
source /vault/secrets/aws
# Start application
exec node server.js
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 10
periodSeconds: 5
# Vault Agent sidecar automatically injected here
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
How it works: (1) Pod starts with init container that authenticates with Vault, (2) Vault Agent sidecar runs alongside app container, (3) Secrets written to /vault/secrets/ shared volume, (4) App sources secrets from files, (5) Vault Agent automatically renews secrets before expiration.
Secrets Store CSI Driver - Alternative approach using Kubernetes CSI (Container Storage Interface) for volume-based secret injection. Advantages: No sidecar overhead, native Kubernetes integration, works with existing secret management tools. Learn more about Kubernetes secrets management patterns.
Production Deployment: High Availability and Disaster Recovery
Deploying Vault in production requires high availability (HA), automated backups, audit logging, and monitoring. A production-grade Vault cluster ensures 99.99% uptime and rapid disaster recovery.
High Availability Configuration
Deploy a 5-node Raft cluster across 3 availability zones for maximum resilience:
- 3 voting nodes in primary region (Raft quorum)
- 2 non-voting nodes in DR region (replicas only)
- Load balancer distributes traffic across active nodes
- Auto-unseal with cloud KMS eliminates manual intervention
- Automated snapshots every 6 hours to object storage
Policy Management - Create least-privilege policies for each service. Example policy for read-only analytics service:
# analytics-readonly.hcl - Least-Privilege Policy for Analytics Service
# Grants read-only access to specific secret paths
# KV v2 - Read production analytics credentials
path "chatgpt-secrets/data/analytics/*" {
capabilities = ["read"]
}
# Database - Read-only credentials
path "database/creds/chatgpt-readonly" {
capabilities = ["read"]
}
# Transit - Decrypt PII for analytics (no encrypt)
path "transit/decrypt/chatgpt-pii" {
capabilities = ["update"]
}
# Deny all other paths
path "*" {
capabilities = ["deny"]
}
Secret Rotation Script - Automate API key rotation with zero downtime:
#!/bin/bash
# rotate-openai-key.sh - Automated OpenAI API Key Rotation
# Zero-downtime rotation with gradual rollout verification
set -e
VAULT_ADDR="https://vault.example.com"
SECRET_PATH="chatgpt-secrets/data/openai"
NEW_API_KEY="${1:-}"
if [ -z "$NEW_API_KEY" ]; then
echo "Usage: $0 <new-api-key>"
exit 1
fi
echo "[1/6] Reading current secret version..."
CURRENT=$(vault kv get -format=json "$SECRET_PATH" | jq -r '.data.metadata.version')
echo "Current version: $CURRENT"
echo "[2/6] Writing new API key..."
vault kv put "$SECRET_PATH" \
api_key="$NEW_API_KEY" \
organization="$(vault kv get -field=organization "$SECRET_PATH")" \
rotated_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
rotated_by="$(whoami)"
NEW_VERSION=$((CURRENT + 1))
echo "New version: $NEW_VERSION"
echo "[3/6] Testing new API key..."
if ! curl -s -H "Authorization: Bearer $NEW_API_KEY" \
https://api.openai.com/v1/models > /dev/null; then
echo "ERROR: New API key is invalid!"
echo "[ROLLBACK] Reverting to version $CURRENT..."
vault kv rollback -version="$CURRENT" "$SECRET_PATH"
exit 1
fi
echo "[4/6] Triggering gradual rollout..."
# Signal Kubernetes to restart pods (rolling update)
kubectl rollout restart deployment/chatgpt-app -n production
echo "[5/6] Monitoring rollout..."
kubectl rollout status deployment/chatgpt-app -n production --timeout=5m
echo "[6/6] Verifying application health..."
sleep 30
if ! curl -f https://makeaihq.com/health; then
echo "ERROR: Application health check failed!"
echo "[ROLLBACK] Reverting to version $CURRENT..."
vault kv rollback -version="$CURRENT" "$SECRET_PATH"
kubectl rollout undo deployment/chatgpt-app -n production
exit 1
fi
echo "API key rotation complete! New version: $NEW_VERSION"
Audit Logging - Track every Vault operation for compliance and security investigations:
// audit-logger.ts - Stream Vault Audit Logs to SIEM
// Real-time audit log processing for security monitoring
import { createReadStream } from 'fs';
import { createInterface } from 'readline';
import axios from 'axios';
interface AuditLog {
time: string;
type: 'request' | 'response';
auth: {
client_token: string;
accessor: string;
display_name: string;
policies: string[];
token_policies: string[];
metadata: Record<string, string>;
};
request: {
id: string;
operation: string;
path: string;
data: any;
remote_address: string;
client_token_accessor: string;
};
response?: {
data: any;
mount_type: string;
};
error?: string;
}
export class VaultAuditLogger {
private siemEndpoint: string;
private alertThreshold: number;
private suspiciousPatterns: RegExp[];
constructor(siemEndpoint: string) {
this.siemEndpoint = siemEndpoint;
this.alertThreshold = 10; // Alert after 10 failed attempts
this.suspiciousPatterns = [
/secret.*admin/i,
/database\/config/i,
/sys\/auth/i,
];
}
/**
* Stream audit logs and detect anomalies
*/
async streamAuditLogs(logPath: string): Promise<void> {
const fileStream = createReadStream(logPath);
const rl = createInterface({
input: fileStream,
crlfDelay: Infinity,
});
const failedAttempts = new Map<string, number>();
for await (const line of rl) {
try {
const log: AuditLog = JSON.parse(line);
// Send to SIEM
await this.sendToSIEM(log);
// Detect failed authentication attempts
if (log.error && log.request.path.includes('auth/')) {
const accessor = log.request.client_token_accessor || 'unknown';
const count = (failedAttempts.get(accessor) || 0) + 1;
failedAttempts.set(accessor, count);
if (count >= this.alertThreshold) {
await this.sendAlert({
severity: 'HIGH',
message: `Multiple failed auth attempts detected`,
accessor,
count,
path: log.request.path,
remote_address: log.request.remote_address,
});
}
}
// Detect suspicious secret access patterns
if (this.isSuspicious(log.request.path)) {
await this.sendAlert({
severity: 'MEDIUM',
message: 'Suspicious secret path accessed',
path: log.request.path,
user: log.auth?.display_name,
policies: log.auth?.policies,
});
}
} catch (error) {
console.error('[Audit] Failed to parse log:', error);
}
}
}
private isSuspicious(path: string): boolean {
return this.suspiciousPatterns.some((pattern) => pattern.test(path));
}
private async sendToSIEM(log: AuditLog): Promise<void> {
try {
await axios.post(this.siemEndpoint, log, { timeout: 5000 });
} catch (error) {
console.error('[SIEM] Failed to send log:', error);
}
}
private async sendAlert(alert: any): Promise<void> {
console.warn('[ALERT]', JSON.stringify(alert, null, 2));
// Integrate with PagerDuty, Slack, etc.
}
}
Backup Automation - Raft snapshots preserve Vault state for disaster recovery. Automate snapshots with 30-day retention and cross-region replication. For comprehensive disaster recovery strategies, see ChatGPT app backup and recovery patterns.
Conclusion: Production-Ready Secrets Management for ChatGPT Apps
HashiCorp Vault provides enterprise-grade secrets management with dynamic credentials, encryption-as-a-service, and comprehensive audit logging. By implementing Vault for your ChatGPT application, you eliminate hardcoded secrets, automate credential rotation, and achieve compliance with SOC 2, HIPAA, and PCI standards.
Key takeaways: (1) Use KV v2 for static secrets with versioning and metadata, (2) Implement dynamic secrets for databases and cloud providers to eliminate long-lived credentials, (3) Integrate with Kubernetes using Vault Agent or CSI Driver for automatic secret injection, (4) Deploy high-availability Raft clusters with auto-unseal and automated backups, (5) Enforce least-privilege policies with fine-grained access control.
Production deployment requires careful planning: HA cluster topology, disaster recovery procedures, monitoring dashboards, and incident response playbooks. Start with a 3-node Raft cluster in production, configure auto-unseal with cloud KMS, enable audit logging to SIEM, and automate secret rotation for critical credentials. For multi-tenant platforms, implement tenant-specific KV mounts with isolated policies.
Ready to eliminate secrets sprawl from your ChatGPT application? Start building with MakeAIHQ.com - deploy production-ready ChatGPT apps with automated secrets management, Kubernetes integration, and enterprise security. No infrastructure expertise required.
Next steps: Implement transit encryption for PII, configure certificate management with PKI engine, and integrate secrets rotation monitoring. For healthcare applications, explore HIPAA-compliant secrets management patterns. For financial services, review PCI DSS secrets management requirements.
Start your free trial at MakeAIHQ.com and deploy your first ChatGPT app with Vault-powered secrets management in under 48 hours. Join thousands of developers building secure, compliant AI applications without the complexity of managing infrastructure.
Related Resources
- Multi-Tenant Architecture for ChatGPT Apps
- Kubernetes ChatGPT Deployment Guide
- Healthcare HIPAA-Compliant ChatGPT Apps
- Disaster Recovery Patterns for ChatGPT Apps
- Encryption at Rest for ChatGPT Applications
- Kubernetes Secrets Management Best Practices
- PCI Compliance for ChatGPT Payment Apps
External Resources: