Skip to content

Commit

Permalink
[Key Vault] Add Secret URI Parameter to Key Vault Secret Cmdlets (#26222
Browse files Browse the repository at this point in the history
)

* Added secretUri support for all the 'secret' cmdlets

* Updated Changelog

* Added ResourceId aliases for backwards compatibility

* Added Tests, Secret Data Class

* Updated Help Docs

* Use Typed varaibles

* Add example usages in help docs

* Error Suppression

* Change Data Class Accessibility

* Move Split Logic to Constructor

* Added uri format to help docs
  • Loading branch information
notyashhh authored Nov 11, 2024
1 parent 168239a commit 04ad4f4
Show file tree
Hide file tree
Showing 19 changed files with 933 additions and 213 deletions.
65 changes: 65 additions & 0 deletions src/KeyVault/KeyVault.Test/PesterTests/KeyVaultSecretUri.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
BeforeAll {
. "$PSScriptRoot\..\Scripts\Common.ps1" # Common setup script

# Load the Az.KeyVault module from the debug artifacts
$psd1Path = Join-Path $PSScriptRoot "../../../../artifacts/Debug/" -Resolve
$keyVaultPsd1 = Join-Path $psd1Path "./Az.KeyVault/Az.KeyVault.psd1" -Resolve
Import-Module $keyVaultPsd1 -Force

# Define key variables
$resourceGroupName = "yash-rg$(Get-Random)" # Use existing resource group
$location = "eastus"
$vaultName = "yashkv$(Get-Random)" # Generate unique Key Vault name
$secretName = "TestSecret"
$secretValue = ConvertTo-SecureString "InitialSecretValue" -AsPlainText -Force

# Set up resource group
New-AzResourceGroup -Name $resourceGroupName -Location $location

# Create a Key Vault in the existing resource group
New-AzKeyVault -ResourceGroupName $resourceGroupName -VaultName $vaultName -Location $location

# Create a new secret in the Key Vault
Set-AzKeyVaultSecret -VaultName $vaultName -Name $secretName -SecretValue $secretValue
}


Describe 'Azure KeyVault Secret URI Live Tests' {

It 'should retrieve the secret using the Secret URI with Get-AzKeyVaultSecret' {
# Construct the secret URI
$secretUri = "https://$vaultName.vault.azure.net/secrets/$secretName"

# Retrieve the secret using its URI
$retrievedSecret = Get-AzKeyVaultSecret -Id $secretUri -AsPlainText

# Validate that the secret is retrieved successfully
$retrievedSecret | Should -Be "InitialSecretValue"
}

It 'should update the secret value using Set-AzKeyVaultSecret' {
# Update the secret value
$newSecretValue = ConvertTo-SecureString "UpdatedSecretValue" -AsPlainText -Force
Set-AzKeyVaultSecret -VaultName $vaultName -Name $secretName -SecretValue $newSecretValue

# Retrieve the updated secret
$retrievedSecret = Get-AzKeyVaultSecret -VaultName $vaultName -Name $secretName -AsPlainText

# Validate the secret has been updated
$retrievedSecret | Should -Be "UpdatedSecretValue"
}

It 'should remove the secret using Remove-AzKeyVaultSecret' {
# Remove the secret
Remove-AzKeyVaultSecret -VaultName $vaultName -Name $secretName -Force

# Ensure the secret is deleted
Get-AzKeyVaultSecret -VaultName $vaultName -Name $secretName | Should -BeNullOrEmpty
}
}

