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: