Skip to content

Commit 2ac2452

Browse files
authored
[Storage] Support Encryption Scope (Azure#13610)
1 parent b2d1d8b commit 2ac2452

22 files changed

+3556
-31
lines changed

src/Storage/Storage.Management.Test/ScenarioTests/StorageBlobTests.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ public void TestStorageBlobContainer()
4545
TestController.NewInstance.RunPsTest(_logger, "Test-StorageBlobContainer");
4646
}
4747

48+
[Fact]
49+
[Trait(Category.AcceptanceType, Category.CheckIn)]
50+
public void TestStorageBlobContainerEncryptionScope()
51+
{
52+
TestController.NewInstance.RunPsTest(_logger, "Test-StorageBlobContainerEncryptionScope");
53+
}
54+
4855
[Fact]
4956
[Trait(Category.AcceptanceType, Category.CheckIn)]
5057
public void TestStorageBlobContainerLegalHold()

src/Storage/Storage.Management.Test/ScenarioTests/StorageBlobTests.ps1

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,78 @@ function Test-StorageBlobContainer
143143
}
144144
}
145145

146+
<#
147+
.SYNOPSIS
148+
Test StorageAccount container with Encryption Scope
149+
.DESCRIPTION
150+
SmokeTest
151+
#>
152+
function Test-StorageBlobContainerEncryptionScope
153+
{
154+
# Setup
155+
$rgname = Get-StorageManagementTestResourceName;
156+
157+
try
158+
{
159+
# Test
160+
$stoname = 'sto' + $rgname;
161+
$stotype = 'Standard_LRS';
162+
$loc = Get-ProviderLocation ResourceManagement;
163+
$kind = 'StorageV2'
164+
$containerName = "container"+ $rgname
165+
$containerName2 = "container2"+ $rgname
166+
$scopeName = "testscope"
167+
$scopeName2 = "testscope2"
168+
169+
Write-Verbose "RGName: $rgname | Loc: $loc"
170+
New-AzResourceGroup -Name $rgname -Location $loc;
171+
172+
New-AzStorageAccount -ResourceGroupName $rgname -Name $stoname -Location $loc -Type $stotype -Kind $kind
173+
$stos = Get-AzStorageAccount -ResourceGroupName $rgname;
174+
175+
# create Scope
176+
New-AzStorageEncryptionScope -ResourceGroupName $rgname -StorageAccountName $stoname -EncryptionScopeName $scopeName -StorageEncryption
177+
$scope = Get-AzStorageEncryptionScope -ResourceGroupName $rgname -StorageAccountName $stoname -EncryptionScopeName $scopeName
178+
Assert-AreEqual $rgname $scope.ResourceGroupName
179+
Assert-AreEqual $stoname $scope.StorageAccountName
180+
Assert-AreEqual $scopeName $scope.Name
181+
Assert-AreEqual "Microsoft.Storage" $scope.Source
182+
Assert-AreEqual "Enabled" $scope.State
183+
184+
# update Scope
185+
$scope = Update-AzStorageEncryptionScope -ResourceGroupName $rgname -StorageAccountName $stoname -EncryptionScopeName $scopeName -State Disabled
186+
Assert-AreEqual "Disabled" $scope.State
187+
$scope = Update-AzStorageEncryptionScope -ResourceGroupName $rgname -StorageAccountName $stoname -EncryptionScopeName $scopeName -State Enabled
188+
Assert-AreEqual "Enabled" $scope.State
189+
190+
#List Scope
191+
New-AzStorageEncryptionScope -ResourceGroupName $rgname -StorageAccountName $stoname -EncryptionScopeName $scopeName2 -StorageEncryption
192+
$scopes = Get-AzStorageEncryptionScope -ResourceGroupName $rgname -StorageAccountName $stoname
193+
Assert-AreEqual 2 $scopes.Count
194+
195+
#create container
196+
New-AzRmStorageContainer -ResourceGroupName $rgname -StorageAccountName $stoname -Name $containerName -DefaultEncryptionScope $scopename -PreventEncryptionScopeOverride $true
197+
$container = Get-AzRmStorageContainer -ResourceGroupName $rgname -StorageAccountName $stoname -Name $containerName
198+
Assert-AreEqual $rgname $container.ResourceGroupName
199+
Assert-AreEqual $stoname $container.StorageAccountName
200+
Assert-AreEqual $containerName $container.Name
201+
Assert-AreEqual $scopename $container.DefaultEncryptionScope
202+
Assert-AreEqual $true $container.DenyEncryptionScopeOverride
203+
New-AzRmStorageContainer -ResourceGroupName $rgname -StorageAccountName $stoname -Name $containerName2 -DefaultEncryptionScope $scopename2 -PreventEncryptionScopeOverride $false
204+
$container2 = Get-AzRmStorageContainer -ResourceGroupName $rgname -StorageAccountName $stoname -Name $containerName2
205+
Assert-AreEqual $rgname $container2.ResourceGroupName
206+
Assert-AreEqual $stoname $container2.StorageAccountName
207+
Assert-AreEqual $containerName2 $container2.Name
208+
Assert-AreEqual $scopename2 $container2.DefaultEncryptionScope
209+
Assert-AreEqual false $container2.DenyEncryptionScopeOverride
210+
211+
}
212+
finally
213+
{
214+
# Cleanup
215+
Clean-ResourceGroup $rgname
216+
}
217+
}
146218

