diff --git a/docs/deployment/deployment-pipeline.md b/docs/deployment/deployment-pipeline.md index 2f16099f..501e113d 100644 --- a/docs/deployment/deployment-pipeline.md +++ b/docs/deployment/deployment-pipeline.md @@ -422,7 +422,7 @@ The ADO managed identity holds: The managed identity does **not** hold `Key Vault Secrets Officer` — it cannot write secrets. Cloud API tokens must be provisioned separately by the team managing the cloud application. -The managed identity also does **not** hold `AppRoleAssignment.ReadWrite.All`. Microsoft Graph requires this explicit application permission to create app role assignments — being an owner of the enterprise app service principal is insufficient in application auth context. Granting this tenant-wide permission is not permitted under the organisation's Entra policy. Arc machine managed identity app role assignments are therefore granted manually by running `make resource-group-init` under a user account with ownership of `spn-manbrs-web-api-` — see [`scripts/bash/assign_arc_app_roles.sh`](../../scripts/bash/assign_arc_app_roles.sh) and the [Onboard Hospital VM runbook](./runbooks/onboard-hospital-vm.md#step-4--grant-api-access). +The managed identity also does **not** hold `AppRoleAssignment.ReadWrite.All`. Microsoft Graph requires this explicit application permission to create app role assignments — being an owner of the enterprise app service principal is insufficient in application auth context. Granting this tenant-wide permission is not permitted under the organisation's Entra policy. Arc machine managed identity app role assignments are therefore granted manually by running `make assign-arc-app-roles` under a user account with ownership of `spn-manbrs-web-api-` — see [`scripts/bash/assign_arc_app_roles.sh`](../../scripts/bash/assign_arc_app_roles.sh) and the [Onboard Hospital VM runbook](./runbooks/onboard-hospital-vm.md#step-3--grant-api-access). ### Separation of environments diff --git a/docs/deployment/infrastructure/create-environment.md b/docs/deployment/infrastructure/create-environment.md index 0bff7bcb..f4a73e13 100644 --- a/docs/deployment/infrastructure/create-environment.md +++ b/docs/deployment/infrastructure/create-environment.md @@ -54,7 +54,7 @@ az provider show --namespace Microsoft.GuestConfiguration --query registrationSt - Confirm the web API enterprise application exists: - Name: `spn-manbrs-web-api-[environment]` - - If it does not exist, raise a ServiceNow request for the platform team to create it — the `resource-group-init` Bicep deployment and the `assign_arc_app_roles.sh` script both depend on it + - If it does not exist, raise a ServiceNow request for the platform team to create it — the `resource-group-init` Bicep deployment and the `assign-arc-app-roles` make target both depend on it - [Form for ServiceNow](https://nhsdigitallive.service-now.com/nhs_digital?id=sc_cat_item&sys_id=28f3ab4f1bf3ca1078ac4337b04bcb78&sysparm_category=114fced51bdae1502eee65b9bd4bcbdc) ## Code @@ -239,10 +239,10 @@ Terraform automatically discovers Arc machines registered in the Arc-enabled ser make [environment] terraform-apply ``` -After Terraform provisions the Hybrid Connection, re-run `resource-group-init` to assign the `Gateway.Access` app role to the new machine's managed identity: +After Terraform provisions the Hybrid Connection, run `assign-arc-app-roles` to assign the `Gateway.Access` app role to the new machine's managed identity: ```bash -make [environment] resource-group-init +make [environment] assign-arc-app-roles ``` -> **Why is this a separate step?** The pipeline managed identity cannot create app role assignments — `AppRoleAssignment.ReadWrite.All` is required in application auth context regardless of SP ownership, and this permission is not permitted under the organisation's Entra policy. Running `resource-group-init` under a user account with ownership of `spn-manbrs-web-api-[environment]` is sufficient. Without this step the gateway will fail to authenticate against the cloud web API. See [Onboard Hospital VM — Step 4](../runbooks/onboard-hospital-vm.md#step-4--grant-api-access). +> **Why is this a separate step?** The pipeline managed identity cannot create app role assignments — `AppRoleAssignment.ReadWrite.All` is required in application auth context regardless of SP ownership, and this permission is not permitted under the organisation's Entra policy. Running `assign-arc-app-roles` under a user account with ownership of `spn-manbrs-web-api-[environment]` is sufficient. Without this step the gateway will fail to authenticate against the cloud web API. See [Onboard Hospital VM — Step 3](../runbooks/onboard-hospital-vm.md#step-3--grant-api-access). diff --git a/docs/deployment/runbooks/onboard-hospital-vm.md b/docs/deployment/runbooks/onboard-hospital-vm.md index 6e88ee66..856f6e25 100644 --- a/docs/deployment/runbooks/onboard-hospital-vm.md +++ b/docs/deployment/runbooks/onboard-hospital-vm.md @@ -15,7 +15,7 @@ - [ ] Trust ODS code confirmed via the [ODS portal](https://odsportal.nhsbsa.nhs.uk/) - [ ] NHS region confirmed (`nw` | `neyh` | `mids` | `eoe` | `lon` | `se` | `sw`) - [ ] Deployment ring agreed with the programme team -- [ ] `arc-onboarding-spn-client-id` and `arc-onboarding-spn-client-secret` retrieved from Key Vault +- [ ] `arc-onboarding-spn-client-id` retrieved from Entra ID; new `arc-onboarding-spn-client-secret` generated with 1-day expiry and shared with the hospital trust IT team before the onboarding call --- @@ -91,16 +91,7 @@ Logs are written to `C:\ArcSetup\ArcSetup.log`. **Verify**: In the Azure portal, navigate to `rg-mbsgw--uks-arc-enabled-servers` → Azure Arc machines → `gw-hull-university-teaching-hospitals-nhs-trust-rwa-01`. Status should be **Connected**. -## Step 3 — Trigger Terraform to provision the Hybrid Connection - -Run the ADO pipeline **Deploy Arc Infrastructure - \** manually. Terraform discovers the new Arc machine and creates: - -- `hc-gw-hull-university-teaching-hospitals-nhs-trust-rwa-01` in the relay namespace (`relay-manbrs-`) -- `listen` auth rule on that Hybrid Connection - -**Verify**: In the Azure portal, navigate to `relay-manbrs-` → Hybrid Connections → `hc-gw-hull-university-teaching-hospitals-nhs-trust-rwa-01` is present. - -## Step 4 — Grant API access +## Step 3 — Grant API access > [!IMPORTANT] > Without this step the gateway services will start but fail to authenticate against the cloud web API. The Arc machine's managed identity must be assigned the `Gateway.Access` app role on `spn-manbrs-web-api-` before the first deployment. @@ -108,15 +99,24 @@ Run the ADO pipeline **Deploy Arc Infrastructure - \** manually. Terraform Run from a developer machine with Owner access to the enterprise application: ```bash -make resource-group-init +make assign-arc-app-roles ``` This calls [`scripts/bash/assign_arc_app_roles.sh`](../../../scripts/bash/assign_arc_app_roles.sh) which discovers all Arc machines in `rg-mbsgw--uks-arc-enabled-servers` and assigns the `Gateway.Access` role to each machine's managed identity. -> **Why is this manual?** The pipeline managed identity (`mi-mbsgw--adotoaz-uks`) cannot create app role assignments via the pipeline — Microsoft Graph requires `AppRoleAssignment.ReadWrite.All` in application auth context regardless of SP ownership, and this permission cannot be granted under the organisation's Entra policy. Running `resource-group-init` under a user account with ownership of the enterprise app SP is sufficient. See [Deployment Pipeline — Section 12](../deployment-pipeline.md#12-pipeline-identities-and-permissions) for details. +> **Why is this manual?** The pipeline managed identity (`mi-mbsgw--adotoaz-uks`) cannot create app role assignments via the pipeline — Microsoft Graph requires `AppRoleAssignment.ReadWrite.All` in application auth context regardless of SP ownership, and this permission cannot be granted under the organisation's Entra policy. Running `assign-arc-app-roles` under a user account with ownership of the enterprise app SP is sufficient. See [Deployment Pipeline — Section 12](../deployment-pipeline.md#12-pipeline-identities-and-permissions) for details. **Verify**: In the Azure portal navigate to **Enterprise Applications → spn-manbrs-web-api-\ → Users and groups**. The Arc machine (`gw-hull-university-teaching-hospitals-nhs-trust-rwa-01`) should appear with the `Gateway.Access` role. +## Step 4 — Trigger Terraform to provision the Hybrid Connection + +Run the ADO pipeline **Deploy Arc Infrastructure - \** manually. Terraform discovers the new Arc machine and creates: + +- `hc-gw-hull-university-teaching-hospitals-nhs-trust-rwa-01` in the relay namespace (`relay-manbrs-`) +- `listen` auth rule on that Hybrid Connection + +**Verify**: In the Azure portal, navigate to `relay-manbrs-` → Hybrid Connections → `hc-gw-hull-university-teaching-hospitals-nhs-trust-rwa-01` is present. + ## Step 5 — Deploy the gateway application Run the ADO pipeline **Deploy Gateway - \** with: @@ -172,7 +172,7 @@ Check Log Analytics Workspace for an initial heartbeat within 5 minutes of servi Check `C:\ArcSetup\ArcSetup.log` on the VM. Common causes: - **Firewall blocking outbound** — confirm the VM can reach `*.arc.azure.com` on port 443 -- **SPN credentials wrong** — verify client ID and secret from Key Vault are current +- **SPN credentials wrong** — confirm the one-time secret shared before the call has not expired (1-day validity); generate a new one and retry if needed - **VM already registered** — if the machine was previously connected under a different name, disconnect first: `azcmagent disconnect` ### Script execution blocked diff --git a/scripts/terraform/terraform.mk b/scripts/terraform/terraform.mk index e058dc47..68e5179e 100644 --- a/scripts/terraform/terraform.mk +++ b/scripts/terraform/terraform.mk @@ -21,9 +21,11 @@ ci: # Skip manual approvals when running in CI - make ci set-azure-account: # Set the Azure account for the environment - make set-azure-account [ "${SKIP_AZURE_LOGIN}" != "true" ] && az account set -s ${AZURE_SUBSCRIPTION} || true -resource-group-init: set-azure-account get-subscription-ids # Initialise resources required by terraform and assign Gateway.Access role to Arc machine managed identities - make resource-group-init +resource-group-init: set-azure-account get-subscription-ids # Initialise resources required by terraform - make resource-group-init $(eval STORAGE_ACCOUNT_NAME=sa${APP_SHORT_NAME}${ENV_CONFIG}tfstate) scripts/bash/resource_group_init.sh "${REGION}" "${HUB_SUBSCRIPTION_ID}" "${ENABLE_SOFT_DELETE}" "${ENV_CONFIG}" "${STORAGE_ACCOUNT_RG}" "${STORAGE_ACCOUNT_NAME}" "${APP_SHORT_NAME}" "${ARM_SUBSCRIPTION_ID}" + +assign-arc-app-roles: set-azure-account get-subscription-ids # Assign Gateway.Access app role to Arc machine managed identities - make assign-arc-app-roles scripts/bash/assign_arc_app_roles.sh "${ENV_CONFIG}" "${ARM_SUBSCRIPTION_ID}" get-subscription-ids: # Retrieve the hub subscription ID based on the subscription name in ${HUB_SUBSCRIPTION} - make get-subscription-ids