Add secret provider functionality and enhance configuration data resolution

This commit is contained in:
Torsten Brendgen
2026-07-02 14:36:04 +02:00
parent 1cd225c7a0
commit 115b8be385
12 changed files with 343 additions and 11 deletions

View File

@@ -36,10 +36,12 @@ function Assert-ConfigurationDataSecretReference {
throw "Parameter [$Name] secret reference [Name] must not be empty."
}
switch($Provider.ToLowerInvariant()){
"keepass" { return }
default {
throw "Parameter [$Name] uses unsupported secret provider [$Provider]."
}
$ProviderDefinition = Get-ConfigurationDataSecretProvider -Name $Provider
if($null -eq $ProviderDefinition){
throw "Parameter [$Name] uses unsupported secret provider [$Provider]."
}
if($ProviderDefinition.SupportedTypes -notcontains $TypeName.ToLowerInvariant()){
throw "Parameter [$Name] uses provider [$Provider], but it does not support type [$TypeName]."
}
}

View File

@@ -0,0 +1,19 @@
function ConvertTo-ConfigurationDataCredential {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string]
$UserName,
[Parameter(Mandatory=$true)]
$Password
)
if($Password -is [System.Security.SecureString]){
$SecurePassword = $Password
}else{
$SecurePassword = ConvertTo-SecureString -String ([string]$Password) -AsPlainText -Force
}
return [System.Management.Automation.PSCredential]::new($UserName, $SecurePassword)
}

View File

@@ -6,8 +6,15 @@ function Get-ConfigurationDataMapValue {
[Parameter(Mandatory=$true)]
[string]
$Key
$Key,
[AllowNull()]
$DefaultValue = $null
)
if(-not (Test-ConfigurationDataMapContainsKey -Map $Map -Key $Key)){
return $DefaultValue
}
return $Map[$Key]
}

View File

@@ -0,0 +1,19 @@
function Get-ConfigurationDataSecretProvider {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string]
$Name
)
if($null -eq $script:ConfigurationDataSecretProviders){
$script:ConfigurationDataSecretProviders = @{}
}
$ProviderName = $Name.ToLowerInvariant()
if(-not $script:ConfigurationDataSecretProviders.ContainsKey($ProviderName)){
return $null
}
return $script:ConfigurationDataSecretProviders[$ProviderName]
}

View File

@@ -0,0 +1,40 @@
function Register-ConfigurationDataSecretProvider {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string]
$Name,
[Parameter(Mandatory=$true)]
[string[]]
$SupportedTypes,
[Parameter(Mandatory=$true)]
[scriptblock]
$Resolver
)
if([string]::IsNullOrWhiteSpace($Name)){
throw "Secret provider [Name] must not be empty."
}
if($SupportedTypes.Count -eq 0){
throw "Secret provider [$Name] must define at least one supported type."
}
foreach($Type in $SupportedTypes){
if($Type -notin @("credential", "securestring", "string")){
throw "Secret provider [$Name] uses unsupported type [$Type]."
}
}
if($null -eq $script:ConfigurationDataSecretProviders){
$script:ConfigurationDataSecretProviders = @{}
}
$script:ConfigurationDataSecretProviders[$Name.ToLowerInvariant()] = [PSCustomObject]@{
Name = $Name
SupportedTypes = @($SupportedTypes | ForEach-Object { $_.ToLowerInvariant() })
Resolver = $Resolver
}
}

View File

@@ -0,0 +1,42 @@
function Resolve-ConfigurationDataParameterSecrets {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[System.Collections.Hashtable]
$ConfigurationData,
[Parameter(Mandatory=$false)]
[hashtable]
$ProviderSettings = @{}
)
$ResolvedConfigurationData = $ConfigurationData.Clone()
if($ResolvedConfigurationData.ContainsKey("Parameters")){
$ResolvedConfigurationData.Parameters = $ResolvedConfigurationData.Parameters.Clone()
foreach($Parameter in @($ResolvedConfigurationData.Parameters.GetEnumerator())){
$Definition = $Parameter.Value
if(-not (Test-ConfigurationDataMap -Value $Definition)){
continue
}
$Definition = $Definition.Clone()
$ResolvedConfigurationData.Parameters[$Parameter.Name] = $Definition
$TypeName = [string](Get-ConfigurationDataMapValue -Map $Definition -Key "Type" -DefaultValue "")
if($TypeName -notin @("credential", "secureString")){
continue
}
$ExpectedType = $TypeName.ToLowerInvariant()
foreach($ValueKey in @("Value", "DefaultValue")){
if((Test-ConfigurationDataMapContainsKey -Map $Definition -Key $ValueKey) -and (Test-ConfigurationDataSecretReference -Value $Definition[$ValueKey])){
$Definition[$ValueKey] = Resolve-ConfigurationDataSecretReference -Reference $Definition[$ValueKey] -ExpectedType $ExpectedType -ProviderSettings $ProviderSettings
}
}
}
}
return $ResolvedConfigurationData
}

View File

@@ -0,0 +1,35 @@
function Resolve-ConfigurationDataSecretReference {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[System.Collections.IDictionary]
$Reference,
[Parameter(Mandatory=$true)]
[ValidateSet("credential", "securestring", "string")]
[string]
$ExpectedType,
[Parameter(Mandatory=$false)]
[hashtable]
$ProviderSettings = @{}
)
$Provider = [string](Get-ConfigurationDataMapValue -Map $Reference -Key "Provider")
$ProviderDefinition = Get-ConfigurationDataSecretProvider -Name $Provider
if($null -eq $ProviderDefinition){
throw "Unsupported secret provider [$Provider]."
}
if($ProviderDefinition.SupportedTypes -notcontains $ExpectedType.ToLowerInvariant()){
throw "Secret provider [$($ProviderDefinition.Name)] does not support type [$ExpectedType]."
}
$CurrentProviderSettings = @{}
if($ProviderSettings.ContainsKey($ProviderDefinition.Name)){
$CurrentProviderSettings = $ProviderSettings[$ProviderDefinition.Name]
}
return & $ProviderDefinition.Resolver -Reference $Reference -ExpectedType $ExpectedType -ProviderSettings $CurrentProviderSettings
}

View File

@@ -0,0 +1,14 @@
function Test-ConfigurationDataSecretReference {
[CmdletBinding()]
Param(
[AllowNull()]
$Value
)
if(-not (Test-ConfigurationDataMap -Value $Value)){
return $false
}
return (Test-ConfigurationDataMapContainsKey -Map $Value -Key "Provider") -and
(Test-ConfigurationDataMapContainsKey -Map $Value -Key "Name")
}