Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get-AzKeyVaultSecret can -AsPlainText #13730

Merged
merged 1 commit into from
Dec 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/KeyVault/KeyVault.Test/PesterTests/Secret.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
$vaultName = 'yemingkv23'


. ../Scripts/Common.ps1
$secretName = Get-SecretName
$secretText = 'dummy text'
$secretTextV2 = 'dummy text 2'
Set-AzKeyVaultSecret -VaultName $vaultName -Name $secretName -SecretValue (ConvertTo-SecureString $secretText -AsPlainText -Force)
Set-AzKeyVaultSecret -VaultName $vaultName -Name $secretName -SecretValue (ConvertTo-SecureString $secretTextV2 -AsPlainText -Force)

Describe "Get secret" {
It "should write secrets in plain text if -AsPlainText" {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a data-plane API, so I wrote a liveonly test here

Get-AzKeyVaultSecret -VaultName $vaultName -Name $secretName -AsPlainText | Should -BeExactly $secretTextV2

$versions = Get-AzKeyVaultSecret -VaultName $vaultName -Name $secretName -IncludeVersions
Get-AzKeyVaultSecret -VaultName $vaultName -Name $secretName -Version $versions[0].Version -AsPlainText | Should -BeExactly $secretTextV2
Get-AzKeyVaultSecret -VaultName $vaultName -Name $secretName -Version $versions[1].Version -AsPlainText | Should -BeExactly $secretText
}
}
1 change: 1 addition & 0 deletions src/KeyVault/KeyVault/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- Additional information about change #1
-->
## Upcoming Release
* Added a new parameter `-AsPlainText` to `Get-AzKeyVaultSecret` to directly return the secret in plain text
* Supported selective restore a key from a managed HSM full backup [#13526]
* Added missing return objects of `Get-Secret` in SecretManagement module

Expand Down
44 changes: 39 additions & 5 deletions src/KeyVault/KeyVault/Commands/GetAzureKeyVaultSecret.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Runtime.InteropServices;
using System.Security;

namespace Microsoft.Azure.Commands.KeyVault
{
[Cmdlet("Get", ResourceManager.Common.AzureRMConstants.AzurePrefix + "KeyVaultSecret", DefaultParameterSetName = ByVaultNameParameterSet)]
[OutputType(typeof(PSKeyVaultSecretIdentityItem), typeof(PSKeyVaultSecret), typeof(PSDeletedKeyVaultSecretIdentityItem), typeof(PSDeletedKeyVaultSecret))]
[OutputType(typeof(PSKeyVaultSecretIdentityItem), typeof(PSKeyVaultSecret), typeof(PSDeletedKeyVaultSecretIdentityItem), typeof(PSDeletedKeyVaultSecret), typeof(string))]
public class GetAzureKeyVaultSecret : KeyVaultCmdletBase
{
#region Parameter Set Names
Expand Down Expand Up @@ -190,6 +192,13 @@ public class GetAzureKeyVaultSecret : KeyVaultCmdletBase
HelpMessage = "Specifies whether to show the previously deleted secrets in the output.")]
public SwitchParameter InRemovedState { get; set; }

[Parameter(Mandatory = false, ParameterSetName = BySecretNameParameterSet, HelpMessage = "When set, the cmdlet will convert secret in secure string to the decrypted plaintext string as output.")]
[Parameter(Mandatory = false, ParameterSetName = ByVaultNameParameterSet)]
[Parameter(Mandatory = false, ParameterSetName = InputObjectBySecretNameParameterSet)]
[Parameter(Mandatory = false, ParameterSetName = InputObjectByVaultNameParameterSet)]
[Parameter(Mandatory = false, ParameterSetName = ResourceIdBySecretNameParameterSet)]
[Parameter(Mandatory = false, ParameterSetName = ResourceIdByVaultNameParameterSet)]
public SwitchParameter AsPlainText { get; set; }
#endregion

public override void ExecuteCmdlet()
Expand All @@ -209,7 +218,7 @@ public override void ExecuteCmdlet()
if (!string.IsNullOrEmpty(Version))
{
secret = DataServiceClient.GetSecret(VaultName, Name, Version);
WriteObject(secret);
WriteSecret(secret);
wyunchi-ms marked this conversation as resolved.
Show resolved Hide resolved
}
else if (IncludeVersions)
{
Expand Down Expand Up @@ -241,7 +250,7 @@ public override void ExecuteCmdlet()
else
{
secret = DataServiceClient.GetSecret(VaultName, Name, string.Empty);
WriteObject(secret);
WriteSecret(secret);
}
}
}
Expand All @@ -259,7 +268,7 @@ private void GetAndWriteSecrets(string vaultName, string name) =>
{
VaultName = vaultName,
NextLink = null
},
},
(options) => KVSubResourceWildcardFilter(name, DataServiceClient.GetSecrets(options)));

