Refactor secret management providers and introduce unified handling

- Removed KeePass and SecretStore provider implementations.
- Integrated KeePass and SecretStore as vaults under the SecretManagement provider.
- Added new functions: Get-DSCConfigurationDataCredentialProvider and Set-DSCConfigurationDataCredentialProvider for managing credential providers.
- Implemented Unlock-ConfigurationDataSecretManagementVault to handle vault unlocking with master passwords.
- Updated README to reflect changes in provider usage and examples.
- Enhanced error handling and validation for vault registration and settings.
This commit is contained in:
Torsten Brendgen
2026-07-06 22:50:39 +02:00
parent 3fa52d7ada
commit 45e71c093c
12 changed files with 608 additions and 550 deletions

View File

@@ -1,10 +1,19 @@
function Register-DSCConfigurationDataCredentialProvider {
[CmdletBinding(SupportsShouldProcess=$true)]
Param(
[Parameter(Mandatory=$true)]
[Parameter(Mandatory=$true, Position=1)]
[string]
$Vault,
[Parameter(Mandatory=$false)]
[ValidateSet("Generic", "KeePass")]
[string]
$VaultType = "Generic",
[Parameter(Mandatory=$false)]
[string]
$DatabasePath,
[Parameter(Mandatory=$false)]
[string]
$KeyPath,
@@ -13,10 +22,6 @@ function Register-DSCConfigurationDataCredentialProvider {
[string]
$SettingsPath,
[Parameter(Mandatory=$false)]
[System.Security.SecureString]
$MasterKey,
[Parameter(Mandatory=$false)]
[string]
$ModuleName,
@@ -25,14 +30,6 @@ function Register-DSCConfigurationDataCredentialProvider {
[hashtable]
$VaultParameters = @{},
[Parameter(Mandatory=$false)]
[string]
$SubscriptionId,
[Parameter(Mandatory=$false)]
[string]
$TenantId,
[Parameter(Mandatory=$false)]
[switch]
$RegisterVault,
@@ -47,25 +44,17 @@ function Register-DSCConfigurationDataCredentialProvider {
[Parameter(Mandatory=$false)]
[switch]
$ConfigureSecretStore,
[Parameter(Mandatory=$false)]
[ValidateSet("None", "Password")]
[string]
$Authentication = "None",
[Parameter(Mandatory=$false)]
[ValidateSet("None", "Prompt")]
[string]
$Interaction = "None",
$UseMasterPassword,
[Parameter(Mandatory=$false)]
[Alias("MasterKey")]
[System.Security.SecureString]
$Password,
$MasterPassword,
[Parameter(Mandatory=$false)]
[int]
$PasswordTimeout,
[Alias("MasterKeyPath")]
[string]
$MasterPasswordKeyPath,
[Parameter(Mandatory=$false)]
[switch]
@@ -120,63 +109,98 @@ function Register-DSCConfigurationDataCredentialProvider {
process {
switch($Provider){
"KeePass" {
if([string]::IsNullOrWhiteSpace($KeyPath)){
throw "Provider [KeePass] requires [KeyPath]."
}
if($null -eq $MasterKey){
$MasterKey = Read-Host -Prompt "KeePass MasterKey for vault [$Vault]" -AsSecureString
}
if($PSCmdlet.ShouldProcess($SettingsPath, "Create provider settings for [$Provider]")){
$Key = New-ConfigurationDataAesKeyFile -Path $KeyPath -Force:$Force
$ProtectedValue = $MasterKey | ConvertFrom-SecureString -Key $Key
$ProviderSettings = [ordered]@{
KeePass = [ordered]@{
DefaultVault = $Vault
MasterKey = [ordered]@{
ProtectedValue = $ProtectedValue
KeyPath = $KeyPath
}
}
}
Export-PowerShellDataFile -InputObject $ProviderSettings -Path $SettingsPath -Force:$Force
if($PassThru){
return $ProviderSettings
}
Write-Verbose "Provider settings written to [$SettingsPath]."
}
}
"SecretManagement" {
if([string]::IsNullOrWhiteSpace($ModuleName)){
$ModuleName = "Microsoft.PowerShell.SecretStore"
if($VaultType -eq "KeePass"){
$ModuleName = "SecretManagement.KeePass"
}else{
$ModuleName = "Microsoft.PowerShell.SecretStore"
}
}
if($RegisterVault -or $PSBoundParameters.ContainsKey("ModuleName")){
$CommandParameters = @{
Name = $Vault
ModuleName = $ModuleName
$ShouldRegisterVault = $RegisterVault -or $PSBoundParameters.ContainsKey("ModuleName")
if($VaultType -eq "KeePass" -and $ShouldRegisterVault){
if([string]::IsNullOrWhiteSpace($DatabasePath) -and -not $VaultParameters.ContainsKey("Path")){
throw "SecretManagement KeePass vault registration requires [DatabasePath] or VaultParameters['Path']."
}
if($VaultParameters.Count -gt 0){
$CommandParameters["VaultParameters"] = $VaultParameters
if(-not [string]::IsNullOrWhiteSpace($DatabasePath)){
$VaultParameters["Path"] = $DatabasePath
}
if($DefaultVault){
$CommandParameters["DefaultVault"] = $true
if(-not [string]::IsNullOrWhiteSpace($KeyPath)){
$VaultParameters["KeyPath"] = $KeyPath
}
if($AllowClobber){
$CommandParameters["AllowClobber"] = $true
if($UseMasterPassword){
$VaultParameters["UseMasterPassword"] = $true
}
}
if($PSCmdlet.ShouldProcess($Vault, "Register SecretManagement vault [$ModuleName]")){
Register-SecretVault @CommandParameters
if($ShouldRegisterVault){
if($VaultType -eq "KeePass"){
$KeePassModule = Get-Module -Name SecretManagement.KeePass -ListAvailable | Sort-Object -Property Version -Descending | Select-Object -First 1
if($null -eq $KeePassModule){
throw "SecretManagement KeePass vault registration requires module [SecretManagement.KeePass]."
}
$ModuleReference = $KeePassModule.Name
if(-not [string]::IsNullOrWhiteSpace($KeePassModule.Path)){
$ModuleReference = $KeePassModule.Path
}
$CommandParameters = @{
Name = $Vault
ModuleName = $ModuleReference
VaultParameters = @{
Path = $VaultParameters["Path"]
UseMasterPassword = $false
UseWindowsAccount = $false
KeyPath = $null
ShowFullTitle = $false
ShowRecycleBin = $false
}
}
foreach($Key in @("KeyPath", "UseMasterPassword", "UseWindowsAccount", "ShowFullTitle", "ShowRecycleBin", "SkipValidate")){
if($VaultParameters.ContainsKey($Key)){
$CommandParameters.VaultParameters[$Key] = $VaultParameters[$Key]
}
}
if($DefaultVault){
$CommandParameters["DefaultVault"] = $true
}
if($AllowClobber){
$CommandParameters["AllowClobber"] = $true
}
if($PSCmdlet.ShouldProcess($Vault, "Register KeePass SecretManagement vault [$ModuleReference]")){
Register-SecretVault @CommandParameters
}
}else{
$CommandParameters = @{
Name = $Vault
ModuleName = $ModuleName
}
if($VaultParameters.Count -gt 0){
$CommandParameters["VaultParameters"] = $VaultParameters
}
if($DefaultVault){
$CommandParameters["DefaultVault"] = $true
}
if($AllowClobber){
$CommandParameters["AllowClobber"] = $true
}
if($PSCmdlet.ShouldProcess($Vault, "Register SecretManagement vault [$ModuleName]")){
Register-SecretVault @CommandParameters
}
}
}
@@ -186,80 +210,21 @@ function Register-DSCConfigurationDataCredentialProvider {
}
}
if($PSCmdlet.ShouldProcess($SettingsPath, "Create provider settings for [$Provider]")){
Export-PowerShellDataFile -InputObject $ProviderSettings -Path $SettingsPath -Force:$Force
if($VaultType -ne "Generic"){
$ProviderSettings.SecretManagement["VaultType"] = $VaultType
}
if($PassThru){
return $ProviderSettings
}
}
"SecretStore" {
if($ConfigureSecretStore){
$CommandParameters = @{
Authentication = $Authentication
Interaction = $Interaction
if($null -ne $MasterPassword){
if([string]::IsNullOrWhiteSpace($MasterPasswordKeyPath)){
throw "MasterPassword requires [MasterPasswordKeyPath]."
}
if($null -ne $Password){
$CommandParameters["Password"] = $Password
$Key = New-ConfigurationDataAesKeyFile -Path $MasterPasswordKeyPath -Force:$Force
$ProtectedValue = $MasterPassword | ConvertFrom-SecureString -Key $Key
$ProviderSettings.SecretManagement["MasterPassword"] = [ordered]@{
ProtectedValue = $ProtectedValue
KeyPath = $MasterPasswordKeyPath
}
if($PasswordTimeout -gt 0){
$CommandParameters["PasswordTimeout"] = $PasswordTimeout
}
if($PSCmdlet.ShouldProcess("SecretStore", "Configure local SecretStore")){
Set-SecretStoreConfiguration @CommandParameters -Confirm:$false
}
}
if($RegisterVault){
$CommandParameters = @{
Name = $Vault
ModuleName = "Microsoft.PowerShell.SecretStore"
}
if($DefaultVault){
$CommandParameters["DefaultVault"] = $true
}
if($AllowClobber){
$CommandParameters["AllowClobber"] = $true
}
if($PSCmdlet.ShouldProcess($Vault, "Register SecretStore vault")){
Register-SecretVault @CommandParameters
}
}
$ProviderSettings = [ordered]@{
SecretStore = [ordered]@{
DefaultVault = $Vault
}
}
if($PSCmdlet.ShouldProcess($SettingsPath, "Create provider settings for [$Provider]")){
Export-PowerShellDataFile -InputObject $ProviderSettings -Path $SettingsPath -Force:$Force
}
if($PassThru){
return $ProviderSettings
}
}
"AzureKeyVault" {
$ProviderSettings = [ordered]@{
AzureKeyVault = [ordered]@{
DefaultVault = $Vault
}
}
if(-not [string]::IsNullOrWhiteSpace($SubscriptionId)){
$ProviderSettings["AzureKeyVault"]["SubscriptionId"] = $SubscriptionId
}
if(-not [string]::IsNullOrWhiteSpace($TenantId)){
$ProviderSettings["AzureKeyVault"]["TenantId"] = $TenantId
}
if($PSCmdlet.ShouldProcess($SettingsPath, "Create provider settings for [$Provider]")){