PowerShell / SecretManagement

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

Passswordless SecretManagement #146

Closed mahmoodn closed 3 years ago

mahmoodn commented 3 years ago

Hi Is there a way to use SecretManagement in order to not ask for the vault password every time I want to use that? For the line below

    Connect-VIServer "10.1.1.2" -User $(Get-Secret -Name User -AsPlainText) -Password $(Get-Secret -Name Password -AsPlainText)

I get this prompt

    Vault SecretStore requires a password.
    Enter password:
    ************

That prevents me to automatize the tasks. I see Unlock-SecretStore command however, it only works in the session. As you can see below, before using that, I have to enter the password and after executing that, it doesn't ask for the password.

    PS /home/mahmood> Get-Secret Host
    Vault SecretStore requires a password.
    Enter password:
    ************
    System.Security.SecureString
    PS /home/mahmood> Unlock-SecretStore

    cmdlet Unlock-SecretStore at command pipeline position 1
    Supply values for the following parameters:
    Password: ************
    PS /home/mahmood> Get-Secret Host
    System.Security.SecureString

I need a system-wide solution; something like ssh with rsa key instead of password. Any thought on that?

PaulHigin commented 3 years ago

It is the individual extension vault that enforces authentication for that vault. It sounds like you are using the Microsoft.PowerShell.SecretStore extension vault, and it's default configuration is to require a password and for interactive use. But you can change the configuration for non-interactive use (running unattended scripts).

See the SecretStore documents for more information.

You can also configure SecretStore extension vault to not require a password, and it is less secure but arguably as secure as using rsa keys, if the keys are store in user location. But not as secure if using SSH key management service.

Currently SecretStore can only be configured for individual user accounts (Scope: CurrentUser). We want to support Scope: AllUsers, for system-wide solutions but that is not yet implemented, and we are still thinking about how that would work.

We can consider some kind of rsa key authentication, feel free to create an issue for it.

mahmoodn commented 3 years ago

I ran the following commands prior to Connect-VIServer in order to setup a secure connection.

Install-Module Microsoft.PowerShell.SecretManagement, Microsoft.PowerShell.SecretStore
Register-SecretVault -Name SecretStore -ModuleName Microsoft.PowerShell.SecretStore -DefaultVault
Set-Secret -Name Host -Secret "10.1.1.2"
Set-Secret -Name User -Secret "ADMIN"
Set-Secret -Name Password -Secret "PLAIN_PASSWORD"

Now, I see that current (default) interaction is prompt.

PS /home/mahmood> Get-SecretStoreConfiguration
Vault Microsoft.PowerShell.SecretStore requires a password.
Enter password:
************

      Scope Authentication PasswordTimeout Interaction
      ----- -------------- --------------- -----------
CurrentUser       Password             900      Prompt

I tried to reconfigure that in order to set the interaction to "none". However, the following command doesn't work.

PS /home/mahmood> Set-SecretStoreConfiguration -Scope CurrentUser -Authentication Password -Interaction None -Confirm:$false
PS /home/mahmood> Get-SecretStoreConfiguration                                                                   Get-SecretStoreConfiguration: A valid password is required to access the Microsoft.PowerShell.SecretStore vault.
Use the Unlock-SecretStore cmdlet to provide the required password to access the store.
PS /home/mahmood> Set-SecretStoreConfiguration -Interaction None

Confirm
Are you sure you want to perform this action?
Performing the operation "Changes local store configuration" on target "SecretStore module local store".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): y
Set-SecretStoreConfiguration: A valid password is required to access the Microsoft.PowerShell.SecretStore vault.
Use the Unlock-SecretStore cmdlet to provide the required password to access the store.

May I know how to use the correct form of that command?

PaulHigin commented 3 years ago

It is a kind of chicken and egg problem. Set-SecretStoreConfiguration is useful when configuring a new image before it is used, and before SecretStore default configuration. But Set-SecretStoreConfiguration cannot be used to change an existing configured password (Set-SecretStorePassword is for that). In this case you can use the Reset-SecretStore command, but beware that any existing secrets are deleted.

For example, this would configure for non-interactive use and no password timeout during a PowerShell session. This means unattended script only has to set the password once for the PowerShell session in which the scripts run. You would want to terminate the session after the unattended script completes.

$password = <Obtain password somehow>
Reset-SecretStore -Scope CurrentUser -Authentication Password -Interaction None -Password $password -PasswordTimeout -1 -Force
$password = <Obtain password somehow, environment or CI readonly variable>
Unlock-SecretStore -Password $password
<Run script>
<Terminate process>
mahmoodn commented 3 years ago

OK. I was able to set the interaction to None. Please see below.

PS /home/mahmood> Unlock-SecretStore

cmdlet Unlock-SecretStore at command pipeline position 1
Supply values for the following parameters:
Password: ************
PS /home/mahmood> Set-SecretStoreConfiguration -Interaction None

Confirm
Are you sure you want to perform this action?
Performing the operation "Changes local store configuration" on target "SecretStore module local store".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): y
PS /home/mahmood> exit

However, when the script is executed, at the line Connect-VIServer "10.1.1.2" -User $(Get-Secret -Name User -AsPlainText) -Password $(Get-Secret -Name Password -AsPlainText), I get an error that the valid password is required. It then proceeds to ask remote machine user name and password and then it works.

Line |
   9 |  … er $vcenter_server -User $(Get-Secret -Name User -AsPlainText) -Passw …
     |                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | A valid password is required to access the Microsoft.PowerShell.SecretStore vault. Use the
     | Unlock-SecretStore cmdlet to provide the required password to access the store.

