Skip to content

Commit 3512e9a

Browse files
authored
selective restore key for a managed hsm backup (#13627)
1 parent ec42120 commit 3512e9a

File tree

11 files changed

+116
-25
lines changed

11 files changed

+116
-25
lines changed

src/KeyVault/KeyVault.Test/PesterTests/ManagedHsmDatePlaneTests.Tests.ps1

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ $sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
44

55
. $PSScriptRoot/ManagedHsmDatePlaneTests.ps1
66
# ImportModules
7-
$hsmName = 'yeminghsm02'
7+
$hsmName = 'bezmhsm'
88
$signInName = '[email protected]'
9-
$storageAccount = 'yemingsa01'
10-
$containerName = 'hsmbackup'
11-
$sasToken = ConvertTo-SecureString -AsPlainText -Force 'insert sas token'
9+
$storageAccount = 'bezstorageaccount'
10+
$containerName = 'backup'
11+
$keyName = 'test'
12+
# $sasToken = ConvertTo-SecureString -AsPlainText -Force 'insert sas token'
1213
$certs = "D:\sd1.cer", "D:\sd2.cer", "D:\sd3.cer" # for security domain
1314
$certsKeys = @{PublicKey = "D:\sd1.cer"; PrivateKey = "D:\sd1.key" }, @{PublicKey = "D:\sd2.cer"; PrivateKey = "D:\sd2.key" }, @{PublicKey = "D:\sd3.cer"; PrivateKey = "D:\sd3.key" }
1415

@@ -170,15 +171,24 @@ Describe "BackupAndRestoreAzManagedHsmKey" {
170171
Describe "BackupAndRestoreAzManagedHsm" {
171172
$script:backupUri = ''
172173
$containerUri = "https://$storageAccount.blob.core.windows.net/$containerName"
173-
174174
It "Backup then restore a managed HSM" {
175175
$script:backupUri = Backup-AzKeyVault -HsmName $hsmName -StorageContainerUri $containerUri -SasToken $sasToken
176176
$script:backupUri | Should -Not -Be $null
177177
}
178178

179+
It "Selective restore a managed HSM"{
180+
$script:backupUri = [System.Uri]::new($script:backupUri)
181+
$backupFolder = $script:backupUri.Segments[$script:backupUri.Segments.Length - 1]
182+
$restoreResult = Restore-AzKeyVault -HsmName $hsmName -KeyName $keyName -StorageContainerUri $containerUri -BackupFolder $backupFolder -SasToken $sasToken -PassThru
183+
$restoreResult | Should -Be $True
184+
}
185+
179186
It "Restore a managed HSM" {
180187
$script:backupUri = [System.Uri]::new($script:backupUri)
181188
$backupFolder = $script:backupUri.Segments[$script:backupUri.Segments.Length - 1]
189+
# Clean hsm
190+
Get-AzKeyVaultKey -HsmName $hsmName | Remove-AzKeyVaultKey -Force
191+
Get-AzKeyVaultKey -HsmName $hsmName -InRemovedState| Remove-AzKeyVaultKey -InRemovedState -Force
182192
$restoreResult = Restore-AzKeyVault -HsmName $hsmName -StorageContainerUri $containerUri -BackupFolder $backupFolder -SasToken $sasToken -PassThru
183193
$restoreResult | Should -Be $True
184194
}

src/KeyVault/KeyVault/ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
- Additional information about change #1
1919
-->
2020
## Upcoming Release
21+
* Supported selective restore a key from a managed HSM full backup [#13526]
2122
* Added missing return objects of `Get-Secret` in SecretManagement module
2223

2324
## Version 3.2.0

src/KeyVault/KeyVault/Commands/FullBackupRestore/FullBackupRestoreCmdletBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ public abstract class FullBackupRestoreCmdletBase : KeyVaultCmdletBase
4242
[Parameter(Mandatory = true, HelpMessage = "The shared access signature (SAS) token to authenticate the storage account.")]
4343
public SecureString SasToken { get; set; }
4444

45-
[Parameter(ParameterSetName = InputObjectStorageUri, Mandatory = true, HelpMessage = "Managed HSM object")]
46-
[Parameter(ParameterSetName = InputObjectStorageName, Mandatory = true, HelpMessage = "Managed HSM object")]
45+
[Parameter(ParameterSetName = InputObjectStorageUri, Mandatory = true, ValueFromPipeline = true, HelpMessage = "Managed HSM object")]
46+
[Parameter(ParameterSetName = InputObjectStorageName, Mandatory = true, ValueFromPipeline = true, HelpMessage = "Managed HSM object")]
4747
public PSManagedHsm HsmObject { get; set; }
4848

4949
public override void ExecuteCmdlet()

src/KeyVault/KeyVault/Commands/FullBackupRestore/RestoreAzureManagedHsm.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ public class RestoreAzureManagedHsm : FullBackupRestoreCmdletBase
1414
[Parameter(Mandatory = true, HelpMessage = "Folder name of the backup, e.g. 'mhsm-*-2020101309020403'.\nIt can also be nested such as 'backups/mhsm-*-2020101309020403'.")]
1515
public string BackupFolder { get; set; }
1616

17+
[Parameter(Mandatory = false, HelpMessage = "Key name to restore.")]
18+
public string KeyName { get; set; }
19+
1720
[Parameter(Mandatory = false, HelpMessage = "Return true when the HSM is restored.")]
1821
public SwitchParameter PassThru { get; set; }
1922

@@ -23,14 +26,24 @@ public override void DoExecuteCmdlet()
2326
string.Format(Resources.DoFullRestore, StorageContainerUri),
2427
HsmName, () =>
2528
{
29+
var errorMsg = string.Format(Resources.FullRestoreFailed, HsmName);
2630
try
2731
{
28-
Track2DataClient.RestoreHsm(HsmName, StorageContainerUri, SasToken.ConvertToString(), BackupFolder);
32+
if(KeyName == null)
33+
{
34+
Track2DataClient.RestoreHsm(HsmName, StorageContainerUri, SasToken.ConvertToString(), BackupFolder);
35+
}
36+
else
37+
{
38+
Track2DataClient.SelectiveRestoreHsm(HsmName, KeyName,StorageContainerUri, SasToken.ConvertToString(), BackupFolder);
39+
errorMsg = string.Format(Resources.SelectiveRestoreFailed, KeyName, HsmName);
40+
}
2941
}
3042
catch (Exception ex)
3143
{
32-
throw new Exception(string.Format(Resources.FullRestoreFailed, HsmName), ex);
44+
throw new Exception(errorMsg, ex);
3345
}
46+
3447
if (PassThru)
3548
{
3649
WriteObject(true);

src/KeyVault/KeyVault/Models/IKeyVaultDataServiceClient.cs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ namespace Microsoft.Azure.Commands.KeyVault.Models
2525
{
2626
public interface IKeyVaultDataServiceClient
2727
{
28+
#region Key actions
2829
PSKeyVaultKey CreateKey(string vaultName, string keyName, PSKeyVaultKeyAttributes keyAttributes, int? size, string curveName);
30+
2931
PSKeyVaultKey CreateManagedHsmKey(string managedHsmName, string keyName, PSKeyVaultKeyAttributes keyAttributes, int? size, string curveName);
3032

3133
PSKeyVaultKey ImportKey(string vaultName, string keyName, PSKeyVaultKeyAttributes keyAttributes, JsonWebKey webKey, bool? importToHsm);
@@ -68,6 +70,16 @@ public interface IKeyVaultDataServiceClient
6870

6971
PSKeyVaultKey RecoverManagedHsmKey(string managedHsmName, string keyName);
7072

73+
string BackupKey(string vaultName, string keyName, string outputBlobPath);
74+
75+
string BackupManagedHsmKey(string managedHsmName, string keyName, string outputBlobPath);
76+
77+
PSKeyVaultKey RestoreKey(string vaultName, string inputBlobPath);
78+
79+
PSKeyVaultKey RestoreManagedHsmKey(string managedHsmName, string inputBlobPath);
80+
#endregion
81+
82+
#region Secret actions
7183
PSKeyVaultSecret SetSecret(string vaultName, string secretName, SecureString secretValue, PSKeyVaultSecretAttributes secretAttributes);
7284

7385
PSKeyVaultSecret UpdateSecret(string vaultName, string secretName, string secretVersion, PSKeyVaultSecretAttributes secretAttributes);
@@ -88,17 +100,10 @@ public interface IKeyVaultDataServiceClient
88100

89101
PSKeyVaultSecret RecoverSecret(string vaultName, string secretName);
90102

91-
string BackupKey(string vaultName, string keyName, string outputBlobPath);
92-
93-
string BackupManagedHsmKey(string managedHsmName, string keyName, string outputBlobPath);
94-
95-
PSKeyVaultKey RestoreKey(string vaultName, string inputBlobPath);
96-
97-
PSKeyVaultKey RestoreManagedHsmKey(string managedHsmName, string inputBlobPath);
98-
99103
string BackupSecret(string vaultName, string secretName, string outputBlobPath);
100104

101105
PSKeyVaultSecret RestoreSecret(string vaultName, string inputBlobPath);
106+
#endregion
102107

103108
#region Certificate actions
104109

@@ -198,7 +203,10 @@ public interface IKeyVaultDataServiceClient
198203

199204
#region Full backup restore
200205
Uri BackupHsm(string hsmName, Uri blobStorageUri, string sasToken);
206+
201207
void RestoreHsm(string hsmName, Uri backupLocation, string sasToken, string backupFolder);
208+
209+
void SelectiveRestoreHsm(string hsmName, string keyName, Uri backupLocation, string sasToken, string backupFolder);
202210
#endregion
203211

204212
#region RBAC

src/KeyVault/KeyVault/Models/KeyVaultDataServiceClient.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2019,6 +2019,7 @@ public PSKeyVaultKey CreateManagedHsmKey(string managedHsmName, string keyName,
20192019
throw new NotImplementedException("Creating keys on managed HSM is only possible in track 2 SDK.");
20202020
}
20212021

2022+
#region Full backup restore
20222023
public Uri BackupHsm(string hsmName, Uri blobStorageUri, string sasToken)
20232024
{
20242025
throw new NotImplementedException();
@@ -2029,6 +2030,12 @@ public void RestoreHsm(string hsmName, Uri blobStorageUri, string sasToken, stri
20292030
throw new NotImplementedException();
20302031
}
20312032

2033+
public void SelectiveRestoreHsm(string hsmName, string keyName, Uri backupLocation, string sasToken, string backupFolder)
2034+
{
2035+
throw new NotImplementedException();
2036+
}
2037+
#endregion
2038+
20322039
public PSKeyVaultRoleDefinition[] GetHsmRoleDefinitions(string name, string scope)
20332040
{
20342041
throw new NotImplementedException();
@@ -2103,6 +2110,8 @@ public void PurgeManagedHsmKey(string managedHsmName, string keyName)
21032110
throw new NotImplementedException("Purging deleted keys on managed HSM is only possible in track 2 SDK.");
21042111
}
21052112

2113+
2114+
21062115
private VaultUriHelper vaultUriHelper;
21072116
private KeyVaultClient keyVaultClient;
21082117
}

src/KeyVault/KeyVault/Properties/Resources.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/KeyVault/KeyVault/Properties/Resources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,4 +582,7 @@ You can find the object ID using Azure Active Directory Module for Windows Power
582582
<data name="UpdateHsmShouldProcessMessage" xml:space="preserve">
583583
<value>Updating managed HSM '{0}' in resource group '{1}'.</value>
584584
</data>
585+
<data name="SelectiveRestoreFailed" xml:space="preserve">
586+
<value>Failed to selective restore key {0} of managed HSM {1}.</value>
587+
</data>
585588
</root>

src/KeyVault/KeyVault/Track2Models/Track2HsmClient.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,20 @@ public void RestoreHsm(string hsmName, Uri backupLocation, string sasToken, stri
187187
throw;
188188
}
189189
}
190+
191+
public void SelectiveRestoreHsm(string hsmName, string keyName, Uri backupLocation, string sasToken, string backupFolder)
192+
{
193+
var client = CreateBackupClient(hsmName);
194+
try
195+
{
196+
client.StartSelectiveRestore(keyName, backupLocation, sasToken, backupFolder)
197+
.WaitForCompletionAsync().ConfigureAwait(false).GetAwaiter().GetResult();
198+
}
199+
catch
200+
{
201+
throw;
202+
}
203+
}
190204

191205
public PSKeyVaultRoleDefinition[] GetHsmRoleDefinitions(string hsmName, string scope)
192206
{

src/KeyVault/KeyVault/Track2Models/Track2KeyVaultDataServiceClient.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ public PSKeyVaultSecret UpdateSecret(string vaultName, string secretName, string
388388
throw new NotImplementedException();
389389
}
390390

391+
#region Full backup restore
391392
public Uri BackupHsm(string hsmName, Uri blobStorageUri, string sasToken)
392393
{
393394
return HsmClient.BackupHsm(hsmName, blobStorageUri, sasToken);
@@ -398,6 +399,12 @@ public void RestoreHsm(string hsmName, Uri backupLocation, string sasToken, stri
398399
HsmClient.RestoreHsm(hsmName, backupLocation, sasToken, backupFolder);
399400
}
400401

402+
public void SelectiveRestoreHsm(string hsmName, string keyName, Uri backupLocation, string sasToken, string backupFolder)
403+
{
404+
HsmClient.SelectiveRestoreHsm(hsmName, keyName, backupLocation, sasToken, backupFolder);
405+
}
406+
#endregion
407+
401408
public PSKeyVaultRoleDefinition[] GetHsmRoleDefinitions(string hsmName, string scope)
402409
{
403410
return HsmClient.GetHsmRoleDefinitions(hsmName, scope);

src/KeyVault/KeyVault/help/Restore-AzKeyVault.md

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,28 @@ Fully restores a managed HSM from backup.
1414

1515
### InteractiveStorageName (Default)
1616
```
17-
Restore-AzKeyVault -BackupFolder <String> [-PassThru] [-HsmName] <String> -StorageAccountName <String>
18-
-StorageContainerName <String> -SasToken <SecureString> [-DefaultProfile <IAzureContextContainer>] [-WhatIf]
19-
[-Confirm] [<CommonParameters>]
17+
Restore-AzKeyVault -BackupFolder <String> [-KeyName <String>] [-PassThru] [-HsmName] <String>
18+
-StorageAccountName <String> -StorageContainerName <String> -SasToken <SecureString>
19+
[-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm] [<CommonParameters>]
2020
```
2121

2222
### InteractiveStorageUri
2323
```
24-
Restore-AzKeyVault -BackupFolder <String> [-PassThru] [-HsmName] <String> -StorageContainerUri <Uri>
25-
-SasToken <SecureString> [-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm] [<CommonParameters>]
24+
Restore-AzKeyVault -BackupFolder <String> [-KeyName <String>] [-PassThru] [-HsmName] <String>
25+
-StorageContainerUri <Uri> -SasToken <SecureString> [-DefaultProfile <IAzureContextContainer>] [-WhatIf]
26+
[-Confirm] [<CommonParameters>]
2627
```
2728

2829
### InputObjectStorageUri
2930
```
30-
Restore-AzKeyVault -BackupFolder <String> [-PassThru] -StorageContainerUri <Uri> -SasToken <SecureString>
31-
-HsmObject <PSManagedHsm> [-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm] [<CommonParameters>]
31+
Restore-AzKeyVault -BackupFolder <String> [-KeyName <String>] [-PassThru] -StorageContainerUri <Uri>
32+
-SasToken <SecureString> -HsmObject <PSManagedHsm> [-DefaultProfile <IAzureContextContainer>] [-WhatIf]
33+
[-Confirm] [<CommonParameters>]
3234
```
3335

3436
### InputObjectStorageName
3537
```
36-
Restore-AzKeyVault -BackupFolder <String> [-PassThru] -StorageAccountName <String>
38+
Restore-AzKeyVault -BackupFolder <String> [-KeyName <String>] [-PassThru] -StorageAccountName <String>
3739
-StorageContainerName <String> -SasToken <SecureString> -HsmObject <PSManagedHsm>
3840
[-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm] [<CommonParameters>]
3941
```
@@ -112,6 +114,21 @@ Aliases:
112114
Required: True
113115
Position: Named
114116
Default value: None
117+
Accept pipeline input: True (ByValue)
118+
Accept wildcard characters: False
119+
```
120+
121+
### -KeyName
122+
Key name to restore.
123+
124+
```yaml
125+
Type: System.String
126+
Parameter Sets: (All)
127+
Aliases:
128+
129+
Required: False
130+
Position: Named
131+
Default value: None
115132
Accept pipeline input: False
116133
Accept wildcard characters: False
117134
```

0 commit comments

Comments
 (0)