.do
Enterprise

Vault & Secrets Management

Built-in secrets management - store API keys, credentials, and sensitive configuration securely with automatic encryption and access control

The .do platform provides enterprise-grade secrets management out of the box. Store sensitive data securely, rotate credentials automatically, and audit all access - without managing encryption keys or infrastructure.

How It Works

Secrets are stored in the platform vault and accessed via simple APIs:

// Store a secret
await $.Vault.set('stripe-api-key', process.env.STRIPE_API_KEY, {
  description: 'Stripe API key for payment processing',
  rotationPolicy: '90d'
})

// Retrieve a secret
const apiKey = await $.Vault.get('stripe-api-key')

// Use in your code
const stripe = new Stripe(apiKey)

The platform automatically:

  1. Encrypts secrets at rest using AES-256
  2. Controls access via role-based permissions
  3. Logs access for audit trails
  4. Rotates credentials based on policy
  5. Versions secrets for rollback capability

Secret Types

Store different types of sensitive data:

API Keys

// External service credentials
await $.Vault.set('openai-api-key', key, {
  type: 'api-key',
  service: 'openai',
  rotationPolicy: '90d'
})

await $.Vault.set('aws-access-key', accessKey, {
  type: 'api-key',
  service: 'aws',
  metadata: {
    accountId: '123456789',
    region: 'us-east-1'
  }
})

// Access with type safety
const key = await $.Vault.get<APIKey>('openai-api-key')

Database Credentials

// Database connection strings
await $.Vault.set('postgres-connection', {
  host: 'db.example.com',
  port: 5432,
  database: 'production',
  username: 'app',
  password: 'secure-password',
  ssl: true
}, {
  type: 'database',
  rotationPolicy: '30d'
})

// Platform handles connection pooling and rotation
const db = await $.Database.connect(
  await $.Vault.get('postgres-connection')
)

Certificates

// TLS/SSL certificates
await $.Vault.set('api-tls-cert', {
  certificate: certPEM,
  privateKey: keyPEM,
  chain: chainPEM
}, {
  type: 'certificate',
  expiresAt: new Date('2025-12-31'),
  autoRenew: true
})

// Platform monitors expiration and alerts

Signing Keys

// JWT signing keys, webhook signatures, etc.
await $.Vault.set('jwt-signing-key', privateKey, {
  type: 'signing-key',
  algorithm: 'RS256',
  rotationPolicy: '180d'
})

// Use for signing
const token = await $.JWT.sign(payload, {
  key: await $.Vault.get('jwt-signing-key')
})

OAuth Tokens

// OAuth access and refresh tokens
await $.Vault.set('github-oauth-token', {
  accessToken: 'gho_...',
  refreshToken: 'ghr_...',
  expiresAt: new Date('2025-02-01')
}, {
  type: 'oauth-token',
  service: 'github',
  userId: user.id,
  autoRefresh: true
})

// Platform automatically refreshes expired tokens
const token = await $.Vault.get('github-oauth-token')
// Returns fresh token, auto-refreshed if needed

Environment Configuration

// Sensitive environment variables
await $.Vault.set('app-config', {
  STRIPE_WEBHOOK_SECRET: 'whsec_...',
  SENDGRID_API_KEY: 'SG...',
  ENCRYPTION_KEY: 'base64-key',
  SESSION_SECRET: 'random-secret'
}, {
  type: 'config',
  environment: 'production'
})

// Access all at once
const config = await $.Vault.get('app-config')

Access Control

Secrets have granular access control:

// Set secret with permissions
await $.Vault.set('production-db-password', password, {
  permissions: {
    read: ['role:backend-engineer', 'role:sre'],
    write: ['role:sre'],
    delete: ['role:security-admin']
  }
})

// Platform enforces automatically
const password = await $.Vault.get('production-db-password')
// Throws UnauthorizedException if user lacks 'read' permission

// Organization-scoped secrets
await $.Vault.set('org-api-key', apiKey, {
  scope: 'organization',
  organizationId: org.id
})
// Only accessible within that organization

Secret Rotation

Automatic credential rotation:

// Define rotation policy
await $.Vault.set('database-password', password, {
  rotationPolicy: {
    frequency: '30d',
    handler: async (secret) => {
      // Generate new password
      const newPassword = generateSecurePassword()

      // Update in database
      await updateDatabasePassword(secret.metadata.username, newPassword)

      // Return new secret
      return newPassword
    }
  }
})