AfterAll {
# Clean up Key Vault & Resource Group)
Remove-AzKeyVault -VaultName $vaultName -ResourceGroupName $resourceGroupName -Force
Remove-AzResourceGroup -Name $resourceGroupName -Force
}
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 Secret URI Parameter to Key Vault Secret Cmdlets [#23053]

## Version 6.2.0
* Fixed a parameter validation issue in Set-AzureKeyVaultCertificatePolicy. [#25649]
Expand Down
21 changes: 21 additions & 0 deletions src/KeyVault/KeyVault/Commands/Secret/BackupAzureKeyVaultSecret.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using System.Management.Automation;
using Microsoft.Azure.Commands.Common.Authentication;
using Microsoft.Azure.Commands.KeyVault.Models;
using Microsoft.Azure.Commands.KeyVault.Models.Secret;
using Microsoft.Azure.Commands.KeyVault.Properties;
using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters;

Expand All @@ -35,6 +36,7 @@ public class BackupAzureKeyVaultSecret : KeyVaultCmdletBase

private const string BySecretNameParameterSet = "BySecretName";
private const string BySecretObjectParameterSet = "BySecret";
private const string BySecretUriParameterSet = "BySecretUri";

#endregion

Expand Down Expand Up @@ -62,6 +64,17 @@ public class BackupAzureKeyVaultSecret : KeyVaultCmdletBase
[Alias( Constants.SecretName )]
public string Name { get; set; }

/// <summary>
/// KeyVault Secret ID (uri of the secret)
/// </summary>
[Parameter(Mandatory = true,
Position = 0,
ParameterSetName = BySecretUriParameterSet,
HelpMessage = "The URI of the KeyVault Secret.")]
[Alias("SecretId")]
[ValidateNotNullOrEmpty]
public string Id { get; set; }

/// <summary>
/// The secret object to be backed up.
/// </summary>
Expand Down Expand Up @@ -105,6 +118,14 @@ public override void ExecuteCmdlet( )
VaultName = InputObject.VaultName;
}

if (ParameterSetName == BySecretUriParameterSet)
{
SecretUriComponents splitUri = new SecretUriComponents(Id);

VaultName = splitUri.VaultName;
Name = splitUri.SecretName;
}

if ( ShouldProcess( Name, Properties.Resources.BackupSecret ) )
{
if ( string.IsNullOrEmpty( OutputFile ) )
Expand Down
70 changes: 51 additions & 19 deletions src/KeyVault/KeyVault/Commands/Secret/GetAzureKeyVaultSecret.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
// ----------------------------------------------------------------------------------

using Microsoft.Azure.Commands.KeyVault.Models;
using Microsoft.Azure.Commands.KeyVault.Models.Secret;
using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters;
using Microsoft.Azure.Management.Internal.Resources.Utilities.Models;
using System;
using System.Management.Automation;
using System.Runtime.InteropServices;
using System.Security;
Expand All @@ -30,14 +32,15 @@ public class GetAzureKeyVaultSecret : KeyVaultCmdletBase
private const string ByVaultNameParameterSet = "ByVaultName";
private const string BySecretNameParameterSet = "BySecretName";
private const string BySecretVersionsParameterSet = "BySecretVersions";
private const string BySecretUriParameterSet = "BySecretUri";

private const string InputObjectByVaultNameParameterSet = "ByInputObjectVaultName";
private const string InputObjectBySecretNameParameterSet = "ByInputObjectSecretName";
private const string InputObjectBySecretVersionsParameterSet = "ByInputObjectSecretVersions";

private const string ResourceIdByVaultNameParameterSet = "ByResourceIdVaultName";
private const string ResourceIdBySecretNameParameterSet = "ByResourceIdSecretName";
private const string ResourceIdBySecretVersionsParameterSet = "ByResourceIdSecretVersions";
private const string ParentResourceIdByVaultNameParameterSet = "ByParentResourceIdVaultName";
private const string ParentResourceIdBySecretNameParameterSet = "ByParentResourceIdSecretName";
private const string ParentResourceIdBySecretVersionsParameterSet = "ByParentResourceIdSecretVersions";

#endregion

Expand Down Expand Up @@ -84,25 +87,38 @@ public class GetAzureKeyVaultSecret : KeyVaultCmdletBase
public PSKeyVault InputObject { get; set; }

/// <summary>
/// KeyVault Resource ID
/// KeyVault Secret ID
/// </summary>
[Parameter(Mandatory = true,
Position = 0,
ParameterSetName = BySecretUriParameterSet,
HelpMessage = "The URI of the KeyVault Secret.")]
[Alias("SecretId")]
[ValidateNotNullOrEmpty]
public string Id { get; set; }


/// <summary>
/// KeyVault Parent Resource ID
/// </summary>
[Parameter(Mandatory = true,
Position = 0,
ValueFromPipelineByPropertyName = true,
ParameterSetName = ResourceIdByVaultNameParameterSet,
ParameterSetName = ParentResourceIdByVaultNameParameterSet,
HelpMessage = "KeyVault Resource Id.")]
[Parameter(Mandatory = true,
Position = 0,
ValueFromPipelineByPropertyName = true,
ParameterSetName = ResourceIdBySecretNameParameterSet,
ParameterSetName = ParentResourceIdBySecretNameParameterSet,
HelpMessage = "KeyVault Resource Id.")]
[Parameter(Mandatory = true,
Position = 0,
ValueFromPipelineByPropertyName = true,
ParameterSetName = ResourceIdBySecretVersionsParameterSet,
ParameterSetName = ParentResourceIdBySecretVersionsParameterSet,
HelpMessage = "KeyVault Resource Id.")]
[Alias("ResourceId")]
[ValidateNotNullOrEmpty]
public string ResourceId { get; set; }
public string ParentResourceId { get; set; }

/// <summary>
/// Secret name
Expand All @@ -117,7 +133,7 @@ public class GetAzureKeyVaultSecret : KeyVaultCmdletBase
HelpMessage = "Secret name. Cmdlet constructs the FQDN of a secret from vault name, currently selected environment and secret name.")]
[Parameter(Mandatory = false,
Position = 1,
ParameterSetName = ResourceIdByVaultNameParameterSet,
ParameterSetName = ParentResourceIdByVaultNameParameterSet,
HelpMessage = "Secret name. Cmdlet constructs the FQDN of a secret from vault name, currently selected environment and secret name.")]
[Parameter(Mandatory = true,
Position = 1,
Expand All @@ -129,7 +145,7 @@ public class GetAzureKeyVaultSecret : KeyVaultCmdletBase
HelpMessage = "Secret name. Cmdlet constructs the FQDN of a secret from vault name, currently selected environment and secret name.")]
[Parameter(Mandatory = true,
Position = 1,
ParameterSetName = ResourceIdBySecretNameParameterSet,
ParameterSetName = ParentResourceIdBySecretNameParameterSet,
HelpMessage = "Secret name. Cmdlet constructs the FQDN of a secret from vault name, currently selected environment and secret name.")]
[Parameter(Mandatory = true,
Position = 1,
Expand All @@ -141,7 +157,7 @@ public class GetAzureKeyVaultSecret : KeyVaultCmdletBase
HelpMessage = "Secret name. Cmdlet constructs the FQDN of a secret from vault name, currently selected environment and secret name.")]
[Parameter(Mandatory = true,
Position = 1,
ParameterSetName = ResourceIdBySecretVersionsParameterSet,
ParameterSetName = ParentResourceIdBySecretVersionsParameterSet,
HelpMessage = "Secret name. Cmdlet constructs the FQDN of a secret from vault name, currently selected environment and secret name.")]
[ValidateNotNullOrEmpty]
[Alias(Constants.SecretName)]
Expand All @@ -160,7 +176,7 @@ public class GetAzureKeyVaultSecret : KeyVaultCmdletBase
Position = 2,
HelpMessage = "Secret version. Cmdlet constructs the FQDN of a secret from vault name, currently selected environment, secret name and secret version.")]
[Parameter(Mandatory = true,
ParameterSetName = ResourceIdBySecretNameParameterSet,
ParameterSetName = ParentResourceIdBySecretNameParameterSet,
Position = 2,
HelpMessage = "Secret version. Cmdlet constructs the FQDN of a secret from vault name, currently selected environment, secret name and secret version.")]
[Alias("SecretVersion")]
Expand All @@ -173,7 +189,7 @@ public class GetAzureKeyVaultSecret : KeyVaultCmdletBase
ParameterSetName = InputObjectBySecretVersionsParameterSet,
HelpMessage = "Specifies whether to include the versions of the secret in the output.")]
[Parameter(Mandatory = true,
ParameterSetName = ResourceIdBySecretVersionsParameterSet,
ParameterSetName = ParentResourceIdBySecretVersionsParameterSet,
HelpMessage = "Specifies whether to include the versions of the secret in the output.")]
public SwitchParameter IncludeVersions { get; set; }

