How to store and retrieve secrets in PowerShell
Instead of hardcoding secrets such as passwords into your source code, you can use
PowerShell's SecretManagement
module to retrieve secrets from a secret vault
that you create.
You use the SecretManagement
module to register different vault extensions and
access vault secrets. These vault extensions are responsible for authentication and
securely storing and retrieving the secrets and depending on the extension, can store
secretlys locally or remotely in a cloud store like the Azure Key Vault.
The security of SecretManagement is dependent on the extension vaults it hosts. These vaults perform the actual functions of storing and retrieving the secrets.
Per Microsoft's Understanding the security features of SecretManagement and SecretStore, the extension vaults are responsible
for the authentication and security of their secret vaults and secrets, so you should make suree you take that into
consideration when deciding to use SecretManagment
to store your secrets.
Local Secret Vault
To store our secrets locally we will use the default SecretStore
vault extension which uses .NET cryptography APIs to
encrypt the secrets and then stores them on your local file system.
Install and Import Modules
Install-Module Microsoft.PowerShell.SecretManagement
Install-Module Microsoft.PowerShell.SecretStore
Import-Module Microsoft.PowerShell.SecretManagement
Import-Module Microsoft.PowerShell.SecretStore
Create Vault
By default SecretStore
requires a password and you will be prompted to set a password when first creating the vault
and then again when you access the secret vault.
In order to create your local secret vault, you must register it with PowerShell's SecretManagement
module using the Register-SecretVault
cmdlet and specify the Microsoft.PowerShell.SecretStore
extension module using the ModuleName parameter.
This cmdlet will register a new vault with the name MyVault using the extension Microsoft.PowerShell.SecretStore and sets it as the default secret vault.
Register-SecretVault -Name MyVault -ModuleName Microsoft.PowerShell.SecretStore -DefaultVault
The Default parameter defines this as the default secret vault to use you use other cmdlets in the SecretManagement
module and no vault name is specifed using the Name parameters.
Now you can view your registered secret vaults by using Get-SecretVault
:
Get-SecretVault
Name ModuleName IsDefaultVault
---- ---------- --------------
MyVault Microsoft.PowerShell.SecretStore True
Where is the vault stored on the machine?
On Windows the vault is stored in: $env:LOCALAPPDATA\Microsoft\PowerShell\secretmanagement\secretvaultregistry\
For Non-Windows the vault is stored in: $HOME/.secretmanagement/secretvaultregistry/
Change vault password
If you need to change your vault's password, you can use the Set-SecretStorePassword
cmdlet, which takes no parameters and will prompt you for the old and new passwords.
You can also chang the vault password using the Set-SecretStoreConfiguration cmdlet by passing a SecureString
into the Password parameter:
Set-SecretStoreConfiguration
Configure your vault
You can change the configuration of your vault if you want to change the authentication type, password timeout, etc by using the Set-SecretStoreConfiguration cmdlet.
The default password timeout for the SecretStore
extention vault is 15 minutes.
Add your secret to the vault
You of course want to actually use your new secret vault, so lets get to adding a secret to the vault.
You use the Set-Secret
cmdlet to add secrets to your vault, and the secret value can be one of the types below:
- byte[]
- String
- SecureString
- PSCredential
- Hashtable
The first time you use Set-Secret
to create a secret you will be
prompted to set a new vault password. Don't forget this vault password.
Set-Secret -Name MySecret -Secret "SomeSecretPassword" -Vault MyVault
Vault MyVault requires a password.
Enter password:
You can let the Set-Secret
cmdlet prompt you to enter the value of the secret
by omitting the Secret parameter:
Set-Secret -Name MySecret -Vault MyVault
cmdlet Set-Secret at command pipeline position 1
Supply values for the following parameters:
SecureStringSecret: ***********************
You can even store a credential into the secret store:
Set-Secret -Name MyCredential -Secret (Get-Credential) -Vault MyVault
PowerShell credential request
Enter your credentials.
User: username
Password for user username: ****************
You can retrieve the credential from the secret store, but like all secrets,
the secret value is returned as a SecureString
.
Get-Secret -Name MyCredential -Vault MyVault
UserName Password
-------- --------
username System.Security.SecureString
Add metadata to a secret
You can store non-sensitive metadata with your secrets, such as specifying the purpose of the secret, the author, creation date, etc. Metadata is stored as a key-value pair and the SecretStore
vault extension supports the value types:
- string
- int
- DateTime
$metadata = @{
Purpose = 'Testing'
Expires = (Get-Date).AddDays(30)
Limit = 5
}
Set-Secret -Name MySecret -Secret NewSecret -Metadata $metadata
To view the secret's metadata, you use the Get-SecretInfo
cmdlet:
Get-SecretInfo -Name TestSecret | Format-List *
Name : TestSecret
Type : String
VaultName : SecretStore
Metadata : {[Limit, 5], [Expires, 6/23/2022 1:45:09 PM], [Purpose, Testing]}
You can add metadata to an existing secret but keep in mind that this will
overwrite any existing metadata that the secret has.
Set-SecretInfo -Name MySecret -Metadata @{Purpose = "This is a test secret."}
Get-SecretInfo -Name MySecret | Select-Object Name, Metadata
Name Metadata
---- --------
MySecret {[Purpose, This is a test secret.]}
Retrieve your secret
You can retrieve your secrets your the vault by using the Get-Secret
cmdlet, which will return your secret as a SecureString
but you can use the AsPlainText switch to return your secret as an unencrypted string.
Get-Secret MySecret
System.Security.SecureString
Get-Secret -Name MySecret -AsPlainText
SomeSecretPassword
List all secrets
You can get a list of all your secrets:
Get-SecretInfo
Name Type VaultName
---- ---- ---------
MyCredential PSCredential MyVault
MySecret SecureString MyVault
Update your secret
If you wish to update a secret value, you use the same Set-Secret
cmdlet that you
previously used to create the secret.
Set-Secret -Name MySecret -Vault MyVault
Remove your secret
When you need to remove your secret, you can use the Remove-Secret
cmdlet:
Remove-Secret -Name MySecret -Vault MyVault -WhatIf
What if: Performing the operation "Remove secret by name from vault" on target "MyVault".
Remove-Secret -Name MySecret -Vault MyVault
Get-Secret -Name MySecret -Vault MyVault
Get-Secret: The secret MySecret was not found.
Resetting your secret vault
If you need to reset your secret vault and delete all secrets and restore the
vault to the default configuration you can use the Reset-SecretStore
cmdlet.
Removing your secret vault
It does not appear that there is a cmdlet to actually delete your secret vault,
since if you use Unregister-SecretVault
it will only unregister it
and if you register a new vault with the same name, it will restore the previous
vault with that name, like you can see here:
Get-SecretVault
Name ModuleName IsDefaultVault
---- ---------- --------------
MyVault Microsoft.PowerShell.SecretStore True
Get-Secret -Name MySecret -AsPlainText
SomeSecretPassword
Unregister-SecretVault -Name MyVault
Get-SecretVault
<nothing returned>
Register-SecretVault -Name MyVault -ModuleName Microsoft.PowerShell.SecretStore -DefaultVault
Get-Secret -MySecret -AsPlainText
Vault MyVault requires a password.
Enter password:
**************
SomeSecretPassword
If you wish to remove your secret vault, you must use Remove-Secret
on each secret in your vault:
Get-SecretInfo -Vault MyVault | Remove-Secret -WhatIf
Get-SecretInfo -Vault MyVault | Remove-Secret
Example
This is a quick example of mounting an SMB network share
using a secret that contains the network credentials.
<#
.SYNOPSIS
Example of using secrets from a SecretStore
by mounting a SMB share as a network drive.
.DESCRIPTION
Example of using secrets from a SecretStore
by mounting a SMB share as a network drive
and storing the share's credentials as a
secret.
.NOTES
Author: jpann [at] impostr-labs.com
Created on: 11-03-2023
#>
Import-Module Microsoft.PowerShell.SecretManagement
Import-Module Microsoft.PowerShell.SecretStore
# Register our secret vault if it does not already exist
if (-not(Get-SecretVault -Name SMBVault -ErrorAction SilentlyContinue)) {
Write-Host "Creating new vault ..."
Register-SecretVault -Name SMBVault -ModuleName Microsoft.PowerShell.SecretStore
}
# If the secret for our network share credentials does not
# already exist create it.
if (-not(Get-Secret -Name SMBCredentials -Vault SMBVault -ErrorAction SilentlyContinue)) {
Write-Host "Creating new secret ..."
$secretArgs = @{
Name = SMBCredentials
Vault = SMBVault
Secret = (Get-Credential)
Metadata = @{Purpose = "Network credentials for this network path."}
}
Set-Secret @secretArgs
}
$networkDrive = "X:"
$networkPath = Read-Host "Enter network path you wish to mount as drive $networkDrive\ "
if ($networkPath) {
if (-not(Test-Path $networkDrive -PathType Container)) {
# Get credentials from secret
$smbCredentials = Get-Secret -Name SMBCredentials -Vault SMBVault
$smbArgs = @{
LocalPath = $networkDrive
RemotePath = $networkPath
UserName = $smbCredentials.UserName
Password = $smbCredentials.GetNetworkCredential().Password
}
Write-Host "Mounting SMB share $networkPath as $networkDrive ..."
New-SmbMapping @smbArgs
# Remove the variable that was containing the credentials
Remove-Variable -Name smbCredentials
} else {
Write-Error "Drive $networkDrive already exists!"
exit 1
}
}
Write-Host "Removing SMB mapping ..."
Remove-SmbMapping -LocalPath $networkDrive -Force