Skip to content

Commit

Permalink
Remove SAS dependency for Data Protection blob access (#555)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
DrizzlyOwl authored Apr 17, 2024
1 parent 117299a commit 1c455c0
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 13 deletions.
4 changes: 2 additions & 2 deletions Dfe.Academies.External.Web/Dfe.Academies.External.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

<ItemGroup>
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="Azure.Extensions.AspNetCore.DataProtection.Blobs" Version="1.3.3" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.19.1" />
<PackageReference Include="Azure.Extensions.AspNetCore.DataProtection.Keys" Version="1.2.3" />
<PackageReference Include="Azure.Identity" Version="1.11.0" />
<PackageReference Include="Dfe.Academies.Contracts" Version="1.0.10" />
<PackageReference Include="Dfe.Academisation.CorrelationIdMiddleware" Version="2.0.2" />
<PackageReference Include="FluentValidation" Version="11.9.0" />
Expand Down
25 changes: 16 additions & 9 deletions Dfe.Academies.External.Web/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Globalization;
using Azure.Storage.Blobs;
using Azure.Identity;
using Dfe.Academies.External.Web.AutoMapper;
using Dfe.Academies.External.Web.Extensions;
using Dfe.Academies.External.Web.Factories;
Expand Down Expand Up @@ -28,7 +28,7 @@
var builder = WebApplication.CreateBuilder(args);
ConfigurationManager configuration = builder.Configuration;

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

builder.Services
Expand Down Expand Up @@ -206,7 +206,7 @@ static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
options.DefaultRequestCulture = new RequestCulture("en-GB");
// By default the below will be set to whatever the server culture is.
options.SupportedCultures = supportedCultures;
// 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.
// 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.
options.SupportedUICultures = supportedCultures;
});

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

BlobClient blobClient = container.GetBlobClient(blobName);

builder.Services.AddDataProtection()
.PersistKeysToAzureBlobStorage(blobClient);
// If a Key Vault Key URI is defined, expect to encrypt the keys.xml
string? kvProtectionKeyUri = builder.Configuration.GetValue<string>("DataProtection:KeyVaultKey");
if (!string.IsNullOrEmpty(kvProtectionKeyUri))
{
var credentials = new DefaultAzureCredential();
dp.ProtectKeysWithAzureKeyVault(
new Uri(kvProtectionKeyUri),
credentials
);
}
}

builder.Services.AddQuartz(q => { q.UseMicrosoftDependencyInjectionJobFactory(); });
Expand Down
7 changes: 5 additions & 2 deletions Dfe.Academies.External.Web/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"SupportEmail": "[email protected]",
"TestMode": true
},

"Sharepoint": {
"ApiUrl": "",
"ClientId": "",
Expand All @@ -46,6 +46,9 @@
"BlobStorage": "",
"RedisCache": ""
},
"DataProtection": {
"KeyVaultKey": ""
},
"Google": {
"AnalyticsKey": "UA-140729870-2",
"TagManagerId": "GTM-59S3WZ4",
Expand All @@ -71,5 +74,5 @@
}
},
"MaintenanceMode" : false

}
3 changes: 3 additions & 0 deletions terraform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ No providers.
|------|--------|---------|
| <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 |
| <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 |
| <a name="module_data_protection"></a> [data\_protection](#module\_data\_protection) | github.com/DFE-Digital/terraform-azurerm-aspnet-data-protection | v1.0.0 |
| <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 |

## Resources
Expand All @@ -157,6 +158,7 @@ No resources.
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <a name="input_container_command"></a> [container\_command](#input\_container\_command) | Container command | `list(any)` | n/a | yes |
| <a name="input_container_max_replicas"></a> [container\_max\_replicas](#input\_container\_max\_replicas) | Container max replicas | `number` | `2` | no |
Expand All @@ -169,6 +171,7 @@ No resources.
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <a name="input_enable_dns_zone"></a> [enable\_dns\_zone](#input\_enable\_dns\_zone) | Conditionally create a DNS zone | `bool` | n/a | yes |
Expand Down
2 changes: 2 additions & 0 deletions terraform/container-apps-hosting.tf
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ module "azure_container_apps_hosting" {
enable_container_health_probe = local.enable_container_health_probe

enable_container_app_blob_storage = local.enable_container_app_blob_storage
enable_container_app_file_share = local.enable_container_app_file_share
container_app_file_share_mount_path = local.container_app_file_share_mount_path
storage_account_ipv4_allow_list = local.storage_account_ipv4_allow_list
storage_account_public_access_enabled = local.storage_account_public_access_enabled

Expand Down
11 changes: 11 additions & 0 deletions terraform/data-protection.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module "data_protection" {
source = "github.com/DFE-Digital/terraform-azurerm-aspnet-data-protection?ref=v1.0.0"

data_protection_key_vault_assign_role = false
data_protection_key_vault_subnet_prefix = "172.16.100.0/28"
data_protection_key_vault_access_ipv4 = local.key_vault_access_ipv4
data_protection_resource_prefix = "${local.environment}${local.project_name}"
data_protection_azure_location = local.azure_location
data_protection_tags = local.tags
data_protection_resource_group_name = module.azure_container_apps_hosting.azurerm_resource_group_default.name
}
2 changes: 2 additions & 0 deletions terraform/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ locals {
monitor_email_receivers = var.monitor_email_receivers
existing_logic_app_workflow = var.existing_logic_app_workflow
enable_container_app_blob_storage = var.enable_container_app_blob_storage
enable_container_app_file_share = var.enable_container_app_file_share
container_app_file_share_mount_path = var.container_app_file_share_mount_path
storage_account_ipv4_allow_list = var.storage_account_ipv4_allow_list
storage_account_public_access_enabled = var.storage_account_public_access_enabled
existing_network_watcher_name = var.existing_network_watcher_name
Expand Down
11 changes: 11 additions & 0 deletions terraform/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,17 @@ variable "enable_container_app_blob_storage" {
type = bool
}

variable "enable_container_app_file_share" {
description = "Create an Azure Storage Account and File Share to be mounted to the Container Apps"
type = bool
}

variable "container_app_file_share_mount_path" {
description = "A path inside your container where the File Share will be mounted to"
type = string
default = "/srv/app/storage"
}

variable "storage_account_ipv4_allow_list" {
description = "A list of public IPv4 address to grant access to the Blob Storage Account"
type = list(string)
Expand Down

0 comments on commit 1c455c0

Please sign in to comment.