147219
function Test-StorageBlobContainerLegalHold
148220
{

src/Storage/Storage.Management.Test/ScenarioTests/StorageDataPlaneTests.ps1

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,17 @@ function Test-Blob
286286
$immutabilityPolicy = Get-AzRmStorageContainerImmutabilityPolicy -ResourceGroupName $ResourceGroupName -StorageAccountName $StorageAccountName -ContainerName $containerName
287287
Remove-AzRmStorageContainerImmutabilityPolicy -ResourceGroupName $ResourceGroupName -StorageAccountName $StorageAccountName -ContainerName $containerName -Etag $immutabilityPolicy.Etag
288288

289+
# Encryption Scope Test
290+
$scopename = "testscope"
291+
$containerName2 = "testscopecontainer"
292+
New-AzStorageEncryptionScope -ResourceGroupName $ResourceGroupName -StorageAccountName $storageAccountName -EncryptionScopeName $scopename -StorageEncryption
293+
$container = New-AzStorageContainer -Name $containerName2 -Context $storageContext -DefaultEncryptionScope $scopeName2 -PreventEncryptionScopeOverride $true
294+
Assert-AreEqual $scopename $container.BlobContainerProperties.DefaultEncryptionScope
295+
Assert-AreEqual $true $container.BlobContainerProperties.PreventEncryptionScopeOverride
296+
$blob = Set-AzStorageBlobContent -Context $storageContext -File $localSrcFile -Container $containerName -Blob encryscopetest -EncryptionScope $scopename
297+
Assert-AreEqual $scopename $blob.BlobProperties.EncryptionScope
298+
Remove-AzStorageContainer -Name $containerName2 -Force -Context $storageContext
299+
289300
# Clean Storage Account
290301
Remove-AzStorageContainer -Name $containerName -Force -Context $storageContext
291302

src/Storage/Storage.Management.Test/SessionRecords/Microsoft.Azure.Commands.Management.Storage.Test.ScenarioTests.StorageBlobTests/TestStorageBlobContainerEncryptionScope.json

Lines changed: 1764 additions & 0 deletions
Large diffs are not rendered by default.

src/Storage/Storage.Management/Az.Storage.psd1

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,9 @@ CmdletsToExport = 'Get-AzStorageAccount', 'Get-AzStorageAccountKey',
178178
'New-AzStorageBlobRangeToRestore', 'Restore-AzStorageBlobRange',
179179
'Set-AzDataLakeGen2AclRecursive',
180180
'Update-AzDataLakeGen2AclRecursive',
181-
'Remove-AzDataLakeGen2AclRecursive'
181+
'Remove-AzDataLakeGen2AclRecursive',
182+
'New-AzStorageEncryptionScope','Update-AzStorageEncryptionScope',
183+
'Get-AzStorageEncryptionScope'
182184

183185
# Variables to export from this module
184186
# VariablesToExport = @()

src/Storage/Storage.Management/Blob/NewAzureStorageContainer.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,28 @@ public class NewAzureStorageContainerCommand : StorageBlobBaseCmdlet
3535
/// </summary>
3636
private const string AccountObjectParameterSet = "AccountObject";
3737

38+
/// <summary>
39+
/// AccountName EncryptionScope Parameter Set
40+
/// </summary>
41+
private const string AccountNameEncryptionScopeParameterSet = "AccountNameEncryptionScope";
42+
43+
/// <summary>
44+
/// Account object EncryptionScope parameter set
45+
/// </summary>
46+
private const string AccountObjectEncryptionScopeParameterSet = "AccountObjectEncryptionScope";
47+
3848
[Parameter(
3949
Position = 0,
4050
Mandatory = true,
4151
ValueFromPipelineByPropertyName = true,
4252
HelpMessage = "Resource Group Name.",
4353
ParameterSetName = AccountNameParameterSet)]
54+
[Parameter(
55+
Position = 0,
56+
Mandatory = true,
57+
ValueFromPipelineByPropertyName = true,
58+
HelpMessage = "Resource Group Name.",
59+
ParameterSetName = AccountNameEncryptionScopeParameterSet)]
4460
[ValidateNotNullOrEmpty]
4561
public string ResourceGroupName { get; set; }
4662

@@ -50,6 +66,12 @@ public class NewAzureStorageContainerCommand : StorageBlobBaseCmdlet
5066
ValueFromPipelineByPropertyName = true,
5167
HelpMessage = "Storage Account Name.",
5268
ParameterSetName = AccountNameParameterSet)]
69+
[Parameter(
70+
Position = 1,
71+
Mandatory = true,
72+
ValueFromPipelineByPropertyName = true,
73+
HelpMessage = "Storage Account Name.",
74+
ParameterSetName = AccountNameEncryptionScopeParameterSet)]
5375
[Alias(AccountNameAlias)]
5476
[ValidateNotNullOrEmpty]
5577
public string StorageAccountName { get; set; }
@@ -59,6 +81,11 @@ public class NewAzureStorageContainerCommand : StorageBlobBaseCmdlet
5981
ValueFromPipeline = true,
6082
ValueFromPipelineByPropertyName = true,
6183
ParameterSetName = AccountObjectParameterSet)]
84+
[Parameter(Mandatory = true,
85+
HelpMessage = "Storage account object",
86+
ValueFromPipeline = true,
87+
ValueFromPipelineByPropertyName = true,
88+
ParameterSetName = AccountObjectEncryptionScopeParameterSet)]
6289
[ValidateNotNullOrEmpty]
6390
public PSStorageAccount StorageAccount { get; set; }
6491

