Skip to content

Commit 8b22c86

Browse files
kr-santoshBethanyZhouVeryEarly
authored
[CosmosDB] Adds support to allow partition key and id paths to be part of client encryption policy. (Azure#18633)
* Support client encryption policy during container creation * Update SqlOperationsTests.ps1 * Update New-AzCosmosDBSqlContainer.md * Update PSClientEncryptionPolicy.cs * Update NewAzCosmosDBSqlContainer.cs * Update ChangeLog.md * Updated package. * Update CosmosDB.Test.csproj * Updated example, session records. * updated session records. * Fixes update container command on containers with client encryption policy. * Update ChangeLog.md * Update ChangeLog.md * Support partition key and id paths to be part of client encryption policy * Update ChangeLog.md * Update New-AzCosmosDBSqlContainer.md * Update PSClientEncryptionPolicy.cs * Update src/CosmosDB/CosmosDB/ChangeLog.md Co-authored-by: Beisi Zhou <[email protected]> Co-authored-by: Beisi Zhou <[email protected]> Co-authored-by: Yabo Hu <[email protected]>
1 parent 6568795 commit 8b22c86

File tree

4 files changed

+73
-26
lines changed

4 files changed

+73
-26
lines changed

src/CosmosDB/CosmosDB/ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
-->
2020

2121
## Upcoming Release
22+
* Added support for partition key and id paths to be part of client encryption policy.
2223
* Fixed bug related to Update-AzCosmosDBSqlContainer command on containers with Client Encryption Policy.
2324

2425
## Version 1.9.0

src/CosmosDB/CosmosDB/Models/PSClientEncryptionPolicy.cs

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public PSClientEncryptionPolicy(ClientEncryptionPolicy clientEncryptionPolicy)
3636

3737
if (ModelHelper.IsNotNullOrEmpty(clientEncryptionPolicy.IncludedPaths))
3838
{
39-
PSClientEncryptionPolicy.ValidateIncludedPaths(clientEncryptionPolicy.IncludedPaths);
39+
PSClientEncryptionPolicy.ValidateIncludedPaths(clientEncryptionPolicy.IncludedPaths, (int)clientEncryptionPolicy.PolicyFormatVersion);
4040

4141
IncludedPaths = new List<PSClientEncryptionIncludedPath>();
4242
foreach (ClientEncryptionIncludedPath key in clientEncryptionPolicy.IncludedPaths)
@@ -87,9 +87,12 @@ public static ClientEncryptionPolicy ToSDKModel(PSClientEncryptionPolicy pSClien
8787
}
8888
}
8989

90-
PSClientEncryptionPolicy.ValidatePartitionKeyPathsAreNotEncrypted(clientEncryptionPolicy.IncludedPaths, partitionKeyPathTokens);
90+
PSClientEncryptionPolicy.ValidatePartitionKeyPathsAreNotEncrypted(
91+
clientEncryptionPolicy.IncludedPaths,
92+
partitionKeyPathTokens,
93+
pSClientEncryptionPolicy.PolicyFormatVersion);
9194

92-
if(clientEncryptionPolicy.PolicyFormatVersion != 1)
95+
if(clientEncryptionPolicy.PolicyFormatVersion < 1 || clientEncryptionPolicy.PolicyFormatVersion > 2)
9396
{
9497
throw new InvalidOperationException($"Invalid PolicyFormatVersion:{clientEncryptionPolicy.PolicyFormatVersion} used in Client Encryption Policy. ");
9598
}
@@ -102,26 +105,44 @@ public static ClientEncryptionPolicy ToSDKModel(PSClientEncryptionPolicy pSClien
102105
/// </summary>
103106
/// <param name="clientEncryptionIncludedPath">Included paths of the client encryption policy.</param>
104107
/// <param name="partitionKeyPathTokens">Tokens corresponding to validated partition key.</param>
105-
private static void ValidatePartitionKeyPathsAreNotEncrypted(IEnumerable<ClientEncryptionIncludedPath> clientEncryptionIncludedPath, List<string> partitionKeyPathTokens)
108+
/// <param name="policyFormatVersion">Client encryption policy format version.</param>
109+
private static void ValidatePartitionKeyPathsAreNotEncrypted(
110+
IEnumerable<ClientEncryptionIncludedPath> clientEncryptionIncludedPath,
111+
List<string> partitionKeyPathTokens,
112+
int policyFormatVersion)
106113
{
107114
Debug.Assert(partitionKeyPathTokens != null);
108-
IEnumerable<string> propertiesToEncrypt = clientEncryptionIncludedPath.Select(p => p.Path.Substring(1));
115+
109116
foreach (string tokenInPath in partitionKeyPathTokens)
110117
{
111-
Debug.Assert(String.IsNullOrEmpty(tokenInPath));
112-
if (propertiesToEncrypt.Contains(tokenInPath.Substring(1)))
118+
Debug.Assert(String.IsNullOrEmpty(tokenInPath));
119+
120+
string topLevelPath = tokenInPath.Split('/')[1];
121+
// paths in included paths start with "/". Get the ClientEncryptionIncludedPath and validate.
122+
IEnumerable<ClientEncryptionIncludedPath> encryptedPartitionKeyPath = clientEncryptionIncludedPath.Where(p => p.Path.Substring(1).Equals(topLevelPath));
123+
124+
if (encryptedPartitionKeyPath.Any())
113125
{
114-
throw new ArgumentException($"Paths which are part of the partition key({tokenInPath}) may not be included in the Client Encryption Policy. ");
126+
if (policyFormatVersion < 2)
127+
{
128+
throw new ArgumentException($"Path: {encryptedPartitionKeyPath.Select(et => et.Path).FirstOrDefault()} which is part of the partition key cannot be encrypted with PolicyFormatVersion: {policyFormatVersion}. Please use PolicyFormatVersion: 2. ");
129+
}
130+
131+
// for the ClientEncryptionIncludedPath found check the encryption type.
132+
if (encryptedPartitionKeyPath.Select(et => et.EncryptionType).FirstOrDefault() != "Deterministic")
133+
{
134+
throw new ArgumentException($"Path: {encryptedPartitionKeyPath.Select(et => et.Path).FirstOrDefault()} which is part of the partition key has to be encrypted with Deterministic type Encryption.");
135+
}
115136
}
116137
}
117138
}
118139

119-
private static void ValidateIncludedPaths(IEnumerable<ClientEncryptionIncludedPath> clientEncryptionIncludedPath)
140+
private static void ValidateIncludedPaths(IEnumerable<ClientEncryptionIncludedPath> clientEncryptionIncludedPath, int policyFormatVersion)
120141
{
121142
List<string> includedPathsList = new List<string>();
122143
foreach (ClientEncryptionIncludedPath path in clientEncryptionIncludedPath)
123144
{
124-
PSClientEncryptionPolicy.ValidateClientEncryptionIncludedPath(path);
145+
PSClientEncryptionPolicy.ValidateClientEncryptionIncludedPath(path, policyFormatVersion);
125146
if (includedPathsList.Contains(path.Path))
126147
{
127148
throw new ArgumentException($"Duplicate Path({path.Path}) found.", nameof(clientEncryptionIncludedPath));
@@ -131,7 +152,7 @@ private static void ValidateIncludedPaths(IEnumerable<ClientEncryptionIncludedPa
131152
}
132153
}
133154

134-
private static void ValidateClientEncryptionIncludedPath(ClientEncryptionIncludedPath clientEncryptionIncludedPath)
155+
private static void ValidateClientEncryptionIncludedPath(ClientEncryptionIncludedPath clientEncryptionIncludedPath, int policyFormatVersion)
135156
{
136157
if (clientEncryptionIncludedPath == null)
137158
{
@@ -144,8 +165,7 @@ private static void ValidateClientEncryptionIncludedPath(ClientEncryptionInclude
144165
}
145166

146167
if (clientEncryptionIncludedPath.Path[0] != '/'
147-
|| clientEncryptionIncludedPath.Path.LastIndexOf('/') != 0
148-
|| string.Equals(clientEncryptionIncludedPath.Path.Substring(1), "id"))
168+
|| clientEncryptionIncludedPath.Path.LastIndexOf('/') != 0)
149169
{
150170
throw new ArgumentException($"Invalid path '{clientEncryptionIncludedPath.Path ?? string.Empty}'.");
151171
}
@@ -160,6 +180,19 @@ private static void ValidateClientEncryptionIncludedPath(ClientEncryptionInclude
160180
throw new ArgumentNullException(nameof(clientEncryptionIncludedPath.EncryptionType));
161181
}
162182

183+
if (string.Equals(clientEncryptionIncludedPath.Path.Substring(1), "id"))
184+
{
185+
if (policyFormatVersion < 2)
186+
{
187+
throw new ArgumentException($"Path: {clientEncryptionIncludedPath.Path} cannot be encrypted with PolicyFormatVersion: {policyFormatVersion}. Please use PolicyFormatVersion: 2. ");
188+
}
189+
190+
if (clientEncryptionIncludedPath.EncryptionType != "Deterministic")
191+
{
192+
throw new ArgumentException($"Only Deterministic encryption type is supported for path: {clientEncryptionIncludedPath.Path}. ");
193+
}
194+
}
195+
163196
if (!string.Equals(clientEncryptionIncludedPath.EncryptionType, "Deterministic") &&
164197
!string.Equals(clientEncryptionIncludedPath.EncryptionType, "Randomized"))
165198
{

src/CosmosDB/CosmosDB/Models/Sql/PSSqlClientEncryptionPolicy.cs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// limitations under the License.
1313
// ----------------------------------------------------------------------------------
1414
using Microsoft.Azure.Management.CosmosDB.Models;
15+
using System;
1516

1617
namespace Microsoft.Azure.Commands.CosmosDB.Models
1718
{
@@ -20,15 +21,28 @@ public class PSSqlClientEncryptionPolicy : PSClientEncryptionPolicy
2021
{
2122
public PSSqlClientEncryptionPolicy() : base()
2223
{
23-
}
24+
}
2425

25-
public PSSqlClientEncryptionPolicy(ClientEncryptionPolicy clientEncryptionPolicy) : base(PSSqlClientEncryptionPolicy.SetSupportedPolicyVersionOnClientEncryptionPolicy(clientEncryptionPolicy))
26+
public PSSqlClientEncryptionPolicy(ClientEncryptionPolicy clientEncryptionPolicy) : base(PSSqlClientEncryptionPolicy.SetSupportedPolicyVersionOnClientEncryptionPolicy(clientEncryptionPolicy, clientEncryptionPolicy.PolicyFormatVersion))
2627
{
2728
}
2829

29-
private static ClientEncryptionPolicy SetSupportedPolicyVersionOnClientEncryptionPolicy(ClientEncryptionPolicy clientEncryptionPolicy)
30+
private static ClientEncryptionPolicy SetSupportedPolicyVersionOnClientEncryptionPolicy(ClientEncryptionPolicy clientEncryptionPolicy, int? policyFormatVersion = null)
3031
{
31-
clientEncryptionPolicy.PolicyFormatVersion = 1;
32+
if (policyFormatVersion == null)
33+
{
34+
clientEncryptionPolicy.PolicyFormatVersion = 1;
35+
}
36+
else
37+
{
38+
if(policyFormatVersion > 2 || policyFormatVersion < 1)
39+
{
40+
throw new ArgumentException($"Supported versions of client encryption policy are 1 and 2. ");
41+
}
42+
43+
clientEncryptionPolicy.PolicyFormatVersion = policyFormatVersion;
44+
}
45+
3246
return clientEncryptionPolicy;
3347
}
3448
}

src/CosmosDB/CosmosDB/help/New-AzCosmosDBSqlContainer.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,14 @@ Resource : Microsoft.Azure.Commands.CosmosDB.Models.PSSqlContainerGetPropertiesR
5757

5858
### Example 2: Create a new CosmosDB Sql Container with Client Encryption Policy
5959
```powershell
60-
$includedPath1 = [Microsoft.Azure.Management.CosmosDB.Models.ClientEncryptionIncludedPath]::new("/path1","key1","Deterministic","AEAD_AES_256_CBC_HMAC_SHA256");
61-
$includedPath2 = [Microsoft.Azure.Management.CosmosDB.Models.ClientEncryptionIncludedPath]::new("/path2","key2","Randomized","AEAD_AES_256_CBC_HMAC_SHA256");
62-
$listofIncludedPaths = New-Object Collections.Generic.List[Microsoft.Azure.Management.CosmosDB.Models.ClientEncryptionIncludedPath]
63-
$listofIncludedPaths.Add($includedPath1)
64-
$listofIncludedPaths.Add($includedPath2)
65-
$newClientEncryptionPolicy = New-Object Microsoft.Azure.Management.CosmosDB.Models.ClientEncryptionPolicy
66-
$newClientEncryptionPolicy.IncludedPaths = $listofIncludedPaths
67-
$newPSSqlClientEncryptionPolicy = [Microsoft.Azure.Commands.CosmosDB.Models.PSSqlClientEncryptionPolicy]::new($newClientEncryptionPolicy)
68-
New-AzCosmosDBSqlContainer -AccountName myAccountName -DatabaseName myDatabaseName -ResourceGroupName myRgName -Name myContainerName -PartitionKeyPath /a/b/c -PartitionKeyKind Hash -ClientEncryptionPolicy $newPSSqlClientEncryptionPolicy
60+
PS C:\> $includedPath1 = [Microsoft.Azure.Management.CosmosDB.Models.ClientEncryptionIncludedPath]::new("/path1","key1","Deterministic","AEAD_AES_256_CBC_HMAC_SHA256");
61+
PS C:\> $includedPath2 = [Microsoft.Azure.Management.CosmosDB.Models.ClientEncryptionIncludedPath]::new("/path2","key2","Randomized","AEAD_AES_256_CBC_HMAC_SHA256");
62+
PS C:\> $listofIncludedPaths = New-Object Collections.Generic.List[Microsoft.Azure.Management.CosmosDB.Models.ClientEncryptionIncludedPath]
63+
PS C:\> $listofIncludedPaths.Add($includedPath1)
64+
PS C:\> $listofIncludedPaths.Add($includedPath2)
65+
PS C:\> $newClientEncryptionPolicy = [Microsoft.Azure.Management.CosmosDB.Models.ClientEncryptionPolicy]::new($listofIncludedPaths, 2)
66+
PS C:\> $newPSSqlClientEncryptionPolicy = [Microsoft.Azure.Commands.CosmosDB.Models.PSSqlClientEncryptionPolicy]::new($newClientEncryptionPolicy)
67+
PS C:\> New-AzCosmosDBSqlContainer -AccountName myAccountName -DatabaseName myDatabaseName -ResourceGroupName myRgName -Name myContainerName -PartitionKeyPath /a/b/c -PartitionKeyKind Hash -ClientEncryptionPolicy $newPSSqlClientEncryptionPolicy
6968
```
7069

7170
```output

0 commit comments

Comments
 (0)