// Platform rotates automatically every 30 days
// Old version kept for 7 days for rollback

Manual Rotation

Rotate secrets on demand:

// Rotate immediately
await $.Vault.rotate('api-key')

// Rotate with new value
await $.Vault.rotate('api-key', newValue)

// Rotate and notify
await $.Vault.rotate('api-key', {
  value: newValue,
  notify: ['security-team']
})

Versioning

Secrets are versioned automatically:

// Update secret (creates new version)
await $.Vault.set('api-key', newKey)

// Get latest version
const latest = await $.Vault.get('api-key')

// Get specific version
const v1 = await $.Vault.get('api-key', { version: 1 })
const v2 = await $.Vault.get('api-key', { version: 2 })

// Rollback to previous version
await $.Vault.rollback('api-key', { version: 1 })

// List versions
const versions = await $.Vault.versions('api-key')
// Returns: [
//   { version: 2, createdAt: '2025-01-15', createdBy: userId },
//   { version: 1, createdAt: '2025-01-01', createdBy: userId }
// ]

Encryption

All secrets are encrypted:

At Rest

  • AES-256-GCM encryption
  • Key Encryption Keys (KEK) rotated annually
  • Data Encryption Keys (DEK) unique per secret
  • Hardware Security Modules (HSM) for key storage

In Transit

  • TLS 1.3 for all API communication
  • Certificate pinning for platform services
  • Encrypted backups with separate keys

In Memory

  • Secrets cleared after use
  • No logging of secret values
  • Encrypted swap on platform infrastructure

Dynamic Secrets

Generate short-lived credentials on demand:

// Define dynamic secret generator
await $.Vault.defineDynamic('temp-database-user', {
  type: 'database',
  generator: async (userId) => {
    // Create temporary database user
    const username = `temp_${userId}_${Date.now()}`
    const password = generateSecurePassword()

    await db.query(`
      CREATE USER ${username} WITH PASSWORD '${password}';
      GRANT SELECT ON ALL TABLES IN SCHEMA public TO ${username};
    `)

    return {
      username,
      password,
      ttl: 3600 // 1 hour
    }
  },
  cleanup: async (credentials) => {
    // Revoke user when TTL expires
    await db.query(`DROP USER ${credentials.username}`)
  }
})

// Request dynamic secret
const tempCreds = await $.Vault.generate('temp-database-user')
// Use for 1 hour, then automatically cleaned up

Integration Patterns

Environment Variables

// Load secrets as environment variables
on($.Worker.starting, async () => {
  const secrets = await $.Vault.get('app-config')

  // Inject into environment
  for (const [key, value] of Object.entries(secrets)) {
    process.env[key] = value
  }
})

Configuration Files

// Generate config file from secrets
on($.Deployment.starting, async () => {
  const config = await $.Vault.get('app-config')

  // Write to secure location
  await $.File.writeSecure('.env.production',
    Object.entries(config)
      .map(([k, v]) => `${k}=${v}`)
      .join('\n')
  )
})

Third-Party Services

// Sync secrets to external vault
on($.Vault.secret.updated, async ({ secret }) => {
  if (secret.metadata.sync) {
    await syncToHashiCorpVault(secret)
  }
})

Compliance

Vault meets compliance requirements:

SOC 2

  • Encryption at rest and in transit
  • Access logging and monitoring
  • Regular security audits
  • Incident response procedures

HIPAA

  • PHI encryption requirements
  • Access controls and audit trails
  • Breach notification procedures
  • Business associate agreements

PCI DSS

  • Encryption of cardholder data
  • Key management procedures
  • Access control mechanisms
  • Security logging and monitoring

GDPR

  • Data protection by design
  • Encryption of personal data
  • Access controls and consent
  • Data breach procedures

Audit & Monitoring

All secret access is logged:

// Every access creates audit log
const secret = await $.Vault.get('api-key')
// Logs: {
//   userId,
//   action: 'vault.secret.read',
//   secretId: 'api-key',
//   timestamp,
//   ipAddress,
//   userAgent
// }

// Query audit logs
const logs = await $.AuditLog.list({
  type: 'vault.secret',
  secretId: 'api-key',
  period: 'last_30_days'
})

