From 36a9fdffd9138b034cb1157238f7847effad6531 Mon Sep 17 00:00:00 2001 From: Beisi Zhou Date: Wed, 1 Jun 2022 17:58:25 +0800 Subject: [PATCH 1/5] Supported creating/updating key with release policy in a Managed HSM --- .../PesterTests/ManagedHsmDataPlaneTests.ps1 | 4 +- .../PesterTests/MhsmKey.Tests.ps1 | 118 ++++++++++++ .../Resources/releasepolicy.json | 15 ++ src/KeyVault/KeyVault/ChangeLog.md | 1 + .../Commands/Key/AddAzureKeyVaultKey.cs | 138 ++++++++++++-- .../GetAzKeyVaultKeyRotationPolicy.cs | 0 .../InvokeAzKeyVaultKeyRotation.cs | 0 .../SetAzKeyVaultKeyRotationPolicy.cs | 0 .../Commands/Key/UpdateAzureKeyVaultKey.cs | 45 ++++- .../KeyVault/Helpers/UtilityExtensions.cs | 14 ++ src/KeyVault/KeyVault/KeyVault.csproj | 2 +- src/KeyVault/KeyVault/KeyVault.format.ps1xml | 30 ++++ .../Models/{ => Key}/PSDeletedKeyVaultKey.cs | 0 .../PSDeletedKeyVaultKeyIdentityItem.cs | 0 .../KeyVault/Models/Key/PSKeyReleasePolicy.cs | 72 ++++++++ .../Models/{ => Key}/PSKeyRotationPolicy.cs | 6 +- .../Models/{ => Key}/PSKeyVaultKey.cs | 82 ++++----- .../Models/Key/PSKeyVaultKeyAttributes.cs | 169 ++++++++++++++++++ .../{ => Key}/PSKeyVaultKeyIdentityItem.cs | 25 ++- .../Models/PSKeyRotationLifetimeAction.cs | 11 +- .../Models/PSKeyVaultKeyAttributes.cs | 96 ---------- .../KeyVault/Models/VaultUriHelper.cs | 15 ++ .../KeyVault/Properties/Resources.Designer.cs | 27 ++- .../KeyVault/Properties/Resources.resx | 7 +- .../KeyVault/Track2Models/Track2HsmClient.cs | 28 ++- .../Track2Models/Track2VaultClient.cs | 18 +- .../KeyVault/help/Add-AzKeyVaultKey.md | 67 ++++++- 27 files changed, 799 insertions(+), 191 deletions(-) create mode 100644 src/KeyVault/KeyVault.Test/PesterTests/MhsmKey.Tests.ps1 create mode 100644 src/KeyVault/KeyVault.Test/Resources/releasepolicy.json rename src/KeyVault/KeyVault/Commands/Key/{KeyRotationPolicy => KeyRotation}/GetAzKeyVaultKeyRotationPolicy.cs (100%) rename src/KeyVault/KeyVault/Commands/Key/{KeyRotationPolicy => KeyRotation}/InvokeAzKeyVaultKeyRotation.cs (100%) rename src/KeyVault/KeyVault/Commands/Key/{KeyRotationPolicy => KeyRotation}/SetAzKeyVaultKeyRotationPolicy.cs (100%) rename src/KeyVault/KeyVault/Models/{ => Key}/PSDeletedKeyVaultKey.cs (100%) rename src/KeyVault/KeyVault/Models/{ => Key}/PSDeletedKeyVaultKeyIdentityItem.cs (100%) create mode 100644 src/KeyVault/KeyVault/Models/Key/PSKeyReleasePolicy.cs rename src/KeyVault/KeyVault/Models/{ => Key}/PSKeyRotationPolicy.cs (93%) rename src/KeyVault/KeyVault/Models/{ => Key}/PSKeyVaultKey.cs (52%) create mode 100644 src/KeyVault/KeyVault/Models/Key/PSKeyVaultKeyAttributes.cs rename src/KeyVault/KeyVault/Models/{ => Key}/PSKeyVaultKeyIdentityItem.cs (80%) delete mode 100644 src/KeyVault/KeyVault/Models/PSKeyVaultKeyAttributes.cs diff --git a/src/KeyVault/KeyVault.Test/PesterTests/ManagedHsmDataPlaneTests.ps1 b/src/KeyVault/KeyVault.Test/PesterTests/ManagedHsmDataPlaneTests.ps1 index 6f7ab3aad015..48d80be99023 100644 --- a/src/KeyVault/KeyVault.Test/PesterTests/ManagedHsmDataPlaneTests.ps1 +++ b/src/KeyVault/KeyVault.Test/PesterTests/ManagedHsmDataPlaneTests.ps1 @@ -35,6 +35,6 @@ function ImportModules { $psd1Path = Join-Path $PSScriptRoot "../../../../artifacts/Debug/" -Resolve $accountsPsd1 = Join-Path $psd1Path "./Az.Accounts/Az.Accounts.psd1" -Resolve $keyVaultPsd1 = Join-Path $psd1Path "./Az.KeyVault/Az.KeyVault.psd1" -Resolve - Import-Module $accountsPsd1 - Import-Module $keyVaultPsd1 + Import-Module $accountsPsd1 -Force + Import-Module $keyVaultPsd1 -Force } \ No newline at end of file diff --git a/src/KeyVault/KeyVault.Test/PesterTests/MhsmKey.Tests.ps1 b/src/KeyVault/KeyVault.Test/PesterTests/MhsmKey.Tests.ps1 new file mode 100644 index 000000000000..e0e36de77567 --- /dev/null +++ b/src/KeyVault/KeyVault.Test/PesterTests/MhsmKey.Tests.ps1 @@ -0,0 +1,118 @@ + +$hsmName = 'bezmhsm' +. $PSScriptRoot/ManagedHsmDataPlaneTests.ps1 + +function Get-KeyName{ + return GetRandomName "bez-key" +} + + +Describe "Exportable and ReleasePolicyPath shoud show up at the same time"{ + + It "Both Exportable and ReleasePolicyPath don't show up"{ + { + Add-AzKeyVaultKey -HsmName $hsmName -KeyName (Get-KeyName) -KeyType RSA + } | Should -Not -Throw + } + + It "Exportable shows up but ReleasePolicyPath not" -skip { + { + Add-AzKeyVaultKey -HsmName $hsmName -KeyName (Get-KeyName) -KeyType RSA -Exportable + } | Should -Throw + } + + It "ReleasePolicyPath shows up but Exportable not" -skip { + { + Add-AzKeyVaultKey -HsmName $hsmName -KeyName (Get-KeyName) -KeyType RSA -ReleasePolicyPath "$PSScriptRoot\..\Resources\releasepolicy.json" + } | Should -Throw + } + + It "Both ReleasePolicyPath and Exportable show up"{ + $keyName = Get-KeyName + { + Add-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName -KeyType RSA -Exportable -ReleasePolicyPath "$PSScriptRoot\..\Resources\releasepolicy.json" + } | Should -Not -Throw + $key = Get-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName + $key.ReleasePolicy | Should -Not -BeNullOrEmpty + $key.Attributes.Exportable | Should -Be $true + } +} + +Describe "Create secure key"{ + It "Create a key without immutable property and release policy" { + { + Add-AzKeyVaultKey -HsmName $hsmName -KeyName (Get-KeyName) -KeyType RSA + } | Should -Not -Throw + } + + It "Create a key with immutable property but release policy" -skip { + $keyName = Get-KeyName + { + Add-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName -KeyType RSA -Immutable + } | Should -Throw "Please provide release policy when Immutable is present." + } + + It "Create a key with release policy but immutable property" { + $keyName = Get-KeyName + { + Add-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName -KeyType RSA -Exportable -ReleasePolicyPath "$PSScriptRoot\..\Resources\releasepolicy.json" + } | Should -Not -Throw + $key = Get-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName + $key.ReleasePolicy | Should -Not -BeNullOrEmpty + $key.ReleasePolicy.Immutable | Should -Be $false + } + + It "Create a key with both release policy and immutable property" { + $keyName = Get-KeyName + { + Add-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName -KeyType RSA -Exportable -ReleasePolicyPath "$PSScriptRoot\..\Resources\releasepolicy.json" -Immutable + } | Should -Not -Throw + $key = Get-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName + $key.ReleasePolicy | Should -Not -BeNullOrEmpty + $key.ReleasePolicy.Immutable | Should -Be $true + } +} + +Describe "Update secure key"{ + + It "Update a key with immutable property but release policy" -skip { + $keyName = Get-KeyName + Add-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName -KeyType RSA -Exportable -ReleasePolicyPath "$PSScriptRoot\..\Resources\releasepolicy.json" + { Update-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName -Immutable} | Should -Throw "Please provide release policy when Immutable is present." + } + + + It "Update a key with release policy but immutable property" { + $keyName = Get-KeyName + Add-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName -KeyType RSA -Exportable -ReleasePolicyPath "$PSScriptRoot\..\Resources\releasepolicy.json" + { Update-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName -ReleasePolicyPath "$PSScriptRoot\..\Resources\releasepolicy.json"} | Should -Not -Throw + $key = Get-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName + $key.ReleasePolicy | Should -Not -BeNullOrEmpty + $key.ReleasePolicy.Immutable | Should -Be $false + } + + It "Update a key with both release policy and immutable property" { + $keyName = Get-KeyName + Add-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName -KeyType RSA -Exportable -ReleasePolicyPath "$PSScriptRoot\..\Resources\releasepolicy.json" + { Update-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName -ReleasePolicyPath "$PSScriptRoot\..\Resources\releasepolicy.json" -Immutable} | Should -Not -Throw + $updatedKey = Get-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName + $updatedKey.ReleasePolicy | Should -Not -BeNullOrEmpty + $updatedKey.ReleasePolicy.Immutable | Should -Be $true + } + + It "Update an immutable release policy" -skip { + $keyName = Get-KeyName + $key = Add-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName -KeyType RSA -Exportable -ReleasePolicyPath "$PSScriptRoot\..\Resources\releasepolicy.json" -Immutable + $key.ReleasePolicy | Should -Not -BeNullOrEmpty + $key.ReleasePolicy.Immutable | Should -Be $true + { Update-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName -ReleasePolicyPath "$PSScriptRoot\..\Resources\releasepolicy.json" } | Should -Throw "Please provide release policy when Immutable is present." + } + + It "Update a mutable release policy" { + $keyName = Get-KeyName + $key = Add-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName -KeyType RSA -Exportable -ReleasePolicyPath "$PSScriptRoot\..\Resources\releasepolicy.json" + $key.ReleasePolicy | Should -Not -BeNullOrEmpty + $key.ReleasePolicy.Immutable | Should -Be $false + { Update-AzKeyVaultKey -HsmName $hsmName -KeyName $keyName -ReleasePolicyPath "$PSScriptRoot\..\Resources\releasepolicy.json"} | Should -Not -Throw + } +} \ No newline at end of file diff --git a/src/KeyVault/KeyVault.Test/Resources/releasepolicy.json b/src/KeyVault/KeyVault.Test/Resources/releasepolicy.json new file mode 100644 index 000000000000..f7e7e7620214 --- /dev/null +++ b/src/KeyVault/KeyVault.Test/Resources/releasepolicy.json @@ -0,0 +1,15 @@ +{ + "anyOf": [ + { + "authority": "https://sharedeus.eus.attest.azure.net/", + "allOf": [ + { + "claim": "x-ms-sgx-is-debuggable", + "equals": "true" + } + ] + } + ], + "version": "1.0.0" + } + diff --git a/src/KeyVault/KeyVault/ChangeLog.md b/src/KeyVault/KeyVault/ChangeLog.md index 1d431599595f..221fc7497976 100644 --- a/src/KeyVault/KeyVault/ChangeLog.md +++ b/src/KeyVault/KeyVault/ChangeLog.md @@ -18,6 +18,7 @@ - Additional information about change #1 --> ## Upcoming Release +* Supported creating/updating key with release policy in a Managed HSM ## Version 4.5.0 * Added `Rotate` into the list of permissions to keys [#17970] diff --git a/src/KeyVault/KeyVault/Commands/Key/AddAzureKeyVaultKey.cs b/src/KeyVault/KeyVault/Commands/Key/AddAzureKeyVaultKey.cs index ac5016d4dd1a..6dd48356cbda 100644 --- a/src/KeyVault/KeyVault/Commands/Key/AddAzureKeyVaultKey.cs +++ b/src/KeyVault/KeyVault/Commands/Key/AddAzureKeyVaultKey.cs @@ -12,6 +12,7 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using Microsoft.Azure.Commands.Common; using Microsoft.Azure.Commands.Common.Exceptions; using Microsoft.Azure.Commands.KeyVault.Helpers; using Microsoft.Azure.Commands.KeyVault.Models; @@ -19,11 +20,14 @@ using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters; using Microsoft.Azure.KeyVault.WebKey; using Microsoft.Azure.Management.Internal.Resources.Utilities.Models; +using Microsoft.WindowsAzure.Commands.Utilities.Common; + using System; using System.Collections; using System.IO; using System.Linq; using System.Management.Automation; +using System.Net.Http; using System.Security; using Track2Sdk = Azure.Security.KeyVault.Keys; @@ -49,12 +53,15 @@ public class AddAzureKeyVaultKey : KeyVaultCmdletBase private const string InteractiveCreateParameterSet = "InteractiveCreate"; private const string InputObjectCreateParameterSet = "InputObjectCreate"; private const string ResourceIdCreateParameterSet = "ResourceIdCreate"; + private const string InteractiveImportParameterSet = "InteractiveImport"; private const string InputObjectImportParameterSet = "InputObjectImport"; private const string ResourceIdImportParameterSet = "ResourceIdImport"; + private const string HsmInteractiveCreateParameterSet = "HsmInteractiveCreate"; private const string HsmInputObjectCreateParameterSet = "HsmInputObjectCreate"; private const string HsmResourceIdCreateParameterSet = "HsmResourceIdCreate"; + private const string HsmInteractiveImportParameterSet = "HsmInteractiveImport"; private const string HsmInputObjectImportParameterSet = "HsmInputObjectImport"; private const string HsmResourceIdImportParameterSet = "HsmResourceIdImport"; @@ -64,6 +71,12 @@ public class AddAzureKeyVaultKey : KeyVaultCmdletBase #endregion + #region Constants + + private const string DefaultCVMPolicyUrl = "https://cvmprivatepreviewsa.blob.core.windows.net/cvmpublicpreviewcontainer/skr-policy.json"; + + #endregion + #region Input Parameter Definitions /// @@ -314,12 +327,58 @@ public class AddAzureKeyVaultKey : KeyVaultCmdletBase ParameterSetName = ResourceIdImportParameterSet)] [PSArgumentCompleter("P-256", "P-256K", "P-384", "P-521")] public string CurveName { get; set; } + + [Parameter(Mandatory = false, + ParameterSetName = HsmInteractiveCreateParameterSet, + HelpMessage = "Indicates if the private key can be exported.")] + [Parameter(Mandatory = false, + ParameterSetName = HsmInputObjectCreateParameterSet)] + [Parameter(Mandatory = false, + ParameterSetName = HsmResourceIdCreateParameterSet)] + public SwitchParameter Exportable { get; set; } + + [Parameter(Mandatory = false, + ParameterSetName = HsmInteractiveCreateParameterSet, + HelpMessage = "Sets the release policy as immutable state. Once marked immutable, this flag cannot be reset and the policy cannot be changed under any circumstances.")] + [Parameter(Mandatory = false, + ParameterSetName = HsmInputObjectCreateParameterSet)] + [Parameter(Mandatory = false, + ParameterSetName = HsmResourceIdCreateParameterSet)] + public SwitchParameter Immutable { get; set; } + + [Parameter(Mandatory = false, + ParameterSetName = HsmInteractiveCreateParameterSet, + HelpMessage = "A path to a file containing JSON policy definition. The policy rules under which a key can be exported.")] + [Parameter(Mandatory = false, + ParameterSetName = HsmInputObjectCreateParameterSet)] + [Parameter(Mandatory = false, + ParameterSetName = HsmResourceIdCreateParameterSet)] + public string ReleasePolicyPath { get; set; } + + [Parameter(Mandatory = false, + ParameterSetName = HsmInteractiveCreateParameterSet, + HelpMessage = "Specifies to use default policy under which the key can be exported for CVM disk encryption.")] + [Parameter(Mandatory = false, + ParameterSetName = HsmInputObjectCreateParameterSet)] + [Parameter(Mandatory = false, + ParameterSetName = HsmResourceIdCreateParameterSet)] + public SwitchParameter UseDefaultCVMPolicy { get; set; } #endregion + private PSKeyReleasePolicy ReleasePolicy { get; set; } + + protected override void BeginProcessing() + { + // Preprocess relative path + KeyFilePath = this.TryResolvePath(KeyFilePath); + ReleasePolicyPath = this.TryResolvePath(ReleasePolicyPath); + base.BeginProcessing(); + } + public override void ExecuteCmdlet() { + ValidateParameters(); NormalizeKeySourceParameters(); - ValidateKeyExchangeKey(); if (ShouldProcess(Name, Properties.Resources.AddKey)) { PSKeyVaultKey keyBundle; @@ -359,9 +418,37 @@ private void NormalizeKeySourceParameters() var resourceIdentifier = new ResourceIdentifier(ResourceId); HsmName = resourceIdentifier.ResourceName; } + + if (this.UseDefaultCVMPolicy.IsPresent) + { + try + { + using (var client = new HttpClient()) + { + ReleasePolicy = new PSKeyReleasePolicy() + { + PolicyContent = client.GetStringAsync(DefaultCVMPolicyUrl).ConfigureAwait(true).GetAwaiter().GetResult(), + Immutable = this.Immutable.IsPresent + }; + } + } + catch(Exception e) + { + // Swallow exception to fetch default policy + WriteWarning(string.Format(Resources.FetchDefaultCVMPolicyFailed, e.Message)); + } + } + + if(this.IsParameterBound(c => c.ReleasePolicyPath)) + { + ReleasePolicy = new PSKeyReleasePolicy(this.ReleasePolicyPath) + { + Immutable = this.Immutable.IsPresent + }; + } } - private void ValidateKeyExchangeKey() + private void ValidateParameters() { if (KeyOps != null && KeyOps.Contains(Constants.KeyOpsImport)) { @@ -370,6 +457,29 @@ private void ValidateKeyExchangeKey() // When KeyOps is 'import', KeyType MUST be RSA-HSM if (Destination != HsmDestination) { throw new ArgumentException(Resources.KEKMustBeHSM); } } + + if (this.IsParameterBound(c => c.Exportable) && !this.IsParameterBound(c => c.ReleasePolicyPath)) + { + throw new AzPSArgumentException("Exportable keys must have release policy.", nameof(ReleasePolicyPath), ErrorKind.UserError); + } + else if (this.IsParameterBound(c => c.ReleasePolicyPath) && !this.IsParameterBound(c => c.Exportable)) + { + throw new AzPSArgumentException("Non-exportable keys must not have release policy.", nameof(ReleasePolicyPath), ErrorKind.UserError); + } + + if (this.IsParameterBound(c => c.Immutable) && !this.IsParameterBound(c => c.ReleasePolicyPath)) + { + throw new AzPSArgumentException("Please provide release policy when Immutable is present.", nameof(Immutable), ErrorKind.UserError); + } + + // Verify the ReleasePolicyPath whether exists + if(this.IsParameterBound(c => c.ReleasePolicyPath)) + { + if (!File.Exists(ReleasePolicyPath)) + { + throw new AzPSArgumentException(string.Format(Resources.FileNotFound, this.ReleasePolicyPath), nameof(ReleasePolicyPath)); + } + } } private PSKeyVaultKey CreateKeyVaultKey() @@ -407,7 +517,7 @@ private PSKeyVaultKey CreateHsmKey() } else { - WriteWarning("Specifying parameter `Disable`, `Expires`, `NotBefore` and `Tag` is not supported when importing key on Managed HSM. Please use `Update-AzKeyVaultKey` after importing."); + WriteWarning("Specifying parameter `Disable`, `Expires`, `NotBefore`, `Tag`, `Exportable`, `ReleasePolicy` and `Immutable` is not supported when importing key on Managed HSM. Please use `Update-AzKeyVaultKey` after importing."); return this.Track2DataClient.ImportManagedHsmKey( HsmName, Name, CreateTrack2WebKeyFromFile()); @@ -431,13 +541,17 @@ internal PSKeyVaultKeyAttributes CreateKeyAttributes() } } - return new Models.PSKeyVaultKeyAttributes( - !Disable.IsPresent, - Expires, - NotBefore, - KeyType, - KeyOps, - Tag); + return new PSKeyVaultKeyAttributes() + { + Enabled = !this.Disable.IsPresent, + Expires = this.Expires, + NotBefore = this.NotBefore, + KeyType = this.KeyType, + KeyOps = this.KeyOps, + Exportable = this.Exportable.IsPresent ? true as bool? : null, + ReleasePolicy = ReleasePolicy , + Tags = Tag + }; } internal JsonWebKey CreateWebKeyFromFile() @@ -447,7 +561,7 @@ internal JsonWebKey CreateWebKeyFromFile() FileInfo keyFile = new FileInfo(this.GetUnresolvedProviderPathFromPSPath(this.KeyFilePath)); if (!keyFile.Exists) { - throw new FileNotFoundException(string.Format(Resources.KeyFileNotFound, this.KeyFilePath)); + throw new FileNotFoundException(string.Format(Resources.FileNotFound, this.KeyFilePath)); } var converterChain = WebKeyConverterFactory.CreateConverterChain(); @@ -478,7 +592,7 @@ internal Track2Sdk.JsonWebKey CreateTrack2WebKeyFromFile() FileInfo keyFile = new FileInfo(this.GetUnresolvedProviderPathFromPSPath(this.KeyFilePath)); if (!keyFile.Exists) { - throw new FileNotFoundException(string.Format(Resources.KeyFileNotFound, this.KeyFilePath)); + throw new FileNotFoundException(string.Format(Resources.FileNotFound, this.KeyFilePath)); } var converterChain = WebKeyConverterFactory.CreateConverterChain(); diff --git a/src/KeyVault/KeyVault/Commands/Key/KeyRotationPolicy/GetAzKeyVaultKeyRotationPolicy.cs b/src/KeyVault/KeyVault/Commands/Key/KeyRotation/GetAzKeyVaultKeyRotationPolicy.cs similarity index 100% rename from src/KeyVault/KeyVault/Commands/Key/KeyRotationPolicy/GetAzKeyVaultKeyRotationPolicy.cs rename to src/KeyVault/KeyVault/Commands/Key/KeyRotation/GetAzKeyVaultKeyRotationPolicy.cs diff --git a/src/KeyVault/KeyVault/Commands/Key/KeyRotationPolicy/InvokeAzKeyVaultKeyRotation.cs b/src/KeyVault/KeyVault/Commands/Key/KeyRotation/InvokeAzKeyVaultKeyRotation.cs similarity index 100% rename from src/KeyVault/KeyVault/Commands/Key/KeyRotationPolicy/InvokeAzKeyVaultKeyRotation.cs rename to src/KeyVault/KeyVault/Commands/Key/KeyRotation/InvokeAzKeyVaultKeyRotation.cs diff --git a/src/KeyVault/KeyVault/Commands/Key/KeyRotationPolicy/SetAzKeyVaultKeyRotationPolicy.cs b/src/KeyVault/KeyVault/Commands/Key/KeyRotation/SetAzKeyVaultKeyRotationPolicy.cs similarity index 100% rename from src/KeyVault/KeyVault/Commands/Key/KeyRotationPolicy/SetAzKeyVaultKeyRotationPolicy.cs rename to src/KeyVault/KeyVault/Commands/Key/KeyRotation/SetAzKeyVaultKeyRotationPolicy.cs diff --git a/src/KeyVault/KeyVault/Commands/Key/UpdateAzureKeyVaultKey.cs b/src/KeyVault/KeyVault/Commands/Key/UpdateAzureKeyVaultKey.cs index 3bfb6dc10af4..a28f6d776d6a 100644 --- a/src/KeyVault/KeyVault/Commands/Key/UpdateAzureKeyVaultKey.cs +++ b/src/KeyVault/KeyVault/Commands/Key/UpdateAzureKeyVaultKey.cs @@ -12,10 +12,16 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using Microsoft.Azure.Commands.Common; +using Microsoft.Azure.Commands.Common.Exceptions; using Microsoft.Azure.Commands.KeyVault.Models; +using Microsoft.Azure.Commands.KeyVault.Properties; using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters; +using Microsoft.WindowsAzure.Commands.Utilities.Common; + using System; using System.Collections; +using System.IO; using System.Management.Automation; namespace Microsoft.Azure.Commands.KeyVault @@ -120,6 +126,20 @@ public class UpdateAzureKeyVaultKey : KeyVaultCmdletBase HelpMessage = "The operations that can be performed with the key. If not specified, the existing key operations of the key remain unchanged.")] public string[] KeyOps { get; set; } + [Parameter(Mandatory = false, + ParameterSetName = HsmInteractiveParameterSet, + HelpMessage = "Sets the release policy as immutable state. Once marked immutable, this flag cannot be reset and the policy cannot be changed under any circumstances.")] + public SwitchParameter Immutable { get; set; } + + /// + /// A path to a file containing JSON policy definition. The policy rules under which a key can be exported. + /// + [Parameter(Mandatory = false, + ParameterSetName = HsmInteractiveParameterSet, + HelpMessage = "A path to a file containing JSON policy definition. The policy rules under which a key can be exported.")] + public string ReleasePolicyPath { get; set; } + + [Parameter(Mandatory = false, HelpMessage = "A hashtable represents key tags. If not specified, the existings tags of the key remain unchanged.")] [Alias(Constants.TagsAlias)] @@ -134,6 +154,7 @@ public class UpdateAzureKeyVaultKey : KeyVaultCmdletBase public override void ExecuteCmdlet() { NormalizeParameterSets(); + ValidateParameters(); if (ShouldProcess(Name, Properties.Resources.SetKeyAttribute)) { @@ -151,8 +172,15 @@ public override void ExecuteCmdlet() keyBundle = this.Track2DataClient.UpdateManagedHsmKey( HsmName, Name, - Version ?? string.Empty, - new PSKeyVaultKeyAttributes(Enable, Expires, NotBefore, null, KeyOps, Tag)); + Version, + new PSKeyVaultKeyAttributes(Enable, Expires, NotBefore, null, KeyOps, Tag) + { + ReleasePolicy = this.IsParameterBound(c => c.ReleasePolicyPath) && File.Exists(this.ReleasePolicyPath) ? + new PSKeyReleasePolicy(this.ReleasePolicyPath) + { + Immutable = this.Immutable.IsPresent ? (true as bool?) : null + } : null, + }); } if (PassThru) @@ -162,6 +190,19 @@ public override void ExecuteCmdlet() } } + private void ValidateParameters() + { + if (this.IsParameterBound(c => c.Immutable) && !this.IsParameterBound(c => c.ReleasePolicyPath)) + { + throw new AzPSArgumentException("Please provide release policy when Immutable is present.", nameof(Immutable), ErrorKind.UserError); + } + + if (this.IsParameterBound(c => c.ReleasePolicyPath) && !File.Exists(ReleasePolicyPath)) + { + throw new AzPSArgumentException(string.Format(Resources.FileNotFound, this.ReleasePolicyPath), nameof(ReleasePolicyPath)); + } + } + private void NormalizeParameterSets() { if (InputObject != null) diff --git a/src/KeyVault/KeyVault/Helpers/UtilityExtensions.cs b/src/KeyVault/KeyVault/Helpers/UtilityExtensions.cs index 75c28626bf02..9d0c6a94a524 100644 --- a/src/KeyVault/KeyVault/Helpers/UtilityExtensions.cs +++ b/src/KeyVault/KeyVault/Helpers/UtilityExtensions.cs @@ -12,7 +12,12 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using Azure.Security.KeyVault.Keys; + +using Microsoft.Azure.Commands.KeyVault.Models; + using System; +using System.Collections.Generic; using System.Runtime.InteropServices; using System.Security; @@ -33,5 +38,14 @@ public static string ToPlainText(this SecureString secureString) Marshal.FreeBSTR(bstr); } } + + public static PSKeyReleasePolicy ToPSKeyReleasePolicy(this KeyReleasePolicy keyReleasePolicy) + { + if (keyReleasePolicy == null) + { + return null; + } + return new PSKeyReleasePolicy(keyReleasePolicy); + } } } diff --git a/src/KeyVault/KeyVault/KeyVault.csproj b/src/KeyVault/KeyVault/KeyVault.csproj index 398d70cfabbd..3a56c8925fa1 100644 --- a/src/KeyVault/KeyVault/KeyVault.csproj +++ b/src/KeyVault/KeyVault/KeyVault.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/KeyVault/KeyVault/KeyVault.format.ps1xml b/src/KeyVault/KeyVault/KeyVault.format.ps1xml index ea0cabe36b7c..68837e02d45d 100644 --- a/src/KeyVault/KeyVault/KeyVault.format.ps1xml +++ b/src/KeyVault/KeyVault/KeyVault.format.ps1xml @@ -120,6 +120,10 @@ RecoveryLevel + + + ReleasePolicy + TagsTable @@ -779,6 +783,32 @@ + + Microsoft.Azure.Commands.KeyVault.Models.PSKeyReleasePolicy + + Microsoft.Azure.Commands.KeyVault.Models.PSKeyReleasePolicy + + + + + + + + ContentType + + + + PolicyContent + + + + Immutable + + + + + + Microsoft.Azure.Commands.KeyVault.Models.PSKeyVaultSecret diff --git a/src/KeyVault/KeyVault/Models/PSDeletedKeyVaultKey.cs b/src/KeyVault/KeyVault/Models/Key/PSDeletedKeyVaultKey.cs similarity index 100% rename from src/KeyVault/KeyVault/Models/PSDeletedKeyVaultKey.cs rename to src/KeyVault/KeyVault/Models/Key/PSDeletedKeyVaultKey.cs diff --git a/src/KeyVault/KeyVault/Models/PSDeletedKeyVaultKeyIdentityItem.cs b/src/KeyVault/KeyVault/Models/Key/PSDeletedKeyVaultKeyIdentityItem.cs similarity index 100% rename from src/KeyVault/KeyVault/Models/PSDeletedKeyVaultKeyIdentityItem.cs rename to src/KeyVault/KeyVault/Models/Key/PSDeletedKeyVaultKeyIdentityItem.cs diff --git a/src/KeyVault/KeyVault/Models/Key/PSKeyReleasePolicy.cs b/src/KeyVault/KeyVault/Models/Key/PSKeyReleasePolicy.cs new file mode 100644 index 000000000000..c783b1883a7d --- /dev/null +++ b/src/KeyVault/KeyVault/Models/Key/PSKeyReleasePolicy.cs @@ -0,0 +1,72 @@ +using Azure.Security.KeyVault.Keys; + +using Newtonsoft.Json; + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Text.Json; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + public class PSKeyReleasePolicy + { + // Summary: + // Gets or sets the content type and version of key release policy. The service + // default is "application/json; charset=utf-8". + public string ContentType { get; set; } = "application/json; charset=utf-8"; + + // Summary: + // Gets the policy rules under which the key can be released encoded based on the + // Azure.Security.KeyVault.Keys.KeyReleasePolicy.ContentType. + private BinaryData EncodedPolicy; + + public string PolicyContent { get; set; } + + // + // Summary: + // Gets or sets the mutability state of the policy. Once marked immutable, this + // flag cannot be reset and the policy cannot be changed under any circumstances. + public bool? Immutable { get; set; } + + public PSKeyReleasePolicy() { } + + internal PSKeyReleasePolicy(string keyReleasePolicyPath) + { + // Assume File.Exists(keyReleasePolicyPath) is true + this.PolicyContent = File.Exists(keyReleasePolicyPath) ? File.ReadAllText(keyReleasePolicyPath) : null; + } + + internal PSKeyReleasePolicy(KeyReleasePolicy keyReleasePolicy) + { + this.ContentType = keyReleasePolicy?.ContentType; + this.EncodedPolicy = keyReleasePolicy?.EncodedPolicy; + this.PolicyContent = EncodedPolicy.ToString(); + this.Immutable = keyReleasePolicy?.Immutable; + } + + internal KeyReleasePolicy ToKeyReleasePolicy() + { + this.EncodedPolicy = this.EncodedPolicy ?? (this.PolicyContent == null ? null : new BinaryData(this.PolicyContent)); + return new KeyReleasePolicy(this.EncodedPolicy) + { + ContentType = this.ContentType, + Immutable = this.Immutable + }; + } + + public override string ToString() + { + if (this == null) return string.Empty; + + var sb = new StringBuilder(); + sb.AppendLine(); + sb.AppendFormat("{0, -15}: {1}{2}", "Content Type", ContentType, Environment.NewLine); + sb.AppendFormat("{0, -15}: {1}{2}", "Policy Content", PolicyContent, Environment.NewLine); + sb.AppendFormat("{0, -15}: {1}{2}", "Immutable", Immutable, Environment.NewLine); + sb.AppendLine(); + return sb.ToString(); + } + } +} diff --git a/src/KeyVault/KeyVault/Models/PSKeyRotationPolicy.cs b/src/KeyVault/KeyVault/Models/Key/PSKeyRotationPolicy.cs similarity index 93% rename from src/KeyVault/KeyVault/Models/PSKeyRotationPolicy.cs rename to src/KeyVault/KeyVault/Models/Key/PSKeyRotationPolicy.cs index 75f8b7e1d8fa..eb9bd9f7a26d 100644 --- a/src/KeyVault/KeyVault/Models/PSKeyRotationPolicy.cs +++ b/src/KeyVault/KeyVault/Models/Key/PSKeyRotationPolicy.cs @@ -17,6 +17,7 @@ using System; using System.Collections.Generic; +using System.Xml; namespace Microsoft.Azure.Commands.KeyVault.Models { @@ -63,7 +64,10 @@ public PSKeyRotationPolicy(KeyRotationPolicy keyRotationPolicy, string vaultName { LifetimeActions.Add(new PSKeyRotationLifetimeAction(action)); } - ExpiresIn = keyRotationPolicy.ExpiresIn; + if (!string.IsNullOrEmpty(keyRotationPolicy.ExpiresIn)) + { + ExpiresIn = XmlConvert.ToTimeSpan(keyRotationPolicy.ExpiresIn); + } CreatedOn = keyRotationPolicy.CreatedOn; UpdatedOn = keyRotationPolicy.UpdatedOn; } diff --git a/src/KeyVault/KeyVault/Models/PSKeyVaultKey.cs b/src/KeyVault/KeyVault/Models/Key/PSKeyVaultKey.cs similarity index 52% rename from src/KeyVault/KeyVault/Models/PSKeyVaultKey.cs rename to src/KeyVault/KeyVault/Models/Key/PSKeyVaultKey.cs index f9d4a1818fae..9957efbf85e7 100644 --- a/src/KeyVault/KeyVault/Models/PSKeyVaultKey.cs +++ b/src/KeyVault/KeyVault/Models/Key/PSKeyVaultKey.cs @@ -19,16 +19,19 @@ using System.Linq; using KeyVaultProperties = Microsoft.Azure.Commands.KeyVault.Properties; +using Track1Sdk = Microsoft.Azure.KeyVault.Models; using Track2Sdk = Azure.Security.KeyVault.Keys; namespace Microsoft.Azure.Commands.KeyVault.Models { public class PSKeyVaultKey : PSKeyVaultKeyIdentityItem { + #region Constructors public PSKeyVaultKey() { } - internal PSKeyVaultKey(Microsoft.Azure.KeyVault.Models.KeyBundle keyBundle, VaultUriHelper vaultUriHelper, bool isHsm = false) + internal PSKeyVaultKey(Track1Sdk.KeyBundle keyBundle, VaultUriHelper vaultUriHelper, bool isHsm = false) + : base(keyBundle, isHsm) { if (keyBundle == null) throw new ArgumentNullException("keyBundle"); @@ -37,68 +40,39 @@ internal PSKeyVaultKey(Microsoft.Azure.KeyVault.Models.KeyBundle keyBundle, Vaul SetObjectIdentifier(vaultUriHelper, keyBundle.KeyIdentifier); + // Key properties Key = keyBundle.Key; + // Quick access for key properties KeySize = JwkHelper.ConvertToRSAKey(Key)?.KeySize; - Attributes = new PSKeyVaultKeyAttributes( - keyBundle.Attributes.Enabled, - keyBundle.Attributes.Expires, - keyBundle.Attributes.NotBefore, - keyBundle.Key.Kty, - keyBundle.Key.KeyOps.ToArray(), - keyBundle.Attributes.Created, - keyBundle.Attributes.Updated, - keyBundle.Attributes.RecoveryLevel, - keyBundle.Tags); - - Enabled = keyBundle.Attributes.Enabled; - Expires = keyBundle.Attributes.Expires; - NotBefore = keyBundle.Attributes.NotBefore; - Created = keyBundle.Attributes.Created; - Updated = keyBundle.Attributes.Updated; - RecoveryLevel = keyBundle.Attributes.RecoveryLevel; - Tags = (keyBundle.Tags == null) ? null : keyBundle.Tags.ConvertToHashtable(); - - IsHsm = isHsm; + // Key additional properties + Attributes = new PSKeyVaultKeyAttributes(keyBundle); } - internal PSKeyVaultKey(Track2Sdk.KeyVaultKey key, VaultUriHelper vaultUriHelper, bool isHsm = false) + internal PSKeyVaultKey(Track2Sdk.KeyVaultKey key, VaultUriHelper vaultUriHelper, bool isHsm) + :base(key?.Properties, null, isHsm) { if (key == null) throw new ArgumentNullException("key"); if (key.Key == null || key.Properties == null) throw new ArgumentException(KeyVaultProperties.Resources.InvalidKeyBundle); + // Set Id, Name, Version and VaultName SetObjectIdentifier(vaultUriHelper, new Microsoft.Azure.KeyVault.KeyIdentifier(key.Id.ToString())); + // Key properties Key = key.Key.ToTrack1JsonWebKey(); + + // Quick access for key properties KeySize = JwkHelper.ConvertToRSAKey(Key)?.KeySize; - Attributes = new PSKeyVaultKeyAttributes( - key.Properties.Enabled, - /// see https://docs.microsoft.com/en-us/dotnet/standard/datetime/converting-between-datetime-and-offset#conversions-from-datetimeoffset-to-datetime - key.Properties.ExpiresOn?.UtcDateTime, // time returned by key vault are UTC - key.Properties.NotBefore?.UtcDateTime, - key.KeyType.ToString(), - key.KeyOperations.Select(op => op.ToString()).ToArray(), - key.Properties.CreatedOn?.UtcDateTime, - key.Properties.UpdatedOn?.UtcDateTime, - key.Properties.RecoveryLevel, - key.Properties.Tags - ); - - Enabled = key.Properties.Enabled; - Expires = key.Properties.ExpiresOn?.UtcDateTime; - NotBefore = key.Properties.NotBefore?.UtcDateTime; - Created = key.Properties.CreatedOn?.UtcDateTime; - Updated = key.Properties.UpdatedOn?.UtcDateTime; - RecoveryLevel = key.Properties.RecoveryLevel; - Tags = key.Properties.Tags.ConvertToHashtable(); - IsHsm = isHsm; - } - public PSKeyVaultKeyAttributes Attributes { get; set; } + // Key additional properties + Attributes = new PSKeyVaultKeyAttributes(key); + } + #endregion + #region Basic attributes public JsonWebKey Key { get; set; } public string KeyType @@ -106,12 +80,28 @@ public string KeyType get { return Key.Kty; } } + public PSKeyVaultKeyAttributes Attributes { get; set; } + #endregion + + #region Quick access for additional properties + // Quick access for additional property CurveName public string CurveName { get { return Key.CurveName; } } - + + // Quick access for additional property KeySize public int? KeySize; + // Quick access for additional property KeySize + public PSKeyReleasePolicy ReleasePolicy + { + get + { + return Attributes.ReleasePolicy; + } + } + + #endregion } } diff --git a/src/KeyVault/KeyVault/Models/Key/PSKeyVaultKeyAttributes.cs b/src/KeyVault/KeyVault/Models/Key/PSKeyVaultKeyAttributes.cs new file mode 100644 index 000000000000..7f9fc6d47b10 --- /dev/null +++ b/src/KeyVault/KeyVault/Models/Key/PSKeyVaultKeyAttributes.cs @@ -0,0 +1,169 @@ +// ---------------------------------------------------------------------------------- +// +// 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.Collections; +using System.Collections.Generic; +using System.Linq; + +using Track1Sdk = Microsoft.Azure.KeyVault.Models; +using Track2Sdk = Azure.Security.KeyVault.Keys; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + /// + /// Key attributes from PSH perspective + /// + public class PSKeyVaultKeyAttributes + { + public PSKeyVaultKeyAttributes() + { } + + internal PSKeyVaultKeyAttributes(Track1Sdk.KeyBundle keyBundle) + { + Enabled = keyBundle.Attributes.Enabled; + Expires = keyBundle.Attributes.Expires; + NotBefore = keyBundle.Attributes.NotBefore; + KeyType = keyBundle.Key.Kty; + KeyOps = keyBundle.Key.KeyOps.ToArray(); + Created = keyBundle.Attributes.Created; + Updated = keyBundle.Attributes.Updated; + RecoveryLevel = keyBundle.Attributes.RecoveryLevel; + Tags = keyBundle.Tags?.ConvertToHashtable(); + Managed = Managed = keyBundle.Managed; + } + + internal PSKeyVaultKeyAttributes(Track2Sdk.KeyVaultKey key) + { + Enabled = key.Properties.Enabled; + // see https://docs.microsoft.com/en-us/dotnet/standard/datetime/converting-between-datetime-and-offset#conversions-from-datetimeoffset-to-datetime + // time returned by key vault are UTC + Expires = key.Properties.ExpiresOn?.UtcDateTime; + NotBefore = key.Properties.NotBefore?.UtcDateTime; + KeyType = key.KeyType.ToString(); + KeyOps = key.KeyOperations.Select(op => op.ToString()).ToArray(); + Created = key.Properties.CreatedOn?.UtcDateTime; + Updated = key.Properties.UpdatedOn?.UtcDateTime; + RecoveryLevel = key.Properties.RecoveryLevel; + Tags = key.Properties.Tags?.ConvertToHashtable(); + Exportable = key.Properties.Exportable; + ReleasePolicy = key.Properties.ReleasePolicy?.ToPSKeyReleasePolicy(); + RecoverableDays = key.Properties.RecoverableDays; + Managed = key.Properties.Managed; + } + + internal PSKeyVaultKeyAttributes(bool? enabled, DateTime? expires, DateTime? notBefore, string keyType, string[] keyOps, Hashtable tags) { + this.Enabled = enabled; + this.Expires = expires; + this.NotBefore = notBefore; + this.KeyType = keyType; + this.KeyOps = keyOps; + this.Tags = tags; + } + + internal PSKeyVaultKeyAttributes(bool? enabled, DateTime? expires, DateTime? notBefore, string keyType, + string[] keyOps, DateTime? created, DateTime? updated, string deletionRecoveryLevel, IDictionary tags) + { + this.Enabled = enabled; + this.Expires = expires; + this.NotBefore = notBefore; + this.KeyType = keyType; + this.KeyOps = keyOps; + this.Created = created; + this.Updated = updated; + this.RecoveryLevel = deletionRecoveryLevel; + this.Tags = (tags == null) ? null : tags.ConvertToHashtable(); + } + + public bool? Enabled { get; set; } + + public DateTime? Expires { get; set; } + + public DateTime? NotBefore { get; set; } + + public string[] KeyOps { get; set; } + + public string KeyType { get; internal set; } + + public DateTime? Created { get; internal set; } + + public DateTime? Updated { get; internal set; } + + public string RecoveryLevel { get; internal set; } + + // Summary: + // Gets the number of days a key is retained before being deleted for a soft delete-enabled + // Key Vault. + public int? RecoverableDays { get; internal set; } + + // Summary: + // Gets a value indicating whether the key's lifetime is managed by Key Vault. If + // this key is backing a Key Vault certificate, the value will be true. + public bool? Managed { get; internal set; } + + public bool? Exportable { get; internal set; } + + public PSKeyReleasePolicy ReleasePolicy { get; internal set; } + + public Hashtable Tags { get; set; } + + public string TagsTable + { + get + { + return (Tags == null) ? null : Tags.ConvertToTagsTable(); + } + } + + public Dictionary TagsDirectionary + { + get + { + return (Tags == null) ? null : Tags.ConvertToDictionary(); + } + } + + public static explicit operator Track1Sdk.KeyAttributes(PSKeyVaultKeyAttributes attr) + { + return new Track1Sdk.KeyAttributes() + { + Enabled = attr.Enabled, + NotBefore = attr.NotBefore, + Expires = attr.Expires + }; + } + + public Track2Sdk.KeyProperties ToKeyProperties(string keyName, Track2Sdk.KeyProperties keyProperties = null) + { + if(null == keyProperties) + { + keyProperties = new Track2Sdk.KeyProperties(keyName); + } + keyProperties.ExpiresOn = this.Expires; + keyProperties.NotBefore = this.NotBefore; + keyProperties.Exportable = this.Exportable; + keyProperties.Enabled = this.Enabled; + if (this.Tags != null) + { + keyProperties.Tags.Clear(); + foreach (KeyValuePair entry in this.TagsDirectionary) + { + keyProperties.Tags.Add(entry.Key, entry.Value); + } + } + keyProperties.ReleasePolicy = this.ReleasePolicy?.ToKeyReleasePolicy(); + return keyProperties; + } + } +} diff --git a/src/KeyVault/KeyVault/Models/PSKeyVaultKeyIdentityItem.cs b/src/KeyVault/KeyVault/Models/Key/PSKeyVaultKeyIdentityItem.cs similarity index 80% rename from src/KeyVault/KeyVault/Models/PSKeyVaultKeyIdentityItem.cs rename to src/KeyVault/KeyVault/Models/Key/PSKeyVaultKeyIdentityItem.cs index 9d56282c3143..076aae5d9cf2 100644 --- a/src/KeyVault/KeyVault/Models/PSKeyVaultKeyIdentityItem.cs +++ b/src/KeyVault/KeyVault/Models/Key/PSKeyVaultKeyIdentityItem.cs @@ -15,6 +15,7 @@ using System; using System.Collections; using KeyVaultProperties = Microsoft.Azure.Commands.KeyVault.Properties; +using Track1Sdk = Microsoft.Azure.KeyVault.Models; using Track2Sdk = Azure.Security.KeyVault.Keys; namespace Microsoft.Azure.Commands.KeyVault.Models @@ -45,6 +46,24 @@ internal PSKeyVaultKeyIdentityItem(Azure.KeyVault.Models.KeyItem keyItem, VaultU IsHsm = isHsm; } + protected PSKeyVaultKeyIdentityItem(Track1Sdk.KeyBundle keyBundle, bool isHsm = false) + { + if (keyBundle == null) + throw new ArgumentNullException("keyBundle"); + if (keyBundle.Attributes == null) + throw new ArgumentException(KeyVaultProperties.Resources.InvalidKeyAttributes); + + Enabled = keyBundle.Attributes.Enabled; + Expires = keyBundle.Attributes.Expires; + NotBefore = keyBundle.Attributes.NotBefore; + Created = keyBundle.Attributes.Created; + Updated = keyBundle.Attributes.Updated; + RecoveryLevel = keyBundle.Attributes.RecoveryLevel; + Tags = (keyBundle.Tags == null) ? null : keyBundle.Tags.ConvertToHashtable();; + IsHsm = isHsm; + + } + internal PSKeyVaultKeyIdentityItem(PSKeyVaultKey keyBundle, bool isHsm = false) { if (keyBundle == null) @@ -64,6 +83,7 @@ internal PSKeyVaultKeyIdentityItem(PSKeyVaultKey keyBundle, bool isHsm = false) IsHsm = isHsm; } + internal PSKeyVaultKeyIdentityItem(Track2Sdk.KeyProperties keyProperties, VaultUriHelper vaultUriHelper, bool isHsm = false) { if (keyProperties == null) @@ -71,7 +91,10 @@ internal PSKeyVaultKeyIdentityItem(Track2Sdk.KeyProperties keyProperties, VaultU if (keyProperties.Id == null || keyProperties.Name == null) throw new ArgumentException(KeyVaultProperties.Resources.InvalidKeyProperties); - SetObjectIdentifier(vaultUriHelper, new Microsoft.Azure.KeyVault.KeyIdentifier(keyProperties.Id.ToString())); + if(null != vaultUriHelper) + { + SetObjectIdentifier(vaultUriHelper, new Microsoft.Azure.KeyVault.KeyIdentifier(keyProperties.Id.ToString())); + } Enabled = keyProperties.Enabled; Expires = keyProperties.ExpiresOn?.UtcDateTime; diff --git a/src/KeyVault/KeyVault/Models/PSKeyRotationLifetimeAction.cs b/src/KeyVault/KeyVault/Models/PSKeyRotationLifetimeAction.cs index bddd28b4917d..9b3bf97ca830 100644 --- a/src/KeyVault/KeyVault/Models/PSKeyRotationLifetimeAction.cs +++ b/src/KeyVault/KeyVault/Models/PSKeyRotationLifetimeAction.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Text; +using System.Xml; namespace Microsoft.Azure.Commands.KeyVault.Models { @@ -29,8 +30,14 @@ public PSKeyRotationLifetimeAction() { } public PSKeyRotationLifetimeAction(KeyRotationLifetimeAction keyRotationLifetimeAction) { Action = keyRotationLifetimeAction.Action.ToString(); - TimeAfterCreate = keyRotationLifetimeAction.TimeAfterCreate; - TimeBeforeExpiry = keyRotationLifetimeAction.TimeBeforeExpiry; + if (!string.IsNullOrEmpty(keyRotationLifetimeAction.TimeAfterCreate)) + { + TimeAfterCreate = XmlConvert.ToTimeSpan(keyRotationLifetimeAction.TimeAfterCreate); + } + if (!string.IsNullOrEmpty(keyRotationLifetimeAction.TimeBeforeExpiry)) + { + TimeBeforeExpiry = XmlConvert.ToTimeSpan(keyRotationLifetimeAction.TimeBeforeExpiry); + } } public override string ToString() diff --git a/src/KeyVault/KeyVault/Models/PSKeyVaultKeyAttributes.cs b/src/KeyVault/KeyVault/Models/PSKeyVaultKeyAttributes.cs deleted file mode 100644 index e17cc091527f..000000000000 --- a/src/KeyVault/KeyVault/Models/PSKeyVaultKeyAttributes.cs +++ /dev/null @@ -1,96 +0,0 @@ -// ---------------------------------------------------------------------------------- -// -// 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.Collections; -using System.Collections.Generic; - -namespace Microsoft.Azure.Commands.KeyVault.Models -{ - /// - /// Key attributes from PSH perspective - /// - public class PSKeyVaultKeyAttributes - { - public PSKeyVaultKeyAttributes() - { } - - internal PSKeyVaultKeyAttributes(bool? enabled, DateTime? expires, DateTime? notBefore, string keyType, string[] keyOps, Hashtable tags) - { - this.Enabled = enabled; - this.Expires = expires; - this.NotBefore = notBefore; - this.KeyType = keyType; - this.KeyOps = keyOps; - this.Tags = tags; - } - - internal PSKeyVaultKeyAttributes(bool? enabled, DateTime? expires, DateTime? notBefore, string keyType, - string[] keyOps, DateTime? created, DateTime? updated, string deletionRecoveryLevel, IDictionary tags) - { - this.Enabled = enabled; - this.Expires = expires; - this.NotBefore = notBefore; - this.KeyType = keyType; - this.KeyOps = keyOps; - this.Created = created; - this.Updated = updated; - this.RecoveryLevel = deletionRecoveryLevel; - this.Tags = (tags == null) ? null : tags.ConvertToHashtable(); - } - - public bool? Enabled { get; set; } - - public DateTime? Expires { get; set; } - - public DateTime? NotBefore { get; set; } - - public string[] KeyOps { get; set; } - - public string KeyType { get; private set; } - - public DateTime? Created { get; private set; } - - public DateTime? Updated { get; private set; } - - public string RecoveryLevel { get; private set; } - - public Hashtable Tags { get; set; } - public string TagsTable - { - get - { - return (Tags == null) ? null : Tags.ConvertToTagsTable(); - } - } - - public Dictionary TagsDirectionary - { - get - { - return (Tags == null) ? null : Tags.ConvertToDictionary(); - } - } - - public static explicit operator Azure.KeyVault.Models.KeyAttributes(PSKeyVaultKeyAttributes attr) - { - return new Azure.KeyVault.Models.KeyAttributes() - { - Enabled = attr.Enabled, - NotBefore = attr.NotBefore, - Expires = attr.Expires - }; - } - } -} diff --git a/src/KeyVault/KeyVault/Models/VaultUriHelper.cs b/src/KeyVault/KeyVault/Models/VaultUriHelper.cs index 01d18f35e180..7309e42ea668 100644 --- a/src/KeyVault/KeyVault/Models/VaultUriHelper.cs +++ b/src/KeyVault/KeyVault/Models/VaultUriHelper.cs @@ -12,8 +12,12 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using Microsoft.Azure.Commands.Common.Exceptions; + using System; using System.Linq; +using System.Text; + using KeyVaultProperties = Microsoft.Azure.Commands.KeyVault.Properties; namespace Microsoft.Azure.Commands.KeyVault.Models @@ -80,5 +84,16 @@ public Uri CreateManagedHsmUri(string name) return builder.Uri; } + + public Uri CreateaMagedHsmKeyUri(Uri mhsmUri, string keyName, string version) + { + if (null == mhsmUri) + throw new ArgumentNullException("mhsmUri"); + if (string.IsNullOrEmpty(keyName)) + throw new ArgumentNullException("keyName"); + + string relativePath = new StringBuilder().Append("keys/").Append(keyName).Append("/").Append(version).ToString(); + return new Uri(mhsmUri, relativePath); + } } } diff --git a/src/KeyVault/KeyVault/Properties/Resources.Designer.cs b/src/KeyVault/KeyVault/Properties/Resources.Designer.cs index d62fb47e5b47..0b77540a44f0 100644 --- a/src/KeyVault/KeyVault/Properties/Resources.Designer.cs +++ b/src/KeyVault/KeyVault/Properties/Resources.Designer.cs @@ -432,6 +432,24 @@ internal static string EcButNoCurveName { } } + /// + /// Looks up a localized string similar to Fetch default CVM Policy failed, {0}. + /// + internal static string FetchDefaultCVMPolicyFailed { + get { + return ResourceManager.GetString("FetchDefaultCVMPolicyFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Can not find file '{0}'.. + /// + internal static string FileNotFound { + get { + return ResourceManager.GetString("FileNotFound", resourceCulture); + } + } + /// /// Looks up a localized string similar to Overwrite File ?. /// @@ -792,15 +810,6 @@ internal static string KEKMustBeHSM { } } - /// - /// Looks up a localized string similar to Can not find key file '{0}'.. - /// - internal static string KeyFileNotFound { - get { - return ResourceManager.GetString("KeyFileNotFound", resourceCulture); - } - } - /// /// Looks up a localized string similar to The "import" operation is exclusive, it cannot be combined with any other value(s).. /// diff --git a/src/KeyVault/KeyVault/Properties/Resources.resx b/src/KeyVault/KeyVault/Properties/Resources.resx index c48e2404a1fc..3fa86667836d 100644 --- a/src/KeyVault/KeyVault/Properties/Resources.resx +++ b/src/KeyVault/KeyVault/Properties/Resources.resx @@ -216,8 +216,8 @@ You can find the object ID using Azure Active Directory Module for Windows Power Invalid vault uri '{0}'. Vault uri must contain valid dns host name with domain suffix '{1}'. - - Can not find key file '{0}'. + + Can not find file '{0}'. There is no default user account associated with this subscription. Certificate accounts are not supported with Azure Key Vault. @@ -606,4 +606,7 @@ You can find the object ID using Azure Active Directory Module for Windows Power Purge managed HSM + + Fetch default CVM Policy failed, {0} + \ No newline at end of file diff --git a/src/KeyVault/KeyVault/Track2Models/Track2HsmClient.cs b/src/KeyVault/KeyVault/Track2Models/Track2HsmClient.cs index 3e35973e0d4d..2d431f6a2dcd 100644 --- a/src/KeyVault/KeyVault/Track2Models/Track2HsmClient.cs +++ b/src/KeyVault/KeyVault/Track2Models/Track2HsmClient.cs @@ -14,6 +14,7 @@ using KeyVaultProperties = Microsoft.Azure.Commands.KeyVault.Properties; using Azure.Security.KeyVault.Keys.Cryptography; using Microsoft.WindowsAzure.Commands.Utilities.Common; +using System.Xml; namespace Microsoft.Azure.Commands.KeyVault.Track2Models { @@ -103,9 +104,14 @@ private PSKeyVaultKey CreateKey(KeyClient client, string keyName, PSKeyVaultKeyA { options = new CreateKeyOptions(); } + + // Common key attributes options.NotBefore = keyAttributes.NotBefore; options.ExpiresOn = keyAttributes.Expires; options.Enabled = keyAttributes.Enabled; + options.Exportable = keyAttributes.Exportable; + options.ReleasePolicy = keyAttributes.ReleasePolicy?.ToKeyReleasePolicy(); + if (keyAttributes.KeyOps != null) { foreach (var keyOp in keyAttributes.KeyOps) @@ -113,6 +119,7 @@ private PSKeyVaultKey CreateKey(KeyClient client, string keyName, PSKeyVaultKeyA options.KeyOperations.Add(new KeyOperation(keyOp)); } } + if (keyAttributes.Tags != null) { foreach (DictionaryEntry entry in keyAttributes.Tags) @@ -292,12 +299,17 @@ internal PSKeyVaultKey UpdateKey(string managedHsmName, string keyName, string k private PSKeyVaultKey UpdateKey(KeyClient client, string keyName, string keyVersion, PSKeyVaultKeyAttributes keyAttributes) { - KeyVaultKey keyBundle = client.GetKeyAsync(keyName, keyVersion).GetAwaiter().GetResult(); - KeyProperties keyProperties = keyBundle.Properties; - keyProperties.Enabled = keyAttributes.Enabled; - keyProperties.ExpiresOn = keyAttributes.Expires; - keyProperties.NotBefore = keyAttributes.NotBefore; + KeyVaultKey keyBundle = null; + // Update updatable properties + KeyProperties keyProperties = new KeyProperties(_uriHelper.CreateaMagedHsmKeyUri(client.VaultUri, keyName, keyVersion)) + { + Enabled = keyAttributes.Enabled, + ExpiresOn = keyAttributes.Expires, + NotBefore = keyAttributes.NotBefore, + ReleasePolicy = keyAttributes.ReleasePolicy?.ToKeyReleasePolicy() + }; + if (keyAttributes.Tags != null) { keyProperties.Tags.Clear(); @@ -531,7 +543,7 @@ internal PSKeyRotationPolicy SetKeyRotationPolicy(PSKeyRotationPolicy psKeyRotat var client = CreateKeyClient(psKeyRotationPolicy.VaultName); var policy = new KeyRotationPolicy() { - ExpiresIn = psKeyRotationPolicy.ExpiresIn, + ExpiresIn = psKeyRotationPolicy.ExpiresIn.HasValue ? XmlConvert.ToString(psKeyRotationPolicy.ExpiresIn.Value) : null, LifetimeActions = { } }; @@ -540,8 +552,8 @@ internal PSKeyRotationPolicy SetKeyRotationPolicy(PSKeyRotationPolicy psKeyRotat new KeyRotationLifetimeAction() { Action = psKeyRotationLifetimeAction.Action, - TimeAfterCreate = psKeyRotationLifetimeAction.TimeAfterCreate, - TimeBeforeExpiry = psKeyRotationLifetimeAction.TimeBeforeExpiry + TimeAfterCreate = psKeyRotationLifetimeAction.TimeAfterCreate.HasValue ? XmlConvert.ToString(psKeyRotationLifetimeAction.TimeAfterCreate.Value) : null, + TimeBeforeExpiry = psKeyRotationLifetimeAction.TimeBeforeExpiry.HasValue ? XmlConvert.ToString(psKeyRotationLifetimeAction.TimeBeforeExpiry.Value) : null } )); diff --git a/src/KeyVault/KeyVault/Track2Models/Track2VaultClient.cs b/src/KeyVault/KeyVault/Track2Models/Track2VaultClient.cs index 92c62313a7e8..f17d4919f7c0 100644 --- a/src/KeyVault/KeyVault/Track2Models/Track2VaultClient.cs +++ b/src/KeyVault/KeyVault/Track2Models/Track2VaultClient.cs @@ -8,6 +8,7 @@ using System; using System.Collections; +using System.Xml; namespace Microsoft.Azure.Commands.KeyVault.Track2Models { @@ -58,6 +59,9 @@ private PSKeyVaultKey CreateKey(KeyClient client, string keyName, PSKeyVaultKeyA options.NotBefore = keyAttributes.NotBefore; options.ExpiresOn = keyAttributes.Expires; options.Enabled = keyAttributes.Enabled; + options.Exportable = keyAttributes.Exportable; + options.ReleasePolicy = keyAttributes.ReleasePolicy?.ToKeyReleasePolicy(); ; + if (keyAttributes.KeyOps != null) { foreach (var keyOp in keyAttributes.KeyOps) @@ -75,11 +79,11 @@ private PSKeyVaultKey CreateKey(KeyClient client, string keyName, PSKeyVaultKeyA if (keyAttributes.KeyType == KeyType.Rsa || keyAttributes.KeyType == KeyType.RsaHsm) { - return new PSKeyVaultKey(client.CreateRsaKey(options as CreateRsaKeyOptions).Value, _vaultUriHelper); + return new PSKeyVaultKey(client.CreateRsaKey(options as CreateRsaKeyOptions).Value, _vaultUriHelper, false); } else if (keyAttributes.KeyType == KeyType.Ec || keyAttributes.KeyType == KeyType.EcHsm) { - return new PSKeyVaultKey(client.CreateEcKey(options as CreateEcKeyOptions).Value, _vaultUriHelper); + return new PSKeyVaultKey(client.CreateEcKey(options as CreateEcKeyOptions).Value, _vaultUriHelper, false); } else { @@ -121,7 +125,7 @@ internal PSKeyVaultKey GetKey(string vaultName, string keyName, string keyVersio private PSKeyVaultKey GetKey(KeyClient client, string keyName, string keyVersion) { - return new PSKeyVaultKey(client.GetKey(keyName, keyVersion).Value, _vaultUriHelper); + return new PSKeyVaultKey(client.GetKey(keyName, keyVersion).Value, _vaultUriHelper, false); } internal PSKeyOperationResult UnwrapKey(string vaultName, string keyName, string keyVersion, string wrapAlgorithm, byte[] value) @@ -162,7 +166,7 @@ internal PSKeyVaultKey RotateKey(string vaultName, string keyName) private PSKeyVaultKey RotateKey(KeyClient client, string keyName) { - return new PSKeyVaultKey(client.RotateKey(keyName), _vaultUriHelper); + return new PSKeyVaultKey(client.RotateKey(keyName), _vaultUriHelper, false); } internal PSKeyRotationPolicy GetKeyRotationPolicy(string vaultName, string keyName) @@ -181,7 +185,7 @@ internal PSKeyRotationPolicy SetKeyRotationPolicy(PSKeyRotationPolicy psKeyRotat var client = CreateKeyClient(psKeyRotationPolicy.VaultName); var policy = new KeyRotationPolicy() { - ExpiresIn = psKeyRotationPolicy.ExpiresIn, + ExpiresIn = psKeyRotationPolicy.ExpiresIn.HasValue ? XmlConvert.ToString(psKeyRotationPolicy.ExpiresIn.Value) : null, LifetimeActions = {} }; @@ -190,8 +194,8 @@ internal PSKeyRotationPolicy SetKeyRotationPolicy(PSKeyRotationPolicy psKeyRotat new KeyRotationLifetimeAction() { Action = psKeyRotationLifetimeAction.Action, - TimeAfterCreate = psKeyRotationLifetimeAction.TimeAfterCreate, - TimeBeforeExpiry = psKeyRotationLifetimeAction.TimeBeforeExpiry + TimeAfterCreate = psKeyRotationLifetimeAction.TimeAfterCreate.HasValue ? XmlConvert.ToString(psKeyRotationLifetimeAction.TimeAfterCreate.Value) : null, + TimeBeforeExpiry = psKeyRotationLifetimeAction.TimeBeforeExpiry.HasValue ? XmlConvert.ToString(psKeyRotationLifetimeAction.TimeBeforeExpiry.Value) : null } )); diff --git a/src/KeyVault/KeyVault/help/Add-AzKeyVaultKey.md b/src/KeyVault/KeyVault/help/Add-AzKeyVaultKey.md index 67b2b10b3f05..0199b9682349 100644 --- a/src/KeyVault/KeyVault/help/Add-AzKeyVaultKey.md +++ b/src/KeyVault/KeyVault/help/Add-AzKeyVaultKey.md @@ -32,6 +32,7 @@ Add-AzKeyVaultKey [-VaultName] [-Name] -KeyFilePath ``` Add-AzKeyVaultKey -HsmName [-Name] [-Disable] [-KeyOps ] [-Expires ] [-NotBefore ] [-Tag ] [-Size ] -KeyType [-CurveName ] + [-Exportable] [-Immutable] [-ReleasePolicyPath ] [-UseDefaultCVMPolicy] [-DefaultProfile ] [-WhatIf] [-Confirm] [] ``` @@ -62,7 +63,8 @@ Add-AzKeyVaultKey [-InputObject] [-Name] -KeyFilePath [-Name] [-Disable] [-KeyOps ] [-Expires ] [-NotBefore ] [-Tag ] [-Size ] -KeyType - [-CurveName ] [-DefaultProfile ] [-WhatIf] [-Confirm] [] + [-CurveName ] [-Exportable] [-Immutable] [-ReleasePolicyPath ] [-UseDefaultCVMPolicy] + [-DefaultProfile ] [-WhatIf] [-Confirm] [] ``` ### HsmInputObjectImport @@ -92,7 +94,8 @@ Add-AzKeyVaultKey [-ResourceId] [-Name] -KeyFilePath ``` Add-AzKeyVaultKey -HsmResourceId [-Name] [-Disable] [-KeyOps ] [-Expires ] [-NotBefore ] [-Tag ] [-Size ] -KeyType - [-CurveName ] [-DefaultProfile ] [-WhatIf] [-Confirm] [] + [-CurveName ] [-Exportable] [-Immutable] [-ReleasePolicyPath ] [-UseDefaultCVMPolicy] + [-DefaultProfile ] [-WhatIf] [-Confirm] [] ``` ### HsmResourceIdImport @@ -435,6 +438,21 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -Exportable +Indicates if the private key can be exported. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: HsmInteractiveCreate, HsmInputObjectCreate, HsmResourceIdCreate +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -HsmName HSM name. Cmdlet constructs the FQDN of a managed HSM based on the name and currently selected environment. @@ -480,6 +498,21 @@ Accept pipeline input: True (ByPropertyName) Accept wildcard characters: False ``` +### -Immutable +Sets the release policy as immutable state. Once marked immutable, this flag cannot be reset and the policy cannot be changed under any circumstances. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: HsmInteractiveCreate, HsmInputObjectCreate, HsmResourceIdCreate +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -InputObject Vault object. @@ -621,6 +654,21 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -ReleasePolicyPath +A path to a file containing JSON policy definition. The policy rules under which a key can be exported. + +```yaml +Type: System.String +Parameter Sets: HsmInteractiveCreate, HsmInputObjectCreate, HsmResourceIdCreate +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -ResourceId Vault Resource Id. @@ -667,6 +715,21 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -UseDefaultCVMPolicy +Specifies to use default policy under which the key can be exported for CVM disk encryption. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: HsmInteractiveCreate, HsmInputObjectCreate, HsmResourceIdCreate +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -VaultName Specifies the name of the key vault to which this cmdlet adds the key. This cmdlet constructs the FQDN of a key vault based on the name that this parameter specifies and your current environment. From ca5fbef3a338c6fa153f3962d9d22e6c91775c64 Mon Sep 17 00:00:00 2001 From: Beisi Zhou Date: Wed, 1 Jun 2022 18:14:51 +0800 Subject: [PATCH 2/5] Refine codes --- .../KeyVault/Models/{ => Key}/PSKeyOperationResult.cs | 0 .../Models/{ => Key}/PSKeyRotationLifetimeAction.cs | 10 ++-------- .../KeyVault/Models/Key/PSKeyRotationPolicy.cs | 6 ++---- .../KeyVault/Models/Key/PSKeyVaultKeyIdentityItem.cs | 2 +- .../KeyVault/Models/KeyVaultDataServiceClient.cs | 4 ++-- 5 files changed, 7 insertions(+), 15 deletions(-) rename src/KeyVault/KeyVault/Models/{ => Key}/PSKeyOperationResult.cs (100%) rename src/KeyVault/KeyVault/Models/{ => Key}/PSKeyRotationLifetimeAction.cs (77%) diff --git a/src/KeyVault/KeyVault/Models/PSKeyOperationResult.cs b/src/KeyVault/KeyVault/Models/Key/PSKeyOperationResult.cs similarity index 100% rename from src/KeyVault/KeyVault/Models/PSKeyOperationResult.cs rename to src/KeyVault/KeyVault/Models/Key/PSKeyOperationResult.cs diff --git a/src/KeyVault/KeyVault/Models/PSKeyRotationLifetimeAction.cs b/src/KeyVault/KeyVault/Models/Key/PSKeyRotationLifetimeAction.cs similarity index 77% rename from src/KeyVault/KeyVault/Models/PSKeyRotationLifetimeAction.cs rename to src/KeyVault/KeyVault/Models/Key/PSKeyRotationLifetimeAction.cs index 9b3bf97ca830..aa9ae50ef659 100644 --- a/src/KeyVault/KeyVault/Models/PSKeyRotationLifetimeAction.cs +++ b/src/KeyVault/KeyVault/Models/Key/PSKeyRotationLifetimeAction.cs @@ -30,14 +30,8 @@ public PSKeyRotationLifetimeAction() { } public PSKeyRotationLifetimeAction(KeyRotationLifetimeAction keyRotationLifetimeAction) { Action = keyRotationLifetimeAction.Action.ToString(); - if (!string.IsNullOrEmpty(keyRotationLifetimeAction.TimeAfterCreate)) - { - TimeAfterCreate = XmlConvert.ToTimeSpan(keyRotationLifetimeAction.TimeAfterCreate); - } - if (!string.IsNullOrEmpty(keyRotationLifetimeAction.TimeBeforeExpiry)) - { - TimeBeforeExpiry = XmlConvert.ToTimeSpan(keyRotationLifetimeAction.TimeBeforeExpiry); - } + TimeAfterCreate = string.IsNullOrEmpty(keyRotationLifetimeAction.TimeAfterCreate) ? null : XmlConvert.ToTimeSpan(keyRotationLifetimeAction.TimeAfterCreate) as TimeSpan?; + TimeBeforeExpiry = string.IsNullOrEmpty(keyRotationLifetimeAction.TimeBeforeExpiry) ? null : XmlConvert.ToTimeSpan(keyRotationLifetimeAction.TimeBeforeExpiry) as TimeSpan?; } public override string ToString() diff --git a/src/KeyVault/KeyVault/Models/Key/PSKeyRotationPolicy.cs b/src/KeyVault/KeyVault/Models/Key/PSKeyRotationPolicy.cs index eb9bd9f7a26d..1e1c45c47f2f 100644 --- a/src/KeyVault/KeyVault/Models/Key/PSKeyRotationPolicy.cs +++ b/src/KeyVault/KeyVault/Models/Key/PSKeyRotationPolicy.cs @@ -64,10 +64,8 @@ public PSKeyRotationPolicy(KeyRotationPolicy keyRotationPolicy, string vaultName { LifetimeActions.Add(new PSKeyRotationLifetimeAction(action)); } - if (!string.IsNullOrEmpty(keyRotationPolicy.ExpiresIn)) - { - ExpiresIn = XmlConvert.ToTimeSpan(keyRotationPolicy.ExpiresIn); - } + + ExpiresIn = string.IsNullOrEmpty(keyRotationPolicy.ExpiresIn) ? null : XmlConvert.ToTimeSpan(keyRotationPolicy.ExpiresIn) as TimeSpan?; CreatedOn = keyRotationPolicy.CreatedOn; UpdatedOn = keyRotationPolicy.UpdatedOn; } diff --git a/src/KeyVault/KeyVault/Models/Key/PSKeyVaultKeyIdentityItem.cs b/src/KeyVault/KeyVault/Models/Key/PSKeyVaultKeyIdentityItem.cs index 076aae5d9cf2..1c0721370d5a 100644 --- a/src/KeyVault/KeyVault/Models/Key/PSKeyVaultKeyIdentityItem.cs +++ b/src/KeyVault/KeyVault/Models/Key/PSKeyVaultKeyIdentityItem.cs @@ -25,7 +25,7 @@ public class PSKeyVaultKeyIdentityItem : ObjectIdentifier public PSKeyVaultKeyIdentityItem() { } - internal PSKeyVaultKeyIdentityItem(Azure.KeyVault.Models.KeyItem keyItem, VaultUriHelper vaultUriHelper, bool isHsm = false) + internal PSKeyVaultKeyIdentityItem(Azure.KeyVault.Models.KeyItem keyItem, VaultUriHelper vaultUriHelper, bool isHsm) { if (keyItem == null) throw new ArgumentNullException("keyItem"); diff --git a/src/KeyVault/KeyVault/Models/KeyVaultDataServiceClient.cs b/src/KeyVault/KeyVault/Models/KeyVaultDataServiceClient.cs index 4d2bcf9ef9b3..dc047b5efd29 100644 --- a/src/KeyVault/KeyVault/Models/KeyVaultDataServiceClient.cs +++ b/src/KeyVault/KeyVault/Models/KeyVaultDataServiceClient.cs @@ -211,7 +211,7 @@ public IEnumerable GetKeys(KeyVaultObjectFilterOption options.NextLink = result.NextPageLink; return (result == null) ? new List() : - result.Select((keyItem) => new PSKeyVaultKeyIdentityItem(keyItem, this.vaultUriHelper)); + result.Select((keyItem) => new PSKeyVaultKeyIdentityItem(keyItem, this.vaultUriHelper, false)); } catch (Exception ex) { @@ -242,7 +242,7 @@ public IEnumerable GetKeyVersions(KeyVaultObjectFilte result = this.keyVaultClient.GetKeyVersionsNextAsync(options.NextLink).GetAwaiter().GetResult(); options.NextLink = result.NextPageLink; - return result.Select((keyItem) => new PSKeyVaultKeyIdentityItem(keyItem, this.vaultUriHelper)); + return result.Select((keyItem) => new PSKeyVaultKeyIdentityItem(keyItem, this.vaultUriHelper, false)); } catch (Exception ex) { From b1adbd58e902b919e5125475ea0e05eaca2981aa Mon Sep 17 00:00:00 2001 From: Beisi Zhou Date: Wed, 1 Jun 2022 18:20:00 +0800 Subject: [PATCH 3/5] Update update-azkeyvault.md --- .../KeyVault/help/Update-AzKeyVaultKey.md | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/KeyVault/KeyVault/help/Update-AzKeyVaultKey.md b/src/KeyVault/KeyVault/help/Update-AzKeyVaultKey.md index 6d2ab3987333..85bbdc973135 100644 --- a/src/KeyVault/KeyVault/help/Update-AzKeyVaultKey.md +++ b/src/KeyVault/KeyVault/help/Update-AzKeyVaultKey.md @@ -22,8 +22,9 @@ Update-AzKeyVaultKey [-VaultName] [-Name] [[-Version] ### HsmInteractive ``` Update-AzKeyVaultKey -HsmName [-Name] [[-Version] ] [-Enable ] - [-Expires ] [-NotBefore ] [-KeyOps ] [-Tag ] [-PassThru] - [-DefaultProfile ] [-WhatIf] [-Confirm] [] + [-Expires ] [-NotBefore ] [-KeyOps ] [-Immutable] [-ReleasePolicyPath ] + [-Tag ] [-PassThru] [-DefaultProfile ] [-WhatIf] [-Confirm] + [] ``` ### InputObject @@ -153,6 +154,21 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -Immutable +Sets the release policy as immutable state. Once marked immutable, this flag cannot be reset and the policy cannot be changed under any circumstances. + +```yaml +Type: System.Management.Automation.SwitchParameter +Parameter Sets: HsmInteractive +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -InputObject Key object @@ -232,6 +248,21 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -ReleasePolicyPath +A path to a file containing JSON policy definition. The policy rules under which a key can be exported. + +```yaml +Type: System.String +Parameter Sets: HsmInteractive +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Tag A hashtable represents key tags. If not specified, the existings tags of the key remain unchanged. From 0686c59115eb6151854024d72a2c32b4964029c9 Mon Sep 17 00:00:00 2001 From: Beisi Zhou Date: Thu, 2 Jun 2022 15:18:58 +0800 Subject: [PATCH 4/5] add example for secure key --- .../KeyVault/help/Add-AzKeyVaultKey.md | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/KeyVault/KeyVault/help/Add-AzKeyVaultKey.md b/src/KeyVault/KeyVault/help/Add-AzKeyVaultKey.md index 0199b9682349..14a4c515a00e 100644 --- a/src/KeyVault/KeyVault/help/Add-AzKeyVaultKey.md +++ b/src/KeyVault/KeyVault/help/Add-AzKeyVaultKey.md @@ -332,6 +332,54 @@ $key = Add-AzKeyVaultKey -VaultName $vaultName -Name $keyName -Destination HSM - Generates a key (referred to as a Key Exchange Key (KEK)). The KEK must be an RSA-HSM key that has only the import key operation. Only Key Vault Premium SKU supports RSA-HSM keys. For more details please refer to https://docs.microsoft.com/azure/key-vault/keys/hsm-protected-keys +### Example 9: Create a secure key in managed hsm + +```powershell +<# release_policy_template.json +{ + "anyOf": [ + { + "allOf": [ + { + "claim": "", + "equals": "" + } + ], + "authority": "" + } + ], + "version": "1.0.0" +} +#> +Add-AzKeyVaultKey -HsmName testmhsm -Name test-key -KeyType RSA -Exportable -ReleasePolicyPath release_policy.json +``` + +```output +Vault/HSM Name : testmhsm +Name : test-key +Key Type : RSA +Key Size : 2048 +Curve Name : +Version : ed6b026bf0a605042006635713d33ef6 +Id : https://testmhsm.managedhsm.azure.net:443/keys/test-key/ed6b026bf0a605042006635713d33ef6 +Enabled : True +Expires : +Not Before : +Created : 6/2/2022 7:14:37 AM +Updated : 6/2/2022 7:14:37 AM +Recovery Level : Recoverable+Purgeable +Release Policy : + Content Type : application/json; charset=utf-8 + Policy Content : {"anyOf":[{"allOf":[{"claim":"x-ms-sgx-is-debuggable","equals":"true"}],"authority":"htt + ps://sharedeus.eus.attest.azure.net/"}],"version":"1.0.0"} + Immutable : False + + +Tags : +``` + +Create a secure key in managed hsm named testmhsm. Its name is test-key and type is RSA. + ## PARAMETERS ### -CurveName @@ -784,6 +832,8 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ### Microsoft.Azure.Commands.KeyVault.Models.PSKeyVault +### Microsoft.Azure.Commands.KeyVault.Models.PSManagedHsm + ### System.String ## OUTPUTS From c7508c27959992f1d620df51ebfb6727ef2bd198 Mon Sep 17 00:00:00 2001 From: Beisi Zhou Date: Thu, 2 Jun 2022 15:28:21 +0800 Subject: [PATCH 5/5] upgrade Azure.Security.KeyVault.Keys to 4.3.0-beta.7 --- src/CosmosDB/CosmosDB/CosmosDB.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CosmosDB/CosmosDB/CosmosDB.csproj b/src/CosmosDB/CosmosDB/CosmosDB.csproj index 78ae462544e2..c2064331a71a 100644 --- a/src/CosmosDB/CosmosDB/CosmosDB.csproj +++ b/src/CosmosDB/CosmosDB/CosmosDB.csproj @@ -6,7 +6,7 @@ - +