Skip to content

Commit

Permalink
Get-AzKeyVaultSecret can -AsPlainText (#13730)
Browse files Browse the repository at this point in the history
Co-authored-by: Yeming Liu <yeliu@microsoft.com>
  • Loading branch information
isra-fel and Yeming Liu authored Dec 15, 2020
1 parent 83d920a commit 4f94e7b
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 43 deletions.
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" {
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);
}
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. " +
"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

0 comments on commit 4f94e7b

Please sign in to comment.