private void GetAndWriteSecretVersions(string vaultName, string name, string currentSecretVersion) =>
Expand All @@ -268,7 +277,32 @@ private void GetAndWriteSecretVersions(string vaultName, string name, string cur
VaultName = vaultName,
Name = name,
NextLink = null
},
},
(options) => DataServiceClient.GetSecretVersions(options).Where(s => s.Version != currentSecretVersion));

private void WriteSecret(PSKeyVaultSecret secret)
{
if (AsPlainText)
{
WriteObject(ConvertFromSecureString(secret.SecretValue));
}
else
{
WriteObject(secret);
}
}

private string ConvertFromSecureString(SecureString secretValue)
{
var ssPtr = Marshal.SecureStringToBSTR(secretValue);
try
{
return Marshal.PtrToStringBSTR(ssPtr);
}
finally
{
Marshal.ZeroFreeBSTR(ssPtr);
}
}
}
}
3 changes: 0 additions & 3 deletions src/KeyVault/KeyVault/Commands/RemoveAzureKeyVaultSecret.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@

namespace Microsoft.Azure.Commands.KeyVault
{
[GenericBreakingChange("If you have soft-delete protection enabled on this key vault, this secret will be moved to the soft deleted state. " +
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have been removed in last major release

"You will not be able to create a secret with the same name within this key vault until the secret has been purged from the soft-deleted state. Please see the following documentation for additional guidance. " +
"https://docs.microsoft.com/en-us/azure/key-vault/general/soft-delete-overview")]
[Cmdlet("Remove", ResourceManager.Common.AzureRMConstants.AzurePrefix + "KeyVaultSecret",SupportsShouldProcess = true,DefaultParameterSetName = ByVaultNameParameterSet)]
[OutputType(typeof(PSDeletedKeyVaultSecret))]
public class RemoveAzureKeyVaultSecret : KeyVaultCmdletBase
Expand Down
2 changes: 1 addition & 1 deletion src/KeyVault/KeyVault/help/Backup-AzKeyVault.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Aliases:
Required: True
Position: Named
Default value: None
Accept pipeline input: False
Accept pipeline input: True (ByValue)
Accept wildcard characters: False
```

Expand Down
11 changes: 2 additions & 9 deletions src/KeyVault/KeyVault/help/Get-AzKeyVaultCertificate.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,8 @@ This command gets the certificate named TestCert01 from the key vault named Cont

```powershell
$cert = Get-AzKeyVaultCertificate -VaultName "ContosoKV01" -Name "TestCert01"
$secret = Get-AzKeyVaultSecret -VaultName $vaultName -Name $cert.Name
$secretValueText = '';
$ssPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secret.SecretValue)
try {
$secretValueText = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ssPtr)
} finally {
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ssPtr)
}
$secretByte = [Convert]::FromBase64String($secretValueText)
$secret = Get-AzKeyVaultSecret -VaultName $vaultName -Name $cert.Name -AsPlainText
$secretByte = [Convert]::FromBase64String($secret)
$x509Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($secretByte, "", "Exportable,PersistKeySet")
$type = [System.Security.Cryptography.X509Certificates.X509ContentType]::Pfx
$pfxFileByte = $x509Cert.Export($type, $password)
Expand Down
48 changes: 23 additions & 25 deletions src/KeyVault/KeyVault/help/Get-AzKeyVaultSecret.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ Gets the secrets in a key vault.

### ByVaultName (Default)
```
Get-AzKeyVaultSecret [-VaultName] <String> [[-Name] <String>] [-InRemovedState]
Get-AzKeyVaultSecret [-VaultName] <String> [[-Name] <String>] [-InRemovedState] [-AsPlainText]
[-DefaultProfile <IAzureContextContainer>] [<CommonParameters>]
```

