Private/Resolve-AzLocalItsmSecret.ps1
|
function Resolve-AzLocalItsmSecret { <# .SYNOPSIS Resolves an ITSM secret reference to a plaintext value. .DESCRIPTION Accepts a secret reference in one of these forms and returns the resolved plaintext string (the caller is responsible for handling the result securely): - 'kv://<vault>/<secret>' -- Azure Key Vault, current Az session - 'env://<NAME>' -- environment variable - '<bareName>' -- when -DefaultKeyVault is supplied, the bare name is resolved as a Key Vault secret in that vault - 'literal://<value>' -- explicit literal (only when -AllowLiteral is passed; defends against accidental in-config secrets) Designed for the AzLocal.UpdateManagement ITSM connector. #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Reference, [Parameter(Mandatory = $false)] [string]$DefaultKeyVault, [Parameter(Mandatory = $false)] [switch]$AllowLiteral ) if ($Reference -match '^kv://([^/]+)/(.+)$') { $vault = $Matches[1] $secret = $Matches[2] return Get-AzKeyVaultSecretPlainText -VaultName $vault -SecretName $secret } if ($Reference -match '^env://(.+)$') { $envName = $Matches[1] $value = [Environment]::GetEnvironmentVariable($envName) if ([string]::IsNullOrEmpty($value)) { throw "ITSM secret reference '$Reference' resolved to an empty environment variable. Set `$env:$envName before running." } return $value } if ($Reference -match '^literal://(.*)$') { if (-not $AllowLiteral) { throw "ITSM secret reference uses 'literal://' but -AllowLiteral was not specified. Refusing to treat config-embedded literal as a secret." } return $Matches[1] } if ($Reference -match '^[A-Za-z0-9._-]+$') { if (-not $DefaultKeyVault) { throw "ITSM secret reference '$Reference' is a bare name but no DefaultKeyVault was provided. Use 'kv://<vault>/<secret>' or 'env://<NAME>' instead." } return Get-AzKeyVaultSecretPlainText -VaultName $DefaultKeyVault -SecretName $Reference } throw "ITSM secret reference '$Reference' is not a recognised form. Use 'kv://<vault>/<secret>', 'env://<NAME>', or a bare secret name with -DefaultKeyVault." } function Get-AzKeyVaultSecretPlainText { <# .SYNOPSIS Thin wrapper around Get-AzKeyVaultSecret -AsPlainText that exists so the parent function can be unit-tested by mocking just this call. #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory = $true)][string]$VaultName, [Parameter(Mandatory = $true)][string]$SecretName ) if (-not (Get-Command Get-AzKeyVaultSecret -ErrorAction SilentlyContinue)) { throw "Az.KeyVault module is not loaded. Install with: Install-Module Az.KeyVault -Scope CurrentUser" } try { $value = Get-AzKeyVaultSecret -VaultName $VaultName -Name $SecretName -AsPlainText -ErrorAction Stop } catch { throw "Failed to read Key Vault secret '$SecretName' from vault '$VaultName': $($_.Exception.Message)" } if ([string]::IsNullOrEmpty($value)) { throw "Key Vault secret '$VaultName/$SecretName' resolved to an empty value." } return $value } |