The web interface that is supplied with Vault has a Search capability, but it is limited. Users are not able to search for nested secrets or Key names. The PowerShell function below can be used to export complete secret paths and the key names. It requires use of the vault command line and that the user has already logged in to Vault.
function Traverse-Secrets {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]$enginePath,
[Parameter(Mandatory=$true)]
[string]$vaultAddr
)
try {
# Retrieve secrets from Vault
Write-Verbose "Retrieving secrets from Vault at $vaultAddr"
$secrets = vault kv list -format=json -address $vaultAddr "$enginepath"
$jSecrets = $secrets | ConvertFrom-Json
$currentDate = Get-Date -Format "M/dd/yyyy"
# Create an array to hold the custom objects
$secretObjects = @()
# Iterate over each secret
foreach ($secret in $jSecrets) {
Write-Verbose "Processing secret: $secret"
$secretKeysObject = $null
$keysObject = $null
$secretKeys = $null
# Create a custom object and add it to the array
$splat = [ordered]@{
ReportDate = "$currentDate"
Path = "$enginepath"
Secret = "$secret"
Key = $null
}
if (-not ($secret -match "/")) {
# If the secret does not contain a "/", retrieve the keys
Write-Verbose "Retrieving keys for secret: $secret"
$secretKeysObject = vault kv get -format=json "$enginepath$secret" | ConvertFrom-Json
$keysObject = $secretKeysObject.data.data
$secretKeys = $keysObject | Get-Member -ErrorAction SilentlyContinue -MemberType NoteProperty | Select-Object -ExpandProperty Name
foreach($key in $secretKeys){
$splat.Key = $key
$secretObject = New-Object PSObject -Property $splat
$secretObjects += $secretObject
}
}elseif ($secret -match "/") {
# If the secret contains a "/", recursively call Traverse-Secrets
Write-Verbose "Recursively calling Traverse-Secrets for secret: $secret"
Traverse-Secrets -enginePath "$enginepath$secret" -vaultAddr $vaultAddr
}
}
# Return the array of custom objects
return $secretObjects
} catch {
Write-Error "Error executing: $_"
}
}