Get-Secret: /home/mahmood/get_ip_list.ps1:9
Line |
   9 |  … ser -AsPlainText) -Password $(Get-Secret -Name Password -AsPlainText)
     |                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | A valid password is required to access the Microsoft.PowerShell.SecretStore vault. Use the
     | Unlock-SecretStore cmdlet to provide the required password to access the store.

Specify Credential
Please specify server credential
User: ADMIN
Password for user ADMIN: ************

Here is the summary:

With both setting, I am not able to automatize the tasks. Any Thought for that?

PaulHigin commented 3 years ago

The prompt is coming from PowerShell because Set-SecretStoreConfiguration is a high impact operation. You can suppress the prompt:

Set-SetSecretStoreConfiguration -Interaction None -Confirm:$false

If SecretStore requires a password, then changing the configuration requires a password to allow the change:

$password = ...
Set-SecretStoreConfiguration -Interaction Prompt -Password $password -Confirm:$false

or

$password = ...
Unlock-SecretStore $password
Set-SecretStoreConfiguration -Interaction Prompt -Confirm:$false

Again, the best way is to ensure you have the configuration you want is to set it at the very beginning and leave it that way. SecretStore applies the default configuration only once at first use. If the default configuration is set beforehand, the best way to change it to what you want is to use Reset-SecretStore as shown above, realizing any existing secrets are removed.

mahmoodn commented 3 years ago

@paulcallen The problem is confusing... As you can see below, when I run Reset-SecretStore, it is mandatory to set a password. Again, setting the interaction to None doesn't work.

PS /home/mahmood> Reset-SecretStore
WARNING: !!This operation completely removes all SecretStore module secrets and resets configuration settings to new values!!

Reset SecretStore
Are you sure you want to erase all secrets in SecretStore and reset configuration settings to default?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "N"): y
Creating a new Microsoft.PowerShell.SecretStore vault. A password is required by the current store configuration.
Enter password:
***********
Enter password again for verification:
***********
PS /home/mahmood> Get-SecretStoreConfiguration
Vault Microsoft.PowerShell.SecretStore requires a password.
Enter password:
***********

      Scope Authentication PasswordTimeout Interaction
      ----- -------------- --------------- -----------
CurrentUser       Password             900      Prompt

PS /home/mahmood> $password = "Mahmood2021"
PS /home/mahmood> Set-SecretStoreConfiguration -Interaction None -Password $password -Confirm:$false
Set-SecretStoreConfiguration: Cannot bind parameter 'Password'. Cannot convert the "Mahmood2021" value of type "System.String" to type "System.Security.SecureString".
PS /home/mahmood> Unlock-SecretStore $password
Unlock-SecretStore: Cannot bind parameter 'Password'. Cannot convert the "Mahmood2021" value of type "System.String" to type "System.Security.SecureString".
PaulHigin commented 3 years ago

This is typical PowerShell. Use the -Force parameter to suppress prompting. You don't need to use Set-SecretStoreConfiguration because Reset-SecretStore also allows you do define the configuration. Also, for security you need to pass a SecureString type to Unlock-SecretStore.

Reset-SecretStore -Interaction None -Password $password -PasswordTimeout -1 -Force
Unlock-SecretStore -Password (ConvertTo-SecureString -String $password -AsPlainText -Force)
mahmoodn commented 3 years ago

I was able to run the following commands based on your suggestion.

PS /home/mahmood> $password = "Mahmood2021"
PS /home/mahmood> Reset-SecretStore -Interaction None -Password (ConvertTo-SecureString -String $password -AsPlainText -Force) -PasswordTimeout -1 -Force
WARNING: !!This operation completely removes all SecretStore module secrets and resets configuration settings to new values!!
PS /home/mahmood> Get-SecretStoreConfiguration

      Scope Authentication PasswordTimeout Interaction
      ----- -------------- --------------- -----------
CurrentUser       Password              -1        None

As you can see I wrote the password as a variable which is not a very method because I am going to give the scripts to frontend developers. Is there any way to store SecretStore password in an encrypted file and then read that file?

PaulHigin commented 3 years ago

On Windows platforms you can use the Export-CliXml and Import-CliXml cmdlets to write and read a SecureString to file. They use the Windows DPAPI to encrypt the SecureString contents based on user log in context. Otherwise, securely passing in passwords can be a problem. I know that some devops platforms provide a way to pass readonly variables into PowerShell scripts, that have some security. Environment variables are an option, but less secure.

mahmoodn commented 3 years ago

OK I finally managed to fix it. The steps I took are:

1- Storing vault password securely on disk. The username in Get-Credential is not important because we will later use the password only.

$Credential = Get-Credential
$Credential | Export-Clixml ./cred_vault.xml
Get-Content ./cred_vault.xml

2- Register a SecretStore

Register-SecretVault -Name SecretStore -ModuleName Microsoft.PowerShell.SecretStore -DefaultVault
Set-Secret -Name Host -Secret "10.1.1.2"
Set-Secret -Name User -Secret "ADMIN"
Set-Secret -Name Password -Secret "PASSWORD"

3- Import vault credential

$Credentials = Import-CliXml -Path ./cred_vault.xml
Unlock-SecretStore -Password (ConvertTo-SecureString -String $Credentials.Password -AsPlainText -Force)
Connect-VIServer "10.1.1.2" -User $(Get-Secret -Name User -AsPlainText) -Password $(Get-Secret -Name Password -AsPlainText)

The last command will be Connect-VIServer "10.1.1.2" -User ADMIN -Password PASSWORD.

Thanks for your help.