### BySecretName
```
Get-AzKeyVaultSecret [-VaultName] <String> [-Name] <String> [-Version] <String>
Get-AzKeyVaultSecret [-VaultName] <String> [-Name] <String> [-Version] <String> [-AsPlainText]
[-DefaultProfile <IAzureContextContainer>] [<CommonParameters>]
```

Expand All @@ -33,13 +33,13 @@ Get-AzKeyVaultSecret [-VaultName] <String> [-Name] <String> [-IncludeVersions]

### ByInputObjectVaultName
```
Get-AzKeyVaultSecret [-InputObject] <PSKeyVault> [[-Name] <String>] [-InRemovedState]
Get-AzKeyVaultSecret [-InputObject] <PSKeyVault> [[-Name] <String>] [-InRemovedState] [-AsPlainText]
[-DefaultProfile <IAzureContextContainer>] [<CommonParameters>]
```

### ByInputObjectSecretName
```
Get-AzKeyVaultSecret [-InputObject] <PSKeyVault> [-Name] <String> [-Version] <String>
Get-AzKeyVaultSecret [-InputObject] <PSKeyVault> [-Name] <String> [-Version] <String> [-AsPlainText]
[-DefaultProfile <IAzureContextContainer>] [<CommonParameters>]
```

Expand All @@ -51,13 +51,13 @@ Get-AzKeyVaultSecret [-InputObject] <PSKeyVault> [-Name] <String> [-IncludeVersi

### ByResourceIdVaultName
```
Get-AzKeyVaultSecret [-ResourceId] <String> [[-Name] <String>] [-InRemovedState]
Get-AzKeyVaultSecret [-ResourceId] <String> [[-Name] <String>] [-InRemovedState] [-AsPlainText]
[-DefaultProfile <IAzureContextContainer>] [<CommonParameters>]
```

### ByResourceIdSecretName
```
Get-AzKeyVaultSecret [-ResourceId] <String> [-Name] <String> [-Version] <String>
Get-AzKeyVaultSecret [-ResourceId] <String> [-Name] <String> [-Version] <String> [-AsPlainText]
[-DefaultProfile <IAzureContextContainer>] [<CommonParameters>]
```

Expand Down Expand Up @@ -175,27 +175,10 @@ This command gets a specific version of the secret named secret1 in the key vaul

### Example 5: Get the plain text value of the current version of a specific secret
```powershell
PS C:\> $secret = Get-AzKeyVaultSecret -VaultName 'Contoso' -Name 'ITSecret'

# Method 1: requires PowerShell >= 7.0
PS C:\> $secretInPlainText = $secret.SecretValue | ConvertFrom-SecureString -AsPlainText

# Method 2: works on older PowerShell versions
PS C:\> $secretValueText = '';
PS C:\> $ssPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secret.SecretValue)
PS C:\> try {
$secretInPlainText = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ssPtr)
} finally {
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ssPtr)
}

# Method 3: works in ConstrainedLanguage mode
$secretInPlainText = [pscredential]::new("DoesntMatter", $secret.SecretValue).GetNetworkCredential().Password
PS C:\> $secretText = Get-AzKeyVaultSecret -VaultName 'Contoso' -Name 'ITSecret' -AsPlainText
```

These commands get the current version of a secret named ITSecret, and then displays the plain text value of that secret.

(Note: use method 3 if you are working in PowerShell [ConstrainedLanguage mode](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_language_modes?view=powershell-7.1#constrained-language-constrained-language), for example, on secure/privileged access workstations.)
The cmdlet returns the secret as a string when `-AsPlainText` is applied.

### Example 6: Get all the secrets that have been deleted but not purged for this key vault.
```powershell
Expand Down Expand Up @@ -285,6 +268,21 @@ This command gets the current versions of all secrets in the key vault named Con

## PARAMETERS

### -AsPlainText
When set, the cmdlet will convert secret in secure string to the decrypted plaintext string as output.

```yaml
Type: System.Management.Automation.SwitchParameter
Parameter Sets: ByVaultName, BySecretName, ByInputObjectVaultName, ByInputObjectSecretName, ByResourceIdVaultName, ByResourceIdSecretName
Aliases:

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -DefaultProfile
The credentials, account, tenant, and subscription used for communication with azure

Expand Down