From e29014de4fd5bc0232064a4c0efdc51fd7209385 Mon Sep 17 00:00:00 2001 From: Dragos Avadanei Date: Wed, 12 Apr 2017 12:34:05 -0700 Subject: [PATCH 1/4] adding support for backing up and restoring of KeyVault secrets revising KeyVault backup/restore cmdlets: adding support for pipelining allowing overwriting of dest file using session data store for file operations addressing CR feedback: using nameof, discarding redundant parameter set clauses more CR feedback addressing CR feedback: using nameof, discarding redundant parameter set clauses fix build break following merge CR feedback and fixing build breaks from merging changes adding support for backing up and restoring of KeyVault secrets addressing CR feedback: using nameof, discarding redundant parameter set clauses addressing CR feedback: using nameof, discarding redundant parameter set clauses --- .../KeyVault/AzureRM.KeyVault.psd1 | 4 +- .../Resource.Designer.cs | 2 - .../ControlPlane/KeyVaultManagementTests.ps1 | 4 +- .../Scripts/RunKeyVaultTests.ps1 | 21 +- .../Scripts/VaultKeyTests.ps1 | 36 +++- .../Scripts/VaultSecretTests.ps1 | 103 +++++++++ .../Commands.KeyVault.csproj | 2 + .../Commands/BackupAzureKeyVaultKey.cs | 113 ++++++---- .../Commands/BackupAzureKeyVaultSecret.cs | 141 ++++++++++++ .../Commands/RestoreAzureKeyVaultSecret.cs | 72 +++++++ .../Models/IKeyVaultDataServiceClient.cs | 4 + .../Models/KeyVaultCmdletBase.cs | 15 +- .../Models/KeyVaultDataServiceClient.cs | 204 +++++++++++------- .../Properties/Resources.Designer.cs | 56 ++++- .../Properties/Resources.resx | 18 ++ .../help/AzureRM.KeyVault.md | 6 + .../help/Backup-AzureKeyVaultKey.md | 36 +++- .../help/Backup-AzureKeyVaultSecret.md | 193 +++++++++++++++++ .../help/Restore-AzureKeyVaultSecret.md | 120 +++++++++++ 19 files changed, 1008 insertions(+), 142 deletions(-) create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultSecret.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Commands/RestoreAzureKeyVaultSecret.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/help/Backup-AzureKeyVaultSecret.md create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/help/Restore-AzureKeyVaultSecret.md diff --git a/src/ResourceManager/KeyVault/AzureRM.KeyVault.psd1 b/src/ResourceManager/KeyVault/AzureRM.KeyVault.psd1 index 727e34e49a08..3005c3d26c95 100644 --- a/src/ResourceManager/KeyVault/AzureRM.KeyVault.psd1 +++ b/src/ResourceManager/KeyVault/AzureRM.KeyVault.psd1 @@ -100,7 +100,9 @@ CmdletsToExport = 'Add-AzureKeyVaultCertificate', 'Set-AzureKeyVaultSecretAttribute', 'Get-AzureKeyVaultCertificatePolicy', 'New-AzureKeyVaultCertificateAdministratorDetails', - 'New-AzureKeyVaultCertificateOrganizationDetails' + 'New-AzureKeyVaultCertificateOrganizationDetails', + 'Backup-AzureKeyVaultSecret', + 'Restore-AzureKeyVaultSecret' # Variables to export from this module # VariablesToExport = @() diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resource.Designer.cs b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resource.Designer.cs index e6ee07174dcb..ce99094ff6a5 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resource.Designer.cs +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resource.Designer.cs @@ -10,8 +10,6 @@ namespace Microsoft.Azure.Commands.KeyVault.Test { using System; - - /// /// A strongly-typed resource class, for looking up localized strings, etc. /// diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/ControlPlane/KeyVaultManagementTests.ps1 b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/ControlPlane/KeyVaultManagementTests.ps1 index e6936f79f75c..dae91c927319 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/ControlPlane/KeyVaultManagementTests.ps1 +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/ControlPlane/KeyVaultManagementTests.ps1 @@ -408,7 +408,7 @@ function Test-SetRemoveAccessPolicyByUPN Param($existingVaultName, $rgName, $upn) $PermToKeys = @("encrypt", "decrypt", "unwrapKey", "wrapKey", "verify", "sign", "get", "list", "update", "create", "import", "delete", "backup", "restore") - $PermToSecrets = @("get", "list", "set", "delete") + $PermToSecrets = @("get", "list", "set", "delete", "backup", "restore") $PermToCertificates = @("get", "list", "create", "delete") $vault = Set-AzureRmKeyVaultAccessPolicy -VaultName $existingVaultName -ResourceGroupName $rgName -UserPrincipalName $upn -PermissionsToKeys $PermToKeys -PermissionsToSecrets $PermToSecrets -PermissionsToCertificates $PermToCertificates -PassThru @@ -566,7 +566,7 @@ function Test-ModifyAccessPolicy # Add some perms now $PermToKeys = @("encrypt", "decrypt", "unwrapKey", "wrapKey", "verify", "sign", "get", "list", "update", "create", "import", "delete", "backup", "restore") - $PermToSecrets = @("get", "list", "set", "delete") + $PermToSecrets = @("get", "list", "set", "delete", "backup", "restore") $PermToCertificates = @("list", "delete") $vault = Set-AzureRmKeyVaultAccessPolicy -VaultName $existingVaultName -ResourceGroupName $rgName -ObjectId $objId -PermissionsToKeys $PermToKeys -PermissionsToSecrets $PermToSecrets -PermissionsToCertificates $PermToCertificates -PassThru diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/RunKeyVaultTests.ps1 b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/RunKeyVaultTests.ps1 index ab8ac09b3931..e7f145342620 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/RunKeyVaultTests.ps1 +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/RunKeyVaultTests.ps1 @@ -323,11 +323,12 @@ function Run-AllDataPlaneTests Run-TestProtected { Run-KeyTest {Test_RemoveKeyInNoPermissionVault} "Test_RemoveKeyInNoPermissionVault" } "Test_RemoveKeyInNoPermissionVault" # Backup-AzureKeyVaultKey and Restore-AzureKeyVaultKey tests. - Run-TestProtected { Run-KeyTest {Test_BackupRestoreKey} "Test_BackupRestoreKey" } "Test_BackupRestoreKey" - Run-TestProtected { Run-KeyTest {Test_BackupNonExisitingKey} "Test_BackupNonExisitingKey" } "Test_BackupNonExisitingKey" - Run-TestProtected { Run-KeyTest {Test_BackupToANamedFile} "Test_BackupToANamedFile" } "Test_BackupToANamedFile" - Run-TestProtected { Run-KeyTest {Test_BackupToExistingFile} "Test_BackupToExistingFile" } "Test_BackupToExistingFile" - Run-TestProtected { Run-KeyTest {Test_RestoreFromNonExistingFile} "Test_RestoreFromNonExistingFile" } "Test_RestoreFromNonExistingFile" + Run-TestProtected { Run-KeyTest {Test_BackupRestoreKeyByName} "Test_BackupRestoreKeyByName" } "Test_BackupRestoreKeyByName" + Run-TestProtected { Run-KeyTest {Test_BackupRestoreKeyByRef} "Test_BackupRestoreKeyByRef" } "Test_BackupRestoreKeyByRef" + Run-TestProtected { Run-KeyTest {Test_BackupNonExistingKey} "Test_BackupNonExistingKey" } "Test_BackupNonExistingKey" + Run-TestProtected { Run-KeyTest {Test_BackupKeyToANamedFile} "Test_BackupKeyToANamedFile" } "Test_BackupKeyToANamedFile" + Run-TestProtected { Run-KeyTest {Test_BackupKeyToExistingFile} "Test_BackupKeyToExistingFile" } "Test_BackupKeyToExistingFile" + Run-TestProtected { Run-KeyTest {Test_RestoreKeyFromNonExistingFile} "Test_RestoreKeyFromNonExistingFile" } "Test_RestoreKeyFromNonExistingFile" # *-AzureRmKeyVaultKey pipeline tests. Run-TestProtected { Run-KeyTest {Test_PipelineUpdateKeys} "Test_PipelineUpdateKeys" } "Test_PipelineUpdateKeys" @@ -376,7 +377,15 @@ function Run-AllDataPlaneTests Run-TestProtected { Run-SecretTest {Test_RemoveNonExistSecret} "Test_RemoveNonExistSecret" } "Test_RemoveNonExistSecret" Run-TestProtected { Run-SecretTest {Test_RemoveSecretInNoPermissionVault} "Test_RemoveSecretInNoPermissionVault" } "Test_RemoveSecretInNoPermissionVault" - # *-AzureRmKeyVaultKey pipeline tests. + # Backup-AzureKeyVaultSecret and Restore-AzureKeyVaultSecret tests. + Run-TestProtected { Run-SecretTest {Test_BackupRestoreSecretByName} "Test_BackupRestoreSecretByName" } "Test_BackupRestoreSecretByName" + Run-TestProtected { Run-SecretTest {Test_BackupRestoreSecretByRef} "Test_BackupRestoreSecretByRef" } "Test_BackupRestoreSecretByRef" + Run-TestProtected { Run-SecretTest {Test_BackupNonExistingSecret} "Test_BackupNonExistingSecret" } "Test_BackupNonExistingSecret" + Run-TestProtected { Run-SecretTest {Test_BackupSecretToANamedFile} "Test_BackupSecretToANamedFile" } "Test_BackupSecretToANamedFile" + Run-TestProtected { Run-SecretTest {Test_BackupSecretToExistingFile} "Test_BackupSecretToExistingFile" } "Test_BackupSecretToExistingFile" + Run-TestProtected { Run-SecretTest {Test_RestoreSecretFromNonExistingFile} "Test_RestoreSecretFromNonExistingFile" } "Test_RestoreSecretFromNonExistingFile" + + # *-AzureRmKeyVaultSecret pipeline tests. Run-TestProtected { Run-SecretTest {Test_PipelineUpdateSecrets} "Test_PipelineUpdateSecrets" } "Test_PipelineUpdateSecrets" Run-TestProtected { Run-SecretTest {Test_PipelineUpdateSecretAttributes} "Test_PipelineUpdateSecretAttributes" } "Test_PipelineUpdateSecretAttributes" Run-TestProtected { Run-SecretTest {Test_PipelineUpdateSecretVersions} "Test_PipelineUpdateSecretVersions" } "Test_PipelineUpdateSecretVersions" diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultKeyTests.ps1 b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultKeyTests.ps1 index 160cc7a6f8ca..f820b19cacb9 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultKeyTests.ps1 +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultKeyTests.ps1 @@ -838,9 +838,9 @@ function Test_RemoveKeyInNoPermissionVault <# .SYNOPSIS -Tests backup and restore a key +Tests backup and restore a key by name #> -function Test_BackupRestoreKey +function Test_BackupRestoreKeyByName { $keyVault = Get-KeyVault $keyname=Get-KeyName 'backuprestore' @@ -858,9 +858,27 @@ function Test_BackupRestoreKey <# .SYNOPSIS -Tests backup a none existing key +Tests backup and restore a key by object #> -function Test_BackupNonExisitingKey +function Test_BackupRestoreKeyByRef +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'backuprestore' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Destination 'Software' + Assert-NotNull $key + $global:createdKeys += $keyname + + $backupblob = Backup-AzureKeyVaultKey -Key $key + Remove-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Force -Confirm:$false + $restoredKey = Restore-AzureKeyVaultKey -VaultName $keyVault -InputFile $backupblob + Assert-KeyAttributes $restoredKey.Attributes 'RSA' $true $null $null $null +} + +<# +.SYNOPSIS +Tests backup a non-existing key +#> +function Test_BackupNonExistingKey { $keyVault = Get-KeyVault $keyname=Get-KeyName 'backupnonexisting' @@ -872,7 +890,7 @@ function Test_BackupNonExisitingKey .SYNOPSIS Tests backup a key to a specific file and be able to restore #> -function Test_BackupToANamedFile +function Test_BackupKeyToANamedFile { $keyVault = Get-KeyVault $keyname=Get-KeyName 'backupnamedfile' @@ -894,7 +912,7 @@ function Test_BackupToANamedFile .SYNOPSIS Tests backup a key to a specific file which exists #> -function Test_BackupToExistingFile +function Test_BackupKeyToExistingFile { $keyVault = Get-KeyVault $keyname=Get-KeyName 'backupexistingfile' @@ -905,7 +923,7 @@ function Test_BackupToExistingFile $backupfile='.\backup' + ([GUID]::NewGuid()).GUID.ToString() + '.blob' Backup-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname -OutputFile $backupfile - Assert-Throws { Backup-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname -OutputFile $backupfile } + Backup-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname -OutputFile $backupfile -Force -Confirm:$false } @@ -913,7 +931,7 @@ function Test_BackupToExistingFile .SYNOPSIS Tests restore a key from a none existing file #> -function Test_RestoreFromNonExistingFile +function Test_RestoreKeyFromNonExistingFile { $keyVault = Get-KeyVault @@ -935,7 +953,7 @@ function Test_PipelineUpdateKeys Get-AzureKeyVaultKey $keyVault | Where-Object {$_.KeyName -like $keypartialname+'*'} | Set-AzureKeyVaultKeyAttribute -Enable $false Get-AzureKeyVaultKey $keyVault | Where-Object {$_.KeyName -like $keypartialname+'*'} | ForEach-Object { Assert-False { return $_.Enabled } } - } +} <# .SYNOPSIS diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultSecretTests.ps1 b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultSecretTests.ps1 index 81847234b9da..4a56a775378a 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultSecretTests.ps1 +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultSecretTests.ps1 @@ -656,6 +656,109 @@ function Test_RemoveSecretInNoPermissionVault Assert-Throws {Remove-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -Force -Confirm:$false} } +<# +.SYNOPSIS +Tests backup and restoring of a secret by name +#> +function Test_BackupRestoreSecretByName +{ + $keyVault = Get-KeyVault + $name=Get-SecretName 'backuprestore' + $secret=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $name -SecretValue $securedata + Assert-NotNull $secret + $global:createdSecrets += $name + + $backupblob = Backup-AzureKeyVaultSecret -VaultName $keyVault -SecretName $name + Remove-AzureKeyVaultSecret -VaultName $keyVault -Name $name -Force -Confirm:$false + $restoredSecret = Restore-AzureKeyVaultSecret -VaultName $keyVault -InputFile $backupblob + + $retrievedSecret = Get-AzureKeyVaultSecret -VaultName $keyVault -SecretName $name + Assert-AreEqual $retrievedSecret.SecretValueText $data +} + +<# +.SYNOPSIS +Tests backup and restoring of a secret by object +#> +function Test_BackupRestoreSecretByRef +{ + $keyVault = Get-KeyVault + $name=Get-SecretName 'backuprestore' + $secret=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $name -SecretValue $securedata + Assert-NotNull $secret + $global:createdSecrets += $name + + $backupblob = Backup-AzureKeyVaultSecret -Secret $secret + Remove-AzureKeyVaultSecret -VaultName $keyVault -Name $name -Force -Confirm:$false + $restoredSecret = Restore-AzureKeyVaultSecret -VaultName $keyVault -InputFile $backupblob + + $retrievedSecret = Get-AzureKeyVaultSecret -VaultName $keyVault -SecretName $name + Assert-AreEqual $retrievedSecret.SecretValueText $data +} + +<# +.SYNOPSIS +Tests backup of a non-existing secret +#> +function Test_BackupNonExistingSecret +{ + $keyVault = Get-KeyVault + $name=Get-SecretName 'backupnonexisting' + + Assert-Throws { Backup-AzureKeyVaultSecret -VaultName $keyVault -SecretName $name } +} + +<# +.SYNOPSIS +Tests backup of a secret to a specific file and ability to restore +#> +function Test_BackupSecretToANamedFile +{ + $keyVault = Get-KeyVault + $name=Get-SecretName 'backupnamedfile' + $secret=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $name -SecretValue $securedata + Assert-NotNull $secret + $global:createdSecrets += $name + + $backupfile='.\backup' + ([GUID]::NewGuid()).GUID.ToString() + '.blob' + + Backup-AzureKeyVaultSecret -VaultName $keyVault -SecretName $name -OutputFile $backupfile + Remove-AzureKeyVaultSecret -VaultName $keyVault -Name $name -Force -Confirm:$false + $restoredSecret = Restore-AzureKeyVaultSecret -VaultName $keyVault -InputFile $backupfile + + $retrievedSecret = Get-AzureKeyVaultSecret -VaultName $keyVault -SecretName $name + Assert-AreEqual $retrievedSecret.SecretValueText $data +} + +<# +.SYNOPSIS +Tests backup of a key to a specific, existing file +#> +function Test_BackupSecretToExistingFile +{ + $keyVault = Get-KeyVault + $name=Get-SecretName 'backupexistingfile' + $secret=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $name -SecretValue $securedata + Assert-NotNull $secret + $global:createdSecrets += $name + + $backupfile='.\backup' + ([GUID]::NewGuid()).GUID.ToString() + '.blob' + Backup-AzureKeyVaultSecret -VaultName $keyVault -SecretName $name -OutputFile $backupfile + Backup-AzureKeyVaultSecret -VaultName $keyVault -SecretName $name -OutputFile $backupfile -Force -Confirm:$false +} + + +<# +.SYNOPSIS +Tests restoring a secret from a non-existing file +#> +function Test_RestoreSecretFromNonExistingFile +{ + $keyVault = Get-KeyVault + + Assert-Throws { Restore-AzureKeyVaultSecret -VaultName $keyVault -InputFile c:\nonexisting.blob } +} + <# .SYNOPSIS Tests pipeline commands to update values of multiple secrets diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands.KeyVault.csproj b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands.KeyVault.csproj index f24670cb00bb..83d3be93e6ab 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands.KeyVault.csproj +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands.KeyVault.csproj @@ -52,6 +52,8 @@ + + diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultKey.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultKey.cs index e22173e016aa..0d776900eaf3 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultKey.cs +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultKey.cs @@ -12,10 +12,10 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using Microsoft.Azure.Commands.KeyVault.Models; using System; -using System.IO; using System.Management.Automation; +using Microsoft.Azure.Commands.Common.Authentication; +using Microsoft.Azure.Commands.KeyVault.Models; using KeyVaultProperties = Microsoft.Azure.Commands.KeyVault.Properties; namespace Microsoft.Azure.Commands.KeyVault @@ -23,33 +23,58 @@ namespace Microsoft.Azure.Commands.KeyVault /// /// Requests that a backup of the specified key be downloaded and stored to a file /// + /// + /// The cmdlet returns the path of the newly created backup file. + /// [Cmdlet(VerbsData.Backup, "AzureKeyVaultKey", SupportsShouldProcess = true, HelpUri = Constants.KeyVaultHelpUri)] [OutputType(typeof(String))] public class BackupAzureKeyVaultKey : KeyVaultCmdletBase { - public static readonly DateTime EpochDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + #region parameter sets + + private const string ByKeyNameParameterSet = "ByKeyName"; + private const string ByKeyObjectParameterSet = "ByKey"; + + #endregion #region Input Parameter Definitions /// /// Vault name /// - [Parameter(Mandatory = true, - Position = 0, - ValueFromPipelineByPropertyName = true, - HelpMessage = "Vault name. Cmdlet constructs the FQDN of a vault based on the name and currently selected environment.")] + [Parameter( Mandatory = true, + Position = 0, + ValueFromPipelineByPropertyName = true, + ParameterSetName = ByKeyNameParameterSet, + HelpMessage = "Vault name. Cmdlet constructs the FQDN of a vault based on the name and currently selected environment.")] [ValidateNotNullOrEmpty] public string VaultName { get; set; } + /// + /// KeyBundle object to be backed up. + /// + /// + /// Note that the backup applies to the entire family of a key (current and all its versions); + /// since a key bundle represents a single version, the intent of this parameter is to allow pipelining. + /// The backup cmdlet will use the Name and VaultName properties of the KeyBundle parameter. + /// + [Parameter( Mandatory = true, + Position = 0, + ValueFromPipelineByPropertyName = true, + ParameterSetName = ByKeyObjectParameterSet, + HelpMessage = "Key bundle to back up, pipelined in from the output of a retrieval call." )] + public KeyBundle Key { get; set; } + /// /// Key name /// - [Parameter(Mandatory = true, - Position = 1, - ValueFromPipelineByPropertyName = true, - HelpMessage = "Key name. Cmdlet constructs the FQDN of a key from vault name, currently selected environment and key name.")] + [Parameter( Mandatory = true, + Position = 1, + ValueFromPipelineByPropertyName = true, + ParameterSetName = ByKeyNameParameterSet, + HelpMessage = "Key name. Cmdlet constructs the FQDN of a key from vault name, currently selected environment and key name.")] [ValidateNotNullOrEmpty] [Alias(Constants.KeyName)] public string Name { get; set; } @@ -57,47 +82,59 @@ public class BackupAzureKeyVaultKey : KeyVaultCmdletBase /// /// The output file in which the backup blob is to be stored /// - [Parameter(Mandatory = false, - Position = 2, - ValueFromPipelineByPropertyName = true, - HelpMessage = "Output file. The output file to store the backed up key blob in. If not present, a default filename is chosen.")] + [Parameter( Mandatory = false, + Position = 2, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Output file. The output file to store the backed up key blob in. If not present, a default filename is chosen.")] [ValidateNotNullOrEmpty] public string OutputFile { get; set; } + /// + /// Instructs the cmdlet to overwrite the destination file, if it exists. + /// + [Parameter( Mandatory = false, + Position = 3, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Overwrite the given file if it exists" )] + public SwitchParameter Force { get; set; } + #endregion Input Parameter Definition public override void ExecuteCmdlet() { - if (ShouldProcess(Name, Properties.Resources.BackupKey)) + switch ( ParameterSetName ) { - if (string.IsNullOrEmpty(OutputFile)) - { - OutputFile = GetDefaultFile(); - } + case ByKeyNameParameterSet: + // no op + break; - var filePath = ResolvePath(OutputFile); + case ByKeyObjectParameterSet: + Name = Key.Name; + VaultName = Key.VaultName; + break; - var backupBlobPath = this.DataServiceClient.BackupKey(VaultName, Name, filePath); - - this.WriteObject(backupBlobPath); + default: + throw new ArgumentException( KeyVaultProperties.Resources.BadParameterSetName ); } - } - private string GetDefaultFile() - { - var currentPath = CurrentPath(); - var filename = string.Format("{0}\\backup-{1}-{2}-{3}", currentPath, VaultName, Name, DateTime.UtcNow.Subtract(EpochDate).TotalSeconds); - return filename; - } - - private string ResolvePath(string filePath) - { - FileInfo keyFile = new FileInfo(this.GetUnresolvedProviderPathFromPSPath(filePath)); - if (keyFile.Exists) + if ( ShouldProcess(Name, Properties.Resources.BackupKey)) { - throw new IOException(string.Format(KeyVaultProperties.Resources.BackupKeyFileAlreadyExists, filePath)); + if (string.IsNullOrEmpty(OutputFile)) + { + OutputFile = GetDefaultFileForOperation("backup", VaultName, Name); + } + + var filePath = this.GetUnresolvedProviderPathFromPSPath(OutputFile); + + // deny request if the file exists and overwrite is not authorized + if ( !AzureSession.DataStore.FileExists( filePath ) + || Force.IsPresent + || ShouldContinue( string.Format( KeyVaultProperties.Resources.FileOverwriteMessage, filePath ), KeyVaultProperties.Resources.FileOverwriteCaption ) ) + { + var backupBlobPath = this.DataServiceClient.BackupKey(VaultName, Name, filePath); + this.WriteObject( backupBlobPath ); + } } - return keyFile.FullName; } } } diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultSecret.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultSecret.cs new file mode 100644 index 000000000000..8c510f19fb59 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultSecret.cs @@ -0,0 +1,141 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Management.Automation; +using Microsoft.Azure.Commands.Common.Authentication; +using Microsoft.Azure.Commands.KeyVault.Models; +using KeyVaultProperties = Microsoft.Azure.Commands.KeyVault.Properties; + +namespace Microsoft.Azure.Commands.KeyVault +{ + /// + /// Requests that a backup of the specified key be downloaded and stored to a file + /// + /// + /// The cmdlet returns the path of the newly created backup file. + /// + [Cmdlet( VerbsData.Backup, "AzureKeyVaultSecret", + SupportsShouldProcess = true, + HelpUri = Constants.KeyVaultHelpUri )] + [OutputType( typeof( String ) )] + public class BackupAzureKeyVaultSecret : KeyVaultCmdletBase + { + #region parameter sets + + private const string BySecretNameParameterSet = "BySecretName"; + private const string BySecretObjectParameterSet = "BySecret"; + + #endregion + + #region Input Parameter Definitions + + /// + /// Vault name + /// + [Parameter( Mandatory = true, + Position = 0, + ValueFromPipelineByPropertyName = true, + ParameterSetName = BySecretNameParameterSet, + HelpMessage = "Vault name. Cmdlet constructs the FQDN of a vault based on the name and currently selected environment." )] + [ValidateNotNullOrEmpty] + public string VaultName { get; set; } + + /// + /// The secret object to be backed up. + /// + /// + /// Note that the backup applies to the entire family of a secret (current and all its versions); + /// since a key bundle represents a single version, the intent of this parameter is to allow pipelining. + /// The backup cmdlet will use the Name and VaultName properties of the KeyBundle parameter. + /// + [Parameter( Mandatory = true, + Position = 0, + ValueFromPipelineByPropertyName = true, + ParameterSetName = BySecretObjectParameterSet, + HelpMessage = "Secret to be backed up, pipelined in from the output of a retrieval call." )] + [ValidateNotNullOrEmpty] + public Secret Secret { get; set; } + + /// + /// Secret name + /// + [Parameter( Mandatory = true, + Position = 1, + ValueFromPipelineByPropertyName = true, + ParameterSetName = BySecretNameParameterSet, + HelpMessage = "Secret name. Cmdlet constructs the FQDN of a secret from vault name, currently selected environment and secret name." )] + [ValidateNotNullOrEmpty] + [Alias( Constants.SecretName )] + public string Name { get; set; } + + /// + /// The output file in which the backup blob is to be stored + /// + [Parameter( Mandatory = false, + Position = 2, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Output file. The output file to store the backed up secret blob in. If not present, a default filename is chosen." )] + [ValidateNotNullOrEmpty] + public string OutputFile { get; set; } + + /// + /// Instructs the cmdlet to overwrite the destination file, if it exists. + /// + [Parameter( Mandatory = false, + Position = 3, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Overwrite the given file if it exists" )] + public SwitchParameter Force { get; set; } + + #endregion Input Parameter Definition + + public override void ExecuteCmdlet( ) + { + switch ( ParameterSetName ) + { + case BySecretNameParameterSet: + // no op + break; + + case BySecretObjectParameterSet: + Name = Secret.Name; + VaultName = Secret.VaultName; + break; + + default: + throw new ArgumentException( KeyVaultProperties.Resources.BadParameterSetName ); + } + + if ( ShouldProcess( Name, Properties.Resources.BackupSecret ) ) + { + if ( string.IsNullOrEmpty( OutputFile ) ) + { + OutputFile = GetDefaultFileForOperation( "backup", VaultName, Name ); + } + + var filePath = this.GetUnresolvedProviderPathFromPSPath(OutputFile); + + // deny request if the file exists and overwrite is not authorized + if ( !AzureSession.DataStore.FileExists( filePath ) + || Force.IsPresent + || ShouldContinue( string.Format( KeyVaultProperties.Resources.FileOverwriteMessage, filePath ), KeyVaultProperties.Resources.FileOverwriteCaption ) ) + { + var backupBlobPath = this.DataServiceClient.BackupSecret(VaultName, Name, filePath); + this.WriteObject( backupBlobPath ); + } + } + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/RestoreAzureKeyVaultSecret.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/RestoreAzureKeyVaultSecret.cs new file mode 100644 index 000000000000..b98def2cbe18 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/RestoreAzureKeyVaultSecret.cs @@ -0,0 +1,72 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System.IO; +using System.Management.Automation; +using Microsoft.Azure.Commands.Common.Authentication; +using Microsoft.Azure.Commands.KeyVault.Models; +using KeyVaultProperties = Microsoft.Azure.Commands.KeyVault.Properties; + +namespace Microsoft.Azure.Commands.KeyVault +{ + /// + /// Restores the backup secret into a vault + /// + [Cmdlet( VerbsData.Restore, "AzureKeyVaultSecret", + SupportsShouldProcess = true, + HelpUri = Constants.KeyVaultHelpUri )] + [OutputType( typeof( Secret ) )] + public class RestoreAzureKeyVaultSecret : KeyVaultCmdletBase + { + #region Input Parameter Definitions + + /// + /// Vault name + /// + [Parameter( Mandatory = true, + Position = 0, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Vault name. Cmdlet constructs the FQDN of a vault based on the name and currently selected environment." )] + [ValidateNotNullOrEmpty] + public string VaultName { get; set; } + + /// + /// The input file in which the backup blob is stored + /// + [Parameter( Mandatory = true, + Position = 1, + HelpMessage = "Input file. The input file containing the backed-up blob" )] + [ValidateNotNullOrEmpty] + public string InputFile { get; set; } + + #endregion Input Parameter Definitions + + public override void ExecuteCmdlet( ) + { + if ( ShouldProcess( VaultName, Properties.Resources.RestoreSecret ) ) + { + var resolvedFilePath = this.GetUnresolvedProviderPathFromPSPath( InputFile ); + + if ( !AzureSession.DataStore.FileExists( resolvedFilePath ) ) + { + throw new FileNotFoundException( string.Format( KeyVaultProperties.Resources.BackupSecretFileNotFound, resolvedFilePath ) ); + } + + var restoredSecret = this.DataServiceClient.RestoreSecret(VaultName, resolvedFilePath); + + this.WriteObject( restoredSecret ); + } + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/IKeyVaultDataServiceClient.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/IKeyVaultDataServiceClient.cs index 49ee0eb8e836..e74dc9660eaf 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/IKeyVaultDataServiceClient.cs +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/IKeyVaultDataServiceClient.cs @@ -68,6 +68,10 @@ public interface IKeyVaultDataServiceClient KeyBundle RestoreKey(string vaultName, string inputBlobPath); + string BackupSecret(string vaultName, string secretName, string outputBlobPath); + + Secret RestoreSecret(string vaultName, string inputBlobPath); + #region Certificate actions Contacts SetCertificateContacts(string vaultName, Contacts contacts); diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultCmdletBase.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultCmdletBase.cs index ac1c19c337a8..5c117a763c97 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultCmdletBase.cs +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultCmdletBase.cs @@ -12,16 +12,17 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using Microsoft.Azure.Commands.Common.Authentication; -using Microsoft.Azure.Commands.ResourceManager.Common; using System; using System.Collections.Generic; -using System.Net.Http; +using Microsoft.Azure.Commands.Common.Authentication; +using Microsoft.Azure.Commands.ResourceManager.Common; namespace Microsoft.Azure.Commands.KeyVault.Models { public class KeyVaultCmdletBase : AzureRMCmdlet { + public static readonly DateTime EpochDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + internal IKeyVaultDataServiceClient DataServiceClient { get @@ -41,6 +42,14 @@ internal IKeyVaultDataServiceClient DataServiceClient } } + protected string GetDefaultFileForOperation( string operationName, string vaultName, string entityName ) + { + // caller is responsible for parameter validation + var currentPath = CurrentPath(); + var filename = string.Format("{0}\\{1}-{2}-{3}", currentPath, vaultName, entityName, DateTime.UtcNow.Subtract(EpochDate).TotalSeconds); + + return filename; + } private IKeyVaultDataServiceClient dataServiceClient; diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultDataServiceClient.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultDataServiceClient.cs index 55a2ca9f606f..156be9f89da7 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultDataServiceClient.cs +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultDataServiceClient.cs @@ -34,9 +34,9 @@ internal class KeyVaultDataServiceClient : IKeyVaultDataServiceClient public KeyVaultDataServiceClient(IAuthenticationFactory authFactory, AzureContext context) { if (authFactory == null) - throw new ArgumentNullException("authFactory"); + throw new ArgumentNullException(nameof(authFactory)); if (context == null) - throw new ArgumentNullException("context"); + throw new ArgumentNullException(nameof(context)); if (context.Environment == null) throw new ArgumentException(KeyVaultProperties.Resources.InvalidAzureEnvironment); @@ -58,11 +58,11 @@ public KeyVaultDataServiceClient() public KeyBundle CreateKey(string vaultName, string keyName, KeyAttributes keyAttributes) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(keyName)) - throw new ArgumentNullException("keyName"); + throw new ArgumentNullException(nameof(keyName)); if (keyAttributes == null) - throw new ArgumentNullException("keyAttributes"); + throw new ArgumentNullException(nameof(keyAttributes)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); var attributes = (Azure.KeyVault.Models.KeyAttributes)keyAttributes; @@ -89,11 +89,11 @@ public KeyBundle CreateKey(string vaultName, string keyName, KeyAttributes keyAt public CertificateBundle MergeCertificate(string vaultName, string certName, X509Certificate2Collection certs, IDictionary tags) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(certName)) - throw new ArgumentNullException("certName"); + throw new ArgumentNullException(nameof(certName)); if (null == certs) - throw new ArgumentNullException("certs"); + throw new ArgumentNullException(nameof(certs)); CertificateBundle certBundle; @@ -115,11 +115,11 @@ public CertificateBundle MergeCertificate(string vaultName, string certName, X50 public CertificateBundle ImportCertificate(string vaultName, string certName, string base64CertColl, SecureString certPassword, IDictionary tags) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(certName)) - throw new ArgumentNullException("certName"); + throw new ArgumentNullException(nameof(certName)); if (string.IsNullOrEmpty(base64CertColl)) - throw new ArgumentNullException("base64CertColl"); + throw new ArgumentNullException(nameof(base64CertColl)); CertificateBundle certBundle; @@ -149,11 +149,11 @@ public CertificateBundle ImportCertificate(string vaultName, string certName, st public CertificateBundle ImportCertificate(string vaultName, string certName, X509Certificate2Collection certificateCollection, IDictionary tags) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(certName)) - throw new ArgumentNullException("certName"); + throw new ArgumentNullException(nameof(certName)); if (null == certificateCollection) - throw new ArgumentNullException("certificateCollection"); + throw new ArgumentNullException(nameof(certificateCollection)); CertificateBundle certBundle; var vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -179,13 +179,13 @@ public CertificateBundle ImportCertificate(string vaultName, string certName, X5 public KeyBundle ImportKey(string vaultName, string keyName, KeyAttributes keyAttributes, JsonWebKey webKey, bool? importToHsm) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(keyName)) - throw new ArgumentNullException("keyName"); + throw new ArgumentNullException(nameof(keyName)); if (keyAttributes == null) - throw new ArgumentNullException("keyAttributes"); + throw new ArgumentNullException(nameof(keyAttributes)); if (webKey == null) - throw new ArgumentNullException("webKey"); + throw new ArgumentNullException(nameof(webKey)); if (webKey.Kty == JsonWebKeyType.RsaHsm && (importToHsm.HasValue && !importToHsm.Value)) throw new ArgumentException(KeyVaultProperties.Resources.ImportByokAsSoftkeyError); @@ -214,11 +214,11 @@ public KeyBundle ImportKey(string vaultName, string keyName, KeyAttributes keyAt public KeyBundle UpdateKey(string vaultName, string keyName, string keyVersion, KeyAttributes keyAttributes) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(keyName)) - throw new ArgumentNullException("keyName"); + throw new ArgumentNullException(nameof(keyName)); if (keyAttributes == null) - throw new ArgumentNullException("keyAttributes"); + throw new ArgumentNullException(nameof(keyAttributes)); var attributes = (Azure.KeyVault.Models.KeyAttributes)keyAttributes; var keyIdentifier = new KeyIdentifier(this.vaultUriHelper.CreateVaultAddress(vaultName), keyName, keyVersion); @@ -240,7 +240,7 @@ public KeyBundle UpdateKey(string vaultName, string keyName, string keyVersion, public Contacts GetCertificateContacts(string vaultName) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -268,9 +268,9 @@ public Contacts GetCertificateContacts(string vaultName) public CertificateBundle GetCertificate(string vaultName, string certName, string certificateVersion) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(certName)) - throw new ArgumentNullException("certName"); + throw new ArgumentNullException(nameof(certName)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -298,9 +298,9 @@ public CertificateBundle GetCertificate(string vaultName, string certName, strin public KeyBundle GetKey(string vaultName, string keyName, string keyVersion) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(keyName)) - throw new ArgumentNullException("keyName"); + throw new ArgumentNullException(nameof(keyName)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -327,7 +327,7 @@ public KeyBundle GetKey(string vaultName, string keyName, string keyVersion) public IEnumerable GetCertificates(KeyVaultObjectFilterOptions options) { if (options == null) - throw new ArgumentNullException("options"); + throw new ArgumentNullException(nameof(options)); if (string.IsNullOrEmpty(options.VaultName)) throw new ArgumentException(KeyVaultProperties.Resources.InvalidVaultName); @@ -356,7 +356,7 @@ public IEnumerable GetCertificates(KeyVaultObjectFilter public IEnumerable GetCertificateVersions(KeyVaultObjectFilterOptions options) { if (options == null) - throw new ArgumentNullException("options"); + throw new ArgumentNullException(nameof(options)); if (string.IsNullOrEmpty(options.VaultName)) throw new ArgumentException(KeyVaultProperties.Resources.InvalidVaultName); @@ -387,7 +387,7 @@ public IEnumerable GetCertificateVersions(KeyVaultObjec public IEnumerable GetKeys(KeyVaultObjectFilterOptions options) { if (options == null) - throw new ArgumentNullException("options"); + throw new ArgumentNullException(nameof(options)); if (string.IsNullOrEmpty(options.VaultName)) throw new ArgumentException(KeyVaultProperties.Resources.InvalidVaultName); @@ -416,7 +416,7 @@ public IEnumerable GetKeys(KeyVaultObjectFilterOptions options) public IEnumerable GetKeyVersions(KeyVaultObjectFilterOptions options) { if (options == null) - throw new ArgumentNullException("options"); + throw new ArgumentNullException(nameof(options)); if (string.IsNullOrEmpty(options.VaultName)) throw new ArgumentException(KeyVaultProperties.Resources.InvalidVaultName); @@ -447,9 +447,9 @@ public IEnumerable GetKeyVersions(KeyVaultObjectFilterOptions o public DeletedKeyBundle DeleteKey(string vaultName, string keyName) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(keyName)) - throw new ArgumentNullException("keyName"); + throw new ArgumentNullException(nameof(keyName)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -469,9 +469,9 @@ public DeletedKeyBundle DeleteKey(string vaultName, string keyName) public Contacts SetCertificateContacts(string vaultName, Contacts contacts) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (null == contacts) - throw new ArgumentNullException("contacts"); + throw new ArgumentNullException(nameof(contacts)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -492,13 +492,13 @@ public Contacts SetCertificateContacts(string vaultName, Contacts contacts) public Secret SetSecret(string vaultName, string secretName, SecureString secretValue, SecretAttributes secretAttributes) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(secretName)) - throw new ArgumentNullException("secretName"); + throw new ArgumentNullException(nameof(secretName)); if (secretValue == null) - throw new ArgumentNullException("secretValue"); + throw new ArgumentNullException(nameof(secretValue)); if (secretAttributes == null) - throw new ArgumentNullException("secretAttributes"); + throw new ArgumentNullException(nameof(secretAttributes)); string value = secretValue.ConvertToString(); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -521,11 +521,11 @@ public Secret SetSecret(string vaultName, string secretName, SecureString secret public Secret UpdateSecret(string vaultName, string secretName, string secretVersion, SecretAttributes secretAttributes) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(secretName)) - throw new ArgumentNullException("secretName"); + throw new ArgumentNullException(nameof(secretName)); if (secretAttributes == null) - throw new ArgumentNullException("secretAttributes"); + throw new ArgumentNullException(nameof(secretAttributes)); var secretIdentifier = new SecretIdentifier(this.vaultUriHelper.CreateVaultAddress(vaultName), secretName, secretVersion); @@ -548,9 +548,9 @@ public Secret UpdateSecret(string vaultName, string secretName, string secretVer public Secret GetSecret(string vaultName, string secretName, string secretVersion) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(secretName)) - throw new ArgumentNullException("secretName"); + throw new ArgumentNullException(nameof(secretName)); var secretIdentifier = new SecretIdentifier(this.vaultUriHelper.CreateVaultAddress(vaultName), secretName, secretVersion); SecretBundle secret; @@ -576,7 +576,7 @@ public Secret GetSecret(string vaultName, string secretName, string secretVersio public IEnumerable GetSecrets(KeyVaultObjectFilterOptions options) { if (options == null) - throw new ArgumentNullException("options"); + throw new ArgumentNullException(nameof(options)); if (string.IsNullOrEmpty(options.VaultName)) throw new ArgumentException(KeyVaultProperties.Resources.InvalidVaultName); @@ -604,7 +604,7 @@ public IEnumerable GetSecrets(KeyVaultObjectFilterOptions op public IEnumerable GetSecretVersions(KeyVaultObjectFilterOptions options) { if (options == null) - throw new ArgumentNullException("options"); + throw new ArgumentNullException(nameof(options)); if (string.IsNullOrEmpty(options.VaultName)) throw new ArgumentException(KeyVaultProperties.Resources.InvalidVaultName); if (string.IsNullOrEmpty(options.Name)) @@ -633,9 +633,9 @@ public IEnumerable GetSecretVersions(KeyVaultObjectFilterOpt public CertificateOperation EnrollCertificate(string vaultName, string certificateName, CertificatePolicy certificatePolicy, IDictionary tags) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(certificateName)) - throw new ArgumentNullException("certificateName"); + throw new ArgumentNullException(nameof(certificateName)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -656,9 +656,9 @@ public CertificateOperation EnrollCertificate(string vaultName, string certifica public CertificateBundle UpdateCertificate(string vaultName, string certificateName, string certificateVersion, CertificateAttributes certificateAttributes, IDictionary tags) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(certificateName)) - throw new ArgumentNullException("certificateName"); + throw new ArgumentNullException(nameof(certificateName)); var certificateIdentifier = new CertificateIdentifier(this.vaultUriHelper.CreateVaultAddress(vaultName), certificateName, certificateVersion); @@ -679,9 +679,9 @@ public CertificateBundle UpdateCertificate(string vaultName, string certificateN public CertificateBundle DeleteCertificate(string vaultName, string certName) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(certName)) - throw new ArgumentNullException("certName"); + throw new ArgumentNullException(nameof(certName)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -702,9 +702,9 @@ public CertificateBundle DeleteCertificate(string vaultName, string certName) public CertificateOperation GetCertificateOperation(string vaultName, string certificateName) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(certificateName)) - throw new ArgumentNullException("certificateName"); + throw new ArgumentNullException(nameof(certificateName)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -732,9 +732,9 @@ public CertificateOperation GetCertificateOperation(string vaultName, string cer public CertificateOperation CancelCertificateOperation(string vaultName, string certificateName) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(certificateName)) - throw new ArgumentNullException("certificateName"); + throw new ArgumentNullException(nameof(certificateName)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -755,9 +755,9 @@ public CertificateOperation CancelCertificateOperation(string vaultName, string public CertificateOperation DeleteCertificateOperation(string vaultName, string certificateName) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(certificateName)) - throw new ArgumentNullException("certificateName"); + throw new ArgumentNullException(nameof(certificateName)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -778,9 +778,9 @@ public CertificateOperation DeleteCertificateOperation(string vaultName, string public DeletedSecret DeleteSecret(string vaultName, string secretName) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(secretName)) - throw new ArgumentNullException("secretName"); + throw new ArgumentNullException(nameof(secretName)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -800,11 +800,11 @@ public DeletedSecret DeleteSecret(string vaultName, string secretName) public string BackupKey(string vaultName, string keyName, string outputBlobPath) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(keyName)) - throw new ArgumentNullException("keyName"); + throw new ArgumentNullException(nameof(keyName)); if (string.IsNullOrEmpty(outputBlobPath)) - throw new ArgumentNullException("outputBlobPath"); + throw new ArgumentNullException(nameof(outputBlobPath)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -826,9 +826,9 @@ public string BackupKey(string vaultName, string keyName, string outputBlobPath) public KeyBundle RestoreKey(string vaultName, string inputBlobPath) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(inputBlobPath)) - throw new ArgumentNullException("inputBlobPath"); + throw new ArgumentNullException(nameof(inputBlobPath)); var backupBlob = File.ReadAllBytes(inputBlobPath); @@ -847,12 +847,62 @@ public KeyBundle RestoreKey(string vaultName, string inputBlobPath) return new KeyBundle(keyBundle, this.vaultUriHelper); } + public string BackupSecret( string vaultName, string secretName, string outputBlobPath ) + { + if ( string.IsNullOrEmpty( vaultName ) ) + throw new ArgumentNullException(nameof(vaultName)); + if ( string.IsNullOrEmpty( secretName ) ) + throw new ArgumentNullException(nameof(secretName)); + if ( string.IsNullOrEmpty( outputBlobPath ) ) + throw new ArgumentNullException(nameof(outputBlobPath)); + + string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); + + BackupSecretResult backupSecretResult; + try + { + backupSecretResult = this.keyVaultClient.BackupSecretAsync( vaultAddress, secretName ).GetAwaiter( ).GetResult( ); + } + catch ( Exception ex ) + { + throw GetInnerException( ex ); + } + + File.WriteAllBytes( outputBlobPath, backupSecretResult.Value ); + + return outputBlobPath; + } + + public Secret RestoreSecret( string vaultName, string inputBlobPath ) + { + if ( string.IsNullOrEmpty( vaultName ) ) + throw new ArgumentNullException(nameof(vaultName)); + if ( string.IsNullOrEmpty( inputBlobPath ) ) + throw new ArgumentNullException(nameof(inputBlobPath)); + + var backupBlob = File.ReadAllBytes(inputBlobPath); + + string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); + + Azure.KeyVault.Models.SecretBundle secretBundle; + try + { + secretBundle = this.keyVaultClient.RestoreSecretAsync( vaultAddress, backupBlob ).GetAwaiter( ).GetResult( ); + } + catch ( Exception ex ) + { + throw GetInnerException( ex ); + } + + return new Secret( secretBundle, this.vaultUriHelper ); + } + public CertificatePolicy GetCertificatePolicy(string vaultName, string certificateName) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(certificateName)) - throw new ArgumentNullException("certificateName"); + throw new ArgumentNullException(nameof(certificateName)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -879,11 +929,11 @@ public CertificatePolicy GetCertificatePolicy(string vaultName, string certifica public CertificatePolicy UpdateCertificatePolicy(string vaultName, string certificateName, CertificatePolicy certificatePolicy) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(certificateName)) - throw new ArgumentNullException("certificateName"); + throw new ArgumentNullException(nameof(certificateName)); if (certificatePolicy == null) - throw new ArgumentNullException("certificatePolicy"); + throw new ArgumentNullException(nameof(certificatePolicy)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); CertificatePolicy resultantCertificatePolicy; @@ -903,9 +953,9 @@ public CertificatePolicy UpdateCertificatePolicy(string vaultName, string certif public IssuerBundle GetCertificateIssuer(string vaultName, string issuerName) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(issuerName)) - throw new ArgumentNullException("issuerName"); + throw new ArgumentNullException(nameof(issuerName)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); @@ -932,7 +982,7 @@ public IssuerBundle GetCertificateIssuer(string vaultName, string issuerName) public IEnumerable GetCertificateIssuers(KeyVaultObjectFilterOptions options) { if (options == null) - throw new ArgumentNullException("options"); + throw new ArgumentNullException(nameof(options)); if (string.IsNullOrEmpty(options.VaultName)) throw new ArgumentException(KeyVaultProperties.Resources.InvalidVaultName); @@ -967,11 +1017,11 @@ public IssuerBundle SetCertificateIssuer( KeyVaultCertificateOrganizationDetails organizationDetails) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(issuerName)) - throw new ArgumentNullException("issuerName"); + throw new ArgumentNullException(nameof(issuerName)); if (string.IsNullOrEmpty(issuerProvider)) - throw new ArgumentNullException("issuerProvider"); + throw new ArgumentNullException(nameof(issuerProvider)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); var issuer = new IssuerBundle @@ -1011,9 +1061,9 @@ public IssuerBundle SetCertificateIssuer( public IssuerBundle DeleteCertificateIssuer(string vaultName, string issuerName) { if (string.IsNullOrEmpty(vaultName)) - throw new ArgumentNullException("vaultName"); + throw new ArgumentNullException(nameof(vaultName)); if (string.IsNullOrEmpty(issuerName)) - throw new ArgumentNullException("issuerName"); + throw new ArgumentNullException(nameof(issuerName)); string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.Designer.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.Designer.cs index 940d256987aa..748bd775d3eb 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.Designer.cs +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.Designer.cs @@ -10,8 +10,6 @@ namespace Microsoft.Azure.Commands.KeyVault.Properties { using System; - - /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -153,6 +151,33 @@ internal static string BackupKeyFileNotFound { } } + /// + /// Looks up a localized string similar to Backup secret. + /// + internal static string BackupSecret { + get { + return ResourceManager.GetString("BackupSecret", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The backup secret file '{0}' already exists.. + /// + internal static string BackupSecretFileAlreadyExists { + get { + return ResourceManager.GetString("BackupSecretFileAlreadyExists", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot find backup secret file '{0}'. + /// + internal static string BackupSecretFileNotFound { + get { + return ResourceManager.GetString("BackupSecretFileNotFound", resourceCulture); + } + } + /// /// Looks up a localized string similar to Bad Parameter Set Name. /// @@ -215,6 +240,24 @@ internal static string DeletedVaultNotFound { return ResourceManager.GetString("DeletedVaultNotFound", resourceCulture); } } + + /// + /// Looks up a localized string similar to Overwrite File ?. + /// + internal static string FileOverwriteCaption { + get { + return ResourceManager.GetString("FileOverwriteCaption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Overwrite existing file at '{0}' ?. + /// + internal static string FileOverwriteMessage { + get { + return ResourceManager.GetString("FileOverwriteMessage", resourceCulture); + } + } /// /// Looks up a localized string similar to BYOK key can not be imported as software key. @@ -666,6 +709,15 @@ internal static string RestoreKey { } } + /// + /// Looks up a localized string similar to Restore secret. + /// + internal static string RestoreSecret { + get { + return ResourceManager.GetString("RestoreSecret", resourceCulture); + } + } + /// /// Looks up a localized string similar to Set certificate attribute. /// diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.resx b/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.resx index c496391facc4..c3c3c4c885bb 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.resx +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.resx @@ -135,6 +135,12 @@ You can find the object ID using Azure Active Directory Module for Windows Power Cannot find backup key file '{0}' + + The backup secret file '{0}' already exists. + + + Cannot find backup secret file '{0}' + Bad Parameter Set Name @@ -276,6 +282,9 @@ You can find the object ID using Azure Active Directory Module for Windows Power Backup key + + Backup secret + Create certificate administrator @@ -324,6 +333,9 @@ You can find the object ID using Azure Active Directory Module for Windows Power Restore key + + Restore secret + Set vault access policy @@ -363,4 +375,10 @@ You can find the object ID using Azure Active Directory Module for Windows Power Cannot find deleted vault '{0}' in location '{1}' + + Overwrite File ? + + + Overwrite existing file at '{0}' ? + \ No newline at end of file diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/help/AzureRM.KeyVault.md b/src/ResourceManager/KeyVault/Commands.KeyVault/help/AzureRM.KeyVault.md index 26046d68da88..166c9978c11e 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault/help/AzureRM.KeyVault.md +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/help/AzureRM.KeyVault.md @@ -23,6 +23,9 @@ Creates a key in a key vault or imports a key into a key vault. ### [Backup-AzureKeyVaultKey](Backup-AzureKeyVaultKey.md) Backs up a key in a key vault. +### [Backup-AzureKeyVaultSecret](Backup-AzureKeyVaultSecret.md) +Backs up a secret in a key vault. + ### [Get-AzureKeyVaultCertificate](Get-AzureKeyVaultCertificate.md) Gets a certificate from a key vault. @@ -89,6 +92,9 @@ Removes all permissions for a user or application from a key vault. ### [Restore-AzureKeyVaultKey](Restore-AzureKeyVaultKey.md) Creates a key in a key vault from a backed-up key. +### [Restore-AzureKeyVaultSecret](Restore-AzureKeyVaultSecret.md) +Creates a secret in a key vault from a backed-up secret. + ### [Set-AzureKeyVaultCertificateAttribute](Set-AzureKeyVaultCertificateAttribute.md) Modifies editable attributes of a certificate. diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/help/Backup-AzureKeyVaultKey.md b/src/ResourceManager/KeyVault/Commands.KeyVault/help/Backup-AzureKeyVaultKey.md index 30f059493b5d..0ab0f46b36f9 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault/help/Backup-AzureKeyVaultKey.md +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/help/Backup-AzureKeyVaultKey.md @@ -12,11 +12,17 @@ Backs up a key in a key vault. ## SYNTAX +### ByKeyName ``` Backup-AzureKeyVaultKey [-VaultName] [-Name] [[-OutputFile] ] [-WhatIf] [-Confirm] [] ``` +### ByKey +``` +Backup-AzureKeyVaultKey -Key [[-OutputFile] ] [-WhatIf] [-Confirm] [] +``` + ## DESCRIPTION The **Backup-AzureKeyVaultKey** cmdlet backs up a specified key in a key vault by downloading it and storing it in a file. If there are multiple versions of the key, all versions are included in the backup. @@ -46,14 +52,37 @@ PS C:\>Backup-AzureKeyVaultKey -VaultName 'MyKeyVault' -Name 'MyKey' -OutputFile This command retrieves the key named MyKey from the key vaultnamed MyKeyVault and saves a backup of that key to a file named Backup.blob. +### Example 3: Back up a previously retrieved key to a specified file name, overwriting the destination file without prompting. +``` +PS C:\>$key = Get-AzureKeyVaultKey -VaultName 'MyKeyVault' -Name 'MyKey' +PS C:\>Backup-AzureKeyVaultKey -Key $key -OutputFile 'C:\Backup.blob' -Force +``` + +This command creates a backup of the key named $key.Name in the vault named $key.VaultName to a file named Backup.blob, silently overwriting the file if it exists already. + ## PARAMETERS +### -Key +Specifies a previously retrieved key which is to be backed up. + +```yaml +Type: KeyBundle +Parameter Sets: ByKey +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: True (ByPropertyName) +Accept wildcard characters: False +``` + ### -Name Specifies the name of the key to back up. ```yaml Type: String -Parameter Sets: (All) +Parameter Sets: ByKeyName Aliases: KeyName Required: True @@ -85,7 +114,7 @@ Specifies the name of the key vault that contains the key to back up. ```yaml Type: String -Parameter Sets: (All) +Parameter Sets: ByKeyName Aliases: Required: True @@ -133,6 +162,9 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## OUTPUTS +### String +The cmdlet returns the path of the output file containing the backup of the key. + ## NOTES ## RELATED LINKS diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/help/Backup-AzureKeyVaultSecret.md b/src/ResourceManager/KeyVault/Commands.KeyVault/help/Backup-AzureKeyVaultSecret.md new file mode 100644 index 000000000000..a596346c138a --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/help/Backup-AzureKeyVaultSecret.md @@ -0,0 +1,193 @@ +--- +external help file: Microsoft.Azure.Commands.KeyVault.dll-Help.xml +ms.assetid: 80AAA327-77C6-4372-9461-FFED5A15E678 +online version: http://go.microsoft.com/fwlink/?LinkId=690296 +schema: 2.0.0 +--- + +# Backup-AzureKeyVaultSecret + +## SYNOPSIS +Backs up a secret in a key vault. + +## SYNTAX + +### BySecretName +``` +Backup-AzureKeyVaultSecret [-VaultName] [-Name] [[-OutputFile] ] [-Force] [-WhatIf] + [-Confirm] [] +``` + +### BySecret +``` +Backup-AzureKeyVaultSecret -Secret [[-OutputFile] ] [-Force] [-WhatIf] [-Confirm] + [] +``` + +## DESCRIPTION +The **Backup-AzureKeyVaultSecret** cmdlet backs up a specified secret in a key vault by downloading it and storing it in a file. +If there are multiple versions of the secret, all versions are included in the backup. +Because the downloaded content is encrypted, it cannot be used outside of Azure Key Vault. +You can restore a backed-up secret to any key vault in the subscription that it was backed up from. + +Typical reasons to use this cmdlet are: + +- You want to escrow a copy of your secret, so that you have an offline copy in case you accidentally delete your secret in your key vault. +- You added a secret to a key vault and now want to clone the secret into a different Azure region, so that you can use it from all instances of your distributed application. Use the Backup-AzureKeyVaultSecret cmdlet to retrieve the secret in encrypted format and then use the Restore-AzureKeyVaultSecret cmdlet and specify a key vault in the second region. (Note that the regions must belong to the same geography.) + +## EXAMPLES + +### Example 1: Back up a secret with an automatically generated file name +``` +PS C:\>Backup-AzureKeyVaultSecret -VaultName 'MyKeyVault' -Name 'MySecret' +``` + +This command retrieves the secret named MySecret from the key vault named MyKeyVault and saves a backup of that secret to a file that is automatically named for you, and displays the file name. + +### Example 2: Back up a secret to a specified file name, overwriting the existing file without prompting +``` +PS C:\>Backup-AzureKeyVaultSecret -VaultName 'MyKeyVault' -Name 'MySecret' -OutputFile 'C:\Backup.blob' -Force +``` + +This command retrieves the secret named MySecret from the key vaultnamed MyKeyVault and saves a backup of that secret to a file named Backup.blob. + +### Example 3: Back up a secret previously retrieved to a specified file name +``` +PS C:\>$secret = Get-AzureKeyVaultSecret -VaultName 'MyKeyVault' -Name 'MySecret' +PS C:\>Backup-AzureKeyVaultSecret -Secret $secret -OutputFile 'C:\Backup.blob' +``` + +This command uses the $secret object's vault name and name to retrieves the secret and saves its backup to a file named Backup.blob. + +## PARAMETERS + +### -Force +Prompts you for confirmation before overwriting the output file, if that exists. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: False +Accept pipeline input: True (ByPropertyName) +Accept wildcard characters: False +``` + +### -Name +Specifies the name of the secret to back up. + +```yaml +Type: String +Parameter Sets: BySecretName +Aliases: SecretName + +Required: True +Position: 2 +Default value: None +Accept pipeline input: True (ByPropertyName) +Accept wildcard characters: False +``` + +### -OutputFile +Specifies the output file in which the backup blob is stored. +If you do not specify this parameter, this cmdlet generates a file name for you. +If you specify the name of an existing output file, the operation will not complete and returns an error message that the backup file already exists. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: 3 +Default value: None +Accept pipeline input: True (ByPropertyName) +Accept wildcard characters: False +``` + +### -Secret +Specifies the object whose name and vault should be used for the backup operation. + +```yaml +Type: Secret +Parameter Sets: BySecret +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: True (ByPropertyName) +Accept wildcard characters: False +``` + +### -VaultName +Specifies the name of the key vault that contains the secret to back up. + +```yaml +Type: String +Parameter Sets: BySecretName +Aliases: + +Required: True +Position: 1 +Default value: None +Accept pipeline input: True (ByPropertyName) +Accept wildcard characters: False +``` + +### -Confirm +Prompts you for confirmation before running the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: cf + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -WhatIf +Shows what would happen if the cmdlet runs. +The cmdlet is not run. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: wi + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + +### CommonParameters +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +## OUTPUTS + +### String +The cmdlet returns the path of the output file containing the backup of the key. + +## NOTES + +## RELATED LINKS + +[Set-AzureKeyVaultSecret](./Set-AzureKeyVaultSecret.md) + +[Get-AzureKeyVaultSecret](./Get-AzureKeyVaultSecret.md) + +[Remove-AzureKeyVaultSecret](./Remove-AzureKeyVaultSecret.md) + +[Restore-AzureKeyVaultSecret](./Restore-AzureKeyVaultSecret.md) + diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/help/Restore-AzureKeyVaultSecret.md b/src/ResourceManager/KeyVault/Commands.KeyVault/help/Restore-AzureKeyVaultSecret.md new file mode 100644 index 000000000000..649180686a09 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/help/Restore-AzureKeyVaultSecret.md @@ -0,0 +1,120 @@ +--- +external help file: Microsoft.Azure.Commands.KeyVault.dll-Help.xml +ms.assetid: 70DB088D-4AF5-406B-8D66-118A0F766041 +online version: http://go.microsoft.com/fwlink/?LinkId=690301 +schema: 2.0.0 +--- + +# Restore-AzureKeyVaultSecret + +## SYNOPSIS +Creates a secret in a key vault from a backed-up secret. + +## SYNTAX + +``` +Restore-AzureKeyVaultSecret [-VaultName] [-InputFile] [-WhatIf] [-Confirm] + [] +``` + +## DESCRIPTION +The **Restore-AzureKeyVaultSecret** cmdlet creates a secret in the specified key vault. +This secret is a replica of the backed-up secret in the input file and has the same name as the original secret. +If the key vault already has a secret by the same name, this cmdlet fails instead of overwriting the original secret. +If the backup contains multiple versions of a secret, all versions are restored. + +The key vault that you restore the secret into can be different from the key vault that you backed up the secret from. +However, the key vault must use the same subscription and be in an Azure region in the same geography (for example, North America). +See the Microsoft Azure Trust Center (https://azure.microsoft.com/support/trust-center/) for the mapping of Azure regions to geographies. + +## EXAMPLES + +### Example 1: Restore a backed-up secret +``` +PS C:\>Restore-AzureKeyVaultSecret -VaultName 'MyKeyVault' -InputFile "C:\Backup.blob" +``` + +This command restores a secret, including all of its versions, from the backup file named Backup.blob into the key vault named MyKeyVault. + +## PARAMETERS + +### -InputFile +Specifies the input file that contains the backup of the secret to restore. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: True +Position: 2 +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -VaultName +Specifies the name of the key vault into which to restore the secret. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: True +Position: 1 +Default value: None +Accept pipeline input: True (ByPropertyName) +Accept wildcard characters: False +``` + +### -Confirm +Prompts you for confirmation before running the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: cf + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -WhatIf +Shows what would happen if the cmdlet runs. +The cmdlet is not run. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: wi + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + +### CommonParameters +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +## OUTPUTS + +## NOTES + +## RELATED LINKS + +[Set-AzureKeyVaultSecret](./Set-AzureKeyVaultSecret.md) + +[Backup-AzureKeyVaultSecret](./Backup-AzureKeyVaultSecret.md) + +[Get-AzureKeyVaultSecret](./Get-AzureKeyVaultSecret.md) + +[Remove-AzureKeyVaultSecret](./Remove-AzureKeyVaultSecret.md) + From 4ff54bc8beff8642373c2f5c7797910660e08f9b Mon Sep 17 00:00:00 2001 From: Dragos Avadanei Date: Tue, 2 May 2017 11:50:12 -0700 Subject: [PATCH 2/4] updating change and breaking-change logs setting default parameters for Backup commands --- src/ResourceManager/KeyVault/ChangeLog.md | 10 ++++- .../Commands/BackupAzureKeyVaultKey.cs | 3 +- .../Commands/BackupAzureKeyVaultSecret.cs | 1 + .../upcoming-breaking-changes.md | 37 ++++++++++++++++++- 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/ResourceManager/KeyVault/ChangeLog.md b/src/ResourceManager/KeyVault/ChangeLog.md index d0336b9aeead..c3bd1f9dce86 100644 --- a/src/ResourceManager/KeyVault/ChangeLog.md +++ b/src/ResourceManager/KeyVault/ChangeLog.md @@ -18,7 +18,15 @@ - Additional information about change #1 --> ## Current Release - +* Adding backup/restore support for KeyVault secrets + - Secrets can be backed up and restored, matching the functionality currently supported for Keys + +* Backup cmdlets for Keys and Secrets now accept a corresponding object as an input parameter + - The caller may chain retrieval and backup operations: Get-AzureKeyVaultKey -VaultName myVault -Name myKey | Backup-AzureKeyVaultKey + +* Backup cmdlets now support a -Force switch to overwrite an existing file + - Note that attempting to overwrite an existing file will no longer throw, and will instead prompt the user for a choice on how to proceed. + ## Version 2.8.0 ## Version 2.7.0 diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultKey.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultKey.cs index 0d776900eaf3..8233c4ff1135 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultKey.cs +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultKey.cs @@ -27,7 +27,8 @@ namespace Microsoft.Azure.Commands.KeyVault /// The cmdlet returns the path of the newly created backup file. /// [Cmdlet(VerbsData.Backup, "AzureKeyVaultKey", - SupportsShouldProcess = true, + SupportsShouldProcess = true, + DefaultParameterSetName = ByKeyNameParameterSet, HelpUri = Constants.KeyVaultHelpUri)] [OutputType(typeof(String))] public class BackupAzureKeyVaultKey : KeyVaultCmdletBase diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultSecret.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultSecret.cs index 8c510f19fb59..224c1272ec1e 100644 --- a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultSecret.cs +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/BackupAzureKeyVaultSecret.cs @@ -28,6 +28,7 @@ namespace Microsoft.Azure.Commands.KeyVault /// [Cmdlet( VerbsData.Backup, "AzureKeyVaultSecret", SupportsShouldProcess = true, + DefaultParameterSetName = BySecretNameParameterSet, HelpUri = Constants.KeyVaultHelpUri )] [OutputType( typeof( String ) )] public class BackupAzureKeyVaultSecret : KeyVaultCmdletBase diff --git a/src/ResourceManager/KeyVault/documentation/upcoming-breaking-changes.md b/src/ResourceManager/KeyVault/documentation/upcoming-breaking-changes.md index e01c405de7a3..09588f706419 100644 --- a/src/ResourceManager/KeyVault/documentation/upcoming-breaking-changes.md +++ b/src/ResourceManager/KeyVault/documentation/upcoming-breaking-changes.md @@ -25,4 +25,39 @@ https://github.com/Azure/azure-powershell/blob/dev/documentation/breaking-changes/breaking-change-template.md --> -# Upcoming Breaking Changes \ No newline at end of file +# Upcoming Breaking Changes + +## Release 3.0.0 + + The following cmdlets were affected this release: + + **Backup-AzureKeyVaultKey** + - The cmdlet now accepts a Key object as input + - The cmdlet now accepts a -Force switch to overwrite an existing file + - The cmdlet will no longer throw on attempting to overwrite an existing file without the Force parameter; instead, the + cmdlet will prompt the user to confirm whether it should proceed with overwriting, suspend or abandon the execution. + + ```powershell + # Old + + $key = Add-AzureKeyVaultKey -VaultName myVault -Name myKey -Destination Software + $backupFile = Backup-AzureKeyVaultKey -VaultName $key.VaultName -Name $keyName -OutputFile .\keybackup.file + + Backup-AzureKeyVaultKey -VaultName $key.VaultName -Name $key.Name -OutputFile .\keybackup.file (will throw) + + # New + + # The second Backup call will now yield: + #Overwrite File ? + #Overwrite existing file at '.\keybackup.file' ? + #[Y] Yes [N] No [S] Suspend [?] Help (default is "Y"): + + # The second Backup call can be attempted as: + + Backup-AzureKeyVaultKey -VaultName $key.VaultName -Name $key.Name -OutputFile .\keybackup.file -Force (will overwrite, no prompt) + + or + + Backup-AzureKeyVaultKey -Key $key -OutputFile .\keybackup.file -Force (will overwrite, no prompt) + + ``` From 01a278e4dc3c721824608e9ddaa9c294bf40d61f Mon Sep 17 00:00:00 2001 From: Dragos Avadanei Date: Tue, 2 May 2017 14:50:31 -0700 Subject: [PATCH 3/4] adding suppression for breaking change analysis --- tools/StaticAnalysis/Exceptions/BreakingChangeIssues.csv | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/StaticAnalysis/Exceptions/BreakingChangeIssues.csv b/tools/StaticAnalysis/Exceptions/BreakingChangeIssues.csv index c3fd37d93c95..43be8fab0376 100644 --- a/tools/StaticAnalysis/Exceptions/BreakingChangeIssues.csv +++ b/tools/StaticAnalysis/Exceptions/BreakingChangeIssues.csv @@ -111,3 +111,5 @@ "Microsoft.Azure.Commands.MachineLearning.dll","Microsoft.Azure.Commands.MachineLearning.RemoveAzureMLWebService","Remove-AzureRmMlWebService","0","3000","The type of property 'LocationInfo' of type 'AssetItem' has changed from 'Microsoft.Azure.Management.MachineLearning.WebServices.Models.AssetLocation' to 'Microsoft.Azure.Management.MachineLearning.WebServices.Models.BlobLocation'.","Change the type of property 'LocationInfo' back to 'Microsoft.Azure.Management.MachineLearning.WebServices.Models.AssetLocation'." "Microsoft.Azure.Commands.MachineLearning.dll","Microsoft.Azure.Commands.MachineLearning.RemoveAzureMLWebService","Remove-AzureRmMlWebService","0","3040","The generic type argument for 'property Parameters' has been changed from 'System.String' to 'Microsoft.Azure.Management.MachineLearning.WebServices.Models.WebServiceParameter'.","Change the generic type argument for 'property Parameters' back to 'System.String'." "Microsoft.Azure.Commands.MachineLearning.dll","Microsoft.Azure.Commands.MachineLearning.UpdateAzureMLWebService","Update-AzureRmMlWebService","0","3040","The generic type argument for 'property Parameters' has been changed from 'System.String' to 'Microsoft.Azure.Management.MachineLearning.WebServices.Models.WebServiceParameter'.","Change the generic type argument for 'property Parameters' back to 'System.String'." +"Microsoft.Azure.Commands.KeyVault.dll","Microsoft.Azure.Commands.KeyVault.BackupAzureKeyVaultKey","Backup-AzureKeyVaultKey","0","2100","The parameter 'VaultName' in cmdlet 'Backup-AzureKeyVaultKey' is no longer in the parameter set '__AllParameterSets'.","Add parameter 'VaultName' back to the parameter set '__AllParameterSets'." +"Microsoft.Azure.Commands.KeyVault.dll","Microsoft.Azure.Commands.KeyVault.BackupAzureKeyVaultKey","Backup-AzureKeyVaultKey","0","2100","The parameter 'Name' in cmdlet 'Backup-AzureKeyVaultKey' is no longer in the parameter set '__AllParameterSets'.","Add parameter 'Name' back to the parameter set '__AllParameterSets'." From 2c2e2331e9d8ea338718d015562cca0a2b526bad Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Tue, 2 May 2017 16:35:09 -0700 Subject: [PATCH 4/4] Updating braking change suppressions Removing duplicate value and extra lines --- tools/StaticAnalysis/Exceptions/BreakingChangeIssues.csv | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/StaticAnalysis/Exceptions/BreakingChangeIssues.csv b/tools/StaticAnalysis/Exceptions/BreakingChangeIssues.csv index 4a2530f49873..f8c7b93923d7 100644 --- a/tools/StaticAnalysis/Exceptions/BreakingChangeIssues.csv +++ b/tools/StaticAnalysis/Exceptions/BreakingChangeIssues.csv @@ -117,5 +117,3 @@ "Microsoft.Azure.Commands.MachineLearning.dll","Microsoft.Azure.Commands.MachineLearning.UpdateAzureMLWebService","Update-AzureRmMlWebService","0","3040","The generic type argument for 'property Parameters' has been changed from 'System.String' to 'Microsoft.Azure.Management.MachineLearning.WebServices.Models.WebServiceParameter'.","Change the generic type argument for 'property Parameters' back to 'System.String'." "Microsoft.Azure.Commands.KeyVault.dll","Microsoft.Azure.Commands.KeyVault.BackupAzureKeyVaultKey","Backup-AzureKeyVaultKey","0","2100","The parameter 'VaultName' in cmdlet 'Backup-AzureKeyVaultKey' is no longer in the parameter set '__AllParameterSets'.","Add parameter 'VaultName' back to the parameter set '__AllParameterSets'." "Microsoft.Azure.Commands.KeyVault.dll","Microsoft.Azure.Commands.KeyVault.BackupAzureKeyVaultKey","Backup-AzureKeyVaultKey","0","2100","The parameter 'Name' in cmdlet 'Backup-AzureKeyVaultKey' is no longer in the parameter set '__AllParameterSets'.","Add parameter 'Name' back to the parameter set '__AllParameterSets'." -"Microsoft.Azure.Commands.MachineLearning.dll","Microsoft.Azure.Commands.MachineLearning.UpdateAzureMLWebService","Update-AzureRmMlWebService","0","3040","The generic type argument for 'property Parameters' has been changed from 'System.String' to 'Microsoft.Azure.Management.MachineLearning.WebServices.Models.WebServiceParameter'.","Change the generic type argument for 'property Parameters' back to 'System.String'." -