Files
proxmox/docs/04-configuration/PHOENIX_VAULT_INTEGRATION_GUIDE.md
defiQUG fbda1b4beb
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
docs: Ledger Live integration, contract deploy learnings, NEXT_STEPS updates
- ADD_CHAIN138_TO_LEDGER_LIVE: Ledger form done; public code review repo bis-innovations/LedgerLive; init/push commands
- CONTRACT_DEPLOYMENT_RUNBOOK: Chain 138 gas price 1 gwei, 36-addr check, TransactionMirror workaround
- CONTRACT_*: AddressMapper, MirrorManager deployed 2026-02-12; 36-address on-chain check
- NEXT_STEPS_FOR_YOU: Ledger done; steps completable now (no LAN); run-completable-tasks-from-anywhere
- MASTER_INDEX, OPERATOR_OPTIONAL, SMART_CONTRACTS_INVENTORY_SIMPLE: updates
- LEDGER_BLOCKCHAIN_INTEGRATION_COMPLETE: bis-innovations/LedgerLive reference

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 15:46:57 -08:00

10 KiB

Phoenix Vault Integration Guide

Last Updated: 2026-01-31
Document Version: 1.0
Status: Active Documentation


Date: 2026-01-19
Status: Ready for Integration
Purpose: Guide for integrating Phoenix services with Vault cluster


Overview

This guide provides step-by-step instructions for integrating Phoenix services (API, Portal, and other components) with the deployed Vault cluster.


Prerequisites

  • Vault cluster deployed and operational
  • AppRole authentication configured
  • AppRole credentials available
  • Phoenix services ready for integration

AppRole Credentials

AppRole credentials are stored in:

.secure/vault-credentials/phoenix-approle-credentials-YYYYMMDD.txt

Phoenix API:

  • Role ID: 27f213e2-f15e-b6de-3cf4-db2f02029dd5
  • Secret ID: (stored in credentials file)

Phoenix Portal:

  • Role ID: 70278dee-a85e-9007-c769-46b71a8c1460
  • Secret ID: (stored in credentials file)

Integration Methods

Set environment variables in your Phoenix service configuration:

export VAULT_ADDR=http://192.168.11.200:8200
export VAULT_ROLE_ID=<your-role-id>
export VAULT_SECRET_ID=<your-secret-id>

Method 2: Configuration Files

Create a Vault configuration file (e.g., vault-config.json):

{
  "vault_addr": "http://10.160.0.40:8200",
  "role_id": "<your-role-id>",
  "secret_id": "<your-secret-id>"
}

⚠️ Security: Never commit configuration files with credentials to Git. Use environment variables or secure secret management.


Phoenix API Integration

Node.js/TypeScript Example

import Vault from 'node-vault';

// Initialize Vault client
const vault = Vault({
  endpoint: process.env.VAULT_ADDR || 'http://192.168.11.200:8200',
  token: await authenticateWithAppRole(
    process.env.VAULT_ROLE_ID!,
    process.env.VAULT_SECRET_ID!
  )
});

// Authenticate with AppRole
async function authenticateWithAppRole(roleId: string, secretId: string): Promise<string> {
  const response = await fetch(`${process.env.VAULT_ADDR}/v1/auth/approle/login`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ role_id: roleId, secret_id: secretId })
  });
  const data = await response.json();
  return data.auth.client_token;
}

// Get database credentials
async function getDatabaseCredentials() {
  const response = await vault.read('secret/data/phoenix/database/postgres');
  return {
    username: response.data.data.username,
    password: response.data.data.password,
    host: response.data.data.host,
    port: response.data.data.port,
    database: response.data.data.database
  };
}

// Get JWT secrets
async function getJWTSecrets() {
  const response = await vault.read('secret/data/phoenix/api/jwt-secrets');
  return {
    accessTokenSecret: response.data.data['access-token-secret'],
    refreshTokenSecret: response.data.data['refresh-token-secret']
  };
}

Python Example

import hvac
import os

# Initialize Vault client
client = hvac.Client(url=os.getenv('VAULT_ADDR', 'http://10.160.0.40:8200'))

# Authenticate with AppRole
role_id = os.getenv('VAULT_ROLE_ID')
secret_id = os.getenv('VAULT_SECRET_ID')
client.auth.approle.login(role_id=role_id, secret_id=secret_id)

# Get database credentials
db_secrets = client.secrets.kv.v2.read_secret_version(path='phoenix/database/postgres')
db_config = db_secrets['data']['data']

# Get JWT secrets
jwt_secrets = client.secrets.kv.v2.read_secret_version(path='phoenix/api/jwt-secrets')
jwt_config = jwt_secrets['data']['data']

Phoenix Portal Integration

Similar to API integration, but use the phoenix-portal AppRole:

// Portal-specific Vault configuration
const vault = Vault({
  endpoint: process.env.VAULT_ADDR || 'http://192.168.11.200:8200',
  token: await authenticateWithAppRole(
    process.env.VAULT_PORTAL_ROLE_ID!,
    process.env.VAULT_PORTAL_SECRET_ID!
  )
});

// Get JWT secrets for portal
const jwtSecrets = await vault.read('secret/data/phoenix/api/jwt-secrets');

Secret Paths Reference

Available Secret Paths

