Skip to main content

BeyondTrust Password Safe Cloud → Azure Key Vault Credential Sync (Community Feedback Wanted)

  • July 10, 2026
  • 0 replies
  • 9 views

Hi Beekeepers,

I've been building a small automation project that connects Password Safe Cloud to Azure Key Vault for programmatic credential availability, and I'd love your feedback, ideas, and stress-testing.
Happy to share the full GitHub repo (currently private — DM me and I'll grant access).
 

At my organization, we use BeyondTrust Password Safe Cloud for privileged breakglass credentials, but several downstream consumers (Azure Functions, Logic Apps, Automation Accounts, third-party SaaS) need to pull those same credentials from Azure Key Vault — because that's what they natively integrate with.
The pre-existing process was:

Manual retrieval from Password Safe
Manual paste into Key Vault
No enforced rotation confirmation
No audit trail for SOX / NYDFS

I wanted an automation layer that respects BeyondTrust as the source of truth for the credential lifecycle, but pushes the rotated secret into Key Vault with proper version discipline and evidence.

 

What I Built — S.H.A.N.I.

Safeguard & Harmonize Accounts via Network Integration

A locally-hosted PowerShell REST bridge with a static HTML dashboard.

Components

File Language Role
SHANI-Bridge.ps1 PowerShell 7.x (also runs on 5.1) Local REST server on http://127.0.0.1:8888
SHANI-Dashboard.html HTML + CSS + JS Operator UI, served by the bridge itself
Start-SHANI.ps1 PowerShell Mints token, launches bridge
Stop-SHANI.ps1 PowerShell Graceful shutdown

Per-Account Flow

Rotate → Confirm → Retrieve → Upload → Disable Old → Log
  1. Trigger rotation on the managed account (PUT /ManagedAccounts/{id}/Credentials)
  2. Poll LastChangeDate for up to 60s to confirm rotation actually happened
  3. Request checkout and retrieve the new credential (POST /RequestsGET /Credentials/{id})
  4. Upload to Azure Key Vault as a new secret version (Set-AzKeyVaultSecret)
  5. Disable the prior Key Vault version (Update-AzKeyVaultSecret -Enable $false)
  6. Check-in the BT request
  7. Log to structured audit tables

Batch Behavior

  • Reads a CSV (systemName,accountName) — supports batch mode for many accounts
  • Per-row try/catch so one bad account doesn't kill the batch
  • After completion, prompts operator to download 3 CSVs:
    • shani_full_log_*.csv — complete console trace
    • shani_rotation_log_*.csv — rotation confirmation evidence (System, Account, Rotated=YES/NO, Retrieved=YES/NO, Result)
    • shani_vault_log_*.csv — Key Vault version lifecycle evidence (SecretName, NewVersion, ActivationDate, OldVersionDisabled)

BeyondTrust Configuration Used

Component Value / Setting
Admin Account BTControl_SA (local BT account, member of API group)
API Group Control API User
API Group Permissions 1. API Registration selected 2. Smart Groups (Breakglass 2-2 rules) 3. Credential Management — Full Control (Feature) 4. Password Safe Account Management (Feature)
Auth pattern PS-Auth key=<32-char>; runas=<user>;
API version Public REST v3

Azure Configuration Used

Component Setting
Service Principal Azure AD App Registration
K Get / List / Set on secrets only (no Delete — least privilege)
Vault Naming breakglassaccount-<MACHINENAME> for 1:1 traceability with BT
Vault Hardening Soft-Delete + Purge Protection required
Auth pattern Connect-AzAccount -ServicePrincipal (no browser popup, no interactive login)

Security Hardening Applied (v1.2)

Went through two rounds of InfoSec review. Every fix is backed by a CWE / OWASP / Microsoft reference:

Token & Authentication

  • 256-bit cryptographic RNG token (not GUID)
  • Never printed to console — copied to clipboard or masked fallback
  • DPAPI-encrypted at rest via ConvertFrom-SecureString — file ACL scoped to running user
  • Cleared from memory on process exit
  • Constant-time compare via SHA-256 + CryptographicOperations.FixedTimeEquals (with byte-XOR fallback for PS 5.1)
  • Rate-limited: rolling 60-second window, 10 failures triggers throttle + SECURITY alert log

Listener Binding

  • Bound to literal 127.0.0.1 (not localhost) — no DNS/hosts-file dependency
  • Startup self-check aborts if bound prefix isn't exactly loopback IPv4
  • Prevents IPv6 loopback (::1) mismatch between listener and dashboard

CORS / CSRF Protection

  • Removed Access-Control-Allow-Origin: *
  • Removed Access-Control-Allow-Private-Network: true
  • Dashboard is now served same-origin from the bridge at http://127.0.0.1:8888/ (not opened as file://)
  • Server-side Origin header check — rejects anything not matching the bridge's own address
  • Single-use rotating nonce (X-SHANI-Nonce) on every sensitive call, issued fresh via X-SHANI-Next-Nonce response header
  • Content-Type validation — POST bodies must be application/json or rejected with 415

Cloud Privilege

  • Service Principal reduced to Get / List / Set on secrets — Delete removed (rotation only disables prior versions, never deletes)

Compatibility

  • Works on Windows PowerShell 5.1 AND PowerShell 7 without modification
  • Auto-fallback for .NET 5+ APIs that don't exist on 5.1