@@ -70,6 +97,35 @@ public class NewAzureStorageContainerCommand : StorageBlobBaseCmdlet
7097
[ValidateNotNullOrEmpty]
7198
public string Name { get; set; }
7299

100+
[Parameter(HelpMessage = "Default the container to use specified encryption scope for all writes.",
101+
Mandatory = true,
102+
ParameterSetName = AccountNameEncryptionScopeParameterSet)]
103+
[Parameter(HelpMessage = "Default the container to use specified encryption scope for all writes.",
104+
Mandatory = true,
105+
ParameterSetName = AccountObjectEncryptionScopeParameterSet)]
106+
[ValidateNotNullOrEmpty]
107+
public string DefaultEncryptionScope { get; set; }
108+
109+
[Parameter(HelpMessage = "Block override of encryption scope from the container default.",
110+
Mandatory = true,
111+
ParameterSetName = AccountNameEncryptionScopeParameterSet)]
112+
[Parameter(HelpMessage = "Block override of encryption scope from the container default.",
113+
Mandatory = true,
114+
ParameterSetName = AccountObjectEncryptionScopeParameterSet)]
115+
[ValidateNotNullOrEmpty]
116+
public bool PreventEncryptionScopeOverride
117+
{
118+
get
119+
{
120+
return preventEncryptionScopeOverride is null ? false : preventEncryptionScopeOverride.Value;
121+
}
122+
set
123+
{
124+
preventEncryptionScopeOverride = value;
125+
}
126+
}
127+
private bool? preventEncryptionScopeOverride;
128+
73129
[Parameter(HelpMessage = "Container PublicAccess", Mandatory = false)]
74130
[ValidateNotNullOrEmpty]
75131
public PSPublicAccess PublicAccess
@@ -112,6 +168,8 @@ public override void ExecuteCmdlet()
112168
this.StorageAccountName,
113169
this.Name,
114170
new BlobContainer(
171+
defaultEncryptionScope: this.DefaultEncryptionScope,
172+
denyEncryptionScopeOverride: this.preventEncryptionScopeOverride,
115173
publicAccess: (PublicAccess?)this.publicAccess,
116174
metadata: MetadataDictionary));
117175

src/Storage/Storage.Management/ChangeLog.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@
1818
- Additional information about change #1
1919
-->
2020
## Upcoming Release
21+
* Support create/update/get/list EncryptionScope of a Storage account
22+
- `New-AzStorageEncryptionScope`
23+
- `Update-AzStorageEncryptionScope`
24+
- `Get-AzStorageEncryptionScope`
25+
* Supported create container and upload blob with Encryption Scope setting
26+
- `New-AzRmStorageContainer`
27+
- `New-AzStorageContainer`
28+
- `Set-AzStorageBlobContent`
2129

2230
## Version 3.1.0
2331
* Supported upload Azure File size up to 4 TiB

src/Storage/Storage.Management/Models/PSContainer.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ public PSContainer(StorageModels.ListContainerItem container)
4545
this.LeaseDuration = container.LeaseDuration;
4646
this.HasLegalHold = container.HasLegalHold;
4747
this.HasImmutabilityPolicy = container.HasImmutabilityPolicy;
48+
this.DefaultEncryptionScope = container.DefaultEncryptionScope;
49+
this.DenyEncryptionScopeOverride = container.DenyEncryptionScopeOverride;
4850
}
4951