Path Description Access Policy
secret/data/phoenix/api/jwt-secrets JWT signing secrets phoenix-api, phoenix-portal
secret/data/phoenix/api/api-keys API keys phoenix-api
secret/data/phoenix/database/postgres PostgreSQL credentials phoenix-api
secret/data/phoenix/database/redis Redis credentials phoenix-api
secret/data/phoenix/keycloak/admin-credentials Keycloak admin phoenix-api
secret/data/phoenix/keycloak/oidc-secrets OIDC client secrets phoenix-api
secret/data/phoenix/services/blockchain Blockchain RPC/keys phoenix-api
secret/data/phoenix/services/integrations Integration tokens phoenix-api

Reading Secrets

# Using Vault CLI
export VAULT_ADDR=http://192.168.11.200:8200
export VAULT_TOKEN=$(vault write -field=token auth/approle/login \
  role_id=$VAULT_ROLE_ID secret_id=$VAULT_SECRET_ID)

# Read secret
vault kv get secret/phoenix/database/postgres

Token Management

Token Lifecycle

  • Token TTL: 1 hour (default)
  • Token Max TTL: 4 hours
  • Secret ID TTL: 24 hours

Token Renewal

Tokens should be renewed before expiration:

// Renew token
async function renewToken(token: string): Promise<void> {
  await fetch(`${process.env.VAULT_ADDR}/v1/auth/token/renew-self`, {
    method: 'POST',
    headers: {
      'X-Vault-Token': token
    }
  });
}

Automatic Token Refresh

Implement automatic token refresh in your services:

class VaultClient {
  private token: string | null = null;
  private tokenExpiry: Date | null = null;

  async getToken(): Promise<string> {
    if (!this.token || this.isTokenExpired()) {
      await this.authenticate();
    }
    return this.token!;
  }

  private isTokenExpired(): boolean {
    if (!this.tokenExpiry) return true;
    return new Date() >= this.tokenExpiry;
  }

  private async authenticate(): Promise<void> {
    const response = await fetch(`${process.env.VAULT_ADDR}/v1/auth/approle/login`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        role_id: process.env.VAULT_ROLE_ID,
        secret_id: process.env.VAULT_SECRET_ID
      })
    });
    const data = await response.json();
    this.token = data.auth.client_token;
    this.tokenExpiry = new Date(Date.now() + data.auth.lease_duration * 1000);
  }
}

Error Handling

Common Errors

1. Authentication Failed

Error: invalid role_id or secret_id

Solution: Verify AppRole credentials are correct.

2. Permission Denied

Error: permission denied

Solution: Check that the AppRole has the correct policy attached.

3. Secret Not Found

Error: no secret found at path

Solution: Verify the secret path exists and is accessible.

Retry Logic

Implement retry logic for transient failures:

async function getSecretWithRetry(path: string, maxRetries = 3): Promise<any> {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await vault.read(path);
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
    }
  }
}

Security Best Practices

  1. Never Hardcode Credentials

    • Use environment variables
    • Use secure secret injection
    • Rotate credentials regularly
  2. Use Least Privilege

    • Each service should only access secrets it needs
    • Use separate AppRoles for different services
    • Review policies regularly
  3. Monitor Access

    • Enable audit logging
    • Monitor token usage
    • Alert on suspicious activity
  4. Token Management

    • Implement automatic token renewal
    • Handle token expiration gracefully
    • Use short token TTLs
  5. Network Security

    • Use TLS in production
    • Restrict network access to Vault
    • Use firewall rules

Testing Integration

Test Script

#!/bin/bash
# Test Vault integration

export VAULT_ADDR=http://192.168.11.200:8200
export VAULT_ROLE_ID=<your-role-id>
export VAULT_SECRET_ID=<your-secret-id>

# Authenticate
TOKEN=$(vault write -field=token auth/approle/login \
  role_id=$VAULT_ROLE_ID secret_id=$VAULT_SECRET_ID)

export VAULT_TOKEN=$TOKEN

# Test secret access
echo "Testing secret access..."
vault kv get secret/phoenix/api/jwt-secrets
vault kv get secret/phoenix/database/postgres

echo "✅ Integration test passed"

Troubleshooting

Cannot Connect to Vault

  1. Check network connectivity:
curl http://10.160.0.40:8200/v1/sys/health
  1. Verify Vault is unsealed:
vault status
  1. Check firewall rules

Authentication Fails

  1. Verify credentials:
vault read auth/approle/role/phoenix-api/role-id
  1. Check AppRole is enabled:
vault auth list
  1. Verify policy is attached:
vault read auth/approle/role/phoenix-api

Permission Denied

  1. Check policy:
vault policy read phoenix-api-policy
  1. Verify secret path:
vault kv list secret/phoenix/
  1. Check token capabilities:
vault token capabilities secret/data/phoenix/api/jwt-secrets

Migration from Existing Secrets

If migrating from existing .env files or other secret storage:

  1. Inventory Current Secrets

    • List all secrets currently in use
    • Map to Vault paths
  2. Create Secrets in Vault

    vault kv put secret/phoenix/database/postgres \
      username=current_username \
      password=current_password \
      host=current_host \
      port=5432 \
      database=phoenix
    
  3. Update Services

    • Replace .env file reading with Vault client
    • Test thoroughly
    • Deploy gradually
  4. Remove Old Secrets

    • Delete .env files after migration
    • Update .gitignore if needed


Status: Ready for Integration
Last Updated: 2026-01-19