Skip to content

Commit 1c455c0

Browse files
authored
Remove SAS dependency for Data Protection blob access (#555)
* Updated Storage.Blobs package from 12.16.0 to 12.19.1 Use identity credentials to protect master keyring Added missing appsetting for Key Vault Key * Switch to using local filepath for storage of keys.xml * Removed unnecessary reference * Deploy Key vault for data protection * Deploy a File Share and use it as a local path for data protection Fix readme * Enable overriding of file share path * Better conditional handling
1 parent 117299a commit 1c455c0

File tree

8 files changed

+52
-13
lines changed

8 files changed

+52
-13
lines changed

Dfe.Academies.External.Web/Dfe.Academies.External.Web.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
<ItemGroup>
1919
<PackageReference Include="AutoMapper" Version="13.0.1" />
20-
<PackageReference Include="Azure.Extensions.AspNetCore.DataProtection.Blobs" Version="1.3.3" />
21-
<PackageReference Include="Azure.Storage.Blobs" Version="12.19.1" />
20+
<PackageReference Include="Azure.Extensions.AspNetCore.DataProtection.Keys" Version="1.2.3" />
21+
<PackageReference Include="Azure.Identity" Version="1.11.0" />
2222
<PackageReference Include="Dfe.Academies.Contracts" Version="1.0.10" />
2323
<PackageReference Include="Dfe.Academisation.CorrelationIdMiddleware" Version="2.0.2" />
2424
<PackageReference Include="FluentValidation" Version="11.9.0" />

Dfe.Academies.External.Web/Program.cs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System.Globalization;
2-
using Azure.Storage.Blobs;
2+
using Azure.Identity;
33
using Dfe.Academies.External.Web.AutoMapper;
44
using Dfe.Academies.External.Web.Extensions;
55
using Dfe.Academies.External.Web.Factories;
@@ -28,7 +28,7 @@
2828
var builder = WebApplication.CreateBuilder(args);
2929
ConfigurationManager configuration = builder.Configuration;
3030

31-
//https://github.com/gunndabad/govuk-frontend-aspnetcore
31+
//https://github.com/gunndabad/govuk-frontend-aspnetcore
3232
builder.Services.AddGovUkFrontend();
3333

3434
builder.Services
@@ -206,7 +206,7 @@ static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
206206
options.DefaultRequestCulture = new RequestCulture("en-GB");
207207
// By default the below will be set to whatever the server culture is.
208208
options.SupportedCultures = supportedCultures;
209-
// Supported cultures is a list of cultures that your web app will be able to run under. By default this is set to a the culture of the machine.
209+
// Supported cultures is a list of cultures that your web app will be able to run under. By default this is set to a the culture of the machine.
210210
options.SupportedUICultures = supportedCultures;
211211
});
212212

@@ -230,13 +230,20 @@ static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
230230
var localDevelopment = builder.Configuration.GetValue<bool>("local_development");
231231
if (!localDevelopment)
232232
{
233-
string blobName = "keys.xml";
234-
BlobContainerClient container = new BlobContainerClient(new Uri(builder.Configuration["ConnectionStrings:BlobStorage"]));
233+
// Setup basic Data Protection and persist keys.xml to local file system
234+
var dp = builder.Services.AddDataProtection()
235+
.PersistKeysToFileSystem(new DirectoryInfo(@"/srv/app/storage"));
235236

236-
BlobClient blobClient = container.GetBlobClient(blobName);
237-
238-
builder.Services.AddDataProtection()
239-
.PersistKeysToAzureBlobStorage(blobClient);
237+
// If a Key Vault Key URI is defined, expect to encrypt the keys.xml
238+
string? kvProtectionKeyUri = builder.Configuration.GetValue<string>("DataProtection:KeyVaultKey");
239+
if (!string.IsNullOrEmpty(kvProtectionKeyUri))
240+
{
241+
var credentials = new DefaultAzureCredential();
242+
dp.ProtectKeysWithAzureKeyVault(
243+
new Uri(kvProtectionKeyUri),
244+
credentials
245+
);
246+
}
240247
}
241248

