diff --git a/api_app/.env.sample b/api_app/.env.sample index 8875268125..afeac55292 100644 --- a/api_app/.env.sample +++ b/api_app/.env.sample @@ -43,8 +43,7 @@ SERVICE_BUS_DEPLOYMENT_STATUS_UPDATE_QUEUE=deploymentstatus # Event grid configuration # ------------------------- -EVENT_GRID_TOPIC_ENDPOINT=__CHANGE_ME__ -EVENT_GRID_ACCESS_KEY=__CHANGE_ME__ +EVENT_GRID_STATUS_CHANGED_TOPIC_ENDPOINT=__CHANGE_ME__ # Logging and monitoring # ---------------------- diff --git a/api_app/_version.py b/api_app/_version.py index 771bc6e629..aa4cd15147 100644 --- a/api_app/_version.py +++ b/api_app/_version.py @@ -1 +1 @@ -__version__ = "0.3.9" +__version__ = "0.3.10" diff --git a/api_app/core/config.py b/api_app/core/config.py index 9d0a690096..dc23b156c7 100644 --- a/api_app/core/config.py +++ b/api_app/core/config.py @@ -35,8 +35,7 @@ SERVICE_BUS_DEPLOYMENT_STATUS_UPDATE_QUEUE: str = config("SERVICE_BUS_DEPLOYMENT_STATUS_UPDATE_QUEUE", default="") # Event grid configuration -EVENT_GRID_ACCESS_KEY: str = config("EVENT_GRID_ACCESS_KEY", default="") -EVENT_GRID_TOPIC_ENDPOINT: str = config("EVENT_GRID_TOPIC_ENDPOINT", default="") +EVENT_GRID_STATUS_CHANGED_TOPIC_ENDPOINT: str = config("EVENT_GRID_STATUS_CHANGED_TOPIC_ENDPOINT", default="") # Managed identity configuration MANAGED_IDENTITY_CLIENT_ID: str = config("MANAGED_IDENTITY_CLIENT_ID", default="") diff --git a/api_app/event_grid/helpers.py b/api_app/event_grid/helpers.py index 05e2a6a817..2bd7ad0bd0 100644 --- a/api_app/event_grid/helpers.py +++ b/api_app/event_grid/helpers.py @@ -1,16 +1,27 @@ import logging from azure.eventgrid import EventGridEvent from azure.eventgrid.aio import EventGridPublisherClient -from azure.core.credentials import AzureKeyCredential +from azure.identity.aio import DefaultAzureCredential from models.domain.airlock_request import AirlockRequest from core import config +from contextlib import asynccontextmanager -async def _publish_event(event: EventGridEvent, topic_key: str, topic_endpoint: str): - credential = AzureKeyCredential(topic_key) - client = EventGridPublisherClient(topic_endpoint, credential) +@asynccontextmanager +async def default_credentials(): + """ + Yields the default credentials. + """ + credential = DefaultAzureCredential(managed_identity_client_id=config.MANAGED_IDENTITY_CLIENT_ID) + yield credential + await credential.close() - await client.send([event]) + +async def _publish_event(event: EventGridEvent, topic_endpoint: str): + async with default_credentials() as credential: + client = EventGridPublisherClient(topic_endpoint, credential) + async with client: + await client.send([event]) async def send_status_changed_event(airlock_request: AirlockRequest): @@ -31,4 +42,4 @@ async def send_status_changed_event(airlock_request: AirlockRequest): data_version="2.0" ) logging.info(f"Sending status changed event with request ID {request_id}, status: {status}") - await _publish_event(status_changed_event, config.EVENT_GRID_ACCESS_KEY, config.EVENT_GRID_TOPIC_ENDPOINT) + await _publish_event(status_changed_event, config.EVENT_GRID_STATUS_CHANGED_TOPIC_ENDPOINT) diff --git a/scripts/setup_local_debugging.sh b/scripts/setup_local_debugging.sh index 67ee628226..96a5398a72 100755 --- a/scripts/setup_local_debugging.sh +++ b/scripts/setup_local_debugging.sh @@ -1,12 +1,14 @@ #!/bin/bash set -e -: ${TRE_ID?"You have not set you TRE_ID in ./templates/core/.env"} -: ${RESOURCE_GROUP_NAME?"Check RESOURCE_GROUP_NAME is defined in ./templates/core/private.env"} -: ${SERVICE_BUS_RESOURCE_ID?"Check SERVICE_BUS_RESOURCE_ID is defined in ./templates/core/private.env"} -: ${STATE_STORE_RESOURCE_ID?"Check STATE_STORE_RESOURCE_ID is defined in ./templates/core/private.env"} -: ${COSMOSDB_ACCOUNT_NAME?"Check COSMOSDB_ACCOUNT_NAME is defined in ./templates/core/private.env"} -: ${AZURE_SUBSCRIPTION_ID?"Check AZURE_SUBSCRIPTION_ID is defined in ./templates/core/private.env"} +: "${TRE_ID?"You have not set you TRE_ID in ./templates/core/.env"}" +: "${RESOURCE_GROUP_NAME?"Check RESOURCE_GROUP_NAME is defined in ./templates/core/private.env"}" +: "${SERVICE_BUS_RESOURCE_ID?"Check SERVICE_BUS_RESOURCE_ID is defined in ./templates/core/private.env"}" +: "${STATE_STORE_RESOURCE_ID?"Check STATE_STORE_RESOURCE_ID is defined in ./templates/core/private.env"}" +: "${COSMOSDB_ACCOUNT_NAME?"Check COSMOSDB_ACCOUNT_NAME is defined in ./templates/core/private.env"}" +: "${AZURE_SUBSCRIPTION_ID?"Check AZURE_SUBSCRIPTION_ID is defined in ./templates/core/private.env"}" +: "${EVENT_GRID_STATUS_CHANGED_TOPIC_RESOURCE_ID?"Check EVENT_GRID_STATUS_CHANGED_TOPIC_RESOURCE_ID is defined in ./templates/core/private.env"}" +: "${EVENT_GRID_STATUS_CHANGED_TOPIC_ENDPOINT?"Check EVENT_GRID_STATUS_CHANGED_TOPIC_ENDPOINT is defined in ./templates/core/private.env"}" set -o pipefail set -o nounset @@ -19,23 +21,33 @@ else IPADDR=${PUBLIC_DEPLOYMENT_IP_ADDRESS} fi +# extract eventgrid topic name from endpoint +EVENT_GRID_STATUS_CHANGED_TOPIC_NAME=$(echo "$EVENT_GRID_STATUS_CHANGED_TOPIC_ENDPOINT" | sed 's/https\?:\/\///'| awk -F"." '{print $1}') + echo "Adding local IP Address to ${COSMOSDB_ACCOUNT_NAME}. This may take a while . . . " az cosmosdb update \ - --name ${COSMOSDB_ACCOUNT_NAME} \ - --resource-group ${RESOURCE_GROUP_NAME} \ - --ip-range-filter ${IPADDR} + --name "${COSMOSDB_ACCOUNT_NAME}" \ + --resource-group "${RESOURCE_GROUP_NAME}" \ + --ip-range-filter "${IPADDR}" echo "Adding local IP Address to ${SERVICE_BUS_NAMESPACE}." az servicebus namespace network-rule add \ - --resource-group ${RESOURCE_GROUP_NAME} \ - --namespace-name ${SERVICE_BUS_NAMESPACE} \ - --ip-address ${IPADDR} \ + --resource-group "${RESOURCE_GROUP_NAME}" \ + --namespace-name "${SERVICE_BUS_NAMESPACE}" \ + --ip-address "${IPADDR}" \ --action Allow +echo "Adding local IP Address to ${EVENT_GRID_STATUS_CHANGED_TOPIC_NAME}." +az eventgrid topic update \ + --resource-group "${RESOURCE_GROUP_NAME}" \ + --name "${EVENT_GRID_STATUS_CHANGED_TOPIC_NAME}" \ + --public-network-access enabled \ + --inbound-ip-rules "${IPADDR}" allow + # Get the object id of the currently logged-in identity -if [[ ! -z ${ARM_CLIENT_ID:-} ]]; then +if [[ -n ${ARM_CLIENT_ID:-} ]]; then # if environment includes a SP with subscription access, then we should use that. - LOGGED_IN_OBJECT_ID=$(az ad sp show --id ${ARM_CLIENT_ID} --query objectId -o tsv) + LOGGED_IN_OBJECT_ID=$(az ad sp show --id "${ARM_CLIENT_ID}" --query objectId -o tsv) else LOGGED_IN_OBJECT_ID=$(az ad signed-in-user show --query objectId -o tsv) fi @@ -43,25 +55,25 @@ fi # Assign Role Permissions. az role assignment create \ --role "Azure Service Bus Data Sender" \ - --assignee ${LOGGED_IN_OBJECT_ID} \ - --scope ${SERVICE_BUS_RESOURCE_ID} + --assignee "${LOGGED_IN_OBJECT_ID}" \ + --scope "${SERVICE_BUS_RESOURCE_ID}" az role assignment create \ --role "Azure Service Bus Data Receiver" \ - --assignee ${LOGGED_IN_OBJECT_ID} \ - --scope ${SERVICE_BUS_RESOURCE_ID} + --assignee "${LOGGED_IN_OBJECT_ID}" \ + --scope "${SERVICE_BUS_RESOURCE_ID}" az role assignment create \ --role "Contributor" \ - --assignee ${LOGGED_IN_OBJECT_ID} \ - --scope ${STATE_STORE_RESOURCE_ID} + --assignee "${LOGGED_IN_OBJECT_ID}" \ + --scope "${STATE_STORE_RESOURCE_ID}" if [[ -z ${ARM_CLIENT_ID:-} ]]; then # Configure SP for local resource processor debugging (Porter can't use local creds) echo "Configuring Service Principal for Resource Processor debugging..." - RP_TESTING_SP=$(az ad sp create-for-rbac --name "ResourceProcessorTesting-${TRE_ID}" --role Owner --scopes /subscriptions/${AZURE_SUBSCRIPTION_ID} -o json) - RP_TESTING_SP_APP_ID=$(echo ${RP_TESTING_SP} | jq -r .appId) - RP_TESTING_SP_PASSWORD=$(echo ${RP_TESTING_SP} | jq -r .password) + RP_TESTING_SP=$(az ad sp create-for-rbac --name "ResourceProcessorTesting-${TRE_ID}" --role Owner --scopes /subscriptions/"${AZURE_SUBSCRIPTION_ID}" -o json) + RP_TESTING_SP_APP_ID=$(echo "${RP_TESTING_SP}" | jq -r .appId) + RP_TESTING_SP_PASSWORD=$(echo "${RP_TESTING_SP}" | jq -r .password) else # no need to create a new sp if we already have one available RP_TESTING_SP_APP_ID=${ARM_CLIENT_ID} @@ -71,13 +83,18 @@ fi # Assign Service Bus permissions to the Resource Processor SP az role assignment create \ --role "Azure Service Bus Data Sender" \ - --assignee ${RP_TESTING_SP_APP_ID} \ - --scope ${SERVICE_BUS_RESOURCE_ID} + --assignee "${RP_TESTING_SP_APP_ID}" \ + --scope "${SERVICE_BUS_RESOURCE_ID}" az role assignment create \ --role "Azure Service Bus Data Receiver" \ - --assignee ${RP_TESTING_SP_APP_ID} \ - --scope ${SERVICE_BUS_RESOURCE_ID} + --assignee "${RP_TESTING_SP_APP_ID}" \ + --scope "${SERVICE_BUS_RESOURCE_ID}" + +az role assignment create \ + --role "EventGrid Data Sender" \ + --assignee "${RP_TESTING_SP_APP_ID}" \ + --scope "${EVENT_GRID_STATUS_CHANGED_TOPIC_RESOURCE_ID}" # Write the appId and secret to the private.env file which is used for RP debugging # First check if the env vars are there already and delete them diff --git a/templates/core/terraform/airlock/eventgrid_topics.tf b/templates/core/terraform/airlock/eventgrid_topics.tf index a4e03f1f77..692e343658 100644 --- a/templates/core/terraform/airlock/eventgrid_topics.tf +++ b/templates/core/terraform/airlock/eventgrid_topics.tf @@ -1,8 +1,3 @@ -data "azurerm_key_vault" "kv" { - name = "kv-${var.tre_id}" - resource_group_name = var.resource_group_name -} - # Event grid topics resource "azurerm_eventgrid_topic" "step_result" { name = local.step_result_topic_name @@ -60,16 +55,6 @@ resource "azurerm_private_dns_zone_virtual_network_link" "eg_topic_dns_link" { lifecycle { ignore_changes = [tags] } } - -resource "azurerm_key_vault_secret" "eventgrid_status_changed_access_key" { - name = "eventgrid-status-changed-access-key" - value = azurerm_eventgrid_topic.status_changed.primary_access_key - key_vault_id = data.azurerm_key_vault.kv.id - depends_on = [ - azurerm_eventgrid_topic.status_changed - ] -} - # System topic resource "azurerm_eventgrid_system_topic" "import_inprogress_blob_created" { name = local.import_inprogress_sys_topic_name diff --git a/templates/core/terraform/airlock/identity.tf b/templates/core/terraform/airlock/identity.tf index 89091d6dec..9b45e856bc 100644 --- a/templates/core/terraform/airlock/identity.tf +++ b/templates/core/terraform/airlock/identity.tf @@ -41,3 +41,9 @@ resource "azurerm_role_assignment" "cosmos_contributor" { role_definition_name = "Contributor" principal_id = azurerm_user_assigned_identity.airlock_id.principal_id } + +resource "azurerm_role_assignment" "eventgrid_data_sender" { + scope = azurerm_eventgrid_topic.status_changed.id + role_definition_name = "EventGrid Data Sender" + principal_id = var.api_principal_id +} diff --git a/templates/core/terraform/airlock/output.tf b/templates/core/terraform/airlock/output.tf index de03358b2e..69c464bc91 100644 --- a/templates/core/terraform/airlock/output.tf +++ b/templates/core/terraform/airlock/output.tf @@ -1,7 +1,7 @@ -output "event_grid_topic_endpoint" { +output "event_grid_status_changed_topic_endpoint" { value = azurerm_eventgrid_topic.status_changed.endpoint } -output "event_grid_access_key" { - value = azurerm_eventgrid_topic.status_changed.primary_access_key +output "event_grid_status_changed_topic_resource_id" { + value = azurerm_eventgrid_topic.status_changed.id } diff --git a/templates/core/terraform/airlock/variables.tf b/templates/core/terraform/airlock/variables.tf index cdbb57ff39..333bf47eeb 100644 --- a/templates/core/terraform/airlock/variables.tf +++ b/templates/core/terraform/airlock/variables.tf @@ -4,6 +4,7 @@ variable "resource_group_name" {} variable "shared_subnet_id" {} variable "enable_local_debugging" {} variable "virtual_network_id" {} +variable "api_principal_id" {} variable "docker_registry_server" { type = string diff --git a/templates/core/terraform/api-webapp.tf b/templates/core/terraform/api-webapp.tf index 8cbce5ae52..2893b74a0a 100644 --- a/templates/core/terraform/api-webapp.tf +++ b/templates/core/terraform/api-webapp.tf @@ -10,14 +10,6 @@ data "azurerm_eventgrid_topic" "status_changed" { ] } -data "azurerm_key_vault_secret" "eventgrid_status_changed_access_key" { - name = "eventgrid-status-changed-access-key" - key_vault_id = azurerm_key_vault.kv.id - depends_on = [ - module.airlock_resources - ] -} - locals { version = replace(replace(replace(data.local_file.api_app_version.content, "__version__ = \"", ""), "\"", ""), "\n", "") } @@ -53,8 +45,7 @@ resource "azurerm_app_service" "api" { "STATE_STORE_ENDPOINT" = azurerm_cosmosdb_account.tre-db-account.endpoint "COSMOSDB_ACCOUNT_NAME" = azurerm_cosmosdb_account.tre-db-account.name "SERVICE_BUS_FULLY_QUALIFIED_NAMESPACE" = "sb-${var.tre_id}.servicebus.windows.net" - "EVENT_GRID_TOPIC_ENDPOINT" = data.azurerm_eventgrid_topic.status_changed.endpoint - "EVENT_GRID_ACCESS_KEY" = "@Microsoft.KeyVault(SecretUri=${data.azurerm_key_vault_secret.eventgrid_status_changed_access_key.id})" + "EVENT_GRID_STATUS_CHANGED_TOPIC_ENDPOINT" = data.azurerm_eventgrid_topic.status_changed.endpoint "SERVICE_BUS_RESOURCE_REQUEST_QUEUE" = azurerm_servicebus_queue.workspacequeue.name "SERVICE_BUS_DEPLOYMENT_STATUS_UPDATE_QUEUE" = azurerm_servicebus_queue.service_bus_deployment_status_update_queue.name "MANAGED_IDENTITY_CLIENT_ID" = azurerm_user_assigned_identity.id.client_id diff --git a/templates/core/terraform/json-to-env.sh b/templates/core/terraform/json-to-env.sh index 2469358652..9f852571cf 100755 --- a/templates/core/terraform/json-to-env.sh +++ b/templates/core/terraform/json-to-env.sh @@ -78,12 +78,12 @@ jq -r ' "env_var": "REGISTRY_SERVER" }, { - "path": "event_grid_topic_endpoint", - "env_var": "EVENT_GRID_TOPIC_ENDPOINT" + "path": "event_grid_status_changed_topic_endpoint", + "env_var": "EVENT_GRID_STATUS_CHANGED_TOPIC_ENDPOINT" }, { - "path": "event_grid_access_key", - "env_var": "EVENT_GRID_ACCESS_KEY" + "path": "event_grid_status_changed_topic_resource_id", + "env_var": "EVENT_GRID_STATUS_CHANGED_TOPIC_RESOURCE_ID" } ] as $env_vars_to_extract diff --git a/templates/core/terraform/main.tf b/templates/core/terraform/main.tf index 22d9eadc69..775cbc4758 100644 --- a/templates/core/terraform/main.tf +++ b/templates/core/terraform/main.tf @@ -90,6 +90,7 @@ module "airlock_resources" { docker_registry_server = var.docker_registry_server mgmt_resource_group_name = var.mgmt_resource_group_name mgmt_acr_name = var.acr_name + api_principal_id = azurerm_user_assigned_identity.id.principal_id depends_on = [ azurerm_servicebus_namespace.sb, module.network diff --git a/templates/core/terraform/outputs.tf b/templates/core/terraform/outputs.tf index aaa3d8cea1..61bd33851b 100644 --- a/templates/core/terraform/outputs.tf +++ b/templates/core/terraform/outputs.tf @@ -77,11 +77,10 @@ output "registry_server" { value = var.docker_registry_server } -output "event_grid_topic_endpoint" { - value = module.airlock_resources.event_grid_topic_endpoint +output "event_grid_status_changed_topic_endpoint" { + value = module.airlock_resources.event_grid_status_changed_topic_endpoint } -output "event_grid_access_key" { - value = module.airlock_resources.event_grid_access_key - sensitive = true +output "event_grid_status_changed_topic_resource_id" { + value = module.airlock_resources.event_grid_status_changed_topic_resource_id }