{"id":18192,"date":"2020-02-06T14:59:33","date_gmt":"2020-02-06T22:59:33","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/powershell\/?p=18192"},"modified":"2020-02-06T16:04:43","modified_gmt":"2020-02-07T00:04:43","slug":"secrets-management-module-vault-extensions","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/powershell\/secrets-management-module-vault-extensions\/","title":{"rendered":"Secrets Management Module Vault Extensions"},"content":{"rendered":"<div class=\"markdown-body\" itemprop=\"mainContentOfPage\">\n<h2>\n<a id=\"user-content-secrets-management-module-vault-extensions\" class=\"anchor\" href=\"#secrets-management-module-vault-extensions\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a>Secrets Management Module Vault Extensions<\/h2>\n<p>A new PowerShell <a href=\"https:\/\/www.powershellgallery.com\/packages\/Microsoft.PowerShell.SecretsManagement\" rel=\"nofollow\">Secrets Management<\/a> module has been published on PowerShell Gallery. It is currently in a pre-release state and still in active development. Even though the module is not complete, we have released it to gather early community feedback. Most of the functionality is implemented, but currently the module only works on Windows with Linux support coming next, followed by macOS. This article describes the Secrets Management module in general, but is mostly about how vault extensions work. For a full overview of Secrets Management see this <a href=\"http:\/\/devblogs.microsoft.com\/powershell\/secrets-management-development-release\" rel=\"nofollow\">article<\/a>.<\/p>\n<p>The Secrets Management module is based on the <a href=\"https:\/\/github.com\/PowerShell\/PowerShell-RFC\/pull\/234\">Secrets Management RFC<\/a>, which you can learn more about from this <a href=\"https:\/\/myignite.techcommunity.microsoft.com\/sessions\/83981?source=sessions\" rel=\"nofollow\">great Ignite presentation<\/a>.<\/p>\n<h2>\n<a id=\"user-content-secrets-management-module\" class=\"anchor\" href=\"#secrets-management-module\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a>Secrets Management module<\/h2>\n<p>The purpose of the Secrets Management module is to provide secure storage and access of secrets in your PowerShell scripts. It consists of an always available local storage solution (or vault), along with a vault extension mechanism that allows registration of other secrets storage\/retrieval solutions. A vault extension can implement a local or remote custom storage solution.<\/p>\n<p>The Secrets Management module contains commands for registering vault extensions, and manipulating vault secrets.<\/p>\n<p>For example, this script uses the Secrets Management module to retrieve a NuGet API key in order to publish <code>MyNewModule<\/code> to the PowerShell Gallery, and invoke script remotely using a stored credential:<\/p>\n<div class=\"highlight highlight-source-powershell\">\n<pre>Import-Module Microsoft.PowerShell.SecretsManagement\r\n\r\n# Publish a module to the PowerShell Gallery\r\nPublish-Module -Path C:\\Modules\\Publish\\MyNewModule -NuGetApiKey (Get-Secret NuGetApiKey -AsPlainText)\r\n\r\n# Run management script on multiple machines\r\nInvoke-Command -Cn $machines -FilePath .\\MyMgmtScript.ps1 -Credential (Get-Secret MgmtCred)<\/pre>\n<\/div>\n<h2>\n<a id=\"user-content-built-in-local-vault\" class=\"anchor\" href=\"#built-in-local-vault\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a>Built-in local vault<\/h2>\n<p>The Secrets Management module comes with a built-in local vault. It is always present and can be used to safely store and retrieve secrets without any extension vaults registered. On Windows, it is implemented with <a href=\"https:\/\/docs.microsoft.com\/windows\/win32\/secauthn\/credentials-management\" rel=\"nofollow\">CredMan<\/a>. Credential Manager encrypts and stores secrets based on the current user context, and only that same user can access those secrets. On Linux, the built-in local vault will likely use <a href=\"https:\/\/github.com\/GNOME\/gnome-keyring\">Gnome Keyring<\/a> to securely store and retrieve secrets, though others can be added in the future, whether by the PowerShell Team or an external vault extension author.<\/p>\n<p>This example shows the names and types of credentials created and stored in the built-in local vault:<\/p>\n<div class=\"highlight highlight-source-powershell\">\n<pre>Get-SecretInfo\r\n\r\nName                 Vault             TypeName\r\n----                 -----             --------\r\nGitHubPATForRelease  BuiltInLocalVault String\r\nGitRepoAccessToken   BuiltInLocalVault String\r\nLocalAdminCred       BuiltInLocalVault PSCredential\r\nSecretParameters     BuiltInLocalVault Hashtable\r\nPSGalleryPAT         BuiltInLocalVault String<\/pre>\n<\/div>\n<h2>\n<a id=\"user-content-secret-data-types\" class=\"anchor\" href=\"#secret-data-types\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a>Secret data types<\/h2>\n<p>The Secrets Management module supports five data types, and the built-in local vault supports all five types. However, extension vaults can implement any subset of the supported types:<\/p>\n<ul>\n<li>\n<p><code>byte[]<\/code><\/p>\n<\/li>\n<li>\n<p><code>string<\/code><\/p>\n<\/li>\n<li>\n<p><code>SecureString<\/code><\/p>\n<\/li>\n<li>\n<p><code>PSCredential<\/code><\/p>\n<\/li>\n<li>\n<p><code>Hashtable<\/code><\/p>\n<\/li>\n<\/ul>\n<p>The Hashtable data type is used by the module to store optional vault extension parameters.\nBecause the additional parameters may contain secrets, the parameters are stored securely as a Hashtable in the built-in local vault.<\/p>\n<h2>\n<a id=\"user-content-vault-extensions\" class=\"anchor\" href=\"#vault-extensions\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a>Vault extensions<\/h2>\n<p>In addition to the built-in local vault, any number of vault extensions can be registered. A vault extension can store secrets on the local machine or remotely. For example, a remote vault extension could use Azure KeyVault to store secrets. A vault extension is registered to the current logged in user context, and only that user can access the registered vault.<\/p>\n<p>Vault extensions are PowerShell modules. Extensions can be either script based PowerShell modules or binary modules. Script based extension modules must implement and export four module functions. Binary based extension modules must include a C# class that derives from an abstract extension class, and implements four required methods.<\/p>\n<h3>\n<a id=\"user-content-extension-vault-registration-cmdlets\" class=\"anchor\" href=\"#extension-vault-registration-cmdlets\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a>Extension vault registration cmdlets<\/h3>\n<ul>\n<li>\n<p><code>Register-SecretsVault<\/code> registers a PowerShell module as an extension vault for the current user context. Validation is performed to ensure the module either provides the required binary with implementing type or the required script commands. If a dictionary of additional parameters is specified then it will be stored securely in the built-in local vault.<\/p>\n<\/li>\n<li>\n<p><code>Get-SecretsVault<\/code> returns a list of extension vaults currently registered in the user context.<\/p>\n<\/li>\n<li>\n<p><code>Unregister-SecretsVault<\/code> un-registers an extension vault.<\/p>\n<\/li>\n<\/ul>\n<div class=\"highlight highlight-source-powershell\">\n<pre>Register-SecretsVault -Name CodeLocalVault -ModuleName CodeLocalVault\r\n\r\nGet-SecretsVault\r\n\r\nName              ModuleName       ImplementingType\r\n----              ----------       ----------------\r\nBuiltInLocalVault\r\nCodeLocalVault    CodeLocalVault   CodeLocalVault.ImplementingClass\r\nScriptLocalVault  ScriptLocalVault<\/pre>\n<\/div>\n<h3>\n<a id=\"user-content-script-vault-extension-module\" class=\"anchor\" href=\"#script-vault-extension-module\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a>Script vault extension module<\/h3>\n<p>A script based vault extension must be a PowerShell module that includes a subdirectory named &#8216;ImplementingModule&#8217;, and which is in the same directory as the PowerShell module manifest file. The ImplementingModule subdirectory must contain PowerShell script module files named &#8216;ImplementingModule&#8217;, e.g. ImplementingModule.psd1, ImplementingModule.psm1, and which implement the required script functions.<\/p>\n<p>The ImplementingModule module is in a subdirectory so as not to expose the SetSecret, GetSecret, RemoveSecret, GetSecretInfo script functions to the user through PowerShell&#8217;s command discovery. This way the functions will only be available for internal use.<\/p>\n<p>NOTE:\nWe plan to change the &#8216;ImplementingModule&#8217; name to &#8216;SecretsManagementExtension&#8217;, since it is more descriptive. Remember, this is a work in progress!<\/p>\n<p><code>ImplementingModule.psd1<\/code><\/p>\n<div class=\"highlight highlight-source-powershell\">\n<pre>@{\r\n    ModuleVersion = '1.0'\r\n    RootModule = '.\\ImplementingModule.psm1'\r\n    FunctionsToExport = @('Set-Secret','Get-Secret','Remove-Secret','Get-SecretInfo')\r\n}<\/pre>\n<\/div>\n<p><code>ImplementingModule.psm1<\/code><\/p>\n<div class=\"highlight highlight-source-powershell\">\n<pre>function Set-Secret\r\n{\r\n    param (\r\n        [string] $Name,\r\n        [object] $Secret,\r\n        [hashtable] $AdditionalParameters\r\n    )\r\n}\r\n\r\nfunction Get-Secret\r\n{\r\n    param (\r\n        [string] $Name,\r\n        [hashtable] $AdditionalParameters\r\n    )\r\n}\r\n\r\nfunction Remove-Secret\r\n{\r\n    param (\r\n        [string] $Name,\r\n        [hashtable] $AdditionalParameters\r\n    )\r\n}\r\n\r\nfunction Get-SecretInfo\r\n{\r\n    param (\r\n        [string] $,\r\n        [hashtable] $AdditionalParameters\r\n    )\r\n}<\/pre>\n<\/div>\n<p>For an example of a script based vault extension, check out the <a href=\"https:\/\/github.com\/PowerShell\/Modules\/tree\/master\/Samples\/VaultExtension\/Modules\/ScriptLocalVault\">ScriptLocalVault<\/a> module.<\/p>\n<h3>\n<a id=\"user-content-c-vault-extension-module\" class=\"anchor\" href=\"#c-vault-extension-module\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a>C# vault extension module<\/h3>\n<p>A C# vault extension is a PowerShell module that includes a binary assembly which implements the <code>SecretsManagementExtension<\/code> abstract class. The abstract class requires the implementation of four methods that are essentially the same as the required four functions of a script based vault extension. The PowerShell module is sparse, requiring only a PowerShell manifest file that identifies the implementing type in the &#8216;RequiredAssemblies&#8217; entry.<\/p>\n<p><code>CodeLocalVault.psd1<\/code><\/p>\n<div class=\"highlight highlight-source-powershell\">\n<pre>@{\r\n    ModuleVersion = '1.0'\r\n    RequiredAssemblies = @('CodeLocalVault')\r\n}<\/pre>\n<\/div>\n<p><code>CodeLocalVault.cs<\/code><\/p>\n<div class=\"highlight highlight-source-cs\">\n<pre>\/\/ CodeLocalVault implements these SecretsManagementExtension abstract class methods\r\npublic abstract bool SetSecret(\r\n    string name,\r\n    object secret,\r\n    IReadOnlyDictionary&lt;string, object&gt; parameters,\r\n    out Exception error);\r\n\r\npublic abstract object GetSecret(\r\n    string name,\r\n    IReadOnlyDictionary&lt;string, object&gt; parameters,\r\n    outException error);\r\n\r\npublic abstract bool RemoveSecret(\r\n    string name,\r\n    IReadOnlyDictionary&lt;string, object&gt; parameters,\r\n    outException error);\r\n\r\npublic abstract KeyValuePair&lt;string, string&gt;[] GetSecretInfo(\r\n    string filter,\r\n    IReadOnlyDictionary&lt;string, object&gt; parameters,\r\n    out Exception error);<\/pre>\n<\/div>\n<p>For an example of a C# code based vault extension module, check out the <a href=\"https:\/\/github.com\/PowerShell\/Modules\/tree\/master\/Samples\/VaultExtension\/Modules\/CodeLocalVault\">CodeLocalVault<\/a> module.<\/p>\n<h3>\n<a id=\"user-content-extension-vault-module-required-functions\" class=\"anchor\" href=\"#extension-vault-module-required-functions\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a>Extension vault module required functions<\/h3>\n<p>Both script based and binary module vault extensions must implement the same four functions.<\/p>\n<p>The script function versions will write any errors to the error stream. The C# function versions will return an error as an out variable Exception object.<\/p>\n<h4>\n<a id=\"user-content-setsecret\" class=\"anchor\" href=\"#setsecret\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a><code>SetSecret<\/code>\n<\/h4>\n<p>This function stores a secret object to the vault. It takes three input parameters: <code>name<\/code>, <code>secret<\/code>, <code>parameters<\/code>. The <code>name<\/code> parameter is the name of the secret to store. The <code>secret<\/code> parameter is the secret object to be stored. The <code>parameters<\/code> parameter is an optional dictionary (Hashtable) of name\/value pairs for additional parameters. The function returns a boolean true on success and false otherwise.<\/p>\n<h4>\n<a id=\"user-content-getsecret\" class=\"anchor\" href=\"#getsecret\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a><code>GetSecret<\/code>\n<\/h4>\n<p>This function returns a single secret object from the vault. It takes two input parameters: <code>name<\/code>, <code>parameters<\/code>.\nThe <code>name<\/code> parameter is the name of the secret to store. The <code>parameters<\/code> parameter is an optional dictionary (Hashtable) of name\/value pairs for additional parameters. The function returns a single secret object or null if secret name does not exist.<\/p>\n<h4>\n<a id=\"user-content-removesecret\" class=\"anchor\" href=\"#removesecret\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a><code>RemoveSecret<\/code>\n<\/h4>\n<p>This function removes a single secret from the vault. It takes two input parameters: <code>name<\/code>, <code>parameters<\/code>. The <code>name<\/code> parameter is the name of the secret to store. The <code>parameters<\/code> parameter is an optional dictionary (Hashtable) of name\/value pairs for additional parameters. The function returns a boolean true on success and false otherwise.<\/p>\n<h4>\n<a id=\"user-content-getsecretinfo\" class=\"anchor\" href=\"#getsecretinfo\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a><code>GetSecretInfo<\/code>\n<\/h4>\n<p>Returns an array of string pairs representing each secret. The first string of the pair is the secret name. The second string is the secret object type name. This function never returns the actual secret object, but only information about the secret. This function takes two input parameters: <code>name<\/code>, <code>parameters<\/code>. The <code>name<\/code> parameter is the name of the secret to store. The <code>parameters<\/code> parameter is an optional dictionary (Hashtable) of name\/value pairs for additional parameters.<\/p>\n<p>The GetSecretInfo function returns different objects depending on whether it is implemented in script or C#.<\/p>\n<p>A script function will return a <code>pscustomobject<\/code> for each secret.<\/p>\n<div class=\"highlight highlight-source-powershell\">\n<pre>Write-Output ([pscustomobject] @{\r\n    Name = \"MyCredential\"                                    # Secret name\r\n    Value = \"PSCredential\"                                   # Secret object type name\r\n})<\/pre>\n<\/div>\n<p>A C# method will return a <code>KeyValuePair<\/code> object for each secret.<\/p>\n<div class=\"highlight highlight-source-cs\">\n<pre>secretInfo.Add(\r\n    new KeyValuePair&lt;string, string&gt;(\r\n        key: \"MyCredential\",                                \/\/ Secret name\r\n        value: SupportedTypes.PSCredential.ToString<\/span>()));    \/\/ Secret object type name<\/pre>\n<\/div>\n<p>For a consistent user experience, be sure and use the approved name for a secret object type.\nThere is a public enum in the SecretsManagementExtension abstract class called <code>SupportedTypes<\/code> and that can be used for secret type names. The supported secret type names are:<\/p>\n<ul>\n<li>\n<code>ByteArray<\/code> : Secret as an array of bytes<\/li>\n<li>\n<code>String<\/code> : Secret as a string object<\/li>\n<li>\n<code>SecureString<\/code> : Secret as a SecureString object<\/li>\n<li>\n<code>PSCredential<\/code> : Secret as a PowerShell credential (contains both user name and password secret)<\/li>\n<li>\n<code>Hashtable<\/code> : Secrets collected in a Hashtable<\/li>\n<\/ul>\n<h3>\n<a id=\"user-content-about-vault-extension-examples\" class=\"anchor\" href=\"#about-vault-extension-examples\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a>About vault extension examples<\/h3>\n<p>Two simple vault extension examples are provided at these links:<\/p>\n<p><a href=\"https:\/\/github.com\/PowerShell\/Modules\/tree\/master\/Samples\/VaultExtension\/Modules\/ScriptLocalVault\">ScriptLocalVault<\/a><\/p>\n<p><a href=\"https:\/\/github.com\/PowerShell\/Modules\/tree\/master\/Samples\/VaultExtension\/Modules\/CodeLocalVault\">CodeLocalVault<\/a><\/p>\n<p>These two examples are intended only as demonstrations of the basics of creating script and code based vault extensions. The vaults are not secure and should not be used to store sensitive information. Make sure you perform a full security review on any extension vaults you implement.<\/p>\n<p>These example extension vaults use PowerShell&#8217;s Export-CliXml and Import-CliXml cmdlets to serialize secret objects to file. The files are stored in the temporary directory of the current user context.<\/p>\n<h2>\n<a id=\"user-content-security\" class=\"anchor\" href=\"#security\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a>Security<\/h2>\n<p>The security of Secrets Management is dependent on the underlying storage mechanism of each vault. It is critical that each extension vault be carefully reviewed for security. Using known and trusted secret storage solutions, such as Windows Credential Manager, Gnome Keyring, or Azure KeyVault, is the best path to implementing a secure vault extension.<\/p>\n<h2>\n<a id=\"user-content-summary\" class=\"anchor\" href=\"#summary\" aria-hidden=\"true\"><span aria-hidden=\"true\" class=\"octicon octicon-link\"><\/span><\/a>Summary<\/h2>\n<p>The Secrets Management module is useful right out of the box for accessing secrets in PowerShell scripts. But the vault extension feature allows an even more powerful, cloud based way, to safely use secrets in script running on potentially any machine at any location.<\/p>\n<p>Try Secrets Management out on Windows, and please give us feedback about your experience. Whether managing secrets or authoring vault extensions, you can give feedback <a href=\"https:\/\/github.com\/powershell\/Modules\/issues\">here<\/a>.<\/p>\n<p>Paul Higinbotham\nSenior Software Engineer, PowerShell<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Secrets Management Module Vault Extensions A new PowerShell Secrets Management module has been published on PowerShell Gallery. It is currently in a pre-release state and still in active development. Even though the module is not complete, we have released it to gather early community feedback. Most of the functionality is implemented, but currently the module [&hellip;]<\/p>\n","protected":false},"author":7325,"featured_media":13641,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-18192","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell"],"acf":[],"blog_post_summary":"<p>Secrets Management Module Vault Extensions A new PowerShell Secrets Management module has been published on PowerShell Gallery. It is currently in a pre-release state and still in active development. Even though the module is not complete, we have released it to gather early community feedback. Most of the functionality is implemented, but currently the module [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/18192","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/users\/7325"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/comments?post=18192"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/18192\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media\/13641"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media?parent=18192"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/categories?post=18192"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/tags?post=18192"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}