242249
builder.Services.AddQuartz(q => { q.UseMicrosoftDependencyInjectionJobFactory(); });

Dfe.Academies.External.Web/appsettings.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"SupportEmail": "dan.good@education.gov.uk",
2121
"TestMode": true
2222
},
23-
23+
2424
"Sharepoint": {
2525
"ApiUrl": "",
2626
"ClientId": "",
@@ -46,6 +46,9 @@
4646
"BlobStorage": "",
4747
"RedisCache": ""
4848
},
49+
"DataProtection": {
50+
"KeyVaultKey": ""
51+
},
4952
"Google": {
5053
"AnalyticsKey": "UA-140729870-2",
5154
"TagManagerId": "GTM-59S3WZ4",
@@ -71,5 +74,5 @@
7174
}
7275
},
7376
"MaintenanceMode" : false
74-
77+
7578
}

terraform/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ No providers.
138138
|------|--------|---------|
139139
| <a name="module_azure_container_apps_hosting"></a> [azure\_container\_apps\_hosting](#module\_azure\_container\_apps\_hosting) | github.com/DFE-Digital/terraform-azurerm-container-apps-hosting | v1.6.1 |
140140
| <a name="module_azurerm_key_vault"></a> [azurerm\_key\_vault](#module\_azurerm\_key\_vault) | github.com/DFE-Digital/terraform-azurerm-key-vault-tfvars | v0.4.1 |
141+
| <a name="module_data_protection"></a> [data\_protection](#module\_data\_protection) | github.com/DFE-Digital/terraform-azurerm-aspnet-data-protection | v1.0.0 |
141142
| <a name="module_statuscake-tls-monitor"></a> [statuscake-tls-monitor](#module\_statuscake-tls-monitor) | github.com/dfe-digital/terraform-statuscake-tls-monitor | v0.1.3 |
142143

143144
## Resources
@@ -157,6 +158,7 @@ No resources.
157158
| <a name="input_cdn_frontdoor_origin_fqdn_override"></a> [cdn\_frontdoor\_origin\_fqdn\_override](#input\_cdn\_frontdoor\_origin\_fqdn\_override) | Manually specify the hostname that the CDN Front Door should target. Defaults to the Container App FQDN | `string` | `""` | no |
158159
| <a name="input_cdn_frontdoor_origin_host_header_override"></a> [cdn\_frontdoor\_origin\_host\_header\_override](#input\_cdn\_frontdoor\_origin\_host\_header\_override) | Manually specify the host header that the CDN sends to the target. Defaults to the recieved host header. Set to null to set it to the host\_name (`cdn_frontdoor_origin_fqdn_override`) | `string` | `""` | no |
159160
| <a name="input_cdn_frontdoor_rate_limiting_threshold"></a> [cdn\_frontdoor\_rate\_limiting\_threshold](#input\_cdn\_frontdoor\_rate\_limiting\_threshold) | Maximum number of concurrent requests per minute threshold before rate limiting is applied | `number` | n/a | yes |
161+
| <a name="input_container_app_file_share_mount_path"></a> [container\_app\_file\_share\_mount\_path](#input\_container\_app\_file\_share\_mount\_path) | A path inside your container where the File Share will be mounted to | `string` | `"/srv/app/storage"` | no |
160162
| <a name="input_container_apps_allow_ips_inbound"></a> [container\_apps\_allow\_ips\_inbound](#input\_container\_apps\_allow\_ips\_inbound) | Restricts access to the Container Apps by creating a network security group rule that only allow inbound traffic from the provided list of IPs | `list(string)` | `[]` | no |
161163
| <a name="input_container_command"></a> [container\_command](#input\_container\_command) | Container command | `list(any)` | n/a | yes |
162164
| <a name="input_container_max_replicas"></a> [container\_max\_replicas](#input\_container\_max\_replicas) | Container max replicas | `number` | `2` | no |
@@ -169,6 +171,7 @@ No resources.
169171
| <a name="input_enable_cdn_frontdoor"></a> [enable\_cdn\_frontdoor](#input\_enable\_cdn\_frontdoor) | Enable Azure CDN Front Door. This will use the Container Apps endpoint as the origin. | `bool` | n/a | yes |
170172
| <a name="input_enable_cdn_frontdoor_health_probe"></a> [enable\_cdn\_frontdoor\_health\_probe](#input\_enable\_cdn\_frontdoor\_health\_probe) | Enable CDN Front Door health probe | `bool` | `false` | no |
171173
| <a name="input_enable_container_app_blob_storage"></a> [enable\_container\_app\_blob\_storage](#input\_enable\_container\_app\_blob\_storage) | Create an Azure Storage Account and Storage Container to be accessed by the Container App | `bool` | n/a | yes |
174+
| <a name="input_enable_container_app_file_share"></a> [enable\_container\_app\_file\_share](#input\_enable\_container\_app\_file\_share) | Create an Azure Storage Account and File Share to be mounted to the Container Apps | `bool` | n/a | yes |
172175
| <a name="input_enable_container_health_probe"></a> [enable\_container\_health\_probe](#input\_enable\_container\_health\_probe) | Enable liveness probes for the Container | `bool` | `true` | no |
173176
| <a name="input_enable_container_registry"></a> [enable\_container\_registry](#input\_enable\_container\_registry) | Set to true to create a container registry | `bool` | n/a | yes |
174177
| <a name="input_enable_dns_zone"></a> [enable\_dns\_zone](#input\_enable\_dns\_zone) | Conditionally create a DNS zone | `bool` | n/a | yes |

terraform/container-apps-hosting.tf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ module "azure_container_apps_hosting" {
5151
enable_container_health_probe = local.enable_container_health_probe
5252

5353
enable_container_app_blob_storage = local.enable_container_app_blob_storage
54+
enable_container_app_file_share = local.enable_container_app_file_share
55+
container_app_file_share_mount_path = local.container_app_file_share_mount_path
5456
storage_account_ipv4_allow_list = local.storage_account_ipv4_allow_list
5557
storage_account_public_access_enabled = local.storage_account_public_access_enabled
5658

terraform/data-protection.tf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module "data_protection" {
2+
source = "github.com/DFE-Digital/terraform-azurerm-aspnet-data-protection?ref=v1.0.0"
3+
4+
data_protection_key_vault_assign_role = false
5+
data_protection_key_vault_subnet_prefix = "172.16.100.0/28"
6+
data_protection_key_vault_access_ipv4 = local.key_vault_access_ipv4
7+
data_protection_resource_prefix = "${local.environment}${local.project_name}"
8+
data_protection_azure_location = local.azure_location
9+
data_protection_tags = local.tags
10+
data_protection_resource_group_name = module.azure_container_apps_hosting.azurerm_resource_group_default.name
11+
}

terraform/locals.tf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ locals {
4141
monitor_email_receivers = var.monitor_email_receivers
4242
existing_logic_app_workflow = var.existing_logic_app_workflow
4343
enable_container_app_blob_storage = var.enable_container_app_blob_storage
44+
enable_container_app_file_share = var.enable_container_app_file_share
45+
container_app_file_share_mount_path = var.container_app_file_share_mount_path
4446
storage_account_ipv4_allow_list = var.storage_account_ipv4_allow_list
4547
storage_account_public_access_enabled = var.storage_account_public_access_enabled
4648
existing_network_watcher_name = var.existing_network_watcher_name

terraform/variables.tf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,17 @@ variable "enable_container_app_blob_storage" {
243243
type = bool
244244
}
245245

246+
variable "enable_container_app_file_share" {
247+
description = "Create an Azure Storage Account and File Share to be mounted to the Container Apps"
248+
type = bool
249+
}
250+
251+
variable "container_app_file_share_mount_path" {
252+
description = "A path inside your container where the File Share will be mounted to"
253+
type = string
254+
default = "/srv/app/storage"
255+
}
256+
246257
variable "storage_account_ipv4_allow_list" {
247258
description = "A list of public IPv4 address to grant access to the Blob Storage Account"
248259
type = list(string)

0 commit comments

Comments
 (0)