Feature Change - Data Partition - Enable CORS configuration for Blob Containers on Storage Accounts
Why is this change needed?
The issue was raised by clients when they have tried to access the Signed URLs generated by File Service from a UI. Generally browsers do perform a Preflight request if any HTTP call is made on a different domain. Because the current blob containers are not configured with CORS rules, the Storage Account's blob service returns a 403 response against the Pre-Flight Request.
Current behavior
Here is the sample response sent by the Storage Account if CORS rule is not configured.
curl --location --request OPTIONS 'https://krvedurutest.blob.core.windows.net/' --header 'Origin: http://krveduru' --header 'Access-Control-Request-Method: PUT' --data-raw 'foo'
<?xml version="1.0" encoding="utf-8"?>
<Error>
<Code>CorsPreflightFailure</Code>
<Message>CORS not enabled or no matching rule found for this request.
RequestId:361fa49d-d01e-008d-0f09-e4a669000000
Time:2021-01-06T08:52:18.7406133Z</Message>
<MessageDetails>No CORS rules matches this request</MessageDetails>
</Error>
Expected behavior
Once CORS rules are enabled and the required domains are whitelisted, the OPTIONS call would return a 200 OK status and the subsequent PUT / GET calls will be allowed.
Current Design
Current Module doesn't allow for any support on Blob Properties
resource "azurerm_storage_account" "main" {
# required
name = lower(var.name)
resource_group_name = data.azurerm_resource_group.main.name
location = data.azurerm_resource_group.main.location
account_tier = var.performance_tier
account_replication_type = var.replication_type
# optional
account_kind = var.kind
enable_https_traffic_only = var.https
tags = var.resource_tags
# enrolls storage account into azure 'managed identities' authentication
identity {
type = "SystemAssigned"
}
}
Initial Design Proposal
A simple enhancement to the module can add in support for CORS rules as necessary and the module can be backward compatible by setting the default rule as an empty []
# Empty Variable by default is *NO CORS* configuration
variable "cors_rule" {
description = "CORS rules for storage account."
type = list(object({
allowed_origins = list(string),
allowed_methods = list(string),
allowed_headers = list(string),
exposed_headers = list(string),
max_age_in_seconds = number
}))
default = []
}
resource "azurerm_storage_account" "storage" {
# required
name = lower(var.name)
resource_group_name = data.azurerm_resource_group.main.name
location = data.azurerm_resource_group.main.location
account_tier = var.performance_tier
account_replication_type = var.replication_type
# optional
account_kind = var.kind
enable_https_traffic_only = var.https
tags = var.resource_tags
blob_properties {
dynamic "cors_rule" {
for_each = var.cors_rule
content {
allowed_origins = cors_rule.value.allowed_origins
allowed_methods = cors_rule.value.allowed_methods
allowed_headers = cors_rule.value.allowed_headers
exposed_headers = cors_rule.value.exposed_headers
max_age_in_seconds = cors_rule.value.max_age_in_seconds
}
}
}
}
The Template design for Data Partition can also add in the Variable so it can be set independently for each configuration and then just passed through to the module.
Possible Issues
-
The feature needs to be tested to ensure no breaking changes. To mitigate the risk the suggestion is to roll the feature out in 2 steps. Step 1 is implement the change but don't enable use of the change. This will ensure no breaking change. Then Step 2 enable the change.
-
CORS Rules have an environment specific value associated to it that would be the allowed origins. Investigation needs to occur on what the rule would be for necessary domain origins and how this would be known ahead of time prior to infrastructure build. Does this mean a desired DNS name is now required to be known prior to building out infra?
Acceptance Criteria
- Design Feature to ensure can be implemented with a non breaking change.
- Update Storage Module
- Ensure all Module Unit Tests Pass
- Ensure all Template Unit Tests and Integration Tests Pass
- Update all required documentation