$script:ModuleRoot = Split-Path -Parent $PSScriptRoot $script:ModuleManifest = Join-Path -Path $script:ModuleRoot -ChildPath 'Resolve-DSCConfigurationData.psd1' Import-Module $script:ModuleManifest -Force function global:Get-KeePassEntry { param( [string] $DatabaseProfileName, [string] $Title, [System.Security.SecureString] $MasterKey ) switch($Title){ 'SetupAccount' { [pscustomobject]@{ UserName = 'CONTOSO\svc-setup' Password = 'KeePass-Setup-Password!' } } 'FarmPassphrase' { [pscustomobject]@{ UserName = '' Password = 'KeePass-Farm-Passphrase!' } } default { $null } } } function global:Get-Secret { param( [string] $Vault, [string] $Name ) switch($Name){ 'SetupCredential' { [pscredential]::new( 'CONTOSO\svc-secret-setup', (ConvertTo-SecureString -String 'Secret-Setup-Password!' -AsPlainText -Force) ) } 'FarmPassphrase' { ConvertTo-SecureString -String 'Secret-Farm-Passphrase!' -AsPlainText -Force } 'PlainSecret' { 'Secret-Plain-Value!' } default { $null } } } function global:Get-AzKeyVaultSecret { param( [string] $VaultName, [string] $Name, [switch] $AsPlainText ) if($AsPlainText){ return "Az-$Name-Plain!" } [pscustomobject]@{ SecretValue = ConvertTo-SecureString -String "Az-$Name-Secure!" -AsPlainText -Force } } function global:Set-AzContext { param( [string] $SubscriptionId, [string] $Tenant ) [pscustomobject]@{ SubscriptionId = $SubscriptionId Tenant = $Tenant } } function ConvertFrom-TestSecureString { param( [Parameter(Mandatory)] [System.Security.SecureString] $SecureString ) $Pointer = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString) try { [Runtime.InteropServices.Marshal]::PtrToStringBSTR($Pointer) } finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($Pointer) } } function New-TestConfigurationData { param( [Parameter(Mandatory)] [string] $Provider, [Parameter(Mandatory)] [string] $Vault, [Parameter(Mandatory)] [string] $CredentialName, [Parameter(Mandatory)] [string] $PassphraseName, [Parameter(Mandatory)] [string] $PlainSecretName, [string] $UserName = '' ) $CredentialReference = @{ Provider = $Provider Vault = $Vault Name = $CredentialName } if(-not [string]::IsNullOrWhiteSpace($UserName)){ $CredentialReference.UserName = $UserName } @{ Parameters = @{ SetupCredential = @{ Type = 'credential' Value = $CredentialReference } FarmPassphrase = @{ Type = 'secureString' Value = @{ Provider = $Provider Vault = $Vault Name = $PassphraseName } } PlainSecret = @{ Type = 'string' Value = @{ Provider = $Provider Vault = $Vault Name = $PlainSecretName } } } Resources = @{ Test = @{ SetupCredential = "[parameters('SetupCredential')]" FarmPassphrase = "[parameters('FarmPassphrase')]" PlainSecret = "[parameters('PlainSecret')]" } } } } Describe 'DSC ConfigurationData credential providers' { It 'registers all built-in providers in the dynamic ValidateSet' { $ProviderValues = (Get-Command Register-DSCConfigurationDataCredentialProvider). Parameters['Provider']. Attributes | Where-Object { $_ -is [System.Management.Automation.ValidateSetAttribute] } | ForEach-Object { $_.ValidValues } ($ProviderValues -contains 'AzureKeyVault') | Should Be $true ($ProviderValues -contains 'KeePass') | Should Be $true ($ProviderValues -contains 'SecretManagement') | Should Be $true ($ProviderValues -contains 'SecretStore') | Should Be $true } It 'writes Azure Key Vault provider settings without storing credentials' { $SettingsPath = Join-Path -Path $TestDrive -ChildPath 'ProviderSettings' $Settings = Register-DSCConfigurationDataCredentialProvider ` -Provider AzureKeyVault ` -Vault contoso-kv ` -SubscriptionId '00000000-0000-0000-0000-000000000000' ` -TenantId '11111111-1111-1111-1111-111111111111' ` -SettingsPath $SettingsPath ` -Force ` -PassThru $Settings.AzureKeyVault.DefaultVault | Should Be 'contoso-kv' $Settings.AzureKeyVault.SubscriptionId | Should Be '00000000-0000-0000-0000-000000000000' $Settings.AzureKeyVault.TenantId | Should Be '11111111-1111-1111-1111-111111111111' $Settings.AzureKeyVault.Contains('ClientSecret') | Should Be $false (Join-Path -Path $SettingsPath -ChildPath 'ProviderSettings.AzureKeyVault.psd1') | Should Exist } It 'resolves KeePass credential, secureString, and string references' { $ConfigurationData = New-TestConfigurationData ` -Provider KeePass ` -Vault Test ` -CredentialName SetupAccount ` -PassphraseName FarmPassphrase ` -PlainSecretName FarmPassphrase $Resolved = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData ($Resolved.Resources.Test.SetupCredential -is [System.Management.Automation.PSCredential]) | Should Be $true $Resolved.Resources.Test.SetupCredential.UserName | Should Be 'CONTOSO\svc-setup' $Resolved.Resources.Test.SetupCredential.GetNetworkCredential().Password | Should Be 'KeePass-Setup-Password!' ConvertFrom-TestSecureString -SecureString $Resolved.Resources.Test.FarmPassphrase | Should Be 'KeePass-Farm-Passphrase!' $Resolved.Resources.Test.PlainSecret | Should Be 'KeePass-Farm-Passphrase!' } It 'resolves SecretManagement credential, secureString, and string references' { $ConfigurationData = New-TestConfigurationData ` -Provider SecretManagement ` -Vault LocalStore ` -CredentialName SetupCredential ` -PassphraseName FarmPassphrase ` -PlainSecretName PlainSecret $Resolved = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData ($Resolved.Resources.Test.SetupCredential -is [System.Management.Automation.PSCredential]) | Should Be $true $Resolved.Resources.Test.SetupCredential.UserName | Should Be 'CONTOSO\svc-secret-setup' $Resolved.Resources.Test.SetupCredential.GetNetworkCredential().Password | Should Be 'Secret-Setup-Password!' ConvertFrom-TestSecureString -SecureString $Resolved.Resources.Test.FarmPassphrase | Should Be 'Secret-Farm-Passphrase!' $Resolved.Resources.Test.PlainSecret | Should Be 'Secret-Plain-Value!' } It 'resolves SecretStore credential, secureString, and string references' { $ConfigurationData = New-TestConfigurationData ` -Provider SecretStore ` -Vault LocalStore ` -CredentialName SetupCredential ` -PassphraseName FarmPassphrase ` -PlainSecretName PlainSecret $Resolved = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData ($Resolved.Resources.Test.SetupCredential -is [System.Management.Automation.PSCredential]) | Should Be $true $Resolved.Resources.Test.SetupCredential.UserName | Should Be 'CONTOSO\svc-secret-setup' $Resolved.Resources.Test.SetupCredential.GetNetworkCredential().Password | Should Be 'Secret-Setup-Password!' ConvertFrom-TestSecureString -SecureString $Resolved.Resources.Test.FarmPassphrase | Should Be 'Secret-Farm-Passphrase!' $Resolved.Resources.Test.PlainSecret | Should Be 'Secret-Plain-Value!' } It 'resolves Azure Key Vault credential, secureString, and string references' { $ConfigurationData = New-TestConfigurationData ` -Provider AzureKeyVault ` -Vault contoso-kv ` -CredentialName setup-password ` -PassphraseName farm-passphrase ` -PlainSecretName plain-secret ` -UserName 'CONTOSO\svc-app-setup' $Resolved = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData -ProviderSettings @{ AzureKeyVault = @{ DefaultVault = 'contoso-kv' SubscriptionId = '00000000-0000-0000-0000-000000000000' TenantId = '11111111-1111-1111-1111-111111111111' } } ($Resolved.Resources.Test.SetupCredential -is [System.Management.Automation.PSCredential]) | Should Be $true $Resolved.Resources.Test.SetupCredential.UserName | Should Be 'CONTOSO\svc-app-setup' $Resolved.Resources.Test.SetupCredential.GetNetworkCredential().Password | Should Be 'Az-setup-password-Secure!' ConvertFrom-TestSecureString -SecureString $Resolved.Resources.Test.FarmPassphrase | Should Be 'Az-farm-passphrase-Secure!' $Resolved.Resources.Test.PlainSecret | Should Be 'Az-plain-secret-Plain!' } }