Expand All @@ -184,33 +200,49 @@ public class GetAzureKeyVaultSecret : KeyVaultCmdletBase
ParameterSetName = InputObjectByVaultNameParameterSet,
HelpMessage = "Specifies whether to show the previously deleted secrets in the output.")]
[Parameter(Mandatory = false,
ParameterSetName = ResourceIdByVaultNameParameterSet,
ParameterSetName = ParentResourceIdByVaultNameParameterSet,
HelpMessage = "Specifies whether to show the previously deleted secrets in the output.")]
[Parameter(Mandatory = false,
ParameterSetName = BySecretUriParameterSet,
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 = BySecretUriParameterSet)]
[Parameter(Mandatory = false, ParameterSetName = InputObjectBySecretNameParameterSet)]
[Parameter(Mandatory = false, ParameterSetName = InputObjectByVaultNameParameterSet)]
[Parameter(Mandatory = false, ParameterSetName = ResourceIdBySecretNameParameterSet)]
[Parameter(Mandatory = false, ParameterSetName = ResourceIdByVaultNameParameterSet)]
[Parameter(Mandatory = false, ParameterSetName = ParentResourceIdBySecretNameParameterSet)]
[Parameter(Mandatory = false, ParameterSetName = ParentResourceIdByVaultNameParameterSet)]
public SwitchParameter AsPlainText { get; set; }
#endregion