// Set up alerts
on($.Vault.secret.accessed, async ({ secret, user }) => {
  if (secret.metadata.sensitive) {
    await $.Alert.send({
      severity: 'medium',
      message: `Sensitive secret accessed: ${secret.id}`,
      user: user.email,
      recipient: 'security-team'
    })
  }
})

Backup & Recovery

Secrets are backed up securely:

// Automatic encrypted backups
// - Hourly incremental backups
// - Daily full backups
// - 30-day retention
// - Separate encryption keys

// Manual backup
const backup = await $.Vault.backup({
  secrets: ['api-key', 'database-password'],
  encrypt: true
})

// Restore from backup
await $.Vault.restore(backup, {
  verify: true,
  dryRun: false
})

// Disaster recovery
// - Multi-region replication
// - Cross-datacenter backups
// - Recovery time objective: `<1` hour
// - Recovery point objective: `<5` minutes

Performance

Vault operations are optimized:

  • <10ms read latency - Secrets cached in memory
  • <50ms write latency - Asynchronous encryption
  • 1000+ requests/sec - Per-worker throughput
  • Regional caching - Edge-cached for global access
// Batch secret retrieval
const secrets = await $.Vault.getMany([
  'api-key-1',
  'api-key-2',
  'api-key-3'
])
// Single request, parallel decryption

// Cache frequently accessed secrets
const cached = await $.Vault.get('api-key', {
  cache: true,
  ttl: 300 // Cache for 5 minutes
})

Best Practices

1. Principle of Least Privilege

Grant minimum access necessary:

// Good: Role-based access
await $.Vault.set('production-key', key, {
  permissions: {
    read: ['role:backend-service']
  }
})

// Avoid: Overly permissive
await $.Vault.set('production-key', key, {
  permissions: {
    read: ['*']  // Too broad
  }
})

2. Rotation Policies

Rotate secrets regularly:

// Good: Automatic rotation
await $.Vault.set('database-password', password, {
  rotationPolicy: '30d'
})

// Avoid: Static secrets
await $.Vault.set('database-password', password)
// No rotation, security risk over time

3. Never Log Secrets

Prevent accidental exposure:

// Good: Log without sensitive data
console.log('API request successful')

// Avoid: Logging secrets
console.log('Using API key:', apiKey)  // Secret in logs!

// Platform prevents this automatically
await $.Log.info('API request', {
  apiKey  // Platform redacts automatically
})
// Logged as: { apiKey: '[REDACTED]' }

4. Use Dynamic Secrets

Prefer short-lived credentials:

// Good: Dynamic secrets
const creds = await $.Vault.generate('temp-db-user')
// Expires after 1 hour

// Avoid: Long-lived static credentials
const password = await $.Vault.get('static-db-password')
// Never expires, higher risk

Migration

Moving from existing secret management:

From Environment Variables

// Before: Plain environment variables
const apiKey = process.env.STRIPE_API_KEY

// After: Vault
const apiKey = await $.Vault.get('stripe-api-key')

From AWS Secrets Manager

// Import from AWS
import { SecretsManager } from '@aws-sdk/client-secrets-manager'

const aws = new SecretsManager()
const secrets = await aws.listSecrets()

for (const secret of secrets.SecretList) {
  const value = await aws.getSecretValue({ SecretId: secret.ARN })

  await $.Vault.set(secret.Name, value.SecretString, {
    source: 'aws-secrets-manager',
    imported: true
  })
}

From HashiCorp Vault

// Import from HashiCorp Vault
import vault from 'node-vault'

const client = vault({ endpoint: 'http://vault:8200' })
const secrets = await client.list('secret/data')

for (const path of secrets.data.keys) {
  const data = await client.read(`secret/data/${path}`)

  await $.Vault.set(path, data.data.data, {
    source: 'hashicorp-vault',
    imported: true
  })
}

CLI Access

Access vault from command line:

# Set secret
do vault set api-key "sk-..."

# Get secret
do vault get api-key

# List secrets
do vault list

# Rotate secret
do vault rotate api-key

# Delete secret
do vault delete api-key

Next Steps


Secrets management is critical for security. The .do platform makes it simple with built-in encryption, automatic rotation, and comprehensive audit trails.