Skip to content

Commit 1d12089

Browse files
committed
Updates
1 parent 2450583 commit 1d12089

File tree

11 files changed

+275
-6
lines changed

11 files changed

+275
-6
lines changed

aspnetcore/release-notes/aspnetcore-9/includes/delete_keys.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
Prior to .NET 9, data protection keys were ___not___ deletable by design, to prevent data loss. Deleting a key renders its protected data irretrievable. Given their small size, the accumulation of these keys generally posed minimal impact. However, to accommodate extremely long-running services, we have introduced the option to delete keys. Generally, only old keys should be deleted. Only delete keys when you can accept the risk of data loss in exchange for storage savings. We recommend data protection keys should ___not___ be deleted.
44

5-
:::code language="csharp" source="~/security/data-protection/configuration/samples/9/deleteKeys/Program.cs" :::
5+
:::code language="csharp" source="~/security/data-protection/configuration/samples/9.x/deleteKeys/Program.cs" :::

aspnetcore/security/data-protection/configuration/default-settings.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Deleting a key makes its protected data permanently inaccessible. To mitigate th
5858

5959
We recommend not deleting data protection keys.
6060

61-
:::code language="csharp" source="~/security/data-protection/configuration/samples/9/deleteKeys/Program.cs" :::
61+
:::code language="csharp" source="~/security/data-protection/configuration/samples/9.x/deleteKeys/Program.cs" :::
6262

6363
## Additional resources
6464

aspnetcore/security/data-protection/configuration/overview.md

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,37 @@ This property represents the table in which the keys are stored. Create the tabl
122122

123123
## Protect keys configuration API (`ProtectKeysWith\*`)
124124

125-
You can configure the system to protect keys at rest by calling any of the [ProtectKeysWith\*](xref:Microsoft.AspNetCore.DataProtection.DataProtectionBuilderExtensions) configuration APIs. Consider the example below, which stores keys on a UNC share and encrypts those keys at rest with a specific X.509 certificate:
125+
You can configure the system to protect keys at rest by calling any of the [`ProtectKeysWith\*`](xref:Microsoft.AspNetCore.DataProtection.DataProtectionBuilderExtensions) configuration APIs. Consider the example below, which stores keys on a UNC share and encrypts those keys at rest with a specific X.509 certificate.
126+
127+
:::moniker-end
128+
129+
:::moniker range=">= aspnetcore-9.0"
130+
131+
You can provide an <xref:System.Security.Cryptography.X509Certificates.X509Certificate2> to <xref:Microsoft.AspNetCore.DataProtection.DataProtectionBuilderExtensions.ProtectKeysWithCertificate%2A> from a file by calling <xref:System.Security.Cryptography.X509Certificates.X509CertificateLoader.LoadCertificateFromFile%2A?displayProperty=nameWithType>:
132+
133+
:::code language="csharp" source="samples/6.x/DataProtectionConfigurationSample/Snippets/Program.cs" id="snippet_AddDataProtectionProtectKeysWithCertificateX509Certificate2":::
134+
135+
The following code example demonstrates how to load a certificate using a thumbprint:
126136

127137
:::code language="csharp" source="samples/6.x/DataProtectionConfigurationSample/Snippets/Program.cs" id="snippet_AddDataProtectionProtectKeysWithCertificate":::
128138

139+
:::moniker-end
140+
141+
:::moniker range=">= aspnetcore-6.0 < aspnetcore-9.0"
142+
129143
You can provide an <xref:System.Security.Cryptography.X509Certificates.X509Certificate2> to <xref:Microsoft.AspNetCore.DataProtection.DataProtectionBuilderExtensions.ProtectKeysWithCertificate%2A>, such as a certificate loaded from a file:
130144

131145
:::code language="csharp" source="samples/6.x/DataProtectionConfigurationSample/Snippets/Program.cs" id="snippet_AddDataProtectionProtectKeysWithCertificateX509Certificate2":::
132146

