diff --git a/docs/adr/ADR-005_Managed_Identity_For_Azure_Relay.md b/docs/adr/ADR-005_Managed_Identity_For_Azure_Relay.md index 8fd1181a..9db9cb08 100644 --- a/docs/adr/ADR-005_Managed_Identity_For_Azure_Relay.md +++ b/docs/adr/ADR-005_Managed_Identity_For_Azure_Relay.md @@ -22,10 +22,11 @@ That said, setting up a working Relay connection locally is already complex. Man In **production** (`ENVIRONMENT=prod`), the gateway uses `ManagedIdentityCredential` exclusively. The SAS token path is unavailable regardless of what environment variables are set. The gateway's managed identity must be assigned the **Azure Relay Listener** role on the hybrid connection resource in Azure. -In **non-production** environments, the auth method is determined by whether `AZURE_RELAY_SHARED_ACCESS_KEY` is set: +In **non-production** environments, SAS-based authentication is only enabled in the review environment -- If set, a SAS token is generated and embedded in the WebSocket URL (`sb-hc-token`), preserving the simpler local development setup. -- If absent, `DefaultAzureCredential` is used, which works with Azure CLI credentials (`az login`) for developers who have the Listener role assigned to their identity. +- In the review environment, a SAS key may be provisioned and injected into `.env` so local testing against the gateway test VM continues to work. +- In dev, preprod, and prod the relay listener uses managed identity / Azure AD authentication and no SAS key is provisioned or injected into `.env`. +- If no SAS key is present, `DefaultAzureCredential` is used for developer scenarios that rely on `az login` and the appropriate Relay Listener role assignment. The token is passed as an `Authorization: Bearer` HTTP header on the WebSocket upgrade request for managed identity paths. Azure Relay validates it against Azure AD. diff --git a/docs/relay-listener/README.md b/docs/relay-listener/README.md index 2be32437..b0e2c9ce 100644 --- a/docs/relay-listener/README.md +++ b/docs/relay-listener/README.md @@ -3,6 +3,7 @@ Relay listener uses websocket communication to Manage Breast Screening service via Azure Relay. The listener processes worklist actions sent from Manage/Django and creates worklist items in the Modality Worklist server. +Note: SAS-based relay authentication is review-only. For dev, preprod, and prod, the listener should use managed identity and no `AZURE_RELAY_SHARED_ACCESS_KEY` should be injected into `.env`. ## Architecture diff --git a/infrastructure/modules/arc-infra/outputs.tf b/infrastructure/modules/arc-infra/outputs.tf index 5030ce4f..7e4e6b92 100644 --- a/infrastructure/modules/arc-infra/outputs.tf +++ b/infrastructure/modules/arc-infra/outputs.tf @@ -35,9 +35,9 @@ output "app_insights_connection_string" { } output "relay_listen_sas_keys" { - description = "Per-machine relay listen SAS primary keys, keyed by Arc resource name. Used by the deploy pipeline to write .env files." + description = "Per-machine relay listen SAS primary keys, keyed by Arc resource name. Populated only for the review environment." sensitive = true - value = var.enable_arc_servers ? { + value = var.enable_arc_servers && var.env_config == "review" ? { for k, rule in azurerm_relay_hybrid_connection_authorization_rule.per_machine_listen : k => rule.primary_key } : {} diff --git a/infrastructure/modules/arc-infra/relay.tf b/infrastructure/modules/arc-infra/relay.tf index db8a945f..41c77bac 100644 --- a/infrastructure/modules/arc-infra/relay.tf +++ b/infrastructure/modules/arc-infra/relay.tf @@ -48,7 +48,11 @@ resource "azurerm_relay_hybrid_connection" "per_machine" { # Listen-only SAS rule per HC — retained for local development / break-glass access. # Production relay authentication uses Managed Identity (see relay_listener_role below). resource "azurerm_relay_hybrid_connection_authorization_rule" "per_machine_listen" { - for_each = local.arc_machines + for_each = { + for machine_name, machine_config in local.arc_machines : + machine_name => machine_config + if var.env_config == "review" + } name = "listen" hybrid_connection_name = azurerm_relay_hybrid_connection.per_machine[each.key].name diff --git a/scripts/bash/deploy_arc_ring.sh b/scripts/bash/deploy_arc_ring.sh index 0b7612a6..5cfc07c0 100755 --- a/scripts/bash/deploy_arc_ring.sh +++ b/scripts/bash/deploy_arc_ring.sh @@ -73,6 +73,13 @@ while IFS= read -r MACHINE_JSON; do LOCATION=$(echo "$MACHINE_JSON" | jq -r '.location') echo "Preparing deploy for $MACHINE ($LOCATION)..." +RELAY_AUTH_BLOCK="" +if [[ "${ENV_CONFIG}" == "review" && -n "${AZURE_RELAY_SHARED_ACCESS_KEY:-}" ]]; then + RELAY_AUTH_BLOCK="AZURE_RELAY_KEY_NAME=listen +AZURE_RELAY_SHARED_ACCESS_KEY=${AZURE_RELAY_SHARED_ACCESS_KEY} +" +fi + # Build .env, then base64-encode to pass newlines as a run command parameter. # NOTE: Arc Run Command drops protectedParameters for inline source.script, # so EnvContentB64 travels as a regular parameter (base64-encoded, not plain text). @@ -92,6 +99,10 @@ PACS_DB_PATH=${BASE_PATH}/data/pacs.db LOG_LEVEL=INFO SAMPLE_IMAGES_PATH=${BASE_PATH}/current/sample_images" + if [[ -n "${RELAY_AUTH_BLOCK}" ]]; then + ENV_CONTENT="${ENV_CONTENT}${RELAY_AUTH_BLOCK}" + fi + # Cross-platform base64 encoding (works on macOS and Linux) ENV_CONTENT_B64=$(printf '%s' "$ENV_CONTENT" | base64 | tr -d '\n')