PowerShell / SecretManagement

PowerShell module to consistent usage of secrets through different extension vaults
MIT License
317 stars 46 forks source link

Make vaults interaction possible #173

Closed saldoukhov closed 2 years ago

saldoukhov commented 2 years ago

Maybe I'm just missing something... I'm creating a Vault Extension that is using an "app_secret" token to talk to the network to fetch the secrets. I'd like to be able to store this token locally, and Microsoft.PowerShell.SecretStore looks like a very good candidate for this. I'm using the following line to get the app_secret (from the module script):

$appSecret = Microsoft.PowerShell.SecretManagement\Get-Secret -Name appSecret -Vault Microsoft.PowerShell.SecretStore

This works when I invoke this code from the cmdlet of my module, but fails to retrieve the secret when it is invoked from the extension's methods (Get-Secret, GetSecretInfo)

Is this a known issue? Can anybody suggest a workaround?

PaulHigin commented 2 years ago

This is not supported. You cannot call SecretManagement commands from within an extension vault command that is currently being invoked by SecretManagement.

But if you wanted to use SecretStore, you could call its extension vault commands directly (and not through a recursive SecretManagement call). For example you could create a function like this:

function Get-SecretTokenFromStore
{
    param (
        [string] $SecretName
    )

    $moduleInstance = Import-Module -Name Microsoft.PowerShell.SecretStore -PassThru
    # Run SecretStore extension vault command using module scope
    & $moduleInstance { Get-Secret -Name $SecretName }
}

The SecretStore extension vault Get-Secret command returns the secret as the same type it was stored as (it does not do any conversions like SecretManagement/Get-Secret command does). So if the secret was stored as a String type it is returned as that type.

But I am not sure if this is the best way to store your token. If SecretStore is configured to require and prompt for a password, then it will do that when Get-Secret command is called. Not sure if that is what you want. If you turn SecretStore password requirement off, then it is less secure.

saldoukhov commented 2 years ago

Thanks, this is exactly what I was looking for - we want to give our users flexibility, they can make their own decision on where they have to store the root secret for our vault and if they need to protect it with a password. Using this approach, users are not even limited to storing the root secret in the SecretStore, they can use any other SecretManagement extension.

saldoukhov commented 2 years ago

Though, the answer is not 100% correct, I figured it out, but I see something that I still do not understand. Basically,

# The $SecretName is MySecret $secret = & $moduleInstance { Get-Secret -Name $SecretName } Write-Host $secret # writes empty string $secret = & $moduleInstance { Get-Secret -Name MySecret } Write-Host $secret # writes secret $secret = & $moduleInstance Get-Secret -Name $SecretName Write-Host $secret # writes secret

What do the brackets around the instance command mean and where I can read on that aspect?

PaulHigin commented 2 years ago

All three cases above are essentially the same. This syntax runs a script block or command in the $moduleInstance scope using the & call operator. In the first two cases the script block (script between the two brackets) are run in the module scope. In the last case it is the Get-Secret command that is being run in the module scope. Since the script block just runs the Get-Secret command, all three versions do the same thing.

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_operators?view=powershell-7.1

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scopes?view=powershell-7.1

saldoukhov commented 2 years ago

Believe me they don't. The first version does not fetch the secret, the second and third do.

Somehow the script block does not evaluate the $SecretName variable.

PaulHigin commented 2 years ago

It depends on how $SecretName is defined (it was left out in your example). If it is script scope then it will not be visible in the module scope script block. But you can change that by defining it globally ($global:SecretName = 'MyName').