133-
See [Key Encryption At Rest](xref:security/data-protection/implementation/key-encryption-at-rest) for more examples and discussion on the built-in key encryption mechanisms.
147+
The following code example demonstrates how to load a certificate using a thumbprint:
148+
149+
:::code language="csharp" source="samples/6.x/DataProtectionConfigurationSample/Snippets/Program.cs" id="snippet_AddDataProtectionProtectKeysWithCertificate":::
150+
151+
:::moniker-end
152+
153+
:::moniker range=">= aspnetcore-6.0"
154+
155+
For examples and discussion on the built-in key encryption mechanisms, see <xref:security/data-protection/implementation/key-encryption-at-rest>.
134156

135157
## Unprotect keys with any certificate (`UnprotectKeysWithAnyCertificate`)
136158

@@ -186,7 +208,7 @@ For more information on how the discriminator is used, see the following section
186208
> app.MapGet("/", () => Assembly.GetEntryAssembly()!.GetName().Name);
187209
>
188210
> app.Run();
189-
> ```
211+
> ```
190212
191213
## Disable automatic key generation (`DisableAutomaticKeyGeneration`)
192214
@@ -418,7 +440,7 @@ public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
418440
419441
This property represents the table in which the keys are stored. Create the table manually or with `DbContext` Migrations. For more information, see <xref:Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey>.
420442
421-
## `ProtectKeysWith\*`
443+
## Protect keys configuration API (`ProtectKeysWith\*`)
422444
423445
You can configure the system to protect keys at rest by calling any of the [`ProtectKeysWith\*`](xref:Microsoft.AspNetCore.DataProtection.DataProtectionBuilderExtensions) configuration APIs. Consider the example below, which stores keys on a UNC share and encrypts those keys at rest with a specific X.509 certificate:
424446
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Azure.Extensions.AspNetCore.DataProtection.Blobs" Version="1.5.0" />
11+
<PackageReference Include="Azure.Extensions.AspNetCore.DataProtection.Keys" Version="1.6.0" />
12+
<PackageReference Include="Azure.Identity" Version="1.14.0" />
13+
<PackageReference Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="9.0.5" />
14+
</ItemGroup>
15+
16+
</Project>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
var builder = WebApplication.CreateBuilder(args);
2+
var app = builder.Build();
3+
4+
app.MapGet("/", () => "Hello World!");
5+
6+
app.Run();
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
using System.Security.Cryptography;
2+
using System.Security.Cryptography.X509Certificates;
3+
using Azure.Identity;
4+
using Microsoft.AspNetCore.DataProtection;
5+
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
6+
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
7+
8+
namespace DataProtectionConfigurationSample.Snippets;
9+
10+
public static class Program
11+
{
12+
public static void AddDataProtectionProtectKeysWithAzureKeyVault(WebApplicationBuilder builder)
13+
{
14+
// <snippet_AddDataProtectionProtectKeysWithAzureKeyVault>
15+
builder.Services.AddDataProtection()
16+
.PersistKeysToAzureBlobStorage(new Uri("<blobUriWithSasToken>"))
17+
.ProtectKeysWithAzureKeyVault(new Uri("<keyIdentifier>"),
18+
new DefaultAzureCredential());
19+
// </snippet_AddDataProtectionProtectKeysWithAzureKeyVault>
20+
}
21+
22+
public static void AddDataProtectionProtectKeysWithAzureKeyVaultConnectionString(WebApplicationBuilder builder)
23+
{
24+
// <snippet_AddDataProtectionProtectKeysWithAzureKeyVaultConnectionString>
25+
builder.Services.AddDataProtection()
26+
// This blob must already exist before the application is run
27+
.PersistKeysToAzureBlobStorage(
28+
"<storageAccountConnectionString", "<containerName>", "<blobName>")
29+
// Removing this line below for an initial run will ensure the file is
30+
// created correctly
31+
.ProtectKeysWithAzureKeyVault(new Uri("<keyIdentifier>"),
32+
new DefaultAzureCredential());
33+
// </snippet_AddDataProtectionProtectKeysWithAzureKeyVaultConnectionString>
34+
}
35+
36+
public static void AddDataProtectionPersistKeysToFileSystem(WebApplicationBuilder builder)
37+
{
38+
// <snippet_AddDataProtectionPersistKeysToFileSystem>
39+
builder.Services.AddDataProtection()
40+
.PersistKeysToFileSystem(
41+
new DirectoryInfo(@"\\server\share\directory\"));
42+
// </snippet_AddDataProtectionPersistKeysToFileSystem>
43+
}
44+
45+
public static void AddDataProtectionPersistKeysToDbContext(WebApplicationBuilder builder)
46+
{
47+
// <snippet_AddDataProtectionPersistKeysToDbContext>
48+
builder.Services.AddDataProtection()
49+
.PersistKeysToDbContext<SampleDbContext>();
50+
// </snippet_AddDataProtectionPersistKeysToDbContext>
51+
}
52+
53+
public static void AddDataProtectionProtectKeysWithCertificate(WebApplicationBuilder builder)
54+
{
55+
// <snippet_AddDataProtectionProtectKeysWithCertificate>
56+
builder.Services.AddDataProtection()
57+
.PersistKeysToFileSystem(
58+
new DirectoryInfo(builder.Configuration["CertificatePath"] ??
59+
throw new Exception("No path")))
60+
.ProtectKeysWithCertificate(
61+
builder.Configuration["CertificateThumbprint"] ??
62+
throw new Exception("No thumbprint"));
63+
// </snippet_AddDataProtectionProtectKeysWithCertificate>
64+
}
65+
66+
public static void AddDataProtectionProtectKeysWithCertificateX509Certificate2(WebApplicationBuilder builder)
67+
{
68+
// <snippet_AddDataProtectionProtectKeysWithCertificateX509Certificate2>
69+
builder.Services.AddDataProtection()
70+
.PersistKeysToFileSystem(new DirectoryInfo(
71+
builder.Configuration["CertificatePath"] ??
72+
throw new Exception("No path")))
73+
.ProtectKeysWithCertificate(
74+
X509CertificateLoader.LoadCertificateFromFile(
75+
builder.Configuration["CertificateFileName"] ??
76+
throw new Exception("No file name")));
77+
// </snippet_AddDataProtectionProtectKeysWithCertificateX509Certificate2>
78+
}
79+
80+
public static void AddDataProtectionUnprotectKeysWithAnyCertificate(WebApplicationBuilder builder)
81+
{
82+
// <snippet_AddDataProtectionUnprotectKeysWithAnyCertificate>
83+
builder.Services.AddDataProtection()
84+
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
85+
.ProtectKeysWithCertificate(
86+
X509CertificateLoader.LoadCertificateFromFile(
87+
builder.Configuration["CertificateFileName"] ??
88+
throw new Exception("No file name")))
89+
.UnprotectKeysWithAnyCertificate(
90+
X509CertificateLoader.LoadCertificateFromFile(
91+
builder.Configuration["CertificateFileName1"] ??
92+
throw new Exception("No file name 1")),
93+
X509CertificateLoader.LoadCertificateFromFile(
94+
builder.Configuration["CertificateFileName2"] ??
95+
throw new Exception("No file name 2")));
96+
// </snippet_AddDataProtectionUnprotectKeysWithAnyCertificate>
97+
}
98+
99+
public static void AddDataProtectionSetDefaultKeyLifetime(WebApplicationBuilder builder)
100+
{
101+
// <snippet_AddDataProtectionSetDefaultKeyLifetime>
102+
builder.Services.AddDataProtection()
103+
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
104+
// </snippet_AddDataProtectionSetDefaultKeyLifetime>
105+
}
106+
107+
public static void AddDataProtectionSetApplicationName(WebApplicationBuilder builder)
108+
{
109+
// <snippet_AddDataProtectionSetApplicationName>
110+
builder.Services.AddDataProtection()
111+
.SetApplicationName("<sharedApplicationName>");
112+
// </snippet_AddDataProtectionSetApplicationName>
113+
}
114+
115+
public static void AddDataProtectionDisableAutomaticKeyGeneration(WebApplicationBuilder builder)
116+
{
117+
// <snippet_AddDataProtectionDisableAutomaticKeyGeneration>
118+
builder.Services.AddDataProtection()
119+
.DisableAutomaticKeyGeneration();
120+
// </snippet_AddDataProtectionDisableAutomaticKeyGeneration>
121+
}
122+
123+
public static void AddDataProtectionUseCryptographicAlgorithms(WebApplicationBuilder builder)
124+
{
125+
// <snippet_AddDataProtectionUseCryptographicAlgorithms>
126+
builder.Services.AddDataProtection()
127+
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
128+
{
129+
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
130+
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
131+
});
132+
// </snippet_AddDataProtectionUseCryptographicAlgorithms>
133+
}
134+
135+
public static void AddDataProtectionUseCustomCryptographicAlgorithms(WebApplicationBuilder builder)
136+
{
137+
// <snippet_AddDataProtectionUseCustomCryptographicAlgorithms>
138+
builder.Services.AddDataProtection()
139+
.UseCustomCryptographicAlgorithms(
140+
new ManagedAuthenticatedEncryptorConfiguration
141+
{
142+
// A type that subclasses SymmetricAlgorithm
143+
EncryptionAlgorithmType = typeof(Aes),
144+
145+
// Specified in bits
146+
EncryptionAlgorithmKeySize = 256,
147+
148+
// A type that subclasses KeyedHashAlgorithm
149+
ValidationAlgorithmType = typeof(HMACSHA256)
150+
});
151+
// </snippet_AddDataProtectionUseCustomCryptographicAlgorithms>
152+
}
153+
154+
#pragma warning disable CA1416 // Validate platform compatibility
155+
public static void AddDataProtectionUseCustomCryptographicAlgorithmsCngCbc(WebApplicationBuilder builder)
156+
{
157+
// <snippet_AddDataProtectionUseCustomCryptographicAlgorithmsCngCbc>
158+
builder.Services.AddDataProtection()
159+
.UseCustomCryptographicAlgorithms(
160+
new CngCbcAuthenticatedEncryptorConfiguration
161+
{
162+
// Passed to BCryptOpenAlgorithmProvider
163+
EncryptionAlgorithm = "AES",
164+
EncryptionAlgorithmProvider = null,
165+
166+
// Specified in bits
167+
EncryptionAlgorithmKeySize = 256,
168+
169+
// Passed to BCryptOpenAlgorithmProvider
170+
HashAlgorithm = "SHA256",
171+
HashAlgorithmProvider = null
172+
});
173+
// </snippet_AddDataProtectionUseCustomCryptographicAlgorithmsCngCbc>
174+
}
175+
176+
public static void AddDataProtectionUseCustomCryptographicAlgorithmsCngGcm(WebApplicationBuilder builder)
177+
{
178+
// <snippet_AddDataProtectionUseCustomCryptographicAlgorithmsCngGcm>
179+
builder.Services.AddDataProtection()
180+
.UseCustomCryptographicAlgorithms(
181+
new CngGcmAuthenticatedEncryptorConfiguration
182+
{
183+
// Passed to BCryptOpenAlgorithmProvider
184+
EncryptionAlgorithm = "AES",
185+
EncryptionAlgorithmProvider = null,
186+
187+
// Specified in bits
188+
EncryptionAlgorithmKeySize = 256
189+
});
190+
// </snippet_AddDataProtectionUseCustomCryptographicAlgorithmsCngGcm>
191+
}
192+
#pragma warning restore CA1416 // Validate platform compatibility
193+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
2+
using Microsoft.EntityFrameworkCore;
3+
4+
namespace DataProtectionConfigurationSample.Snippets;
5+
6+
public class SampleDbContext : DbContext, IDataProtectionKeyContext
7+
{
8+
public SampleDbContext(DbContextOptions<SampleDbContext> dbContextOptions)
9+
: base(dbContextOptions) { }
10+
11+
// <snippet_DataProtectionKeys>
12+
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; } = null!;
13+
// </snippet_DataProtectionKeys>
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
}
8+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning",
6+
"Microsoft.AspNetCore.DataProtection": "Information"
7+
}
8+
},
9+
"AllowedHosts": "*"
10+
}

0 commit comments

Comments
 (0)