September 16th, 2020

SecretManagement Module Preview Design Changes

Paul Higinbotham
Senior Software Engineer

SecretManagement Module Preview Design Changes

This article is intended primarily for SecretManagement extension vault developers. It covers design changes that an extension vault implementer must be aware of.

It has been about 6 months since we published a pre-release alpha version of SecretManagement. Since that time we have received a bunch of great feedback from the community. There have been a number of incremental changes and improvements (including changing the name of the module). But it also became clear that the original vision and design suffered some shortcomings. Consequently, we re-thought the design and have been experimenting with various changes. For this preview release, we now have what we feel is a better and simpler design providing a consistent cross-platform experience.

Changes

Design Issues

One problem with the previous alpha release was that it depended on the Windows Credential Manager (CredMan) for the built-in local vault. The built-in local vault is a secure local store that is always available, regardless of whether any extension vaults are registered. CredMan is Windows platform only, and so the pre-release version of SecretManagement worked only on Windows. The plan was to eventually find similar third party solutions for non-Windows platforms. However it turns out that CredMan is pretty unique, and there are no equivalent solutions on non-Windows platforms. In addition community members pointed out that CredMan only works for interactive log-in accounts, and this means SecretManagement pre-release would not work with Windows built-in accounts or over PowerShell remoting.

Another problem was the decision to allow extension vaults to be written either as a binary C# implementing type or a PowerShell module. These two forms of an extension vault are quite different, and the code became complex trying to accommodate them both. The result was that extension vaults written in the two forms would have different behavior.

An original design goal was to abstract both management of secrets and management of secret vaults. But we found that the way we abstracted secret vaults was too restrictive to accommodate the wide variety of existing local and cloud based secure store solutions we saw. With this new design we are focusing on abstracting the management of secrets. The purpose of SecretManagement is to provide scripts a common way to access secrets from widely different secret store solutions. So the new design leaves it to the individual vault solutions how they are installed, configured, and authenticated.

Built-In Local Vault

The built-in local vault served two purposes. It provided an out-of-the-box secure local store, and also provided a way to store sensitive registration data for extension vaults. But using CredMan as the local store limited SecretManagement to Windows platform, without any good similar solutions on other platforms. Nevertheless, a CredMan based extension vault is still useful for many Windows platform scenarios, and so we now have a CredMan based extension vault example available in the GitHub repo.

The original design allowed extension vault implementations to store additional vault registry information securely in the built-in local vault. But we never saw a case where this was needed. Secure store solutions have their own way to authenticate a user and don’t need to store sensitive data.

Consequently, the built-in local vault has been removed from SecretManagement. All storage mechanisms are now extension vaults only. But SecretManagement without an extension vault is not very useful, so we are also publishing a preview release of a new cross-platform secure store extension vault. You can read more about the new SecretStore Extension Vault in the section below.

We have also added the ability to designate a registered extension vault as a Default vault. The default vault works like the built-in vault did. If no vault is specified when adding a secret, it is added to the default vault. Also the default vault is searched before any other registered vault, when retrieving secrets.

Implementing Type

Support for an extension vault based on an implementing type has been removed. This greatly simplifies SecretManagement and provides a more uniform development experience.

Now, extension vaults are just PowerShell modules that implement five required functions. When an extension vault is registered as a module, it is verified to have the correct form and to implement the expected functions. The extension vaults can be PowerShell script modules or binary modules, and the SecretManagement GitHub repo has examples of both forms.

Extension Vault User Interaction

Previously, an extension vault communicated to the user indirectly by passing results and error messages up to SecretManagement. However, this greatly complicated writing extension vaults around existing secret store solutions on various platforms. It was very difficult or impossible to support different forms of authentication. For example, an extension vault couldn’t prompt the user directly for some action such as providing a password.

But now extension vaults are just PowerShell modules and their exposed functions (cmdlets) are called on the UI thread. So each extension vault can now write to the pipeline, error or data streams, and can directly prompt users for actions.

This means an extension vault now has much more leeway in how it communicates to the user. But it is also responsible for ensuring a consistent user experience with other vaults. An extension vault should take care to write only expected data to the pipeline, and to write error data only for abnormal conditions specific to the vault implementation. Common error conditions, such as secret not found should be left to SecretManagement.

Extension Vault Module Format