public override void ExecuteCmdlet()
{
PSKeyVaultSecret secret;

// Check input object
if (InputObject != null)
{
VaultName = InputObject.VaultName.ToString();
}
else if (!string.IsNullOrEmpty(ResourceId))
else if (!string.IsNullOrEmpty(ParentResourceId))
{
var parsedParentResourceId = new ResourceIdentifier(ParentResourceId);
VaultName = parsedParentResourceId.ResourceName;
}

// Handle SecretId (uri) parameter
if (ParameterSetName == BySecretUriParameterSet)
{
var parsedResourceId = new ResourceIdentifier(ResourceId);
VaultName = parsedResourceId.ResourceName;
SecretUriComponents splitUri = new SecretUriComponents(Id);

VaultName = splitUri.VaultName;
Name = splitUri.SecretName;
Version = splitUri.SecretVersion;
}

// Check Version/s of Sceret to get.
if (!string.IsNullOrEmpty(Version))
{
secret = DataServiceClient.GetSecret(VaultName, Name, Version);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// ----------------------------------------------------------------------------------

using Microsoft.Azure.Commands.KeyVault.Models;
using Microsoft.Azure.Commands.KeyVault.Models.Secret;
using Microsoft.Azure.Commands.KeyVault.Properties;
using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters;
using Microsoft.WindowsAzure.Commands.Common.CustomAttributes;
Expand All @@ -30,6 +31,7 @@ public class RemoveAzureKeyVaultSecret : KeyVaultCmdletBase

private const string ByVaultNameParameterSet = "ByVaultName";
private const string ByInputObjectParameterSet = "ByInputObject";
private const string BySecretUriParameterSet = "BySecretUri";

#endregion

Expand Down Expand Up @@ -57,6 +59,17 @@ public class RemoveAzureKeyVaultSecret : KeyVaultCmdletBase
[Alias(Constants.SecretName)]
public string Name { get; set; }

/// <summary>
/// KeyVault Secret ID (uri of the secret)
/// </summary>
[Parameter(Mandatory = true,
Position = 0,
ParameterSetName = BySecretUriParameterSet,
HelpMessage = "The URI of the KeyVault Secret.")]
[Alias("SecretId")]
[ValidateNotNullOrEmpty]
public string Id { get; set; }

/// <summary>
/// Secret Object
/// </summary>
Expand Down Expand Up @@ -96,7 +109,15 @@ public override void ExecuteCmdlet()
Name = InputObject.Name;
}

if(InRemovedState.IsPresent)
if (ParameterSetName == BySecretUriParameterSet)
{
SecretUriComponents splitUri = new SecretUriComponents(Id);

VaultName = splitUri.VaultName;
Name = splitUri.SecretName;
}

if (InRemovedState.IsPresent)
{
ConfirmAction(
Force.IsPresent,
Expand Down
Loading

0 comments on commit 04ad4f4

Please sign in to comment.