5052
public PSContainer(BlobContainer container)
@@ -65,6 +67,8 @@ public PSContainer(BlobContainer container)
6567
this.LeaseDuration = container.LeaseDuration;
6668
this.HasLegalHold = container.HasLegalHold;
6769
this.HasImmutabilityPolicy = container.HasImmutabilityPolicy;
70+
this.DefaultEncryptionScope = container.DefaultEncryptionScope;
71+
this.DenyEncryptionScopeOverride = container.DenyEncryptionScopeOverride;
6872
}
6973

7074
[Ps1Xml(Label = "ResourceGroupName", Target = ViewControl.List, Position = 0)]
@@ -106,6 +110,10 @@ public PSContainer(BlobContainer container)
106110
[Ps1Xml(Label = "HasImmutabilityPolicy", Target = ViewControl.List, Position = 6)]
107111
public bool? HasImmutabilityPolicy { get; set; }
108112

113+
public string DefaultEncryptionScope { get; set; }
114+
115+
public bool? DenyEncryptionScopeOverride { get; set; }
116+
109117

110118
public static string ParseResourceGroupFromId(string idFromServer)
111119
{
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
16+
using Microsoft.Azure.Management.Storage;
17+
using Microsoft.Azure.Management.Storage.Models;
18+
using Microsoft.WindowsAzure.Commands.Common.Attributes;
19+
using Microsoft.WindowsAzure.Commands.Common.Storage;
20+
using Microsoft.WindowsAzure.Commands.Storage.Adapters;
21+
using Microsoft.Azure.Storage;
22+
using System;
23+
using System.Collections.Generic;
24+
using StorageModels = Microsoft.Azure.Management.Storage.Models;
25+
26+
namespace Microsoft.Azure.Commands.Management.Storage.Models
27+
{
28+
// wrapper of EncryptionScope
29+
public class PSEncryptionScope
30+
{
31+
public PSEncryptionScope(StorageModels.EncryptionScope scope)
32+
{
33+
this.ResourceGroupName = ParseResourceGroupFromId(scope.Id);
34+
this.StorageAccountName = ParseStorageAccountNameFromId(scope.Id);
35+
this.Id = scope.Id;
36+
this.Name = scope.Name;
37+
this.Type = scope.Type;
38+
this.LastModifiedTime = scope.LastModifiedTime;
39+
this.CreationTime = scope.CreationTime;
40+
this.Source = scope.Source;
41+
this.State = scope.State;
42+
this.KeyVaultProperties = scope.KeyVaultProperties is null ? null : new PSEncryptionScopeKeyVaultProperties(scope.KeyVaultProperties);
43+
}
44+
45+
[Ps1Xml(Label = "ResourceGroupName", Target = ViewControl.List, Position = 0)]
46+
public string ResourceGroupName { get; set; }
47+
48+
[Ps1Xml(Label = "StorageAccountName", Target = ViewControl.List, Position = 1)]
49+
public string StorageAccountName { get; set; }
50+
51+
public string Id { get; set; }
52+
53+
[Ps1Xml(Label = "Name", Target = ViewControl.List, Position = 2)]
54+
public string Name { get; set; }
55+
56+
public string Type { get; set; }
57+
58+
public string Source { get; set; }
59+
60+
public string State { get; set; }
61+
62+
public PSEncryptionScopeKeyVaultProperties KeyVaultProperties { get; set; }
63+
64+
[Ps1Xml(Label = "LastModifiedTime", Target = ViewControl.List, Position = 4)]
65+
public DateTime? LastModifiedTime { get; set; }
66+
67+
public DateTime? CreationTime { get; set; }
68+
69+
public static string ParseResourceGroupFromId(string idFromServer)
70+
{
71+
if (!string.IsNullOrEmpty(idFromServer))
72+
{
73+
string[] tokens = idFromServer.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
74+
75+
return tokens[3];
76+
}
77+
78+
return null;
79+
}
80+
81+
public static string ParseStorageAccountNameFromId(string idFromServer)
82+
{
83+
if (!string.IsNullOrEmpty(idFromServer))
84+
{
85+
string[] tokens = idFromServer.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
86+
87+
return tokens[7];
88+
}
89+
90+
return null;
91+
}
92+
93+
}
94+
95+
//wrapper of EncryptionScopeKeyVaultProperties
96+
public class PSEncryptionScopeKeyVaultProperties
97+
{
98+
public PSEncryptionScopeKeyVaultProperties(StorageModels.EncryptionScopeKeyVaultProperties keyVaultProperties)
99+
{
100+
if (keyVaultProperties != null)
101+
{
102+
this.keyUri = keyVaultProperties.KeyUri;
103+
}
104+
}
105+
106+
public string keyUri { get; set; }
107+
}
108+
109+
110+
}

0 commit comments

Comments
 (0)