Now that SecretManagement calls extension vault functions on the UI thread, there have been some changes in how an extension module resides on file. Each extension vault module implements the same five functions. SecretManagement needs to disambiguate the function calls, and also ensure that these functions do not appear in the user command space.

To do this, an extension vault module must conform a specific file structure. The following is an example of the required file structure for an extension vault named TestVault:

./TestVault
./TestVault/TestVault.psd1
./TestVault/TestStoreImplementation.dll
./TestVault/TestVault.Extension
./TestVault/TestVault.Extension/TestVault.Extension.psd1
./TestVault/TestVault.Extension/TestVault.Extension.psm1

The TestVault module contains a normal TestVault.psd1 PowerShell module manifest file. It also has an optional TestStoreImplementation.dll binary that implements the actual store. The manifest file looks like this:

@{
    ModuleVersion = '1.0'
    RootModule = '.TestStoreImplementation.dll'
    NestedModules = @('.TestVault.Extension')
    CmdletsToExport = @('Set-TestStoreConfiguration','Get-TestStoreConfiguration')
}

The manifest file exports two optional cmdlets used to configure the store. But the only required field is NestedModules that tells PowerShell to load the TestVault.Extension sub module as a nested module of TestVault.

It is the TestVault.Extension module that contains the required function implementations. It must be named with the parent module name plus the .Extension part appended to it. The TestVault.Extension hides the SecretManagement required functions from the user, and also uniquely qualifies the functions for this specific extension vault module. The TestVault.Extension sub module contains the expected .psd1 and .psm1 files. The manifest file looks like:

@{
    ModuleVersion = '1.0'
    RootModule = '.TestVault.Extension.psm1'
    RequiredAssemblies = '..TestStoreImplementation.dll'
    FunctionsToExport = @('Set-Secret','Get-Secret','Remove-Secret','Get-SecretInfo','Test-SecretVault')
}

The TestVault.Extension module is dependent on the TestStoreImplementation.dll binary file, which implements the actual store. But this is optional, and a simpler .Extension module implementation could implement everything within PowerShell script. One example of this might be a cloud based extension vault that is accessed through PowerShell cmdlets or REST APIs.

For more extension vault module examples, see the SecretManagement GitHub repo.

SecretStore Extension Vault

The Microsoft.PowerShell.SecretStore extension vault module is a secure local store for SecretManagement. It is open source and currently available as a preview version on PowerShell Gallery. SecretStore is based on .NET Core cryptographic APIs, and works on all PowerShell supported platforms. Secret data is stored at rest in encrypted form on the file system and in memory, and only decrypted when returned to a user request. SecretStore works within the scope of the current user, and is configurable.

By default SecretStore is configured to require a password, as this provides the strongest security. When a password is provided, it remains valid in the current PowerShell session until the PasswordTimeout time elapses. When the password becomes invalid, the store can be configured to prompt the user or otherwise throw an exception. The user can provide the password through an interactive prompt or with the Unlock-SecretStore cmdlet. The Unlock-SecretStore is intended for automation scenarios where user interaction is not possible.

PS C:> Get-SecretStoreConfiguration

      Scope PasswordRequired PasswordTimeout DoNotPrompt
      ----- ---------------- --------------- -----------
CurrentUser             True             900       False

SecretStore can be configured to not require a password, but will be less secure. Secrets are still encrypted on file and in memory. But the encryption key is stored on file and protected only by the platform file system. It is strongly encouraged that SecretStore be configured to require a password.

The following cmdlets are provided to manage SecretStore:

  • Get-SecretStoreConfiguration
  • Set-SecretStoreConfiguration
  • Unlock-SecretStore
  • Update-SecretStorePassword
  • Reset-SecretStore

Paul Higinbotham
PowerShell Team

Author

Paul Higinbotham
Senior Software Engineer

2 comments

Discussion is closed. Login to edit/delete existing comments.

  • Flux

    Hello, Paul. Thank you, not just for sharing the details of the design changes, but also for your penmanship. 😊 At least, you seem to know the difference between “inbox” and “out-of-the-box”.

    Now, the code snippets in this posts are somewhat damaged. The backslashes are usually missing.

  • Chris Black | Azure MVP | Happy Azure Stacking!!!

    Wow so much good stuff in here! Thanks for updating the module!