Skip to content

Commit

Permalink
Add CMK support for Base Workspace (#4161)
Browse files Browse the repository at this point in the history
* added management key vault

* added cmk for vmss and storage accounts

* add default value for variables

* add CMK for cosmos accounts

* move tre-encryption key from mgmt to core

* fix order of creation for encryption key

* add cmk for the state store in mgmt

* add support for external KV

* revert CMK for cosmos - not working, need to redo this

* refine comments and files names

* remove redundant space

* add space

* upper case in comment

* revert cosmos tags

* update changelog + core version

* remove unused var

* remove redundant variable

* remove redundant variables

* add check for enable_cmk_encryption for the key_store_id variable in tf

* bugfix: remove redundant data keyword

* add enable_cmk_encryption check in module variables

* remove redundant key_vault_id from ignore_changes for cmk

* remove redundant sign/verify

* add cmk support for cosmos db

* update changelog + add comments

* update core version

* fix linting issue

* add null provider to providers block

* remove duplicates that were created by merge

* update core version

* remove redundant terraform data

* Add support for CMK encryption in workspace configuration

* add cmk for the ws storage accounts

* fix encryption_identity being sent when cmk was disabled

* update changelog

* update changelog

* fix linting issues

* bump rp version

* bump core version

* update docs

* use foreach for airlock cmks

* update the porter upgrade command + minor version

* change the default value for key_store_id variable to an empty string

* set default value of key_store_id variable to null

* Update default value of key_store_id variable to 'TWEAKME'

* Remove default value for key_store_id variable in variables.tf

* Set default value of key_store_id variable to an empty string in locals

* update core version

---------

Co-authored-by: Matthew Fortunka <[email protected]>
Co-authored-by: Tim Allen <[email protected]>
  • Loading branch information
3 people authored Dec 9, 2024
1 parent d718721 commit ac5787c
Show file tree
Hide file tree
Showing 21 changed files with 211 additions and 9 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ ENHANCEMENTS:
* Storage accounts should use infrastructure encryption ([#4001](https://github.com/microsoft/AzureTRE/issues/4001))
* Update obsolete Terraform properties ([#4136](https://github.com/microsoft/AzureTRE/issues/4136))
* Update Guacamole version and dependencies ([#4140](https://github.com/microsoft/AzureTRE/issues/4140))
* Add partial (core resources only) support for customer managed keys ([#4141](https://github.com/microsoft/AzureTRE/issues/4142), [#4144](https://github.com/microsoft/AzureTRE/issues/4144))
* Add partial (core resources only) support for customer-managed keys ([#4141](https://github.com/microsoft/AzureTRE/issues/4142), [#4144](https://github.com/microsoft/AzureTRE/issues/4144))
* Update the Azure CLI version to 2.67.0 in dev container and vmss ([#4157](https://github.com/microsoft/AzureTRE/pull/4157))
* Move Github PR bot commands into main documentation ([#4167](https://github.com/microsoft/AzureTRE/pull/4167))
* Block Authentication with keys to CosmosDB SQL account ([#4175](https://github.com/microsoft/AzureTRE/pull/4175))
* Add support for customer-managed keys encryption in base workspace ([#4161](https://github.com/microsoft/AzureTRE/pull/4161))

BUG FIXES:
- Update KeyVault references in API to use the version so Terraform cascades the update ([#4112](https://github.com/microsoft/AzureTRE/pull/4112))
Expand Down
2 changes: 1 addition & 1 deletion core/terraform/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@ locals {
service_bus_namespace_fqdn = regex("(?:(?P<scheme>[^:/?#]+):)?(?://(?P<fqdn>[^/?#:]*))?(?::(?P<port>[0-9]+))?(?P<path>[^?#]*)(?:\\?(?P<query>[^#]*))?(?:#(?P<fragment>.*))?", azurerm_servicebus_namespace.sb.endpoint).fqdn

# The key store for encryption keys could either be external or created by terraform
key_store_id = var.enable_cmk_encryption ? (var.external_key_store_id != null ? var.external_key_store_id : data.azurerm_key_vault.encryption_kv[0].id) : null
key_store_id = var.enable_cmk_encryption ? (var.external_key_store_id != null ? var.external_key_store_id : data.azurerm_key_vault.encryption_kv[0].id) : ""
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ write_files:
OTEL_RESOURCE_ATTRIBUTES=service.name=resource_processor,service.version=${resource_processor_vmss_porter_image_tag}
OTEL_EXPERIMENTAL_RESOURCE_DETECTORS=azure_vm
LOGGING_LEVEL=${logging_level}
ENABLE_CMK_ENCRYPTION=${enable_cmk_encryption}
KEY_STORE_ID=${key_store_id}
${rp_bundle_values}
- path: /etc/cron.hourly/docker-prune
# An hourly cron job to have docker free disk space. Running this frquently
Expand Down
2 changes: 2 additions & 0 deletions core/terraform/resource_processor/vmss_porter/data.tf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ data "template_file" "cloudconfig" {
firewall_sku = var.firewall_sku
logging_level = var.logging_level
rp_bundle_values = local.rp_bundle_values_formatted
enable_cmk_encryption = var.enable_cmk_encryption
key_store_id = var.key_store_id
}
}

Expand Down
2 changes: 1 addition & 1 deletion core/terraform/resource_processor/vmss_porter/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ resource "azurerm_role_assignment" "keyvault_vmss_role" {
resource "azurerm_role_assignment" "vmss_kv_encryption_key_user" {
count = var.enable_cmk_encryption ? 1 : 0
scope = var.key_store_id
role_definition_name = "Key Vault Crypto Service Encryption User"
role_definition_name = "Key Vault Crypto Officer"
principal_id = azurerm_user_assigned_identity.vmss_msi.principal_id
}

Expand Down
1 change: 0 additions & 1 deletion core/terraform/resource_processor/vmss_porter/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ variable "enable_cmk_encryption" {
variable "key_store_id" {
type = string
description = "ID of the Key Vault to store CMKs in (only used if enable_cmk_encryption is true)"
default = null
}

variable "kv_encryption_key_name" {
Expand Down
2 changes: 1 addition & 1 deletion core/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.11.6"
__version__ = "0.11.7"
2 changes: 1 addition & 1 deletion docs/tre-admins/customer-managed-keys.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
You can enable customer-managed keys (CMK) for supporting resources in Azure TRE.

!!! warning
Currently Azure TRE only supports CMK encryption for resources in the TRE core.
Currently Azure TRE only supports CMK encryption for resources in the TRE core and Base Workspace.
CMK encryption is not supported for the rest of the resources such as those deployed by a TRE workspace.


Expand Down
2 changes: 1 addition & 1 deletion resource_processor/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.9.4"
__version__ = "0.9.5"
2 changes: 2 additions & 0 deletions resource_processor/shared/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ def get_config() -> dict:
config["aad_authority_url"] = os.environ.get("AAD_AUTHORITY_URL", "https://login.microsoftonline.com")
config["microsoft_graph_fqdn"] = os.environ.get("MICROSOFT_GRAPH_FQDN", "graph.microsoft.com")
config["firewall_sku"] = os.environ.get("FIREWALL_SKU", "")
config["enable_cmk_encryption"] = os.environ.get("ENABLE_CMK_ENCRYPTION", "false")
config["key_store_id"] = os.environ.get("KEY_STORE_ID", None)

try:
config["number_processes_int"] = int(config["number_processes"])
Expand Down
12 changes: 12 additions & 0 deletions templates/workspaces/base/parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,18 @@
"source": {
"env": "AZURE_ENVIRONMENT"
}
},
{
"name": "enable_cmk_encryption",
"source": {
"env": "enable_cmk_encryption"
}
},
{
"name": "key_store_id",
"source": {
"env": "key_store_id"
}
}
]
}
14 changes: 13 additions & 1 deletion templates/workspaces/base/porter.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
schemaVersion: 1.0.0
name: tre-workspace-base
version: 1.6.1
version: 1.7.0
description: "A base Azure TRE workspace"
dockerfile: Dockerfile.tmpl
registry: azuretre
Expand Down Expand Up @@ -116,6 +116,12 @@ parameters:
default: true
- name: arm_environment
type: string
- name: enable_cmk_encryption
type: boolean
default: false
- name: key_store_id
type: string
default: ""

outputs:
- name: app_role_id_workspace_owner
Expand Down Expand Up @@ -183,6 +189,8 @@ install:
app_service_plan_sku: ${ bundle.parameters.app_service_plan_sku }
enable_airlock: ${ bundle.parameters.enable_airlock }
arm_environment: ${ bundle.parameters.arm_environment }
enable_cmk_encryption: ${ bundle.parameters.enable_cmk_encryption }
key_store_id: ${ bundle.parameters.key_store_id }
backendConfig:
use_azuread_auth: "true"
use_oidc: "true"
Expand Down Expand Up @@ -225,6 +233,8 @@ upgrade:
app_service_plan_sku: ${ bundle.parameters.app_service_plan_sku }
enable_airlock: ${ bundle.parameters.enable_airlock }
arm_environment: ${ bundle.parameters.arm_environment }
enable_cmk_encryption: ${ bundle.parameters.enable_cmk_encryption }
key_store_id: ${ bundle.parameters.key_store_id }
backendConfig:
use_azuread_auth: "true"
use_oidc: "true"
Expand Down Expand Up @@ -290,6 +300,8 @@ uninstall:
app_service_plan_sku: ${ bundle.parameters.app_service_plan_sku }
enable_airlock: ${ bundle.parameters.enable_airlock }
arm_environment: ${ bundle.parameters.arm_environment }
enable_cmk_encryption: ${ bundle.parameters.enable_cmk_encryption }
key_store_id: ${ bundle.parameters.key_store_id }
backendConfig:
use_azuread_auth: "true"
use_oidc: "true"
Expand Down
55 changes: 55 additions & 0 deletions templates/workspaces/base/terraform/airlock/storage_accounts.tf
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ resource "azurerm_storage_account" "sa_import_approved" {
bypass = ["AzureServices"]
}

dynamic "identity" {
for_each = var.enable_cmk_encryption ? [1] : []
content {
type = "UserAssigned"
identity_ids = [var.encryption_identity_id]
}
}

tags = merge(
var.tre_workspace_tags,
{
Expand Down Expand Up @@ -75,6 +83,14 @@ resource "azurerm_storage_account" "sa_export_internal" {
bypass = ["AzureServices"]
}

dynamic "identity" {
for_each = var.enable_cmk_encryption ? [1] : []
content {
type = "UserAssigned"
identity_ids = [var.encryption_identity_id]
}
}

tags = merge(
var.tre_workspace_tags,
{
Expand Down Expand Up @@ -122,6 +138,14 @@ resource "azurerm_storage_account" "sa_export_inprogress" {
# This is true ONLY when Hierarchical Namespace is DISABLED
is_hns_enabled = false

dynamic "identity" {
for_each = var.enable_cmk_encryption ? [1] : []
content {
type = "UserAssigned"
identity_ids = [var.encryption_identity_id]
}
}

# changing this value is destructive, hence attribute is in lifecycle.ignore_changes block below
infrastructure_encryption_enabled = true

Expand Down Expand Up @@ -192,6 +216,14 @@ resource "azurerm_storage_account" "sa_export_rejected" {
bypass = ["AzureServices"]
}

dynamic "identity" {
for_each = var.enable_cmk_encryption ? [1] : []
content {
type = "UserAssigned"
identity_ids = [var.encryption_identity_id]
}
}

tags = merge(
var.tre_workspace_tags,
{
Expand Down Expand Up @@ -247,6 +279,14 @@ resource "azurerm_storage_account" "sa_export_blocked" {
bypass = ["AzureServices"]
}

dynamic "identity" {
for_each = var.enable_cmk_encryption ? [1] : []
content {
type = "UserAssigned"
identity_ids = [var.encryption_identity_id]
}
}

tags = merge(
var.tre_workspace_tags,
{
Expand Down Expand Up @@ -296,3 +336,18 @@ resource "azurerm_role_assignment" "api_sa_data_contributor" {
role_definition_name = "Storage Blob Data Contributor"
principal_id = data.azurerm_user_assigned_identity.api_id.principal_id
}

resource "azurerm_storage_account_customer_managed_key" "sa_encryption" {
for_each = var.enable_cmk_encryption ? {
"sa_import_approved" = azurerm_storage_account.sa_import_approved,
"sa_export_internal" = azurerm_storage_account.sa_export_internal,
"sa_export_inprogress" = azurerm_storage_account.sa_export_inprogress,
"sa_export_rejected" = azurerm_storage_account.sa_export_rejected,
"sa_export_blocked" = azurerm_storage_account.sa_export_blocked
} : {}

storage_account_id = each.value.id
key_vault_id = var.key_store_id
key_name = var.kv_encryption_key_name
user_assigned_identity_id = var.encryption_identity_id
}
14 changes: 13 additions & 1 deletion templates/workspaces/base/terraform/airlock/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,16 @@ variable "tre_workspace_tags" {
}
variable "arm_environment" {
type = string
}
}
variable "enable_cmk_encryption" {
type = bool
}
variable "key_store_id" {
type = string
}
variable "encryption_identity_id" {
type = string
}
variable "kv_encryption_key_name" {
type = string
}
16 changes: 16 additions & 0 deletions templates/workspaces/base/terraform/azure-monitor/azure-monitor.tf
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ resource "azurerm_storage_account" "app_insights" {
cross_tenant_replication_enabled = false
tags = var.tre_workspace_tags

dynamic "identity" {
for_each = var.enable_cmk_encryption ? [1] : []
content {
type = "UserAssigned"
identity_ids = [var.encryption_identity_id]
}
}

# changing this value is destructive, hence attribute is in lifecycle.ignore_changes block below
infrastructure_encryption_enabled = true

Expand All @@ -34,6 +42,14 @@ resource "azurerm_storage_account" "app_insights" {
lifecycle { ignore_changes = [infrastructure_encryption_enabled, tags] }
}

resource "azurerm_storage_account_customer_managed_key" "app_insights_stg_encryption" {
count = var.enable_cmk_encryption ? 1 : 0
storage_account_id = azurerm_storage_account.app_insights.id
key_vault_id = var.key_store_id
key_name = var.kv_encryption_key_name
user_assigned_identity_id = var.encryption_identity_id
}

resource "azurerm_log_analytics_linked_storage_account" "workspace_storage_ingestion" {
data_source_type = "Ingestion"
resource_group_name = var.resource_group_name
Expand Down
12 changes: 12 additions & 0 deletions templates/workspaces/base/terraform/azure-monitor/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,15 @@ variable "tre_resource_id" {
variable "enable_local_debugging" {
type = bool
}
variable "enable_cmk_encryption" {
type = bool
}
variable "key_store_id" {
type = string
}
variable "encryption_identity_id" {
type = string
}
variable "kv_encryption_key_name" {
type = string
}
37 changes: 37 additions & 0 deletions templates/workspaces/base/terraform/cmk-encryption.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
resource "azurerm_user_assigned_identity" "encryption_identity" {
count = var.enable_cmk_encryption ? 1 : 0
resource_group_name = azurerm_resource_group.ws.name
location = azurerm_resource_group.ws.location
tags = local.tre_workspace_tags

name = "id-encryption-${var.tre_id}-${local.short_workspace_id}"

lifecycle { ignore_changes = [tags] }
}

resource "azurerm_role_assignment" "kv_encryption_key_user" {
count = var.enable_cmk_encryption ? 1 : 0
scope = var.key_store_id
role_definition_name = "Key Vault Crypto Service Encryption User"
principal_id = azurerm_user_assigned_identity.encryption_identity[0].principal_id
}

resource "azurerm_key_vault_key" "encryption_key" {
count = var.enable_cmk_encryption ? 1 : 0

name = local.kv_encryption_key_name
key_vault_id = var.key_store_id
key_type = "RSA"
key_size = 2048

key_opts = [
"decrypt",
"encrypt",
"unwrapKey",
"wrapKey",
]

depends_on = [
azurerm_role_assignment.kv_encryption_key_user
]
}
1 change: 1 addition & 0 deletions templates/workspaces/base/terraform/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ locals {
tre_id = var.tre_id
tre_workspace_id = var.tre_resource_id
}
kv_encryption_key_name = "tre-encryption-${local.workspace_resource_name_suffix}"
}
18 changes: 18 additions & 0 deletions templates/workspaces/base/terraform/storage.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ resource "azurerm_storage_account" "stg" {
cross_tenant_replication_enabled = false // not technically needed as cross tenant replication not supported when is_hns_enabled = true
tags = local.tre_workspace_tags

dynamic "identity" {
for_each = var.enable_cmk_encryption ? [1] : []
content {
type = "UserAssigned"
identity_ids = [azurerm_user_assigned_identity.encryption_identity[0].id]
}
}

# changing this value is destructive, hence attribute is in lifecycle.ignore_changes block below
infrastructure_encryption_enabled = true

Expand Down Expand Up @@ -131,3 +139,13 @@ resource "azurerm_private_endpoint" "stgdfspe" {
subresource_names = ["dfs"]
}
}

resource "azurerm_storage_account_customer_managed_key" "stg_encryption" {
count = var.enable_cmk_encryption ? 1 : 0
storage_account_id = azurerm_storage_account.stg.id
key_vault_id = var.key_store_id
key_name = local.kv_encryption_key_name
user_assigned_identity_id = azurerm_user_assigned_identity.encryption_identity[0].id

depends_on = [azurerm_key_vault_key.encryption_key]
}
13 changes: 13 additions & 0 deletions templates/workspaces/base/terraform/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,16 @@ variable "workspace_owner_object_id" {
variable "arm_environment" {
type = string
}

variable "enable_cmk_encryption" {
type = bool
default = false
description = "Enable CMK encryption for the workspace"
}

variable "key_store_id" {
type = string
description = "ID of the Key Vault to store CMKs in (only used if enable_cmk_encryption is true)"
default = null
}

Loading

0 comments on commit ac5787c

Please sign in to comment.