From 2526bfc54c66e5465584e9113f8b15208430f4ae Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Thu, 25 Aug 2022 10:28:52 +0100 Subject: [PATCH 01/31] Add Airlock Manager workspace --- .../workspaces/airlock_manager/.dockerignore | 9 + .../workspaces/airlock_manager/.env.sample | 28 ++ .../airlock_manager/Dockerfile.tmpl | 23 ++ .../airlock_manager/parameters.json | 122 +++++++ .../workspaces/airlock_manager/porter.yaml | 246 +++++++++++++ .../airlock_manager/template_schema.json | 60 ++++ .../terraform/.terraform.lock.hcl | 81 +++++ .../airlock_manager/terraform/aad/aad.tf | 116 ++++++ .../airlock_manager/terraform/aad/outputs.tf | 19 + .../terraform/aad/variables.tf | 7 + .../airlock_manager/terraform/airlock/data.tf | 30 ++ .../terraform/airlock/eventgrid_topics.tf | 209 +++++++++++ .../terraform/airlock/locals.tf | 25 ++ .../terraform/airlock/storage_accounts.tf | 334 ++++++++++++++++++ .../terraform/airlock/variables.tf | 8 + .../terraform/appserviceplan.tf | 10 + .../airlock_manager/terraform/deploy.sh | 15 + .../airlock_manager/terraform/destroy.sh | 16 + .../airlock_manager/terraform/keyvault.tf | 123 +++++++ .../airlock_manager/terraform/locals.tf | 15 + .../airlock_manager/terraform/network/data.tf | 94 +++++ .../terraform/network/locals.tf | 9 + .../terraform/network/network.tf | 67 ++++ .../terraform/network/outputs.tf | 19 + .../terraform/network/security.tf | 212 +++++++++++ .../terraform/network/variables.tf | 6 + .../terraform/network/zone_links.tf | 110 ++++++ .../airlock_manager/terraform/outputs.tf | 26 ++ .../airlock_manager/terraform/providers.tf | 41 +++ .../airlock_manager/terraform/storage.tf | 81 +++++ .../airlock_manager/terraform/variables.tf | 106 ++++++ .../airlock_manager/terraform/workspace.tf | 57 +++ .../airlock_manager/update_redirect_urls.sh | 82 +++++ 33 files changed, 2406 insertions(+) create mode 100644 templates/workspaces/airlock_manager/.dockerignore create mode 100644 templates/workspaces/airlock_manager/.env.sample create mode 100644 templates/workspaces/airlock_manager/Dockerfile.tmpl create mode 100644 templates/workspaces/airlock_manager/parameters.json create mode 100644 templates/workspaces/airlock_manager/porter.yaml create mode 100644 templates/workspaces/airlock_manager/template_schema.json create mode 100644 templates/workspaces/airlock_manager/terraform/.terraform.lock.hcl create mode 100644 templates/workspaces/airlock_manager/terraform/aad/aad.tf create mode 100644 templates/workspaces/airlock_manager/terraform/aad/outputs.tf create mode 100644 templates/workspaces/airlock_manager/terraform/aad/variables.tf create mode 100644 templates/workspaces/airlock_manager/terraform/airlock/data.tf create mode 100644 templates/workspaces/airlock_manager/terraform/airlock/eventgrid_topics.tf create mode 100644 templates/workspaces/airlock_manager/terraform/airlock/locals.tf create mode 100644 templates/workspaces/airlock_manager/terraform/airlock/storage_accounts.tf create mode 100644 templates/workspaces/airlock_manager/terraform/airlock/variables.tf create mode 100644 templates/workspaces/airlock_manager/terraform/appserviceplan.tf create mode 100644 templates/workspaces/airlock_manager/terraform/deploy.sh create mode 100644 templates/workspaces/airlock_manager/terraform/destroy.sh create mode 100644 templates/workspaces/airlock_manager/terraform/keyvault.tf create mode 100644 templates/workspaces/airlock_manager/terraform/locals.tf create mode 100644 templates/workspaces/airlock_manager/terraform/network/data.tf create mode 100644 templates/workspaces/airlock_manager/terraform/network/locals.tf create mode 100644 templates/workspaces/airlock_manager/terraform/network/network.tf create mode 100644 templates/workspaces/airlock_manager/terraform/network/outputs.tf create mode 100644 templates/workspaces/airlock_manager/terraform/network/security.tf create mode 100644 templates/workspaces/airlock_manager/terraform/network/variables.tf create mode 100644 templates/workspaces/airlock_manager/terraform/network/zone_links.tf create mode 100644 templates/workspaces/airlock_manager/terraform/outputs.tf create mode 100644 templates/workspaces/airlock_manager/terraform/providers.tf create mode 100644 templates/workspaces/airlock_manager/terraform/storage.tf create mode 100644 templates/workspaces/airlock_manager/terraform/variables.tf create mode 100644 templates/workspaces/airlock_manager/terraform/workspace.tf create mode 100755 templates/workspaces/airlock_manager/update_redirect_urls.sh diff --git a/templates/workspaces/airlock_manager/.dockerignore b/templates/workspaces/airlock_manager/.dockerignore new file mode 100644 index 0000000000..e2b7cb2a0e --- /dev/null +++ b/templates/workspaces/airlock_manager/.dockerignore @@ -0,0 +1,9 @@ +# Local .terraform directories +**/.terraform/* + +# TF backend files +**/*_backend.tf + +Dockerfile.tmpl +terraform/deploy.sh +terraform/destroy.sh diff --git a/templates/workspaces/airlock_manager/.env.sample b/templates/workspaces/airlock_manager/.env.sample new file mode 100644 index 0000000000..685235ce6e --- /dev/null +++ b/templates/workspaces/airlock_manager/.env.sample @@ -0,0 +1,28 @@ +ARM_CLIENT_ID="__CHANGE_ME__" +ARM_CLIENT_SECRET="__CHANGE_ME__" +ARM_TENANT_ID="__CHANGE_ME__" +ARM_SUBSCRIPTION_ID="__CHANGE_ME__" +AUTH_TENANT_ID="__CHANGE_ME__" + +# These are passed in if Terraform will create the Workspace AAD Application +#REGISTER_AAD_APPLICATION=true +AUTH_CLIENT_ID="__CHANGE_ME__" +AUTH_CLIENT_SECRET="__CHANGE_ME__" +WORKSPACE_OWNER_OBJECT_ID="__CHANGE_ME__" + +# These are passed in if you register the Workspace AAD Application before hand +REGISTER_AAD_APPLICATION=false +CLIENT_ID="__CHANGE_ME__" +CLIENT_SECRET="__CHANGE_ME__" + +# Used by Porter, aka TRE_RESOURCE_ID +ID="MadeUp123" +SP_ID="" +SCOPE_ID="api://ws_0001" +APP_ROLE_ID_WORKSPACE_OWNER="" +APP_ROLE_ID_WORKSPACE_RESEARCHER="" +ADDRESS_SPACE="10.2.8.0/24" +SHARED_STORAGE_QUOTA=50 +ENABLE_LOCAL_DEBUGGING=true + +AAD_REDIRECT_URIS="W10=" diff --git a/templates/workspaces/airlock_manager/Dockerfile.tmpl b/templates/workspaces/airlock_manager/Dockerfile.tmpl new file mode 100644 index 0000000000..421c5d4b82 --- /dev/null +++ b/templates/workspaces/airlock_manager/Dockerfile.tmpl @@ -0,0 +1,23 @@ +# We need azurecli 2.37+ which doesn't exist for strech so the minimum is buster +FROM debian:buster-slim + +ARG BUNDLE_DIR + +# This is a template Dockerfile for the bundle's invocation image +# You can customize it to use different base images, install tools and copy configuration files. +# +# Porter will use it as a template and append lines to it for the mixins +# and to set the CMD appropriately for the CNAB specification. +# +# Add the following line to porter.yaml to instruct Porter to use this template +# dockerfile: Dockerfile.tmpl + +# You can control where the mixin's Dockerfile lines are inserted into this file by moving "# PORTER_MIXINS" line +# another location in this file. If you remove that line, the mixins generated content is appended to this file. +# PORTER_MIXINS + +# Use the BUNDLE_DIR build argument to copy files into the bundle +COPY . $BUNDLE_DIR + +# Install jq +RUN apt-get update && apt-get install -y jq="1.5+dfsg-2+b1" && apt-get clean -y && rm -rf /var/lib/apt/lists/* diff --git a/templates/workspaces/airlock_manager/parameters.json b/templates/workspaces/airlock_manager/parameters.json new file mode 100644 index 0000000000..b220dd2d80 --- /dev/null +++ b/templates/workspaces/airlock_manager/parameters.json @@ -0,0 +1,122 @@ +{ + "schemaVersion": "1.0.0-DRAFT+TODO", + "name": "airlock-manager", + "created": "2021-06-04T13:37:29.5071039+03:00", + "modified": "2021-06-04T13:37:29.5071039+03:00", + "parameters": [ + { + "name": "address_space", + "source": { + "env": "ADDRESS_SPACE" + } + }, + { + "name": "azure_location", + "source": { + "env": "LOCATION" + } + }, + { + "name": "tre_id", + "source": { + "env": "TRE_ID" + } + }, + { + "name": "id", + "source": { + "env": "ID" + } + }, + { + "name": "tfstate_container_name", + "source": { + "env": "TERRAFORM_STATE_CONTAINER_NAME" + } + }, + { + "name": "tfstate_resource_group_name", + "source": { + "env": "MGMT_RESOURCE_GROUP_NAME" + } + }, + { + "name": "tfstate_storage_account_name", + "source": { + "env": "MGMT_STORAGE_ACCOUNT_NAME" + } + }, + { + "name": "shared_storage_quota", + "source": { + "env": "SHARED_STORAGE_QUOTA" + } + }, + { + "name": "enable_local_debugging", + "source": { + "env": "ENABLE_LOCAL_DEBUGGING" + } + }, + { + "name": "register_aad_application", + "source": { + "env": "REGISTER_AAD_APPLICATION" + } + }, + { + "name": "client_id", + "source": { + "env": "CLIENT_ID" + } + }, + { + "name": "client_secret", + "source": { + "env": "CLIENT_SECRET" + } + }, + { + "name": "scope_id", + "source": { + "env": "SCOPE_ID" + } + }, + { + "name": "workspace_owner_object_id", + "source": { + "env": "WORKSPACE_OWNER_OBJECT_ID" + } + }, + { + "name": "sp_id", + "source": { + "env": "SP_ID" + } + }, + { + "name": "app_role_id_workspace_owner", + "source": { + "env": "APP_ROLE_ID_WORKSPACE_OWNER" + } + }, + { + "name": "app_role_id_workspace_researcher", + "source": { + "env": "APP_ROLE_ID_WORKSPACE_RESEARCHER" + } + }, + { + "name": "aad_redirect_uris", + "source": { + "env": "AAD_REDIRECT_URIS" + } + }, + { + "name": "app_service_plan_sku", + "source": { + "env": "APP_SERVICE_PLAN_SKU" + } + } + ] +} diff --git a/templates/workspaces/airlock_manager/porter.yaml b/templates/workspaces/airlock_manager/porter.yaml new file mode 100644 index 0000000000..71e9e4392b --- /dev/null +++ b/templates/workspaces/airlock_manager/porter.yaml @@ -0,0 +1,246 @@ +--- +name: tre-workspace-airlock-manager +version: 0.3.16 +description: "A airlock manager Azure TRE workspace" +dockerfile: Dockerfile.tmpl +registry: azuretre + +credentials: + # Credentials for interacting with the AAD Auth tenant + - name: auth_client_id + env: AUTH_CLIENT_ID + - name: auth_client_secret + env: AUTH_CLIENT_SECRET + - name: auth_tenant_id + env: AUTH_TENANT_ID + # Credentials for interacting with Azure + - name: azure_tenant_id + env: ARM_TENANT_ID + - name: azure_subscription_id + env: ARM_SUBSCRIPTION_ID + - name: azure_client_id + env: ARM_CLIENT_ID + - name: azure_client_secret + env: ARM_CLIENT_SECRET + +parameters: + - name: tre_id + type: string + description: "The ID of the parent TRE instance e.g., mytre-dev-3142" + - name: id + type: string + description: "the resource ID for this installation" + - name: azure_location + type: string + description: "Azure location (region) to deploy to" + - name: address_space + type: string + description: "VNet address space for the workspace services" + - name: tfstate_resource_group_name + type: string + description: "Resource group containing the Terraform state storage account" + - name: tfstate_storage_account_name + type: string + description: "The name of the Terraform state storage account" + - name: tfstate_container_name + type: string + default: "tfstate" + description: "The name of the Terraform state storage container" + - name: arm_use_msi + type: boolean + default: false + - name: shared_storage_quota + type: integer + default: 50 + - name: enable_local_debugging + type: boolean + default: false + - name: register_aad_application + type: boolean + default: false + description: "Whether this bundle should register the workspace in AAD" + - name: workspace_owner_object_id + type: string + description: "The object id of the user that will be granted WorkspaceOwner after it is created." + - name: client_id + type: string + description: + "The client id of the workspace in the identity provider. This value is typically provided to you + when you create the ws application" + - name: client_secret + type: string + description: + "The client secret of the workspace in the identity provider. This value is typically provided to you + when you create the ws application" + default: "" + - name: scope_id + type: string + default: "" + description: "The Service Principal Name or identifierUri (e.g. api://GUID" + - name: sp_id + type: string + default: "" + description: "The Service Principal in the Identity provider to be able to get claims" + - name: app_role_id_workspace_owner + type: string + default: "" + description: "The id of the application role WorkspaceOwner in the identity provider" + - name: app_role_id_workspace_researcher + type: string + default: "" + description: "The id of the application role WorkspaceResearcher in the identity provider" + - name: aad_redirect_uris + type: string + description: "List of redirect URIs in {name:value} format" + default: "W10=" # b64 for [] + - name: app_service_plan_sku + type: string + description: "The SKU used when deploying an Azure App Service Plan" + default: "P1v3" + +outputs: + - name: app_role_id_workspace_owner + type: string + applyTo: + - install + - name: app_role_id_workspace_researcher + type: string + applyTo: + - install + - name: client_id + type: string + applyTo: + - install + - name: scope_id + type: string + applyTo: + - install + - name: sp_id + type: string + applyTo: + - install + +mixins: + - exec + - terraform: + clientVersion: 1.1.7 + initFile: providers.tf + - az + +install: + - terraform: + description: "Deploy workspace" + vars: + tre_id: "{{ bundle.parameters.tre_id }}" + tre_resource_id: "{{ bundle.parameters.id }}" + location: "{{ bundle.parameters.azure_location }}" + address_space: "{{ bundle.parameters.address_space }}" + shared_storage_quota: "{{ bundle.parameters.shared_storage_quota }}" + enable_local_debugging: "{{ bundle.parameters.enable_local_debugging }}" + register_aad_application: "{{ bundle.parameters.register_aad_application }}" + auth_client_id: "{{ bundle.credentials.auth_client_id }}" + auth_client_secret: "{{ bundle.credentials.auth_client_secret }}" + auth_tenant_id: "{{ bundle.credentials.auth_tenant_id }}" + workspace_owner_object_id: "{{ bundle.parameters.workspace_owner_object_id }}" + client_id: "{{ bundle.parameters.client_id }}" + client_secret: "{{ bundle.parameters.client_secret }}" + scope_id: "{{ bundle.parameters.scope_id }}" + sp_id: "{{ bundle.parameters.sp_id }}" + app_role_id_workspace_owner: "{{ bundle.parameters.app_role_id_workspace_owner }}" + app_role_id_workspace_researcher: "{{ bundle.parameters.app_role_id_workspace_researcher }}" + aad_redirect_uris_b64: "{{ bundle.parameters.aad_redirect_uris }}" + app_service_plan_sku: "{{ bundle.parameters.app_service_plan_sku }}" + backendConfig: + resource_group_name: "{{ bundle.parameters.tfstate_resource_group_name }}" + storage_account_name: "{{ bundle.parameters.tfstate_storage_account_name }}" + container_name: "{{ bundle.parameters.tfstate_container_name }}" + key: "{{ bundle.parameters.tre_id }}-ws-{{ bundle.parameters.id }}" + outputs: + - name: app_role_id_workspace_owner + - name: app_role_id_workspace_researcher + - name: client_id + - name: scope_id + - name: sp_id + +upgrade: + # TODO: fix with https://github.com/microsoft/AzureTRE/issues/2114 + # - terraform: + # description: "Upgrade workspace" + # vars: + # tre_id: "{{ bundle.parameters.tre_id }}" + # tre_resource_id: "{{ bundle.parameters.id }}" + # location: "{{ bundle.parameters.azure_location }}" + # address_space: "{{ bundle.parameters.address_space }}" + # shared_storage_quota: "{{ bundle.parameters.shared_storage_quota }}" + # enable_local_debugging: "{{ bundle.parameters.enable_local_debugging }}" + # register_aad_application: "{{ bundle.parameters.register_aad_application }}" + # auth_client_id: "{{ bundle.credentials.auth_client_id }}" + # auth_client_secret: "{{ bundle.credentials.auth_client_secret }}" + # auth_tenant_id: "{{ bundle.credentials.auth_tenant_id }}" + # workspace_owner_object_id: "{{ bundle.parameters.workspace_owner_object_id }}" + # client_id: "{{ bundle.parameters.client_id }}" + # client_secret: "{{ bundle.parameters.client_secret }}" + # scope_id: "{{ bundle.parameters.scope_id }}" + # sp_id: "{{ bundle.parameters.sp_id }}" + # app_role_id_workspace_owner: "{{ bundle.parameters.app_role_id_workspace_owner }}" + # app_role_id_workspace_researcher: "{{ bundle.parameters.app_role_id_workspace_researcher }}" + # aad_redirect_uris_b64: "{{ bundle.parameters.aad_redirect_uris }}" + # backendConfig: + # resource_group_name: "{{ bundle.parameters.tfstate_resource_group_name }}" + # storage_account_name: "{{ bundle.parameters.tfstate_storage_account_name }}" + # container_name: "{{ bundle.parameters.tfstate_container_name }}" + # key: "{{ bundle.parameters.tre_id }}-ws-{{ bundle.parameters.id }}" + # outputs: + # - name: app_role_id_workspace_owner + # - name: app_role_id_workspace_researcher + # - name: client_id + # - name: scope_id + # - name: sp_id + - az: + description: "AAD Application Admin Login" + arguments: + - login + flags: + service-principal: "" + username: "'{{bundle.credentials.auth_client_id}}'" + password: "'{{bundle.credentials.auth_client_secret}}'" + tenant: "'{{bundle.credentials.auth_tenant_id}}'" + allow-no-subscriptions: "" + - exec: + description: "Update workspace app redirect urls" + command: ./update_redirect_urls.sh + flags: + workspace-api-client-id: "{{ bundle.parameters.client_id }}" + aad-redirect-uris-b64: "{{ bundle.parameters.aad_redirect_uris }}" + # always update with the script since we don't run TF for upgrade + # might need to change when https://github.com/microsoft/AzureTRE/issues/2114 is resolved. + register-aad-application: "false" + # register-aad-application: "{{ bundle.parameters.register_aad_application }}" + +uninstall: + - terraform: + description: "Tear down workspace" + vars: + tre_id: "{{ bundle.parameters.tre_id }}" + tre_resource_id: "{{ bundle.parameters.id }}" + location: "{{ bundle.parameters.azure_location }}" + address_space: "{{ bundle.parameters.address_space }}" + shared_storage_quota: "{{ bundle.parameters.shared_storage_quota }}" + enable_local_debugging: "{{ bundle.parameters.enable_local_debugging }}" + register_aad_application: "{{ bundle.parameters.register_aad_application }}" + auth_client_id: "{{ bundle.credentials.auth_client_id }}" + auth_client_secret: "{{ bundle.credentials.auth_client_secret }}" + auth_tenant_id: "{{ bundle.credentials.auth_tenant_id }}" + workspace_owner_object_id: "{{ bundle.parameters.workspace_owner_object_id }}" + client_id: "{{ bundle.parameters.client_id }}" + scope_id: "{{ bundle.parameters.scope_id }}" + sp_id: "{{ bundle.parameters.sp_id }}" + app_role_id_workspace_owner: "{{ bundle.parameters.app_role_id_workspace_owner }}" + app_role_id_workspace_researcher: "{{ bundle.parameters.app_role_id_workspace_researcher }}" + aad_redirect_uris_b64: "{{ bundle.parameters.aad_redirect_uris }}" + app_service_plan_sku: "{{ bundle.parameters.app_service_plan_sku }}" + backendConfig: + resource_group_name: "{{ bundle.parameters.tfstate_resource_group_name }}" + storage_account_name: "{{ bundle.parameters.tfstate_storage_account_name }}" + container_name: "{{ bundle.parameters.tfstate_container_name }}" + key: "{{ bundle.parameters.tre_id }}-ws-{{ bundle.parameters.id }}" diff --git a/templates/workspaces/airlock_manager/template_schema.json b/templates/workspaces/airlock_manager/template_schema.json new file mode 100644 index 0000000000..18d41ad07a --- /dev/null +++ b/templates/workspaces/airlock_manager/template_schema.json @@ -0,0 +1,60 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://github.com/microsoft/AzureTRE/templates/workspaces/airlock_manager/template_schema.json", + "type": "object", + "title": "Airlock manager Workspace", + "description": "This workspace template is to be used to review import Airlock requests", + "required": [ + ], + "properties": { + "shared_storage_quota": { + "$id": "#/properties/shared_storage_quota", + "type": "integer", + "title": "Shared Storage Quota", + "description": "Quota (in GB) to set for the VM Shared Storage." + }, + "aad_redirect_uris": { + "$id": "#/properties/aad_redirect_uris", + "type": "array", + "title": "AAD Redirect URIs", + "description": "Redirect URIs for the AAD app in auto_create mode", + "updateable": true, + "default": [], + "items":{ + "title": "items", + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "title": "name", + "type": "string", + "description": "Redirect URI Name", + "examples": [ + "My Redirect URI" + ], + "pattern": "^.*$" + }, + "value": { + "title": "value", + "type": "string", + "description": "Redirect URI Value", + "examples": [ + "https://a-domain-name.com/oauth/" + ] + } + } + } + }, + "app_service_plan_sku": { + "$id": "#/properties/app_service_plan_sku", + "type": "string", + "enum": ["P1v3", "P1v2"], + "default": "P1v3", + "title": "App Service Plan SKU", + "description": "The SKU that will be used when deploying an Azure App Service Plan." + } + } +} diff --git a/templates/workspaces/airlock_manager/terraform/.terraform.lock.hcl b/templates/workspaces/airlock_manager/terraform/.terraform.lock.hcl new file mode 100644 index 0000000000..a6b6c478d8 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/.terraform.lock.hcl @@ -0,0 +1,81 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/azuread" { + version = "2.20.0" + constraints = "2.20.0" + hashes = [ + "h1:qKo6WfRyml6w4qcnqDoeTmlWCL/kzng4qOB/5/XAW9g=", + "zh:0262b33661825b54edc0c539415ebdc942ecb3e2cf90af75f7ef134a1f901816", + "zh:0b569b6427e0a1f6c38ad19dd50f036bf65d5b64751e8a083fb36df76337faba", + "zh:1c3e89cf19118fc07d7b04257251fc9897e722c16e0a0df7b07fcd261f8c12e7", + "zh:4f3d017077eb9264ad4047ea0eda87ae7bc76da119f98361d10df27654b5b01c", + "zh:5566a523690f75f5fd4577f24a3194c719ebd22c011bf8619b86594a352afc71", + "zh:6101be64bf464d763585d144ee2cafae4aad74eb2f7f5264340addc9a9f227f7", + "zh:632627f20e48ce7e47f3be86a4d5869eb8412bf8083b5770decbb1e3cc335a1c", + "zh:63e7fbf0a34d7be50a4b83853600be6116a7c1600484d2e7ff2f15cc98abcf6f", + "zh:7909a7a074440e50be426f57e616e920745f8c38288537220f37c2d1ec719452", + "zh:e4f20c9887062a9ae1edcd208112d4d90c12afb7577f943220b54b83de8f10b7", + "zh:eb76ecf86977cd310f3311bc8f0015763c0a91594172a6b2d4ddb3d981d9c28e", + "zh:ffe05338f3e98fcbc5ffcf8b19dab8463849558d2ee6284afc91cdf9636c3330", + ] +} + +provider "registry.terraform.io/hashicorp/azurerm" { + version = "3.12.0" + constraints = "3.12.0" + hashes = [ + "h1:KF6bIhK7POPuO1HYK1G8b5Fae+0n8c/gM+9EBVJJQ2Q=", + "zh:0bbc93276a38da205d2b8ce34a2f813e96687a2f6fc7addd9bb05b85dab2a662", + "zh:3af12159e0b5217a7b35f081fba1e34ac8fb995acc7e6d2ec86592a559eb85c8", + "zh:7d1bdc9b4d9b1990409d52cb915e5acbe17bd81b29d28f7fcdaaf96003dca77c", + "zh:81ab77524cfa91aed929e35e2ed63b2ac73add7c33d1b3d5cdc21937606ecc7c", + "zh:84ddddd9f4c695199ef2824eea853d29434e164e0ef3603451aed39d8852ba28", + "zh:9905a5ca2d7c5c6e43a4be1f7b207d584860ec4ddad1aaa475fb03a731333751", + "zh:9cdf3223d9f4a2dbabcd1ebc663beab356a4ee5b1f584088772da8271c74890b", + "zh:a8317436ec286aae91d9bfbcd36edb9b0b58c195a9cd0adffb7f588f124bef1e", + "zh:cea079d3f4eff9e301ca207c7ce676553f9acc3202abf88ff161d6faa1e1a54a", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + "zh:fdaa4de7d6713bd8b1b4a51135c9eadbaa317ea87e7af9c00c52f67018fba288", + "zh:ff25a0a5fb54174a8a37d4e40413fa85737d8bb837c5635b6e88621c36c202bd", + ] +} + +provider "registry.terraform.io/hashicorp/null" { + version = "3.1.1" + hashes = [ + "h1:71sNUDvmiJcijsvfXpiLCz0lXIBSsEJjMxljt7hxMhw=", + "zh:063466f41f1d9fd0dd93722840c1314f046d8760b1812fa67c34de0afcba5597", + "zh:08c058e367de6debdad35fc24d97131c7cf75103baec8279aba3506a08b53faf", + "zh:73ce6dff935150d6ddc6ac4a10071e02647d10175c173cfe5dca81f3d13d8afe", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:8fdd792a626413502e68c195f2097352bdc6a0df694f7df350ed784741eb587e", + "zh:976bbaf268cb497400fd5b3c774d218f3933271864345f18deebe4dcbfcd6afa", + "zh:b21b78ca581f98f4cdb7a366b03ae9db23a73dfa7df12c533d7c19b68e9e72e5", + "zh:b7fc0c1615dbdb1d6fd4abb9c7dc7da286631f7ca2299fb9cd4664258ccfbff4", + "zh:d1efc942b2c44345e0c29bc976594cb7278c38cfb8897b344669eafbc3cddf46", + "zh:e356c245b3cd9d4789bab010893566acace682d7db877e52d40fc4ca34a50924", + "zh:ea98802ba92fcfa8cf12cbce2e9e7ebe999afbf8ed47fa45fc847a098d89468b", + "zh:eff8872458806499889f6927b5d954560f3d74bf20b6043409edf94d26cd906f", + ] +} + +provider "registry.terraform.io/hashicorp/random" { + version = "3.1.2" + constraints = "3.1.2" + hashes = [ + "h1:5A5VsY5wNmOZlupUcLnIoziMPn8htSZBXbP3lI7lBEM=", + "zh:0daceba867b330d3f8e2c5dc895c4291845a78f31955ce1b91ab2c4d1cd1c10b", + "zh:104050099efd30a630741f788f9576b19998e7a09347decbec3da0b21d64ba2d", + "zh:173f4ef3fdf0c7e2564a3db0fac560e9f5afdf6afd0b75d6646af6576b122b16", + "zh:41d50f975e535f968b3f37170fb07937c15b76d85ba947d0ce5e5ff9530eda65", + "zh:51a5038867e5e60757ed7f513dd6a973068241190d158a81d1b69296efb9cb8d", + "zh:6432a568e97a5a36cc8aebca5a7e9c879a55d3bc71d0da1ab849ad905f41c0be", + "zh:6bac6501394b87138a5e17c9f3a41e46ff7833ad0ba2a96197bb7787e95b641c", + "zh:6c0a7f5faacda644b022e7718e53f5868187435be6d000786d1ca05aa6683a25", + "zh:74c89de3fa6ef3027efe08f8473c2baeb41b4c6cee250ba7aeb5b64e8c79800d", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:b29eabbf0a5298f0e95a1df214c7cfe06ea9bcf362c63b3ad2f72d85da7d4685", + "zh:e891458c7a61e5b964e09616f1a4f87d0471feae1ec04cc51776e7dec1a3abce", + ] +} diff --git a/templates/workspaces/airlock_manager/terraform/aad/aad.tf b/templates/workspaces/airlock_manager/terraform/aad/aad.tf new file mode 100644 index 0000000000..2ecdaf1f2f --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/aad/aad.tf @@ -0,0 +1,116 @@ +data "azuread_client_config" "current" {} + +resource "random_uuid" "oauth2_user_impersonation_id" {} +resource "random_uuid" "app_role_workspace_owner_id" {} +resource "random_uuid" "app_role_workspace_researcher_id" {} + +resource "azuread_application" "workspace" { + display_name = var.workspace_resource_name_suffix + identifier_uris = ["api://${var.workspace_resource_name_suffix}"] + owners = [data.azuread_client_config.current.object_id] + + api { + mapped_claims_enabled = true + requested_access_token_version = 2 + + oauth2_permission_scope { + admin_consent_description = "Allow the app to access the Workspace API on behalf of the signed-in user." + admin_consent_display_name = "Access the Workspace API on behalf of signed-in user" + enabled = true + id = random_uuid.oauth2_user_impersonation_id.result + type = "User" + user_consent_description = "Allow the app to access the Workspace API on your behalf." + user_consent_display_name = "Access the Workspace API" + value = "user_impersonation" + } + } + + app_role { + allowed_member_types = ["User", "Application"] + description = "Provides workspace owners access to the Workspace." + display_name = "Workspace Owner" + enabled = true + id = random_uuid.app_role_workspace_owner_id.result + value = "WorkspaceOwner" + } + + app_role { + allowed_member_types = ["User", "Application"] + description = "Provides researchers access to the Workspace." + display_name = "Workspace Researcher" + enabled = true + id = random_uuid.app_role_workspace_researcher_id.result + value = "WorkspaceResearcher" + } + + feature_tags { + enterprise = true + } + + optional_claims { + id_token { + name = "ipaddr" + essential = false + } + + id_token { + name = "email" + essential = false + } + } + + required_resource_access { + resource_app_id = "00000003-0000-0000-c000-000000000000" # Microsoft Graph + + resource_access { + id = "64a6cdd6-aab1-4aaf-94b8-3cc8405e90d0" # Email + type = "Scope" # Delegated + } + resource_access { + id = "37f7f235-527c-4136-accd-4a02d197296e" # Openid + type = "Scope" # Delegated + } + resource_access { + id = "14dad69e-099b-42c9-810b-d002981feec1" # Profile + type = "Scope" # Delegated + } + } + + web { + redirect_uris = jsondecode(base64decode(var.aad_redirect_uris_b64))[*].value + } +} + +resource "azuread_service_principal" "workspace" { + application_id = azuread_application.workspace.application_id + app_role_assignment_required = false + owners = [data.azuread_client_config.current.object_id] + + feature_tags { + enterprise = true + } +} + +resource "azuread_service_principal_password" "workspace" { + service_principal_id = azuread_service_principal.workspace.object_id +} + +resource "azurerm_key_vault_secret" "client_id" { + name = "workspace-client-id" + value = azuread_application.workspace.application_id + key_vault_id = var.key_vault_id + tags = var.tre_workspace_tags +} + +resource "azurerm_key_vault_secret" "client_secret" { + name = "workspace-client-secret" + value = azuread_service_principal_password.workspace.value + key_vault_id = var.key_vault_id + tags = var.tre_workspace_tags +} + +resource "azuread_app_role_assignment" "workspace_owner" { + app_role_id = azuread_service_principal.workspace.app_role_ids["WorkspaceOwner"] + principal_object_id = var.workspace_owner_object_id + resource_object_id = azuread_service_principal.workspace.object_id +} diff --git a/templates/workspaces/airlock_manager/terraform/aad/outputs.tf b/templates/workspaces/airlock_manager/terraform/aad/outputs.tf new file mode 100644 index 0000000000..8c84927878 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/aad/outputs.tf @@ -0,0 +1,19 @@ +output "app_role_workspace_owner_id" { + value = random_uuid.app_role_workspace_owner_id.result +} + +output "app_role_workspace_researcher_id" { + value = random_uuid.app_role_workspace_researcher_id.result +} + +output "client_id" { + value = azuread_application.workspace.application_id +} + +output "scope_id" { + value = "api://${var.workspace_resource_name_suffix}" +} + +output "sp_id" { + value = azuread_service_principal.workspace.object_id +} diff --git a/templates/workspaces/airlock_manager/terraform/aad/variables.tf b/templates/workspaces/airlock_manager/terraform/aad/variables.tf new file mode 100644 index 0000000000..83a5fc217c --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/aad/variables.tf @@ -0,0 +1,7 @@ +variable "key_vault_id" {} +variable "workspace_resource_name_suffix" {} +variable "workspace_owner_object_id" {} +variable "tre_workspace_tags" {} +variable "aad_redirect_uris_b64" { + type = string # list of objects like [{"name": "my uri 1", "value": "https://..."}, {}] +} diff --git a/templates/workspaces/airlock_manager/terraform/airlock/data.tf b/templates/workspaces/airlock_manager/terraform/airlock/data.tf new file mode 100644 index 0000000000..72fc38e229 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/airlock/data.tf @@ -0,0 +1,30 @@ +data "azurerm_user_assigned_identity" "airlock_id" { + name = "id-airlock-${var.tre_id}" + resource_group_name = "rg-${var.tre_id}" +} + +data "azurerm_user_assigned_identity" "api_id" { + name = "id-api-${var.tre_id}" + resource_group_name = "rg-${var.tre_id}" +} + +data "azurerm_private_dns_zone" "blobcore" { + name = "privatelink.blob.core.windows.net" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_servicebus_namespace" "airlock_sb" { + name = "sb-${var.tre_id}" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_servicebus_topic" "blob_created" { + name = local.blob_created_topic_name + resource_group_name = local.core_resource_group_name + namespace_name = data.azurerm_servicebus_namespace.airlock_sb.name +} + +data "azurerm_storage_account" "sa_import_inprogress" { + name = local.import_in_progress_storage_name + resource_group_name = local.core_resource_group_name +} diff --git a/templates/workspaces/airlock_manager/terraform/airlock/eventgrid_topics.tf b/templates/workspaces/airlock_manager/terraform/airlock/eventgrid_topics.tf new file mode 100644 index 0000000000..4297a48a38 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/airlock/eventgrid_topics.tf @@ -0,0 +1,209 @@ +# System topics + +# Below we assign a SYSTEM-assigned identity for the topics. note that a user-assigned identity will not work. + +resource "azurerm_eventgrid_system_topic" "import_approved_blob_created" { + name = local.import_approved_sys_topic_name + location = var.location + resource_group_name = var.ws_resource_group_name + source_arm_resource_id = azurerm_storage_account.sa_import_approved.id + topic_type = "Microsoft.Storage.StorageAccounts" + + identity { + type = "SystemAssigned" + } + + tags = merge( + var.tre_workspace_tags, + { + Publishers = "airlock;approved-import-sa" + } + ) + + depends_on = [ + azurerm_storage_account.sa_import_approved + ] + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_role_assignment" "servicebus_sender_import_approved_blob_created" { + scope = data.azurerm_servicebus_namespace.airlock_sb.id + role_definition_name = "Azure Service Bus Data Sender" + principal_id = azurerm_eventgrid_system_topic.import_approved_blob_created.identity.0.principal_id + + depends_on = [ + azurerm_eventgrid_system_topic.import_approved_blob_created + ] +} + +resource "azurerm_eventgrid_system_topic" "export_inprogress_blob_created" { + name = local.export_inprogress_sys_topic_name + location = var.location + resource_group_name = var.ws_resource_group_name + source_arm_resource_id = azurerm_storage_account.sa_export_inprogress.id + topic_type = "Microsoft.Storage.StorageAccounts" + + tags = merge( + var.tre_workspace_tags, + { + Publishers = "airlock;inprogress-export-sa" + } + ) + + identity { + type = "SystemAssigned" + } + + depends_on = [ + azurerm_storage_account.sa_export_inprogress, + ] + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_role_assignment" "servicebus_sender_export_inprogress_blob_created" { + scope = data.azurerm_servicebus_namespace.airlock_sb.id + role_definition_name = "Azure Service Bus Data Sender" + principal_id = azurerm_eventgrid_system_topic.export_inprogress_blob_created.identity.0.principal_id + + depends_on = [ + azurerm_eventgrid_system_topic.export_inprogress_blob_created + ] +} + +resource "azurerm_eventgrid_system_topic" "export_rejected_blob_created" { + name = local.export_rejected_sys_topic_name + location = var.location + resource_group_name = var.ws_resource_group_name + source_arm_resource_id = azurerm_storage_account.sa_export_rejected.id + topic_type = "Microsoft.Storage.StorageAccounts" + + tags = merge( + var.tre_workspace_tags, + { + Publishers = "airlock;rejected-export-sa" + } + ) + + identity { + type = "SystemAssigned" + } + + depends_on = [ + azurerm_storage_account.sa_export_rejected, + ] + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_role_assignment" "servicebus_sender_export_rejected_blob_created" { + scope = data.azurerm_servicebus_namespace.airlock_sb.id + role_definition_name = "Azure Service Bus Data Sender" + principal_id = azurerm_eventgrid_system_topic.export_rejected_blob_created.identity.0.principal_id + + depends_on = [ + azurerm_eventgrid_system_topic.export_rejected_blob_created + ] +} + +resource "azurerm_eventgrid_system_topic" "export_blocked_blob_created" { + name = local.export_blocked_sys_topic_name + location = var.location + resource_group_name = var.ws_resource_group_name + source_arm_resource_id = azurerm_storage_account.sa_export_blocked.id + topic_type = "Microsoft.Storage.StorageAccounts" + + tags = merge( + var.tre_workspace_tags, + { + Publishers = "airlock;export-blocked-sa" + } + ) + + identity { + type = "SystemAssigned" + } + + depends_on = [ + azurerm_storage_account.sa_export_blocked, + ] + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_role_assignment" "servicebus_sender_export_blocked_blob_created" { + scope = data.azurerm_servicebus_namespace.airlock_sb.id + role_definition_name = "Azure Service Bus Data Sender" + principal_id = azurerm_eventgrid_system_topic.export_blocked_blob_created.identity.0.principal_id + + depends_on = [ + azurerm_eventgrid_system_topic.export_blocked_blob_created + ] +} + + +## Subscriptions +resource "azurerm_eventgrid_event_subscription" "import_approved_blob_created" { + name = "import-approved-blob-created-${var.short_workspace_id}" + scope = azurerm_storage_account.sa_import_approved.id + + service_bus_topic_endpoint_id = data.azurerm_servicebus_topic.blob_created.id + + delivery_identity { + type = "SystemAssigned" + } + + depends_on = [ + azurerm_eventgrid_system_topic.import_approved_blob_created, + azurerm_role_assignment.servicebus_sender_import_approved_blob_created + ] +} + +resource "azurerm_eventgrid_event_subscription" "export_inprogress_blob_created" { + name = "export-inprogress-blob-created-${var.short_workspace_id}" + scope = azurerm_storage_account.sa_export_inprogress.id + + service_bus_topic_endpoint_id = data.azurerm_servicebus_topic.blob_created.id + + delivery_identity { + type = "SystemAssigned" + } + + depends_on = [ + azurerm_eventgrid_system_topic.export_inprogress_blob_created, + azurerm_role_assignment.servicebus_sender_export_inprogress_blob_created + ] +} + +resource "azurerm_eventgrid_event_subscription" "export_rejected_blob_created" { + name = "export-rejected-blob-created-${var.short_workspace_id}" + scope = azurerm_storage_account.sa_export_rejected.id + + service_bus_topic_endpoint_id = data.azurerm_servicebus_topic.blob_created.id + + delivery_identity { + type = "SystemAssigned" + } + + depends_on = [ + azurerm_eventgrid_system_topic.export_rejected_blob_created, + azurerm_role_assignment.servicebus_sender_export_rejected_blob_created + ] +} + +resource "azurerm_eventgrid_event_subscription" "export_blocked_blob_created" { + name = "export-blocked-blob-created-${var.short_workspace_id}" + scope = azurerm_storage_account.sa_export_blocked.id + + service_bus_topic_endpoint_id = data.azurerm_servicebus_topic.blob_created.id + + delivery_identity { + type = "SystemAssigned" + } + + depends_on = [ + azurerm_eventgrid_system_topic.export_blocked_blob_created, + azurerm_role_assignment.servicebus_sender_export_blocked_blob_created + ] +} diff --git a/templates/workspaces/airlock_manager/terraform/airlock/locals.tf b/templates/workspaces/airlock_manager/terraform/airlock/locals.tf new file mode 100644 index 0000000000..56ff86d7ac --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/airlock/locals.tf @@ -0,0 +1,25 @@ +locals { + core_vnet = "vnet-${var.tre_id}" + core_resource_group_name = "rg-${var.tre_id}" + workspace_resource_name_suffix = "${var.tre_id}-ws-${var.short_workspace_id}" + + import_approved_sys_topic_name = "evgt-airlock-import-approved-${local.workspace_resource_name_suffix}" + export_inprogress_sys_topic_name = "evgt-airlock-export-inprog-${local.workspace_resource_name_suffix}" + export_rejected_sys_topic_name = "evgt-airlock-export-rejected-${local.workspace_resource_name_suffix}" + export_blocked_sys_topic_name = "evgt-airlock-export-blocked-${local.workspace_resource_name_suffix}" + + blob_created_topic_name = "airlock-blob-created" + + # STorage AirLock IMport APProved + import_approved_storage_name = lower(replace("stalimapp${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) + # STorage AirLock IMport InProgress + import_in_progress_storage_name = lower(replace("stalimip${var.tre_id}", "-", "")) + # STorage AirLock EXport INTernal + export_internal_storage_name = lower(replace("stalexint${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) + # STorage AirLock EXport InProgress + export_inprogress_storage_name = lower(replace("stalexip${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) + # STorage AirLock EXport REJected + export_rejected_storage_name = lower(replace("stalexrej${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) + # STorage AirLock EXport BLOCKED + export_blocked_storage_name = lower(replace("stalexblocked${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) +} diff --git a/templates/workspaces/airlock_manager/terraform/airlock/storage_accounts.tf b/templates/workspaces/airlock_manager/terraform/airlock/storage_accounts.tf new file mode 100644 index 0000000000..fe7ffe4653 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/airlock/storage_accounts.tf @@ -0,0 +1,334 @@ +# 'Approved' storage account +resource "azurerm_storage_account" "sa_import_approved" { + name = local.import_approved_storage_name + location = var.location + resource_group_name = var.ws_resource_group_name + account_tier = "Standard" + account_replication_type = "GRS" + allow_nested_items_to_be_public = false + + # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. + # This is true ONLY when Hierarchical Namespace is DISABLED + is_hns_enabled = false + + network_rules { + default_action = var.enable_local_debugging ? "Allow" : "Deny" + bypass = ["AzureServices"] + } + + tags = merge( + var.tre_workspace_tags, + { + description = "airlock;import;approved" + } + ) + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_endpoint" "import_approved_pe" { + name = "pe-sa-import-approved-blob-${var.short_workspace_id}" + location = var.location + resource_group_name = var.ws_resource_group_name + subnet_id = var.services_subnet_id + + lifecycle { ignore_changes = [tags] } + + private_dns_zone_group { + name = "private-dns-zone-group-sa-import-approved" + private_dns_zone_ids = [data.azurerm_private_dns_zone.blobcore.id] + } + + private_service_connection { + name = "psc-sa-import-approved-${var.short_workspace_id}" + private_connection_resource_id = azurerm_storage_account.sa_import_approved.id + is_manual_connection = false + subresource_names = ["Blob"] + } +} + + +# 'Drop' location for export +resource "azurerm_storage_account" "sa_export_internal" { + name = local.export_internal_storage_name + location = var.location + resource_group_name = var.ws_resource_group_name + account_tier = "Standard" + account_replication_type = "GRS" + allow_nested_items_to_be_public = false + + # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. + # This is true ONLY when Hierarchical Namespace is DISABLED + is_hns_enabled = false + + network_rules { + default_action = var.enable_local_debugging ? "Allow" : "Deny" + bypass = ["AzureServices"] + } + + tags = merge( + var.tre_workspace_tags, + { + description = "airlock;export;internal" + } + ) + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_endpoint" "stg_import_inprogress_pe" { + name = "stg-ip-import-blob-${var.tre_id}-ws-${var.short_workspace_id}" + location = var.location + resource_group_name = var.ws_resource_group_name + subnet_id = var.services_subnet_id + + lifecycle { ignore_changes = [tags] } + + private_dns_zone_group { + name = "private-dns-zone-group-stg-import-ip" + private_dns_zone_ids = [data.azurerm_private_dns_zone.blobcore.id] + } + + private_service_connection { + name = "psc-stgipimport-${var.tre_id}" + private_connection_resource_id = data.azurerm_storage_account.sa_import_inprogress.id + is_manual_connection = false + subresource_names = ["Blob"] + } + + tags = var.tre_workspace_tags +} + +resource "azurerm_private_endpoint" "export_internal_pe" { + name = "pe-sa-export-int-blob-${var.short_workspace_id}" + location = var.location + resource_group_name = var.ws_resource_group_name + subnet_id = var.services_subnet_id + + lifecycle { ignore_changes = [tags] } + + private_dns_zone_group { + name = "private-dns-zone-group-sa-export-int" + private_dns_zone_ids = [data.azurerm_private_dns_zone.blobcore.id] + } + + private_service_connection { + name = "psc-sa-export-int-${var.short_workspace_id}" + private_connection_resource_id = azurerm_storage_account.sa_export_internal.id + is_manual_connection = false + subresource_names = ["Blob"] + } +} + +# 'In-progress' location for export +resource "azurerm_storage_account" "sa_export_inprogress" { + name = local.export_inprogress_storage_name + location = var.location + resource_group_name = var.ws_resource_group_name + account_tier = "Standard" + account_replication_type = "GRS" + allow_nested_items_to_be_public = false + + # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. + # This is true ONLY when Hierarchical Namespace is DISABLED + is_hns_enabled = false + + tags = merge( + var.tre_workspace_tags, + { + description = "airlock;export;inprogress" + } + ) + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_storage_account_network_rules" "sa_export_inprogress_rules" { + storage_account_id = azurerm_storage_account.sa_export_inprogress.id + + # When the Airlock procssor tried to copy data from the export in-progress SA to the Export approved SA, its not using the PE, as the destination is public, hence, allowing this subnet is mandatory + # It might be possible to add PE to this storage instead of opening the fw to this subnet: https://github.com/microsoft/AzureTRE/issues/2098 + virtual_network_subnet_ids = [var.airlock_processor_subnet_id] + + default_action = var.enable_local_debugging ? "Allow" : "Deny" + bypass = ["AzureServices"] +} + + +resource "azurerm_private_endpoint" "export_inprogress_pe" { + name = "pe-sa-ip-export-blob-${var.short_workspace_id}" + location = var.location + resource_group_name = var.ws_resource_group_name + subnet_id = var.services_subnet_id + + lifecycle { ignore_changes = [tags] } + + private_dns_zone_group { + name = "private-dns-zone-group-sa-export-ip" + private_dns_zone_ids = [data.azurerm_private_dns_zone.blobcore.id] + } + + private_service_connection { + name = "psc-sa-export-ip-${var.short_workspace_id}" + private_connection_resource_id = azurerm_storage_account.sa_export_inprogress.id + is_manual_connection = false + subresource_names = ["Blob"] + } +} + +# 'Rejected' location for export +resource "azurerm_storage_account" "sa_export_rejected" { + name = local.export_rejected_storage_name + location = var.location + resource_group_name = var.ws_resource_group_name + account_tier = "Standard" + account_replication_type = "GRS" + allow_nested_items_to_be_public = false + + # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. + # This is true ONLY when Hierarchical Namespace is DISABLED + is_hns_enabled = false + + network_rules { + default_action = var.enable_local_debugging ? "Allow" : "Deny" + bypass = ["AzureServices"] + } + + tags = merge( + var.tre_workspace_tags, + { + description = "airlock;export;rejected" + } + ) + + lifecycle { ignore_changes = [tags] } +} + + +resource "azurerm_private_endpoint" "export_rejected_pe" { + name = "pe-sa-export-rej-blob-${var.short_workspace_id}" + location = var.location + resource_group_name = var.ws_resource_group_name + subnet_id = var.services_subnet_id + + lifecycle { ignore_changes = [tags] } + + private_dns_zone_group { + name = "private-dns-zone-group-sa-export-rej" + private_dns_zone_ids = [data.azurerm_private_dns_zone.blobcore.id] + } + + private_service_connection { + name = "psc-sa-export-rej-${var.short_workspace_id}" + private_connection_resource_id = azurerm_storage_account.sa_export_rejected.id + is_manual_connection = false + subresource_names = ["Blob"] + } +} + +# 'Blocked' location for export +resource "azurerm_storage_account" "sa_export_blocked" { + name = local.export_blocked_storage_name + location = var.location + resource_group_name = var.ws_resource_group_name + account_tier = "Standard" + account_replication_type = "GRS" + allow_nested_items_to_be_public = false + + # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. + # This is true ONLY when Hierarchical Namespace is DISABLED + is_hns_enabled = false + + network_rules { + default_action = var.enable_local_debugging ? "Allow" : "Deny" + bypass = ["AzureServices"] + } + + tags = merge( + var.tre_workspace_tags, + { + description = "airlock;export;blocked" + } + ) + + lifecycle { ignore_changes = [tags] } +} + + +resource "azurerm_private_endpoint" "export_blocked_pe" { + name = "pe-sa-export-blocked-blob-${var.short_workspace_id}" + location = var.location + resource_group_name = var.ws_resource_group_name + subnet_id = var.services_subnet_id + + lifecycle { ignore_changes = [tags] } + + private_dns_zone_group { + name = "private-dns-zone-group-sa-export-blocked" + private_dns_zone_ids = [data.azurerm_private_dns_zone.blobcore.id] + } + + private_service_connection { + name = "psc-sa-export-blocked-${var.short_workspace_id}" + private_connection_resource_id = azurerm_storage_account.sa_export_blocked.id + is_manual_connection = false + subresource_names = ["Blob"] + } +} + +resource "azurerm_role_assignment" "sa_import_approved" { + scope = azurerm_storage_account.sa_import_approved.id + role_definition_name = "Contributor" + principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id +} + + +resource "azurerm_role_assignment" "sa_export_internal" { + scope = azurerm_storage_account.sa_export_internal.id + role_definition_name = "Contributor" + principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id +} + +resource "azurerm_role_assignment" "sa_export_inprogress" { + scope = azurerm_storage_account.sa_export_inprogress.id + role_definition_name = "Contributor" + principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id +} + +resource "azurerm_role_assignment" "sa_export_rejected" { + scope = azurerm_storage_account.sa_export_rejected.id + role_definition_name = "Contributor" + principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id +} + +resource "azurerm_role_assignment" "sa_export_blocked" { + scope = azurerm_storage_account.sa_export_blocked.id + role_definition_name = "Contributor" + principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id +} + + +resource "azurerm_role_assignment" "sa_import_approved_reader" { + scope = azurerm_storage_account.sa_import_approved.id + role_definition_name = "Reader and Data Access" + principal_id = data.azurerm_user_assigned_identity.api_id.principal_id +} + + +resource "azurerm_role_assignment" "sa_export_internal_reader" { + scope = azurerm_storage_account.sa_export_internal.id + role_definition_name = "Reader and Data Access" + principal_id = data.azurerm_user_assigned_identity.api_id.principal_id +} + +resource "azurerm_role_assignment" "sa_export_inprogress_reader" { + scope = azurerm_storage_account.sa_export_inprogress.id + role_definition_name = "Reader and Data Access" + principal_id = data.azurerm_user_assigned_identity.api_id.principal_id +} + +resource "azurerm_role_assignment" "sa_export_rejected_reader" { + scope = azurerm_storage_account.sa_export_rejected.id + role_definition_name = "Reader and Data Access" + principal_id = data.azurerm_user_assigned_identity.api_id.principal_id +} diff --git a/templates/workspaces/airlock_manager/terraform/airlock/variables.tf b/templates/workspaces/airlock_manager/terraform/airlock/variables.tf new file mode 100644 index 0000000000..4c6aa50b79 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/airlock/variables.tf @@ -0,0 +1,8 @@ +variable "location" {} +variable "tre_id" {} +variable "ws_resource_group_name" {} +variable "enable_local_debugging" {} +variable "services_subnet_id" {} +variable "airlock_processor_subnet_id" {} +variable "short_workspace_id" {} +variable "tre_workspace_tags" {} diff --git a/templates/workspaces/airlock_manager/terraform/appserviceplan.tf b/templates/workspaces/airlock_manager/terraform/appserviceplan.tf new file mode 100644 index 0000000000..5cbafd84c6 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/appserviceplan.tf @@ -0,0 +1,10 @@ +resource "azurerm_service_plan" "workspace" { + count = var.deploy_app_service_plan ? 1 : 0 + + name = "plan-${var.tre_resource_id}" + location = azurerm_resource_group.ws.location + resource_group_name = azurerm_resource_group.ws.name + os_type = "Linux" + sku_name = var.app_service_plan_sku + tags = local.tre_workspace_tags +} diff --git a/templates/workspaces/airlock_manager/terraform/deploy.sh b/templates/workspaces/airlock_manager/terraform/deploy.sh new file mode 100644 index 0000000000..df5663e9e5 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/deploy.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -e + +# This script is not used and is left here for you to debug the creation of the workspace +# at a Terraform level without having to interact with Porter + +# This script assumes you have created an .env from the sample and the variables +# will come from there. +# shellcheck disable=SC2154 +terraform init -reconfigure -input=false -backend=true \ + -backend-config="resource_group_name=${TF_VAR_mgmt_resource_group_name}" \ + -backend-config="storage_account_name=${TF_VAR_mgmt_storage_account_name}" \ + -backend-config="container_name=${TF_VAR_terraform_state_container_name}" \ + -backend-config="key=${TF_VAR_tre_id}-ws-${TF_VAR_tre_resource_id}" +terraform apply -auto-approve diff --git a/templates/workspaces/airlock_manager/terraform/destroy.sh b/templates/workspaces/airlock_manager/terraform/destroy.sh new file mode 100644 index 0000000000..2414544669 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/destroy.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -e + +# This script is not used and is left here for you to debug the creation of the workspace +# at a Terraform level without having to interact with Porter + +# This script assumes you have created an .env from the sample and the variables +# will come from there. +# shellcheck disable=SC2154 +terraform init -reconfigure -input=false -backend=true \ + -backend-config="resource_group_name=${TF_VAR_mgmt_resource_group_name}" \ + -backend-config="storage_account_name=${TF_VAR_mgmt_storage_account_name}" \ + -backend-config="container_name=${TF_VAR_terraform_state_container_name}" \ + -backend-config="key=${TF_VAR_tre_id}-ws-${TF_VAR_tre_resource_id}" + +terraform destroy -auto-approve diff --git a/templates/workspaces/airlock_manager/terraform/keyvault.tf b/templates/workspaces/airlock_manager/terraform/keyvault.tf new file mode 100644 index 0000000000..6fa723c55e --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/keyvault.tf @@ -0,0 +1,123 @@ +data "azurerm_client_config" "current" {} + +resource "azurerm_key_vault" "kv" { + name = local.keyvault_name + location = azurerm_resource_group.ws.location + resource_group_name = azurerm_resource_group.ws.name + sku_name = "standard" + purge_protection_enabled = true + tenant_id = data.azurerm_client_config.current.tenant_id + tags = local.tre_workspace_tags + + network_acls { + bypass = "AzureServices" + default_action = var.enable_local_debugging ? "Allow" : "Deny" + } + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_endpoint" "kvpe" { + name = "kvpe-${local.workspace_resource_name_suffix}" + location = azurerm_resource_group.ws.location + resource_group_name = azurerm_resource_group.ws.name + subnet_id = module.network.services_subnet_id + tags = local.tre_workspace_tags + + depends_on = [ + module.network, + ] + + lifecycle { ignore_changes = [tags] } + + private_dns_zone_group { + name = "private-dns-zone-group" + private_dns_zone_ids = [module.network.vaultcore_zone_id] + } + + private_service_connection { + name = "kvpescv-${local.workspace_resource_name_suffix}" + private_connection_resource_id = azurerm_key_vault.kv.id + is_manual_connection = false + subresource_names = ["Vault"] + } +} + +data "azurerm_user_assigned_identity" "resource_processor_vmss_id" { + name = "id-vmss-${var.tre_id}" + resource_group_name = "rg-${var.tre_id}" +} + +resource "azurerm_key_vault_access_policy" "resource_processor" { + key_vault_id = azurerm_key_vault.kv.id + tenant_id = data.azurerm_user_assigned_identity.resource_processor_vmss_id.tenant_id + object_id = data.azurerm_user_assigned_identity.resource_processor_vmss_id.principal_id + + secret_permissions = ["Get", "List", "Set", "Delete", "Purge", "Recover"] +} + +# If running the terraform locally +resource "azurerm_key_vault_access_policy" "deployer" { + count = var.enable_local_debugging ? 1 : 0 + key_vault_id = azurerm_key_vault.kv.id + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = data.azurerm_client_config.current.object_id + + secret_permissions = ["Get", "List", "Set", "Delete", "Purge", "Recover"] +} + +resource "null_resource" "wait_for_dns_vault" { + provisioner "local-exec" { + command = "bash -c \"sleep 120s\"" + on_failure = fail + } + + triggers = { + always_run = azurerm_private_endpoint.kvpe.private_service_connection[0].private_ip_address # only wait on new/changed private IP address + } + + depends_on = [azurerm_private_endpoint.kvpe] + +} + +resource "azurerm_key_vault_secret" "aad_tenant_id" { + name = "auth-tenant-id" + value = var.auth_tenant_id + key_vault_id = azurerm_key_vault.kv.id + tags = local.tre_workspace_tags + depends_on = [ + azurerm_key_vault_access_policy.deployer, + azurerm_key_vault_access_policy.resource_processor, + null_resource.wait_for_dns_vault + ] +} + +# This secret only gets written if Terraform is not responsible for +# registering the AAD Application +resource "azurerm_key_vault_secret" "client_id" { + name = "workspace-client-id" + value = var.client_id + key_vault_id = azurerm_key_vault.kv.id + count = var.register_aad_application ? 0 : 1 + tags = local.tre_workspace_tags + depends_on = [ + azurerm_key_vault_access_policy.deployer, + azurerm_key_vault_access_policy.resource_processor, + null_resource.wait_for_dns_vault + ] +} + +# This secret only gets written if Terraform is not responsible for +# registering the AAD Application +resource "azurerm_key_vault_secret" "client_secret" { + name = "workspace-client-secret" + value = var.client_secret + key_vault_id = azurerm_key_vault.kv.id + count = var.register_aad_application ? 0 : 1 + tags = local.tre_workspace_tags + depends_on = [ + azurerm_key_vault_access_policy.deployer, + azurerm_key_vault_access_policy.resource_processor, + null_resource.wait_for_dns_vault + ] +} diff --git a/templates/workspaces/airlock_manager/terraform/locals.tf b/templates/workspaces/airlock_manager/terraform/locals.tf new file mode 100644 index 0000000000..a2e6be0f70 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/locals.tf @@ -0,0 +1,15 @@ +locals { + core_vnet = "vnet-${var.tre_id}" + short_workspace_id = substr(var.tre_resource_id, -4, -1) + core_resource_group_name = "rg-${var.tre_id}" + workspace_resource_name_suffix = "${var.tre_id}-ws-${local.short_workspace_id}" + storage_name = lower(replace("stg${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) + keyvault_name = lower("kv-${substr(local.workspace_resource_name_suffix, -20, -1)}") + vnet_subnets = cidrsubnets(var.address_space, 1, 1) + services_subnet_address_prefix = local.vnet_subnets[0] + webapps_subnet_address_prefix = local.vnet_subnets[1] + tre_workspace_tags = { + tre_id = var.tre_id + tre_workspace_id = var.tre_resource_id + } +} diff --git a/templates/workspaces/airlock_manager/terraform/network/data.tf b/templates/workspaces/airlock_manager/terraform/network/data.tf new file mode 100644 index 0000000000..1e3efbb97d --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/network/data.tf @@ -0,0 +1,94 @@ +data "azurerm_virtual_network" "core" { + name = local.core_vnet + resource_group_name = local.core_resource_group_name +} + +data "azurerm_subnet" "core_webapps" { + name = "WebAppSubnet" + virtual_network_name = "vnet-${var.tre_id}" + resource_group_name = "rg-${var.tre_id}" +} + +data "azurerm_subnet" "shared" { + resource_group_name = local.core_resource_group_name + virtual_network_name = local.core_vnet + name = "SharedSubnet" +} + +data "azurerm_subnet" "bastion" { + resource_group_name = local.core_resource_group_name + virtual_network_name = local.core_vnet + name = "AzureBastionSubnet" +} + +data "azurerm_subnet" "resourceprocessor" { + resource_group_name = local.core_resource_group_name + virtual_network_name = local.core_vnet + name = "ResourceProcessorSubnet" +} + +data "azurerm_subnet" "airlockprocessor" { + resource_group_name = local.core_resource_group_name + virtual_network_name = local.core_vnet + name = "AirlockProcessorSubnet" +} + +data "azurerm_route_table" "rt" { + name = "rt-${var.tre_id}" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_private_dns_zone" "azurewebsites" { + name = "privatelink.azurewebsites.net" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_private_dns_zone" "filecore" { + name = "privatelink.file.core.windows.net" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_private_dns_zone" "blobcore" { + name = "privatelink.blob.core.windows.net" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_private_dns_zone" "vaultcore" { + name = "privatelink.vaultcore.azure.net" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_private_dns_zone" "azurecr" { + name = "privatelink.azurecr.io" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_private_dns_zone" "azureml" { + name = "privatelink.api.azureml.ms" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_private_dns_zone" "azuremlcert" { + name = "privatelink.cert.api.azureml.ms" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_private_dns_zone" "notebooks" { + name = "privatelink.notebooks.azure.net" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_private_dns_zone" "mysql" { + name = "privatelink.mysql.database.azure.com" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_private_dns_zone" "postgres" { + name = "privatelink.postgres.database.azure.com" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_private_dns_zone" "nexus" { + name = "nexus-${var.tre_id}.${var.location}.cloudapp.azure.com" + resource_group_name = local.core_resource_group_name +} diff --git a/templates/workspaces/airlock_manager/terraform/network/locals.tf b/templates/workspaces/airlock_manager/terraform/network/locals.tf new file mode 100644 index 0000000000..f477e8bf9a --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/network/locals.tf @@ -0,0 +1,9 @@ +locals { + core_vnet = "vnet-${var.tre_id}" + short_workspace_id = substr(var.tre_resource_id, -4, -1) + core_resource_group_name = "rg-${var.tre_id}" + workspace_resource_name_suffix = "${var.tre_id}-ws-${local.short_workspace_id}" + vnet_subnets = cidrsubnets(var.address_space, 1, 1) + services_subnet_address_prefix = local.vnet_subnets[0] + webapps_subnet_address_prefix = local.vnet_subnets[1] +} diff --git a/templates/workspaces/airlock_manager/terraform/network/network.tf b/templates/workspaces/airlock_manager/terraform/network/network.tf new file mode 100644 index 0000000000..af70e98a5d --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/network/network.tf @@ -0,0 +1,67 @@ +resource "azurerm_virtual_network" "ws" { + name = "vnet-${local.workspace_resource_name_suffix}" + location = var.location + resource_group_name = var.ws_resource_group_name + address_space = [var.address_space] + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_subnet" "services" { + name = "ServicesSubnet" + virtual_network_name = azurerm_virtual_network.ws.name + resource_group_name = var.ws_resource_group_name + address_prefixes = [local.services_subnet_address_prefix] + # notice that private endpoints do not adhere to NSG rules + enforce_private_link_endpoint_network_policies = true + enforce_private_link_service_network_policies = true + + # Eventgrid CAN'T send messages over private endpoints, hence we need to allow service endpoints to the service bus + # We are using service endpoints + managed identity to send these messaages + # https://docs.microsoft.com/en-us/azure/event-grid/consume-private-endpoints + service_endpoints = ["Microsoft.ServiceBus"] +} + +resource "azurerm_subnet" "webapps" { + name = "WebAppsSubnet" + virtual_network_name = azurerm_virtual_network.ws.name + resource_group_name = var.ws_resource_group_name + address_prefixes = [local.webapps_subnet_address_prefix] + # notice that private endpoints do not adhere to NSG rules + enforce_private_link_endpoint_network_policies = true + enforce_private_link_service_network_policies = true + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_virtual_network_peering" "ws-core-peer" { + name = "ws-core-peer-${local.workspace_resource_name_suffix}" + resource_group_name = var.ws_resource_group_name + virtual_network_name = azurerm_virtual_network.ws.name + remote_virtual_network_id = data.azurerm_virtual_network.core.id +} + +resource "azurerm_virtual_network_peering" "core-ws-peer" { + name = "core-ws-peer-${local.workspace_resource_name_suffix}" + resource_group_name = local.core_resource_group_name + virtual_network_name = local.core_vnet + remote_virtual_network_id = azurerm_virtual_network.ws.id +} + +resource "azurerm_subnet_route_table_association" "rt_services_subnet_association" { + route_table_id = data.azurerm_route_table.rt.id + subnet_id = azurerm_subnet.services.id +} + +resource "azurerm_subnet_route_table_association" "rt_webapps_subnet_association" { + route_table_id = data.azurerm_route_table.rt.id + subnet_id = azurerm_subnet.webapps.id +} diff --git a/templates/workspaces/airlock_manager/terraform/network/outputs.tf b/templates/workspaces/airlock_manager/terraform/network/outputs.tf new file mode 100644 index 0000000000..0d2f695af4 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/network/outputs.tf @@ -0,0 +1,19 @@ +output "services_subnet_id" { + value = azurerm_subnet.services.id +} + +output "vaultcore_zone_id" { + value = data.azurerm_private_dns_zone.vaultcore.id +} + +output "filecore_zone_id" { + value = data.azurerm_private_dns_zone.filecore.id +} + +output "blobcore_zone_id" { + value = data.azurerm_private_dns_zone.blobcore.id +} + +output "airlock_processor_subnet_id" { + value = data.azurerm_subnet.airlockprocessor.id +} diff --git a/templates/workspaces/airlock_manager/terraform/network/security.tf b/templates/workspaces/airlock_manager/terraform/network/security.tf new file mode 100644 index 0000000000..c74808801d --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/network/security.tf @@ -0,0 +1,212 @@ +resource "azurerm_network_security_group" "ws" { + location = var.location + name = "nsg-ws" + resource_group_name = var.ws_resource_group_name + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_subnet_network_security_group_association" "services" { + network_security_group_id = azurerm_network_security_group.ws.id + subnet_id = azurerm_subnet.services.id +} + +resource "azurerm_subnet_network_security_group_association" "webapps" { + network_security_group_id = azurerm_network_security_group.ws.id + subnet_id = azurerm_subnet.webapps.id +} + +resource "azurerm_network_security_rule" "deny-outbound-override" { + access = "Deny" + destination_address_prefix = "*" + destination_port_range = "*" + direction = "Outbound" + name = "deny-outbound-override" + network_security_group_name = azurerm_network_security_group.ws.name + priority = 4096 + protocol = "*" + resource_group_name = var.ws_resource_group_name + source_address_prefix = "*" + source_port_range = "*" +} + +resource "azurerm_network_security_rule" "deny-all-inbound-override" { + access = "Deny" + destination_address_prefix = "*" + destination_port_range = "*" + direction = "Inbound" + name = "deny-inbound-override" + network_security_group_name = azurerm_network_security_group.ws.name + priority = 900 + protocol = "*" + resource_group_name = var.ws_resource_group_name + source_address_prefix = "*" + source_port_range = "*" +} + +resource "azurerm_network_security_rule" "allow-inbound-within-services-subnet" { + access = "Allow" + destination_port_range = "*" + destination_address_prefixes = azurerm_subnet.services.address_prefixes + source_address_prefixes = azurerm_subnet.services.address_prefixes + direction = "Inbound" + name = "inbound-within-services-subnet" + network_security_group_name = azurerm_network_security_group.ws.name + priority = 100 + protocol = "*" + resource_group_name = var.ws_resource_group_name + source_port_range = "*" +} + +resource "azurerm_network_security_rule" "allow-outbound-within-services-subnet" { + access = "Allow" + destination_port_range = "*" + destination_address_prefixes = azurerm_subnet.services.address_prefixes + source_address_prefixes = azurerm_subnet.services.address_prefixes + direction = "Outbound" + name = "outbound-within-services-subnet" + network_security_group_name = azurerm_network_security_group.ws.name + priority = 100 + protocol = "*" + resource_group_name = var.ws_resource_group_name + source_port_range = "*" +} + +resource "azurerm_network_security_rule" "allow-outbound-to-shared-services" { + access = "Allow" + destination_address_prefixes = data.azurerm_subnet.shared.address_prefixes + destination_port_range = "*" + direction = "Outbound" + name = "to-shared-services" + network_security_group_name = azurerm_network_security_group.ws.name + priority = 110 + protocol = "*" + resource_group_name = var.ws_resource_group_name + source_address_prefix = "*" + source_port_range = "*" +} + + +resource "azurerm_network_security_rule" "allow-outbound-to-internet" { + access = "Allow" + destination_address_prefix = "INTERNET" + destination_port_range = "443" + direction = "Outbound" + name = "to-internet" + network_security_group_name = azurerm_network_security_group.ws.name + priority = 120 + protocol = "Tcp" + resource_group_name = var.ws_resource_group_name + source_address_prefix = "*" + source_port_range = "*" +} + + +resource "azurerm_network_security_rule" "allow-outbound-from-webapp-to-core-webapp" { + access = "Allow" + destination_port_range = "443" + destination_address_prefixes = data.azurerm_subnet.core_webapps.address_prefixes + source_address_prefixes = azurerm_subnet.webapps.address_prefixes + direction = "Outbound" + name = "outbound-workspace-webapps-to-tre-core-webapps" + network_security_group_name = azurerm_network_security_group.ws.name + priority = 130 + protocol = "Tcp" + resource_group_name = var.ws_resource_group_name + source_port_range = "*" +} + +resource "azurerm_network_security_rule" "allow-outbound-webapps-to-services" { + access = "Allow" + destination_port_ranges = [ + "80", + "443", + "445", + "3306", + "3389", + "5432", + ] + destination_address_prefixes = azurerm_subnet.services.address_prefixes + source_address_prefixes = azurerm_subnet.webapps.address_prefixes + direction = "Outbound" + name = "outbound-from-services-to-webapps-subnets" + network_security_group_name = azurerm_network_security_group.ws.name + priority = 140 + protocol = "Tcp" + resource_group_name = var.ws_resource_group_name + source_port_range = "*" +} + +resource "azurerm_network_security_rule" "allow-inbound-from-bastion" { + access = "Allow" + destination_address_prefixes = azurerm_subnet.services.address_prefixes + destination_port_ranges = [ + "22", + "3389", + ] + direction = "Inbound" + name = "allow-inbound-from-bastion" + network_security_group_name = azurerm_network_security_group.ws.name + priority = 110 + protocol = "Tcp" + resource_group_name = var.ws_resource_group_name + source_address_prefixes = [ + data.azurerm_subnet.bastion.address_prefix + ] + source_port_range = "*" +} + +resource "azurerm_network_security_rule" "allow-inbound-from-resourceprocessor" { + access = "Allow" + destination_address_prefixes = azurerm_subnet.services.address_prefixes + destination_port_range = "443" + direction = "Inbound" + name = "allow-inbound-from-resourceprocessor" + network_security_group_name = azurerm_network_security_group.ws.name + priority = 120 + protocol = "Tcp" + resource_group_name = var.ws_resource_group_name + source_address_prefixes = [ + data.azurerm_subnet.resourceprocessor.address_prefix + ] + source_port_range = "*" +} + + +resource "azurerm_network_security_rule" "allow-inbound-from-airlockprocessor" { + access = "Allow" + destination_address_prefixes = azurerm_subnet.services.address_prefixes + destination_port_range = "443" + direction = "Inbound" + name = "allow-inbound-from-airlockprocessor" + network_security_group_name = azurerm_network_security_group.ws.name + priority = 140 + protocol = "Tcp" + resource_group_name = var.ws_resource_group_name + source_address_prefixes = [ + data.azurerm_subnet.airlockprocessor.address_prefix + ] + source_port_range = "*" +} + +resource "azurerm_network_security_rule" "allow-inbound-from-webapp-to-services" { + access = "Allow" + destination_port_ranges = [ + "80", + "443", + "445", + "3306", + "3389", + "5432", + ] + destination_address_prefixes = azurerm_subnet.services.address_prefixes + source_address_prefixes = azurerm_subnet.webapps.address_prefixes + direction = "Inbound" + name = "inbound-from-webapps-to-services-subnets" + network_security_group_name = azurerm_network_security_group.ws.name + priority = 130 + protocol = "Tcp" + resource_group_name = var.ws_resource_group_name + source_port_range = "*" +} diff --git a/templates/workspaces/airlock_manager/terraform/network/variables.tf b/templates/workspaces/airlock_manager/terraform/network/variables.tf new file mode 100644 index 0000000000..f27b3fb8a4 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/network/variables.tf @@ -0,0 +1,6 @@ +variable "location" {} +variable "tre_id" {} +variable "address_space" {} +variable "ws_resource_group_name" {} +variable "tre_workspace_tags" {} +variable "tre_resource_id" {} diff --git a/templates/workspaces/airlock_manager/terraform/network/zone_links.tf b/templates/workspaces/airlock_manager/terraform/network/zone_links.tf new file mode 100644 index 0000000000..2e9e390973 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/network/zone_links.tf @@ -0,0 +1,110 @@ +resource "azurerm_private_dns_zone_virtual_network_link" "azurewebsites" { + name = "azurewebsites-link-${azurerm_virtual_network.ws.name}" + resource_group_name = local.core_resource_group_name + private_dns_zone_name = data.azurerm_private_dns_zone.azurewebsites.name + virtual_network_id = azurerm_virtual_network.ws.id + registration_enabled = false + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "filecorelink" { + name = "filecorelink-${local.workspace_resource_name_suffix}" + resource_group_name = local.core_resource_group_name + private_dns_zone_name = data.azurerm_private_dns_zone.filecore.name + virtual_network_id = azurerm_virtual_network.ws.id + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "blobcorelink" { + name = "blobcorelink-${local.workspace_resource_name_suffix}" + resource_group_name = local.core_resource_group_name + private_dns_zone_name = data.azurerm_private_dns_zone.blobcore.name + virtual_network_id = azurerm_virtual_network.ws.id + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "vaultcorelink" { + name = "vaultcorelink-${local.workspace_resource_name_suffix}" + resource_group_name = local.core_resource_group_name + private_dns_zone_name = data.azurerm_private_dns_zone.vaultcore.name + virtual_network_id = azurerm_virtual_network.ws.id + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "azurecrlink" { + name = "azurecrlink-${local.workspace_resource_name_suffix}" + resource_group_name = local.core_resource_group_name + private_dns_zone_name = data.azurerm_private_dns_zone.azurecr.name + virtual_network_id = azurerm_virtual_network.ws.id + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "azuremllink" { + name = "azuremllink-${local.workspace_resource_name_suffix}" + resource_group_name = local.core_resource_group_name + private_dns_zone_name = data.azurerm_private_dns_zone.azureml.name + virtual_network_id = azurerm_virtual_network.ws.id + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "azuremlcertlink" { + name = "azuremlcertlink-${local.workspace_resource_name_suffix}" + resource_group_name = local.core_resource_group_name + private_dns_zone_name = data.azurerm_private_dns_zone.azuremlcert.name + virtual_network_id = azurerm_virtual_network.ws.id + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "notebookslink" { + name = "notebookslink-${local.workspace_resource_name_suffix}" + resource_group_name = local.core_resource_group_name + private_dns_zone_name = data.azurerm_private_dns_zone.notebooks.name + virtual_network_id = azurerm_virtual_network.ws.id + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "mysqllink" { + name = "mysqllink-${local.workspace_resource_name_suffix}" + resource_group_name = local.core_resource_group_name + private_dns_zone_name = data.azurerm_private_dns_zone.mysql.name + virtual_network_id = azurerm_virtual_network.ws.id + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "postgreslink" { + name = "postgreslink-${local.workspace_resource_name_suffix}" + resource_group_name = local.core_resource_group_name + private_dns_zone_name = data.azurerm_private_dns_zone.postgres.name + virtual_network_id = azurerm_virtual_network.ws.id + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "nexuslink" { + name = "nexuslink-${local.workspace_resource_name_suffix}" + resource_group_name = local.core_resource_group_name + private_dns_zone_name = data.azurerm_private_dns_zone.nexus.name + virtual_network_id = azurerm_virtual_network.ws.id + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} diff --git a/templates/workspaces/airlock_manager/terraform/outputs.tf b/templates/workspaces/airlock_manager/terraform/outputs.tf new file mode 100644 index 0000000000..5ba52ed6a8 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/outputs.tf @@ -0,0 +1,26 @@ +output "workspace_resource_name_suffix" { + value = local.workspace_resource_name_suffix +} + +# The following outputs are dependent on an Automatic AAD Workspace Application Registration. +# If we are not creating an App Reg we simple pass back the same values that were already created +# This is necessary so that we don't delete workspace properties +output "app_role_id_workspace_owner" { + value = var.register_aad_application ? module.aad[0].app_role_workspace_owner_id : var.app_role_id_workspace_owner +} + +output "app_role_id_workspace_researcher" { + value = var.register_aad_application ? module.aad[0].app_role_workspace_researcher_id : var.app_role_id_workspace_researcher +} + +output "client_id" { + value = var.register_aad_application ? module.aad[0].client_id : var.client_id +} + +output "sp_id" { + value = var.register_aad_application ? module.aad[0].sp_id : var.sp_id +} + +output "scope_id" { + value = var.register_aad_application ? module.aad[0].scope_id : var.scope_id +} diff --git a/templates/workspaces/airlock_manager/terraform/providers.tf b/templates/workspaces/airlock_manager/terraform/providers.tf new file mode 100644 index 0000000000..df558f69ed --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/providers.tf @@ -0,0 +1,41 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "=3.12.0" + } + azuread = { + source = "hashicorp/azuread" + version = "=2.20.0" + } + random = { + source = "hashicorp/random" + version = "=3.1.2" + } + } + + backend "azurerm" {} +} + +provider "azurerm" { + features { + key_vault { + # Don't purge on destroy (this would fail due to purge protection being enabled on keyvault) + purge_soft_delete_on_destroy = false + purge_soft_deleted_secrets_on_destroy = false + purge_soft_deleted_certificates_on_destroy = false + purge_soft_deleted_keys_on_destroy = false + # When recreating an environment, recover any previously soft deleted secrets - set to true by default + recover_soft_deleted_key_vaults = true + recover_soft_deleted_secrets = true + recover_soft_deleted_certificates = true + recover_soft_deleted_keys = true + } + } +} + +provider "azuread" { + client_id = var.auth_client_id + client_secret = var.auth_client_secret + tenant_id = var.auth_tenant_id +} diff --git a/templates/workspaces/airlock_manager/terraform/storage.tf b/templates/workspaces/airlock_manager/terraform/storage.tf new file mode 100644 index 0000000000..26bb86f860 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/storage.tf @@ -0,0 +1,81 @@ +resource "azurerm_storage_account" "stg" { + name = local.storage_name + resource_group_name = azurerm_resource_group.ws.name + location = azurerm_resource_group.ws.location + account_tier = "Standard" + account_replication_type = "GRS" + tags = local.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_storage_share" "shared_storage" { + name = "vm-shared-storage" + storage_account_name = azurerm_storage_account.stg.name + quota = var.shared_storage_quota + + depends_on = [ + azurerm_private_endpoint.stgfilepe, + azurerm_storage_account_network_rules.stgrules + ] +} + +resource "azurerm_storage_account_network_rules" "stgrules" { + storage_account_id = azurerm_storage_account.stg.id + + # When deploying from a local machine we need to "allow" + default_action = var.enable_local_debugging ? "Allow" : "Deny" + bypass = ["AzureServices"] +} + +resource "azurerm_private_endpoint" "stgfilepe" { + name = "stgfilepe-${local.workspace_resource_name_suffix}" + location = azurerm_resource_group.ws.location + resource_group_name = azurerm_resource_group.ws.name + subnet_id = module.network.services_subnet_id + tags = local.tre_workspace_tags + + depends_on = [ + module.network, + ] + + lifecycle { ignore_changes = [tags] } + + private_dns_zone_group { + name = "private-dns-zone-group" + private_dns_zone_ids = [module.network.filecore_zone_id] + } + + private_service_connection { + name = "stgfilepesc-${local.workspace_resource_name_suffix}" + private_connection_resource_id = azurerm_storage_account.stg.id + is_manual_connection = false + subresource_names = ["File"] + } +} + +resource "azurerm_private_endpoint" "stgblobpe" { + name = "stgblobpe-${local.workspace_resource_name_suffix}" + location = azurerm_resource_group.ws.location + resource_group_name = azurerm_resource_group.ws.name + subnet_id = module.network.services_subnet_id + tags = local.tre_workspace_tags + + depends_on = [ + module.network, + ] + + lifecycle { ignore_changes = [tags] } + + private_dns_zone_group { + name = "private-dns-zone-group" + private_dns_zone_ids = [module.network.blobcore_zone_id] + } + + private_service_connection { + name = "stgblobpesc-${local.workspace_resource_name_suffix}" + private_connection_resource_id = azurerm_storage_account.stg.id + is_manual_connection = false + subresource_names = ["Blob"] + } +} diff --git a/templates/workspaces/airlock_manager/terraform/variables.tf b/templates/workspaces/airlock_manager/terraform/variables.tf new file mode 100644 index 0000000000..b742b412c2 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/variables.tf @@ -0,0 +1,106 @@ +variable "tre_id" { + type = string + description = "Unique TRE ID" +} + +variable "tre_resource_id" { + type = string + description = "Resource ID" +} + +variable "shared_storage_quota" { + type = number + default = 50 + description = "Quota (in GB) to set for the VM Shared Storage." +} + +variable "location" { + type = string + description = "Azure location (region) for deployment of core TRE services" +} + +variable "address_space" { + type = string + description = "VNet address space for the workspace services" +} + +variable "deploy_app_service_plan" { + type = bool + default = true + description = "Deploy app service plan" +} + +variable "app_service_plan_sku" { + type = string + description = "App Service Plan SKU" +} + +variable "enable_local_debugging" { + type = bool + default = false + description = "This will allow storage account access over the internet. Set to true to allow deploying this from a local machine." +} + +variable "register_aad_application" { + type = bool + default = false + description = "Create an AAD application automatically for the Workspace." +} + +variable "aad_redirect_uris_b64" { + type = string # B64 encoded list of objects like [{"name": "my uri 1", "value": "https://..."}, {}] + default = "W10=" #b64 for [] +} + +variable "auth_tenant_id" { + type = string + description = "Used to authenticate into the AAD Tenant to create the AAD App" +} +variable "auth_client_id" { + type = string + description = "Used to authenticate into the AAD Tenant to create the AAD App" +} +variable "auth_client_secret" { + type = string + description = "Used to authenticate into the AAD Tenant to create the AAD App" +} + +# These variables are only passed in if you are not registering an AAD +# application as they need passing back out +variable "app_role_id_workspace_owner" { + type = string + default = "" + description = "The id of the application role WorkspaceOwner in the identity provider, this is passed in so that we may return it as an output." +} +variable "app_role_id_workspace_researcher" { + type = string + default = "" + description = "The id of the application role WorkspaceResearcher in the identity provider, this is passed in so that we may return it as an output." +} +variable "client_id" { + type = string + default = "" + description = "The client id of the workspace in the identity provider, this is passed in so that we may return it as an output." +} +variable "client_secret" { + type = string + default = "" + description = "The client secret of the workspace in the identity provider, this is passed in so that we may return it as an output." +} +variable "sp_id" { + type = string + default = "" + description = "The Service Principal in the Identity provider to be able to get claims, this is passed in so that we may return it as an output." +} +variable "scope_id" { + type = string + default = "" + description = "The Service Principal Name or Identifier URI, this is passed in so that we may return it as an output." +} +variable "workspace_owner_object_id" { + type = string + default = "" + description = "The Object Id of the user that you wish to be the Workspace Owner. E.g. the TEST_AUTOMATION_ACCOUNT." +} + + diff --git a/templates/workspaces/airlock_manager/terraform/workspace.tf b/templates/workspaces/airlock_manager/terraform/workspace.tf new file mode 100644 index 0000000000..f8bb69f33f --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/workspace.tf @@ -0,0 +1,57 @@ +resource "azurerm_resource_group" "ws" { + location = var.location + name = "rg-${local.workspace_resource_name_suffix}" + tags = merge( + local.tre_workspace_tags, + { + project = "Azure Trusted Research Environment", + source = "https://github.com/microsoft/AzureTRE/" + }, + ) + + lifecycle { ignore_changes = [tags] } +} + +// Networking is causing dependencies issues when some parts are deployed from +// Azure, especially for storage shares. It became quite difficult to figure out the needed +// dependencies for each resource seperatly, so to make it easier we packed all network +// resources as a single module that should be depended on. +module "network" { + source = "./network" + location = var.location + tre_id = var.tre_id + address_space = var.address_space + ws_resource_group_name = azurerm_resource_group.ws.name + tre_resource_id = var.tre_resource_id + tre_workspace_tags = local.tre_workspace_tags +} + +module "aad" { + source = "./aad" + tre_workspace_tags = local.tre_workspace_tags + count = var.register_aad_application ? 1 : 0 + key_vault_id = azurerm_key_vault.kv.id + workspace_resource_name_suffix = local.workspace_resource_name_suffix + workspace_owner_object_id = var.workspace_owner_object_id + aad_redirect_uris_b64 = var.aad_redirect_uris_b64 + depends_on = [ + azurerm_key_vault_access_policy.deployer, + azurerm_key_vault_access_policy.resource_processor, + null_resource.wait_for_dns_vault + ] +} + +module "airlock" { + source = "./airlock" + location = var.location + tre_id = var.tre_id + tre_workspace_tags = local.tre_workspace_tags + ws_resource_group_name = azurerm_resource_group.ws.name + enable_local_debugging = var.enable_local_debugging + services_subnet_id = module.network.services_subnet_id + short_workspace_id = local.short_workspace_id + airlock_processor_subnet_id = module.network.airlock_processor_subnet_id + depends_on = [ + module.network, + ] +} diff --git a/templates/workspaces/airlock_manager/update_redirect_urls.sh b/templates/workspaces/airlock_manager/update_redirect_urls.sh new file mode 100755 index 0000000000..67380e1392 --- /dev/null +++ b/templates/workspaces/airlock_manager/update_redirect_urls.sh @@ -0,0 +1,82 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +# Uncomment this line to see each command for debugging (careful: this will show secrets!) +# set -o xtrace + +function usage() { + cat < Date: Thu, 25 Aug 2022 10:56:17 +0100 Subject: [PATCH 02/31] Add Airlock Manager workspace --- .../workspaces/airlock_manager/.env.sample | 10 +- .../airlock_manager/Dockerfile.tmpl | 12 +- .../airlock_manager/parameters.json | 14 +- .../workspaces/airlock_manager/porter.yaml | 25 +++- .../airlock_manager/template_schema.json | 123 +++++++++------- .../terraform/.terraform.lock.hcl | 81 +++++++---- .../airlock_manager/terraform/aad/aad.tf | 10 ++ .../airlock_manager/terraform/aad/outputs.tf | 4 + .../terraform/aad/providers.tf | 17 +++ .../airlock_manager/terraform/airlock/data.tf | 5 - .../terraform/airlock/locals.tf | 17 ++- .../terraform/airlock/providers.tf | 9 ++ .../terraform/airlock/storage_accounts.tf | 37 ++--- .../terraform/api-permissions.tf | 15 ++ .../terraform/azure-monitor/azure-monitor.tf | 135 ++++++++++++++++++ .../terraform/azure-monitor/locals.tf | 4 + .../terraform/azure-monitor/outputs.tf | 11 ++ .../terraform/azure-monitor/providers.tf | 13 ++ .../terraform/azure-monitor/variables.tf | 12 ++ .../airlock_manager/terraform/deploy.sh | 0 .../airlock_manager/terraform/destroy.sh | 0 .../airlock_manager/terraform/locals.tf | 5 - .../terraform/network/dns_zones.tf | 84 +++++++++++ .../terraform/network/network.tf | 27 +++- .../terraform/network/outputs.tf | 16 +++ .../terraform/network/providers.tf | 9 ++ .../terraform/network/security.tf | 83 +++++++++-- .../airlock_manager/terraform/outputs.tf | 4 + .../airlock_manager/terraform/providers.tf | 8 +- .../airlock_manager/terraform/variables.tf | 10 ++ .../airlock_manager/terraform/workspace.tf | 21 +++ 31 files changed, 667 insertions(+), 154 deletions(-) mode change 100644 => 100755 templates/workspaces/airlock_manager/parameters.json create mode 100644 templates/workspaces/airlock_manager/terraform/aad/providers.tf create mode 100644 templates/workspaces/airlock_manager/terraform/airlock/providers.tf create mode 100644 templates/workspaces/airlock_manager/terraform/api-permissions.tf create mode 100644 templates/workspaces/airlock_manager/terraform/azure-monitor/azure-monitor.tf create mode 100644 templates/workspaces/airlock_manager/terraform/azure-monitor/locals.tf create mode 100644 templates/workspaces/airlock_manager/terraform/azure-monitor/outputs.tf create mode 100644 templates/workspaces/airlock_manager/terraform/azure-monitor/providers.tf create mode 100644 templates/workspaces/airlock_manager/terraform/azure-monitor/variables.tf mode change 100644 => 100755 templates/workspaces/airlock_manager/terraform/deploy.sh mode change 100644 => 100755 templates/workspaces/airlock_manager/terraform/destroy.sh create mode 100644 templates/workspaces/airlock_manager/terraform/network/dns_zones.tf create mode 100644 templates/workspaces/airlock_manager/terraform/network/providers.tf diff --git a/templates/workspaces/airlock_manager/.env.sample b/templates/workspaces/airlock_manager/.env.sample index 685235ce6e..e7793021f5 100644 --- a/templates/workspaces/airlock_manager/.env.sample +++ b/templates/workspaces/airlock_manager/.env.sample @@ -5,15 +5,16 @@ ARM_SUBSCRIPTION_ID="__CHANGE_ME__" AUTH_TENANT_ID="__CHANGE_ME__" # These are passed in if Terraform will create the Workspace AAD Application -#REGISTER_AAD_APPLICATION=true +REGISTER_AAD_APPLICATION=true AUTH_CLIENT_ID="__CHANGE_ME__" AUTH_CLIENT_SECRET="__CHANGE_ME__" WORKSPACE_OWNER_OBJECT_ID="__CHANGE_ME__" # These are passed in if you register the Workspace AAD Application before hand -REGISTER_AAD_APPLICATION=false -CLIENT_ID="__CHANGE_ME__" -CLIENT_SECRET="__CHANGE_ME__" +# REGISTER_AAD_APPLICATION=false +# CLIENT_ID="__CHANGE_ME__" +# CLIENT_SECRET="__CHANGE_ME__" +# WORKSPACE_OWNER_OBJECT_ID="" # Used by Porter, aka TRE_RESOURCE_ID ID="MadeUp123" @@ -21,6 +22,7 @@ SP_ID="" SCOPE_ID="api://ws_0001" APP_ROLE_ID_WORKSPACE_OWNER="" APP_ROLE_ID_WORKSPACE_RESEARCHER="" +APP_ROLE_ID_WORKSPACE_AIRLOCK_MANAGER="" ADDRESS_SPACE="10.2.8.0/24" SHARED_STORAGE_QUOTA=50 ENABLE_LOCAL_DEBUGGING=true diff --git a/templates/workspaces/airlock_manager/Dockerfile.tmpl b/templates/workspaces/airlock_manager/Dockerfile.tmpl index 421c5d4b82..bf77b0f459 100644 --- a/templates/workspaces/airlock_manager/Dockerfile.tmpl +++ b/templates/workspaces/airlock_manager/Dockerfile.tmpl @@ -3,6 +3,11 @@ FROM debian:buster-slim ARG BUNDLE_DIR +# Install jq +RUN apt-get update && \ + apt-get install -y jq="1.5+dfsg-2+b1" --no-install-recommends && \ + apt-get clean -y && rm -rf /var/lib/apt/lists/* + # This is a template Dockerfile for the bundle's invocation image # You can customize it to use different base images, install tools and copy configuration files. # @@ -19,5 +24,8 @@ ARG BUNDLE_DIR # Use the BUNDLE_DIR build argument to copy files into the bundle COPY . $BUNDLE_DIR -# Install jq -RUN apt-get update && apt-get install -y jq="1.5+dfsg-2+b1" && apt-get clean -y && rm -rf /var/lib/apt/lists/* +# Mirror plugins to prevent network access at runtime +# Remove when available from https://github.com/getporter/terraform-mixin/issues/90 +WORKDIR $BUNDLE_DIR/terraform +RUN terraform init -backend=false \ + && terraform providers mirror /usr/local/share/terraform/plugins diff --git a/templates/workspaces/airlock_manager/parameters.json b/templates/workspaces/airlock_manager/parameters.json old mode 100644 new mode 100755 index b220dd2d80..42329886b4 --- a/templates/workspaces/airlock_manager/parameters.json +++ b/templates/workspaces/airlock_manager/parameters.json @@ -1,6 +1,6 @@ { "schemaVersion": "1.0.0-DRAFT+TODO", - "name": "airlock-manager", + "name": "base", "created": "2021-06-04T13:37:29.5071039+03:00", "modified": "2021-06-04T13:37:29.5071039+03:00", "parameters": [ @@ -106,6 +106,12 @@ "env": "APP_ROLE_ID_WORKSPACE_RESEARCHER" } }, + { + "name": "app_role_id_workspace_airlock_manager", + "source": { + "env": "APP_ROLE_ID_WORKSPACE_AIRLOCK_MANAGER" + } + }, { "name": "aad_redirect_uris", "source": { @@ -117,6 +123,12 @@ "source": { "env": "APP_SERVICE_PLAN_SKU" } + }, + { + "name": "enable_airlock", + "source": { + "env": "ENABLE_AIRLOCK" + } } ] } diff --git a/templates/workspaces/airlock_manager/porter.yaml b/templates/workspaces/airlock_manager/porter.yaml index 71e9e4392b..38baf49370 100644 --- a/templates/workspaces/airlock_manager/porter.yaml +++ b/templates/workspaces/airlock_manager/porter.yaml @@ -1,7 +1,7 @@ --- -name: tre-workspace-airlock-manager -version: 0.3.16 -description: "A airlock manager Azure TRE workspace" +name: tre-workspace-base +version: 0.3.25 +description: "A base Azure TRE workspace" dockerfile: Dockerfile.tmpl registry: azuretre @@ -89,6 +89,10 @@ parameters: type: string default: "" description: "The id of the application role WorkspaceResearcher in the identity provider" + - name: app_role_id_workspace_airlock_manager + type: string + default: "" + description: "The id of the application role AirlockManager in the identity provider" - name: aad_redirect_uris type: string description: "List of redirect URIs in {name:value} format" @@ -97,6 +101,9 @@ parameters: type: string description: "The SKU used when deploying an Azure App Service Plan" default: "P1v3" + - name: enable_airlock + type: boolean + default: true outputs: - name: app_role_id_workspace_owner @@ -107,6 +114,10 @@ outputs: type: string applyTo: - install + - name: app_role_id_workspace_airlock_manager + type: string + applyTo: + - install - name: client_id type: string applyTo: @@ -123,8 +134,7 @@ outputs: mixins: - exec - terraform: - clientVersion: 1.1.7 - initFile: providers.tf + clientVersion: 1.2.6 - az install: @@ -148,8 +158,10 @@ install: sp_id: "{{ bundle.parameters.sp_id }}" app_role_id_workspace_owner: "{{ bundle.parameters.app_role_id_workspace_owner }}" app_role_id_workspace_researcher: "{{ bundle.parameters.app_role_id_workspace_researcher }}" + app_role_id_workspace_airlock_manager: "{{ bundle.parameters.app_role_id_workspace_airlock_manager }}" aad_redirect_uris_b64: "{{ bundle.parameters.aad_redirect_uris }}" app_service_plan_sku: "{{ bundle.parameters.app_service_plan_sku }}" + enable_airlock: "{{ bundle.parameters.enable_airlock }}" backendConfig: resource_group_name: "{{ bundle.parameters.tfstate_resource_group_name }}" storage_account_name: "{{ bundle.parameters.tfstate_storage_account_name }}" @@ -158,6 +170,7 @@ install: outputs: - name: app_role_id_workspace_owner - name: app_role_id_workspace_researcher + - name: app_role_id_workspace_airlock_manager - name: client_id - name: scope_id - name: sp_id @@ -237,8 +250,10 @@ uninstall: sp_id: "{{ bundle.parameters.sp_id }}" app_role_id_workspace_owner: "{{ bundle.parameters.app_role_id_workspace_owner }}" app_role_id_workspace_researcher: "{{ bundle.parameters.app_role_id_workspace_researcher }}" + app_role_id_workspace_airlock_manager: "{{ bundle.parameters.app_role_id_workspace_airlock_manager }}" aad_redirect_uris_b64: "{{ bundle.parameters.aad_redirect_uris }}" app_service_plan_sku: "{{ bundle.parameters.app_service_plan_sku }}" + enable_airlock: "{{ bundle.parameters.enable_airlock }}" backendConfig: resource_group_name: "{{ bundle.parameters.tfstate_resource_group_name }}" storage_account_name: "{{ bundle.parameters.tfstate_storage_account_name }}" diff --git a/templates/workspaces/airlock_manager/template_schema.json b/templates/workspaces/airlock_manager/template_schema.json index 18d41ad07a..db8f728f5a 100644 --- a/templates/workspaces/airlock_manager/template_schema.json +++ b/templates/workspaces/airlock_manager/template_schema.json @@ -1,60 +1,75 @@ { - "$schema": "http://json-schema.org/draft-07/schema", - "$id": "https://github.com/microsoft/AzureTRE/templates/workspaces/airlock_manager/template_schema.json", - "type": "object", - "title": "Airlock manager Workspace", - "description": "This workspace template is to be used to review import Airlock requests", - "required": [ - ], - "properties": { - "shared_storage_quota": { - "$id": "#/properties/shared_storage_quota", - "type": "integer", - "title": "Shared Storage Quota", - "description": "Quota (in GB) to set for the VM Shared Storage." - }, - "aad_redirect_uris": { - "$id": "#/properties/aad_redirect_uris", - "type": "array", - "title": "AAD Redirect URIs", - "description": "Redirect URIs for the AAD app in auto_create mode", - "updateable": true, - "default": [], - "items":{ - "title": "items", - "type": "object", - "required": [ - "name", - "value" - ], - "properties": { - "name": { - "title": "name", - "type": "string", - "description": "Redirect URI Name", - "examples": [ - "My Redirect URI" - ], - "pattern": "^.*$" - }, - "value": { - "title": "value", - "type": "string", - "description": "Redirect URI Value", - "examples": [ - "https://a-domain-name.com/oauth/" - ] - } + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://github.com/microsoft/AzureTRE/templates/workspaces/base/template_schema.json", + "type": "object", + "title": "Base Workspace", + "description": "This workspace template is the foundation for TRE workspaces and workspace services.", + "required": [], + "properties": { + "shared_storage_quota": { + "$id": "#/properties/shared_storage_quota", + "type": "integer", + "title": "Shared Storage Quota", + "description": "Quota (in GB) to set for the VM Shared Storage." + }, + "aad_redirect_uris": { + "$id": "#/properties/aad_redirect_uris", + "type": "array", + "title": "AAD Redirect URIs", + "description": "Redirect URIs for the AAD app in auto_create mode", + "updateable": true, + "default": [], + "items": { + "title": "items", + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "title": "name", + "type": "string", + "description": "Redirect URI Name", + "examples": [ + "My Redirect URI" + ], + "pattern": "^.*$" + }, + "value": { + "title": "value", + "type": "string", + "description": "Redirect URI Value", + "examples": [ + "https://a-domain-name.com/oauth/" + ] } } - }, - "app_service_plan_sku": { - "$id": "#/properties/app_service_plan_sku", - "type": "string", - "enum": ["P1v3", "P1v2"], - "default": "P1v3", - "title": "App Service Plan SKU", - "description": "The SKU that will be used when deploying an Azure App Service Plan." } + }, + "app_service_plan_sku": { + "$id": "#/properties/app_service_plan_sku", + "type": "string", + "enum": [ + "P1v3", + "P1v2", + "S1" + ], + "default": "P1v3", + "title": "App Service Plan SKU", + "description": "The SKU that will be used when deploying an Azure App Service Plan." + }, + "enable_airlock": { + "$id": "#/properties/enable_airlock", + "type": "boolean", + "default": true, + "title": "Enable Airlock", + "description": "If enabled, allows imports and exports for the workspace." } + }, + "uiSchema": { + "aad_redirect_uris": { + "classNames": "tre-hidden" + } + } } diff --git a/templates/workspaces/airlock_manager/terraform/.terraform.lock.hcl b/templates/workspaces/airlock_manager/terraform/.terraform.lock.hcl index a6b6c478d8..a03985c9c2 100644 --- a/templates/workspaces/airlock_manager/terraform/.terraform.lock.hcl +++ b/templates/workspaces/airlock_manager/terraform/.terraform.lock.hcl @@ -3,7 +3,7 @@ provider "registry.terraform.io/hashicorp/azuread" { version = "2.20.0" - constraints = "2.20.0" + constraints = ">= 2.20.0, 2.20.0" hashes = [ "h1:qKo6WfRyml6w4qcnqDoeTmlWCL/kzng4qOB/5/XAW9g=", "zh:0262b33661825b54edc0c539415ebdc942ecb3e2cf90af75f7ef134a1f901816", @@ -22,27 +22,48 @@ provider "registry.terraform.io/hashicorp/azuread" { } provider "registry.terraform.io/hashicorp/azurerm" { - version = "3.12.0" - constraints = "3.12.0" + version = "3.16.0" + constraints = ">= 3.8.0, 3.16.0" hashes = [ - "h1:KF6bIhK7POPuO1HYK1G8b5Fae+0n8c/gM+9EBVJJQ2Q=", - "zh:0bbc93276a38da205d2b8ce34a2f813e96687a2f6fc7addd9bb05b85dab2a662", - "zh:3af12159e0b5217a7b35f081fba1e34ac8fb995acc7e6d2ec86592a559eb85c8", - "zh:7d1bdc9b4d9b1990409d52cb915e5acbe17bd81b29d28f7fcdaaf96003dca77c", - "zh:81ab77524cfa91aed929e35e2ed63b2ac73add7c33d1b3d5cdc21937606ecc7c", - "zh:84ddddd9f4c695199ef2824eea853d29434e164e0ef3603451aed39d8852ba28", - "zh:9905a5ca2d7c5c6e43a4be1f7b207d584860ec4ddad1aaa475fb03a731333751", - "zh:9cdf3223d9f4a2dbabcd1ebc663beab356a4ee5b1f584088772da8271c74890b", - "zh:a8317436ec286aae91d9bfbcd36edb9b0b58c195a9cd0adffb7f588f124bef1e", - "zh:cea079d3f4eff9e301ca207c7ce676553f9acc3202abf88ff161d6faa1e1a54a", + "h1:cBZXnJ4WErrhAzoQ1IMUMkpRlUmr8KQ2a0vLKH6B2a8=", + "zh:02aecc67db3f7cf19bd39ed454824422c43a5dc9f18b44d9547bb79ba66e0beb", + "zh:1775b033e3a29395087d731387efc926251232c4469a6c262f7039669e2f3aed", + "zh:1b955c3134b8fa61486383fee609bc99e46883c9b5148cb8d3bdc3d6d25b1e5e", + "zh:1ca04c35917fcf9f15aa2f24ef52b823575efa213fcb6d241cd189fddb032268", + "zh:20663ca219acc95d1de2129aac941f08eca1093c61cd6775e9c0b239b70a573e", + "zh:28427df342789f106ce500a489c750d7971d67cb58c495274878dc55d52452fe", + "zh:2a2e0755b9ebedbb4dd55de53191ce02e0a5511648610bf816532cd1614f2d7a", + "zh:5cc4c086ff081379070ea8177025a92a53e3c7bec2eabbf8182efa146e05b371", + "zh:5df50ae712c2b6e850b5953d5b89a29aca98ef1ae5fac4cb9225080ac319207c", + "zh:944ec6ceac2a1af58b58c270db90992d5f32614714647f6086ebc42789fa0f15", + "zh:f1e2df2f7db13b234d2cfa5d7c70054df4039532829be6ce8ed11c6f99ba0cf5", "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", - "zh:fdaa4de7d6713bd8b1b4a51135c9eadbaa317ea87e7af9c00c52f67018fba288", - "zh:ff25a0a5fb54174a8a37d4e40413fa85737d8bb837c5635b6e88621c36c202bd", + ] +} + +provider "registry.terraform.io/hashicorp/local" { + version = "2.2.3" + constraints = "~> 2.2.0" + hashes = [ + "h1:aWp5iSUxBGgPv1UnV5yag9Pb0N+U1I0sZb38AXBFO8A=", + "zh:04f0978bb3e052707b8e82e46780c371ac1c66b689b4a23bbc2f58865ab7d5c0", + "zh:6484f1b3e9e3771eb7cc8e8bab8b35f939a55d550b3f4fb2ab141a24269ee6aa", + "zh:78a56d59a013cb0f7eb1c92815d6eb5cf07f8b5f0ae20b96d049e73db915b238", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:8aa9950f4c4db37239bcb62e19910c49e47043f6c8587e5b0396619923657797", + "zh:996beea85f9084a725ff0e6473a4594deb5266727c5f56e9c1c7c62ded6addbb", + "zh:9a7ef7a21f48fabfd145b2e2a4240ca57517ad155017e86a30860d7c0c109de3", + "zh:a63e70ac052aa25120113bcddd50c1f3cfe61f681a93a50cea5595a4b2cc3e1c", + "zh:a6e8d46f94108e049ad85dbed60354236dc0b9b5ec8eabe01c4580280a43d3b8", + "zh:bb112ce7efbfcfa0e65ed97fa245ef348e0fd5bfa5a7e4ab2091a9bd469f0a9e", + "zh:d7bec0da5c094c6955efed100f3fe22fca8866859f87c025be1760feb174d6d9", + "zh:fb9f271b72094d07cef8154cd3d50e9aa818a0ea39130bc193132ad7b23076fd", ] } provider "registry.terraform.io/hashicorp/null" { - version = "3.1.1" + version = "3.1.1" + constraints = "~> 3.1.0" hashes = [ "h1:71sNUDvmiJcijsvfXpiLCz0lXIBSsEJjMxljt7hxMhw=", "zh:063466f41f1d9fd0dd93722840c1314f046d8760b1812fa67c34de0afcba5597", @@ -61,21 +82,21 @@ provider "registry.terraform.io/hashicorp/null" { } provider "registry.terraform.io/hashicorp/random" { - version = "3.1.2" - constraints = "3.1.2" + version = "3.3.2" + constraints = "~> 3.3.0" hashes = [ - "h1:5A5VsY5wNmOZlupUcLnIoziMPn8htSZBXbP3lI7lBEM=", - "zh:0daceba867b330d3f8e2c5dc895c4291845a78f31955ce1b91ab2c4d1cd1c10b", - "zh:104050099efd30a630741f788f9576b19998e7a09347decbec3da0b21d64ba2d", - "zh:173f4ef3fdf0c7e2564a3db0fac560e9f5afdf6afd0b75d6646af6576b122b16", - "zh:41d50f975e535f968b3f37170fb07937c15b76d85ba947d0ce5e5ff9530eda65", - "zh:51a5038867e5e60757ed7f513dd6a973068241190d158a81d1b69296efb9cb8d", - "zh:6432a568e97a5a36cc8aebca5a7e9c879a55d3bc71d0da1ab849ad905f41c0be", - "zh:6bac6501394b87138a5e17c9f3a41e46ff7833ad0ba2a96197bb7787e95b641c", - "zh:6c0a7f5faacda644b022e7718e53f5868187435be6d000786d1ca05aa6683a25", - "zh:74c89de3fa6ef3027efe08f8473c2baeb41b4c6cee250ba7aeb5b64e8c79800d", + "h1:H5V+7iXol/EHB2+BUMzGlpIiCOdV74H8YjzCxnSAWcg=", + "zh:038293aebfede983e45ee55c328e3fde82ae2e5719c9bd233c324cfacc437f9c", + "zh:07eaeab03a723d83ac1cc218f3a59fceb7bbf301b38e89a26807d1c93c81cef8", + "zh:427611a4ce9d856b1c73bea986d841a969e4c2799c8ac7c18798d0cc42b78d32", + "zh:49718d2da653c06a70ba81fd055e2b99dfd52dcb86820a6aeea620df22cd3b30", + "zh:5574828d90b19ab762604c6306337e6cd430e65868e13ef6ddb4e25ddb9ad4c0", + "zh:7222e16f7833199dabf1bc5401c56d708ec052b2a5870988bc89ff85b68a5388", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:b29eabbf0a5298f0e95a1df214c7cfe06ea9bcf362c63b3ad2f72d85da7d4685", - "zh:e891458c7a61e5b964e09616f1a4f87d0471feae1ec04cc51776e7dec1a3abce", + "zh:b1b2d7d934784d2aee98b0f8f07a8ccfc0410de63493ae2bf2222c165becf938", + "zh:b8f85b6a20bd264fcd0814866f415f0a368d1123cd7879c8ebbf905d370babc8", + "zh:c3813133acc02bbebddf046d9942e8ba5c35fc99191e3eb057957dafc2929912", + "zh:e7a41dbc919d1de800689a81c240c27eec6b9395564630764ebb323ea82ac8a9", + "zh:ee6d23208449a8eaa6c4f203e33f5176fa795b4b9ecf32903dffe6e2574732c2", ] } diff --git a/templates/workspaces/airlock_manager/terraform/aad/aad.tf b/templates/workspaces/airlock_manager/terraform/aad/aad.tf index 2ecdaf1f2f..0c35da6518 100644 --- a/templates/workspaces/airlock_manager/terraform/aad/aad.tf +++ b/templates/workspaces/airlock_manager/terraform/aad/aad.tf @@ -3,6 +3,7 @@ data "azuread_client_config" "current" {} resource "random_uuid" "oauth2_user_impersonation_id" {} resource "random_uuid" "app_role_workspace_owner_id" {} resource "random_uuid" "app_role_workspace_researcher_id" {} +resource "random_uuid" "app_role_workspace_airlock_manager_id" {} resource "azuread_application" "workspace" { display_name = var.workspace_resource_name_suffix @@ -43,6 +44,15 @@ resource "azuread_application" "workspace" { value = "WorkspaceResearcher" } + app_role { + allowed_member_types = ["User", "Application"] + description = "Provides airlock managers access to the Workspace and ability to review airlock requests." + display_name = "Airlock Manager" + enabled = true + id = random_uuid.app_role_workspace_airlock_manager_id.result + value = "AirlockManager" + } + feature_tags { enterprise = true } diff --git a/templates/workspaces/airlock_manager/terraform/aad/outputs.tf b/templates/workspaces/airlock_manager/terraform/aad/outputs.tf index 8c84927878..d233607652 100644 --- a/templates/workspaces/airlock_manager/terraform/aad/outputs.tf +++ b/templates/workspaces/airlock_manager/terraform/aad/outputs.tf @@ -6,6 +6,10 @@ output "app_role_workspace_researcher_id" { value = random_uuid.app_role_workspace_researcher_id.result } +output "app_role_workspace_airlock_manager_id" { + value = random_uuid.app_role_workspace_airlock_manager_id.result +} + output "client_id" { value = azuread_application.workspace.application_id } diff --git a/templates/workspaces/airlock_manager/terraform/aad/providers.tf b/templates/workspaces/airlock_manager/terraform/aad/providers.tf new file mode 100644 index 0000000000..5361d62965 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/aad/providers.tf @@ -0,0 +1,17 @@ +terraform { + # In modules we should only specify the min version + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">= 3.8.0" + } + azuread = { + source = "hashicorp/azuread" + version = ">= 2.20" + } + random = { + source = "hashicorp/random" + version = "~>3.3.0" + } + } +} diff --git a/templates/workspaces/airlock_manager/terraform/airlock/data.tf b/templates/workspaces/airlock_manager/terraform/airlock/data.tf index 72fc38e229..e36e3887b8 100644 --- a/templates/workspaces/airlock_manager/terraform/airlock/data.tf +++ b/templates/workspaces/airlock_manager/terraform/airlock/data.tf @@ -23,8 +23,3 @@ data "azurerm_servicebus_topic" "blob_created" { resource_group_name = local.core_resource_group_name namespace_name = data.azurerm_servicebus_namespace.airlock_sb.name } - -data "azurerm_storage_account" "sa_import_inprogress" { - name = local.import_in_progress_storage_name - resource_group_name = local.core_resource_group_name -} diff --git a/templates/workspaces/airlock_manager/terraform/airlock/locals.tf b/templates/workspaces/airlock_manager/terraform/airlock/locals.tf index 56ff86d7ac..f6310739e0 100644 --- a/templates/workspaces/airlock_manager/terraform/airlock/locals.tf +++ b/templates/workspaces/airlock_manager/terraform/airlock/locals.tf @@ -1,5 +1,4 @@ locals { - core_vnet = "vnet-${var.tre_id}" core_resource_group_name = "rg-${var.tre_id}" workspace_resource_name_suffix = "${var.tre_id}-ws-${var.short_workspace_id}" @@ -12,8 +11,6 @@ locals { # STorage AirLock IMport APProved import_approved_storage_name = lower(replace("stalimapp${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) - # STorage AirLock IMport InProgress - import_in_progress_storage_name = lower(replace("stalimip${var.tre_id}", "-", "")) # STorage AirLock EXport INTernal export_internal_storage_name = lower(replace("stalexint${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) # STorage AirLock EXport InProgress @@ -22,4 +19,18 @@ locals { export_rejected_storage_name = lower(replace("stalexrej${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) # STorage AirLock EXport BLOCKED export_blocked_storage_name = lower(replace("stalexblocked${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) + + airlock_blob_data_contributor = [ + azurerm_storage_account.sa_import_approved.id, + azurerm_storage_account.sa_export_internal.id, + azurerm_storage_account.sa_export_inprogress.id, + azurerm_storage_account.sa_export_rejected.id, + azurerm_storage_account.sa_export_blocked.id + ] + + api_sa_data_contributor = [ + azurerm_storage_account.sa_import_approved.id, + azurerm_storage_account.sa_export_internal.id, + azurerm_storage_account.sa_export_inprogress.id + ] } diff --git a/templates/workspaces/airlock_manager/terraform/airlock/providers.tf b/templates/workspaces/airlock_manager/terraform/airlock/providers.tf new file mode 100644 index 0000000000..303382e106 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/airlock/providers.tf @@ -0,0 +1,9 @@ +terraform { + # In modules we should only specify the min version + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">= 3.8.0" + } + } +} diff --git a/templates/workspaces/airlock_manager/terraform/airlock/storage_accounts.tf b/templates/workspaces/airlock_manager/terraform/airlock/storage_accounts.tf index fe7ffe4653..d873e96b85 100644 --- a/templates/workspaces/airlock_manager/terraform/airlock/storage_accounts.tf +++ b/templates/workspaces/airlock_manager/terraform/airlock/storage_accounts.tf @@ -4,7 +4,7 @@ resource "azurerm_storage_account" "sa_import_approved" { location = var.location resource_group_name = var.ws_resource_group_name account_tier = "Standard" - account_replication_type = "GRS" + account_replication_type = "LRS" allow_nested_items_to_be_public = false # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. @@ -31,6 +31,7 @@ resource "azurerm_private_endpoint" "import_approved_pe" { location = var.location resource_group_name = var.ws_resource_group_name subnet_id = var.services_subnet_id + tags = var.tre_workspace_tags lifecycle { ignore_changes = [tags] } @@ -54,7 +55,7 @@ resource "azurerm_storage_account" "sa_export_internal" { location = var.location resource_group_name = var.ws_resource_group_name account_tier = "Standard" - account_replication_type = "GRS" + account_replication_type = "LRS" allow_nested_items_to_be_public = false # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. @@ -76,34 +77,13 @@ resource "azurerm_storage_account" "sa_export_internal" { lifecycle { ignore_changes = [tags] } } -resource "azurerm_private_endpoint" "stg_import_inprogress_pe" { - name = "stg-ip-import-blob-${var.tre_id}-ws-${var.short_workspace_id}" - location = var.location - resource_group_name = var.ws_resource_group_name - subnet_id = var.services_subnet_id - - lifecycle { ignore_changes = [tags] } - - private_dns_zone_group { - name = "private-dns-zone-group-stg-import-ip" - private_dns_zone_ids = [data.azurerm_private_dns_zone.blobcore.id] - } - - private_service_connection { - name = "psc-stgipimport-${var.tre_id}" - private_connection_resource_id = data.azurerm_storage_account.sa_import_inprogress.id - is_manual_connection = false - subresource_names = ["Blob"] - } - - tags = var.tre_workspace_tags -} resource "azurerm_private_endpoint" "export_internal_pe" { name = "pe-sa-export-int-blob-${var.short_workspace_id}" location = var.location resource_group_name = var.ws_resource_group_name subnet_id = var.services_subnet_id + tags = var.tre_workspace_tags lifecycle { ignore_changes = [tags] } @@ -126,7 +106,7 @@ resource "azurerm_storage_account" "sa_export_inprogress" { location = var.location resource_group_name = var.ws_resource_group_name account_tier = "Standard" - account_replication_type = "GRS" + account_replication_type = "LRS" allow_nested_items_to_be_public = false # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. @@ -160,6 +140,7 @@ resource "azurerm_private_endpoint" "export_inprogress_pe" { location = var.location resource_group_name = var.ws_resource_group_name subnet_id = var.services_subnet_id + tags = var.tre_workspace_tags lifecycle { ignore_changes = [tags] } @@ -182,7 +163,7 @@ resource "azurerm_storage_account" "sa_export_rejected" { location = var.location resource_group_name = var.ws_resource_group_name account_tier = "Standard" - account_replication_type = "GRS" + account_replication_type = "LRS" allow_nested_items_to_be_public = false # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. @@ -210,6 +191,7 @@ resource "azurerm_private_endpoint" "export_rejected_pe" { location = var.location resource_group_name = var.ws_resource_group_name subnet_id = var.services_subnet_id + tags = var.tre_workspace_tags lifecycle { ignore_changes = [tags] } @@ -232,7 +214,7 @@ resource "azurerm_storage_account" "sa_export_blocked" { location = var.location resource_group_name = var.ws_resource_group_name account_tier = "Standard" - account_replication_type = "GRS" + account_replication_type = "LRS" allow_nested_items_to_be_public = false # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. @@ -260,6 +242,7 @@ resource "azurerm_private_endpoint" "export_blocked_pe" { location = var.location resource_group_name = var.ws_resource_group_name subnet_id = var.services_subnet_id + tags = var.tre_workspace_tags lifecycle { ignore_changes = [tags] } diff --git a/templates/workspaces/airlock_manager/terraform/api-permissions.tf b/templates/workspaces/airlock_manager/terraform/api-permissions.tf new file mode 100644 index 0000000000..4bd6fe6aeb --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/api-permissions.tf @@ -0,0 +1,15 @@ +# The API needs permissions to stop/start VMs + +data "azurerm_user_assigned_identity" "api_id" { + name = "id-api-${var.tre_id}" + resource_group_name = "rg-${var.tre_id}" +} + + +# TODO: the assigned builtin role gives too wide permissions. +# https://github.com/microsoft/AzureTRE/issues/2389 +resource "azurerm_role_assignment" "api_vm_contributor" { + scope = azurerm_resource_group.ws.id + role_definition_name = "Virtual Machine Contributor" + principal_id = data.azurerm_user_assigned_identity.api_id.principal_id +} diff --git a/templates/workspaces/airlock_manager/terraform/azure-monitor/azure-monitor.tf b/templates/workspaces/airlock_manager/terraform/azure-monitor/azure-monitor.tf new file mode 100644 index 0000000000..246d307413 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/azure-monitor/azure-monitor.tf @@ -0,0 +1,135 @@ +resource "azurerm_log_analytics_workspace" "workspace" { + name = "log-${var.tre_id}-ws-${local.short_workspace_id}" + resource_group_name = var.resource_group_name + location = var.location + retention_in_days = 30 + sku = "PerGB2018" + tags = var.tre_workspace_tags + internet_ingestion_enabled = var.enable_local_debugging ? true : false + + lifecycle { ignore_changes = [tags] } +} + +# Storage account for Application Insights +# Because Private Link is enabled on Application Performance Management (APM), Bring Your Own Storage (BYOS) approach is required +resource "azurerm_storage_account" "app_insights" { + name = lower(replace("stai${var.tre_id}ws${local.short_workspace_id}", "-", "")) + resource_group_name = var.resource_group_name + location = var.location + account_kind = "StorageV2" + account_tier = "Standard" + account_replication_type = "LRS" + allow_nested_items_to_be_public = false + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_log_analytics_linked_storage_account" "workspace_storage_ingestion" { + data_source_type = "ingestion" + resource_group_name = var.resource_group_name + workspace_resource_id = azurerm_log_analytics_workspace.workspace.id + storage_account_ids = [azurerm_storage_account.app_insights.id] +} + +resource "azurerm_log_analytics_linked_storage_account" "workspace_storage_customlogs" { + data_source_type = "customlogs" + resource_group_name = var.resource_group_name + workspace_resource_id = azurerm_log_analytics_workspace.workspace.id + storage_account_ids = [azurerm_storage_account.app_insights.id] +} + +resource "azurerm_monitor_private_link_scope" "workspace" { + name = "ampls-${var.tre_id}-ws-${local.short_workspace_id}" + resource_group_name = var.resource_group_name + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_monitor_private_link_scoped_service" "ampls_log_anaytics" { + name = "ampls-log-anaytics-service" + resource_group_name = var.resource_group_name + scope_name = azurerm_monitor_private_link_scope.workspace.name + linked_resource_id = azurerm_log_analytics_workspace.workspace.id +} + + + +# Application Insights + +resource "azurerm_application_insights" "workspace" { + name = "appi-${var.tre_id}-ws-${local.short_workspace_id}" + location = var.location + resource_group_name = var.resource_group_name + workspace_id = azurerm_log_analytics_workspace.workspace.id + application_type = "web" + internet_ingestion_enabled = var.enable_local_debugging ? true : false + force_customer_storage_for_profiler = true + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_monitor_private_link_scoped_service" "ampls_app_insights" { + name = "ampls-app-insights-service" + resource_group_name = var.resource_group_name + scope_name = azurerm_monitor_private_link_scope.workspace.name + linked_resource_id = azurerm_application_insights.workspace.id +} + +resource "azurerm_private_endpoint" "azure_monitor_private_endpoint" { + name = "pe-ampls-${var.tre_id}-ws-${local.short_workspace_id}" + resource_group_name = var.resource_group_name + location = var.location + subnet_id = var.workspace_subnet_id + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } + + private_service_connection { + private_connection_resource_id = azurerm_monitor_private_link_scope.workspace.id + name = "psc-ampls-${var.tre_id}-ws-${local.short_workspace_id}" + subresource_names = ["azuremonitor"] + is_manual_connection = false + } + + private_dns_zone_group { + name = "azure-monitor-private-dns-zone-group" + + private_dns_zone_ids = [ + var.azure_monitor_dns_zone_id, + var.azure_monitor_oms_opinsights_dns_zone_id, + var.azure_monitor_ods_opinsights_dns_zone_id, + var.azure_monitor_agentsvc_dns_zone_id, + var.blob_core_dns_zone_id, + ] + } + + depends_on = [ + azurerm_monitor_private_link_scoped_service.ampls_app_insights, + ] +} + +# We don't really need this, but if not present the RG will not be empty and won't be destroyed +# TODO: remove when this is resolved: https://github.com/hashicorp/terraform-provider-azurerm/issues/18026 +resource "azurerm_monitor_action_group" "failure_anomalies" { + name = "${azurerm_application_insights.workspace.name}-failure-anomalies-action-group" + resource_group_name = var.resource_group_name + short_name = "Failures" +} + +# We don't really need this, but if not present the RG will not be empty and won't be destroyed +# TODO: remove when this is resolved: https://github.com/hashicorp/terraform-provider-azurerm/issues/18026 +resource "azurerm_monitor_smart_detector_alert_rule" "failure_anomalies" { + name = "Failure Anomalies - ${local.app_insights_name}" + resource_group_name = var.resource_group_name + severity = "Sev3" + scope_resource_ids = [azurerm_application_insights.workspace.id] + frequency = "PT1M" + detector_type = "FailureAnomaliesDetector" + + action_group { + ids = [azurerm_monitor_action_group.failure_anomalies.id] + } +} diff --git a/templates/workspaces/airlock_manager/terraform/azure-monitor/locals.tf b/templates/workspaces/airlock_manager/terraform/azure-monitor/locals.tf new file mode 100644 index 0000000000..7a5f06bdfe --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/azure-monitor/locals.tf @@ -0,0 +1,4 @@ +locals { + short_workspace_id = substr(var.tre_resource_id, -4, -1) + app_insights_name = "appi-${var.tre_id}-ws-${local.short_workspace_id}" +} diff --git a/templates/workspaces/airlock_manager/terraform/azure-monitor/outputs.tf b/templates/workspaces/airlock_manager/terraform/azure-monitor/outputs.tf new file mode 100644 index 0000000000..e09791912c --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/azure-monitor/outputs.tf @@ -0,0 +1,11 @@ +output "app_insights_connection_string" { + value = azurerm_application_insights.workspace.connection_string +} + +output "log_analytics_workspace_id" { + value = azurerm_log_analytics_workspace.workspace.id +} + +output "log_analytics_workspace_name" { + value = azurerm_log_analytics_workspace.workspace.name +} diff --git a/templates/workspaces/airlock_manager/terraform/azure-monitor/providers.tf b/templates/workspaces/airlock_manager/terraform/azure-monitor/providers.tf new file mode 100644 index 0000000000..308d332af3 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/azure-monitor/providers.tf @@ -0,0 +1,13 @@ +terraform { + # In modules we should only specify the min version + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">= 3.8.0" + } + local = { + source = "hashicorp/local" + version = "~> 2.2.0" + } + } +} diff --git a/templates/workspaces/airlock_manager/terraform/azure-monitor/variables.tf b/templates/workspaces/airlock_manager/terraform/azure-monitor/variables.tf new file mode 100644 index 0000000000..452d974f92 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/azure-monitor/variables.tf @@ -0,0 +1,12 @@ +variable "tre_id" {} +variable "location" {} +variable "resource_group_name" {} +variable "tre_workspace_tags" {} +variable "workspace_subnet_id" {} +variable "azure_monitor_dns_zone_id" {} +variable "azure_monitor_oms_opinsights_dns_zone_id" {} +variable "azure_monitor_ods_opinsights_dns_zone_id" {} +variable "azure_monitor_agentsvc_dns_zone_id" {} +variable "blob_core_dns_zone_id" {} +variable "tre_resource_id" {} +variable "enable_local_debugging" {} diff --git a/templates/workspaces/airlock_manager/terraform/deploy.sh b/templates/workspaces/airlock_manager/terraform/deploy.sh old mode 100644 new mode 100755 diff --git a/templates/workspaces/airlock_manager/terraform/destroy.sh b/templates/workspaces/airlock_manager/terraform/destroy.sh old mode 100644 new mode 100755 diff --git a/templates/workspaces/airlock_manager/terraform/locals.tf b/templates/workspaces/airlock_manager/terraform/locals.tf index a2e6be0f70..35d70e5e9e 100644 --- a/templates/workspaces/airlock_manager/terraform/locals.tf +++ b/templates/workspaces/airlock_manager/terraform/locals.tf @@ -1,13 +1,8 @@ locals { - core_vnet = "vnet-${var.tre_id}" short_workspace_id = substr(var.tre_resource_id, -4, -1) - core_resource_group_name = "rg-${var.tre_id}" workspace_resource_name_suffix = "${var.tre_id}-ws-${local.short_workspace_id}" storage_name = lower(replace("stg${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) keyvault_name = lower("kv-${substr(local.workspace_resource_name_suffix, -20, -1)}") - vnet_subnets = cidrsubnets(var.address_space, 1, 1) - services_subnet_address_prefix = local.vnet_subnets[0] - webapps_subnet_address_prefix = local.vnet_subnets[1] tre_workspace_tags = { tre_id = var.tre_id tre_workspace_id = var.tre_resource_id diff --git a/templates/workspaces/airlock_manager/terraform/network/dns_zones.tf b/templates/workspaces/airlock_manager/terraform/network/dns_zones.tf new file mode 100644 index 0000000000..1b6451c252 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/network/dns_zones.tf @@ -0,0 +1,84 @@ +# For recommended Azure private DNS zone names see https://docs.microsoft.com/azure/private-link/private-endpoint-dns#azure-services-dns-zone-configuration + +# To enable connecting to Azure Monitor from within a workspace VNET (where traffic is restricted), we need to have an Azure Monitor Private Link Scope (AMPLS) that is connected to a Private Endpoint within the VNET. +# An AMPLS can be connected to multiple Private Endpoints and multiple Azure Monitor resources, but [an AMPLS can only connect to up to 10 Private Endpoints](https://docs.microsoft.com/en-us/azure/azure-monitor/logs/private-link-design#consider-ampls-limits) so the suggestion is to deploy an AMPLS per workspace for simplicity. +# Because there are some shared endpoints (i.e. not resource-specific), a [single AMPLS should be used for all VNETs that share the same DNS](https://docs.microsoft.com/en-us/azure/azure-monitor/logs/private-link-security#azure-monitor-private-links-rely-on-your-dns). Currently, we have separate VNETs for each workspace but each VNET is linked to the same, single private DNS Zone for Azure Monitor/App Insights. To enable an AMPLS per workspace, we need to update the private DNS Zones for Azure Monitor so that the existing zones are just used for the core VNET and deploy separate zones for each workspace. + + +# Azure Monitor requires 5 DNS zones: +# - privatelink.monitor.azure.com +# - privatelink.oms.opinsights.azure.com +# - privatelink.ods.opinsights.azure.com +# - privatelink.agentsvc.azure-automation.net +# - privatelink.blob.core.windows.net (used also by Storage module) +resource "azurerm_private_dns_zone" "azure_monitor" { + name = "privatelink.monitor.azure.com" + resource_group_name = var.ws_resource_group_name + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "azure_monitor" { + name = "azure-monitor-link" + resource_group_name = var.ws_resource_group_name + virtual_network_id = azurerm_virtual_network.ws.id + private_dns_zone_name = azurerm_private_dns_zone.azure_monitor.name + registration_enabled = false + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone" "azure_monitor_oms_opinsights" { + name = "privatelink.oms.opinsights.azure.com" + resource_group_name = var.ws_resource_group_name + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "azure_monitor_oms_opinsights" { + name = "azure-monitor-link" + resource_group_name = var.ws_resource_group_name + virtual_network_id = azurerm_virtual_network.ws.id + private_dns_zone_name = azurerm_private_dns_zone.azure_monitor_oms_opinsights.name + registration_enabled = false + tags = var.tre_workspace_tags + + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone" "azure_monitor_ods_opinsights" { + name = "privatelink.ods.opinsights.azure.com" + resource_group_name = var.ws_resource_group_name + tags = var.tre_workspace_tags + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "azure_monitor_ods_opinsights" { + name = "azure-monitor-link" + resource_group_name = var.ws_resource_group_name + virtual_network_id = azurerm_virtual_network.ws.id + private_dns_zone_name = azurerm_private_dns_zone.azure_monitor_ods_opinsights.name + registration_enabled = false + tags = var.tre_workspace_tags + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone" "azure_monitor_agentsvc" { + name = "privatelink.agentsvc.azure-automation.net" + resource_group_name = var.ws_resource_group_name + tags = var.tre_workspace_tags + lifecycle { ignore_changes = [tags] } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "azure_monitor_agentsvc" { + name = "azure-monitor-link" + resource_group_name = var.ws_resource_group_name + virtual_network_id = azurerm_virtual_network.ws.id + private_dns_zone_name = azurerm_private_dns_zone.azure_monitor_agentsvc.name + registration_enabled = false + tags = var.tre_workspace_tags + lifecycle { ignore_changes = [tags] } +} diff --git a/templates/workspaces/airlock_manager/terraform/network/network.tf b/templates/workspaces/airlock_manager/terraform/network/network.tf index af70e98a5d..1d146933e4 100644 --- a/templates/workspaces/airlock_manager/terraform/network/network.tf +++ b/templates/workspaces/airlock_manager/terraform/network/network.tf @@ -40,28 +40,51 @@ resource "azurerm_subnet" "webapps" { actions = ["Microsoft.Network/virtualNetworks/subnets/action"] } } + + depends_on = [ + # meant to resolve AnotherOperation errors with one operation in the vnet at a time + azurerm_subnet.services + ] } -resource "azurerm_virtual_network_peering" "ws-core-peer" { +resource "azurerm_virtual_network_peering" "ws_core_peer" { name = "ws-core-peer-${local.workspace_resource_name_suffix}" resource_group_name = var.ws_resource_group_name virtual_network_name = azurerm_virtual_network.ws.name remote_virtual_network_id = data.azurerm_virtual_network.core.id } -resource "azurerm_virtual_network_peering" "core-ws-peer" { +moved { + from = azurerm_virtual_network_peering.ws-core-peer + to = azurerm_virtual_network_peering.ws_core_peer +} + +resource "azurerm_virtual_network_peering" "core_ws_peer" { name = "core-ws-peer-${local.workspace_resource_name_suffix}" resource_group_name = local.core_resource_group_name virtual_network_name = local.core_vnet remote_virtual_network_id = azurerm_virtual_network.ws.id } +moved { + from = azurerm_virtual_network_peering.core-ws-peer + to = azurerm_virtual_network_peering.core_ws_peer +} + resource "azurerm_subnet_route_table_association" "rt_services_subnet_association" { route_table_id = data.azurerm_route_table.rt.id subnet_id = azurerm_subnet.services.id + depends_on = [ + # meant to resolve AnotherOperation errors with one operation in the vnet at a time + azurerm_subnet.webapps + ] } resource "azurerm_subnet_route_table_association" "rt_webapps_subnet_association" { route_table_id = data.azurerm_route_table.rt.id subnet_id = azurerm_subnet.webapps.id + depends_on = [ + # meant to resolve AnotherOperation errors with one operation in the vnet at a time + azurerm_subnet_route_table_association.rt_services_subnet_association + ] } diff --git a/templates/workspaces/airlock_manager/terraform/network/outputs.tf b/templates/workspaces/airlock_manager/terraform/network/outputs.tf index 0d2f695af4..99ddbbc28c 100644 --- a/templates/workspaces/airlock_manager/terraform/network/outputs.tf +++ b/templates/workspaces/airlock_manager/terraform/network/outputs.tf @@ -17,3 +17,19 @@ output "blobcore_zone_id" { output "airlock_processor_subnet_id" { value = data.azurerm_subnet.airlockprocessor.id } + +output "azure_monitor_dns_zone_id" { + value = azurerm_private_dns_zone.azure_monitor.id +} + +output "azure_monitor_oms_opinsights_dns_zone_id" { + value = azurerm_private_dns_zone.azure_monitor_oms_opinsights.id +} + +output "azure_monitor_ods_opinsights_dns_zone_id" { + value = azurerm_private_dns_zone.azure_monitor_ods_opinsights.id +} + +output "azure_monitor_agentsvc_dns_zone_id" { + value = azurerm_private_dns_zone.azure_monitor_agentsvc.id +} diff --git a/templates/workspaces/airlock_manager/terraform/network/providers.tf b/templates/workspaces/airlock_manager/terraform/network/providers.tf new file mode 100644 index 0000000000..303382e106 --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/network/providers.tf @@ -0,0 +1,9 @@ +terraform { + # In modules we should only specify the min version + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">= 3.8.0" + } + } +} diff --git a/templates/workspaces/airlock_manager/terraform/network/security.tf b/templates/workspaces/airlock_manager/terraform/network/security.tf index c74808801d..430b575561 100644 --- a/templates/workspaces/airlock_manager/terraform/network/security.tf +++ b/templates/workspaces/airlock_manager/terraform/network/security.tf @@ -10,14 +10,22 @@ resource "azurerm_network_security_group" "ws" { resource "azurerm_subnet_network_security_group_association" "services" { network_security_group_id = azurerm_network_security_group.ws.id subnet_id = azurerm_subnet.services.id + depends_on = [ + # meant to resolve AnotherOperation errors with one operation in the vnet at a time + azurerm_subnet_route_table_association.rt_webapps_subnet_association + ] } resource "azurerm_subnet_network_security_group_association" "webapps" { network_security_group_id = azurerm_network_security_group.ws.id subnet_id = azurerm_subnet.webapps.id + depends_on = [ + # meant to resolve AnotherOperation errors with one operation in the vnet at a time + azurerm_subnet_network_security_group_association.webapps + ] } -resource "azurerm_network_security_rule" "deny-outbound-override" { +resource "azurerm_network_security_rule" "deny_outbound_override" { access = "Deny" destination_address_prefix = "*" destination_port_range = "*" @@ -31,7 +39,7 @@ resource "azurerm_network_security_rule" "deny-outbound-override" { source_port_range = "*" } -resource "azurerm_network_security_rule" "deny-all-inbound-override" { +resource "azurerm_network_security_rule" "deny_all_inbound_override" { access = "Deny" destination_address_prefix = "*" destination_port_range = "*" @@ -45,7 +53,7 @@ resource "azurerm_network_security_rule" "deny-all-inbound-override" { source_port_range = "*" } -resource "azurerm_network_security_rule" "allow-inbound-within-services-subnet" { +resource "azurerm_network_security_rule" "allow_inbound_within_services_subnet" { access = "Allow" destination_port_range = "*" destination_address_prefixes = azurerm_subnet.services.address_prefixes @@ -59,7 +67,7 @@ resource "azurerm_network_security_rule" "allow-inbound-within-services-subnet" source_port_range = "*" } -resource "azurerm_network_security_rule" "allow-outbound-within-services-subnet" { +resource "azurerm_network_security_rule" "allow_outbound_within_services_subnet" { access = "Allow" destination_port_range = "*" destination_address_prefixes = azurerm_subnet.services.address_prefixes @@ -73,7 +81,7 @@ resource "azurerm_network_security_rule" "allow-outbound-within-services-subnet" source_port_range = "*" } -resource "azurerm_network_security_rule" "allow-outbound-to-shared-services" { +resource "azurerm_network_security_rule" "allow_outbound_to_shared_services" { access = "Allow" destination_address_prefixes = data.azurerm_subnet.shared.address_prefixes destination_port_range = "*" @@ -88,7 +96,7 @@ resource "azurerm_network_security_rule" "allow-outbound-to-shared-services" { } -resource "azurerm_network_security_rule" "allow-outbound-to-internet" { +resource "azurerm_network_security_rule" "allow_outbound_to_internet" { access = "Allow" destination_address_prefix = "INTERNET" destination_port_range = "443" @@ -103,7 +111,7 @@ resource "azurerm_network_security_rule" "allow-outbound-to-internet" { } -resource "azurerm_network_security_rule" "allow-outbound-from-webapp-to-core-webapp" { +resource "azurerm_network_security_rule" "allow_outbound_from_webapp_to_core_webapp" { access = "Allow" destination_port_range = "443" destination_address_prefixes = data.azurerm_subnet.core_webapps.address_prefixes @@ -117,7 +125,7 @@ resource "azurerm_network_security_rule" "allow-outbound-from-webapp-to-core-web source_port_range = "*" } -resource "azurerm_network_security_rule" "allow-outbound-webapps-to-services" { +resource "azurerm_network_security_rule" "allow_outbound_webapps_to_services" { access = "Allow" destination_port_ranges = [ "80", @@ -138,7 +146,7 @@ resource "azurerm_network_security_rule" "allow-outbound-webapps-to-services" { source_port_range = "*" } -resource "azurerm_network_security_rule" "allow-inbound-from-bastion" { +resource "azurerm_network_security_rule" "allow_inbound_from_bastion" { access = "Allow" destination_address_prefixes = azurerm_subnet.services.address_prefixes destination_port_ranges = [ @@ -157,7 +165,7 @@ resource "azurerm_network_security_rule" "allow-inbound-from-bastion" { source_port_range = "*" } -resource "azurerm_network_security_rule" "allow-inbound-from-resourceprocessor" { +resource "azurerm_network_security_rule" "allow_inbound_from_resourceprocessor" { access = "Allow" destination_address_prefixes = azurerm_subnet.services.address_prefixes destination_port_range = "443" @@ -174,7 +182,7 @@ resource "azurerm_network_security_rule" "allow-inbound-from-resourceprocessor" } -resource "azurerm_network_security_rule" "allow-inbound-from-airlockprocessor" { +resource "azurerm_network_security_rule" "allow_inbound_from_airlockprocessor" { access = "Allow" destination_address_prefixes = azurerm_subnet.services.address_prefixes destination_port_range = "443" @@ -190,7 +198,7 @@ resource "azurerm_network_security_rule" "allow-inbound-from-airlockprocessor" { source_port_range = "*" } -resource "azurerm_network_security_rule" "allow-inbound-from-webapp-to-services" { +resource "azurerm_network_security_rule" "allow_inbound_from_webapp_to_services" { access = "Allow" destination_port_ranges = [ "80", @@ -210,3 +218,54 @@ resource "azurerm_network_security_rule" "allow-inbound-from-webapp-to-services" resource_group_name = var.ws_resource_group_name source_port_range = "*" } + + + +moved { + from = azurerm_network_security_rule.deny-outbound-overrid + to = azurerm_network_security_rule.deny_outbound_overrid +} +moved { + from = azurerm_network_security_rule.deny-all-inbound-override + to = azurerm_network_security_rule.deny_all_inbound_override +} +moved { + from = azurerm_network_security_rule.allow-inbound-within-services-subnet + to = azurerm_network_security_rule.allow_inbound_within_services_subnet +} +moved { + from = azurerm_network_security_rule.allow-outbound-within-services-subnet + to = azurerm_network_security_rule.allow_outbound_within_services_subnet +} +moved { + from = azurerm_network_security_rule.allow-outbound-to-shared-services + to = azurerm_network_security_rule.allow_outbound_to_shared_services +} +moved { + from = azurerm_network_security_rule.allow-outbound-to-internet + to = azurerm_network_security_rule.allow_outbound_to_internet +} +moved { + from = azurerm_network_security_rule.allow-outbound-from-webapp-to-core-webapp + to = azurerm_network_security_rule.allow_outbound_from_webapp_to_core_webapp +} +moved { + from = azurerm_network_security_rule.allow-outbound-webapps-to-services + to = azurerm_network_security_rule.allow_outbound_webapps_to_services +} +moved { + from = azurerm_network_security_rule.allow-inbound-from-bastion + to = azurerm_network_security_rule.allow_inbound_from_bastion +} +moved { + from = azurerm_network_security_rule.allow-inbound-from-resourceprocessor + to = azurerm_network_security_rule.allow_inbound_from_resourceprocessor +} +moved { + from = azurerm_network_security_rule.allow-inbound-from-airlockprocessor + to = azurerm_network_security_rule.allow_inbound_from_airlockprocessor +} +moved { + from = azurerm_network_security_rule.allow-inbound-from-webapp-to-services + to = azurerm_network_security_rule.allow_inbound_from_webapp_to_services +} diff --git a/templates/workspaces/airlock_manager/terraform/outputs.tf b/templates/workspaces/airlock_manager/terraform/outputs.tf index 5ba52ed6a8..b7b5e85157 100644 --- a/templates/workspaces/airlock_manager/terraform/outputs.tf +++ b/templates/workspaces/airlock_manager/terraform/outputs.tf @@ -13,6 +13,10 @@ output "app_role_id_workspace_researcher" { value = var.register_aad_application ? module.aad[0].app_role_workspace_researcher_id : var.app_role_id_workspace_researcher } +output "app_role_id_workspace_airlock_manager" { + value = var.register_aad_application ? module.aad[0].app_role_workspace_airlock_manager_id : var.app_role_id_workspace_airlock_manager +} + output "client_id" { value = var.register_aad_application ? module.aad[0].client_id : var.client_id } diff --git a/templates/workspaces/airlock_manager/terraform/providers.tf b/templates/workspaces/airlock_manager/terraform/providers.tf index df558f69ed..07233a4bcb 100644 --- a/templates/workspaces/airlock_manager/terraform/providers.tf +++ b/templates/workspaces/airlock_manager/terraform/providers.tf @@ -2,15 +2,15 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "=3.12.0" + version = "=3.16.0" } azuread = { source = "hashicorp/azuread" version = "=2.20.0" } - random = { - source = "hashicorp/random" - version = "=3.1.2" + null = { + source = "hashicorp/null" + version = "~>3.1.0" } } diff --git a/templates/workspaces/airlock_manager/terraform/variables.tf b/templates/workspaces/airlock_manager/terraform/variables.tf index b742b412c2..c4a618cdbc 100644 --- a/templates/workspaces/airlock_manager/terraform/variables.tf +++ b/templates/workspaces/airlock_manager/terraform/variables.tf @@ -47,6 +47,11 @@ variable "register_aad_application" { description = "Create an AAD application automatically for the Workspace." } +variable "enable_airlock" { + type = bool + description = "Controls the deployment of Airlock resources in the workspace." +} + variable "aad_redirect_uris_b64" { type = string # B64 encoded list of objects like [{"name": "my uri 1", "value": "https://..."}, {}] default = "W10=" #b64 for [] @@ -77,6 +82,11 @@ variable "app_role_id_workspace_researcher" { default = "" description = "The id of the application role WorkspaceResearcher in the identity provider, this is passed in so that we may return it as an output." } +variable "app_role_id_workspace_airlock_manager" { + type = string + default = "" + description = "The id of the application role AirlockManager in the identity provider, this is passed in so that we may return it as an output." +} variable "client_id" { type = string default = "" diff --git a/templates/workspaces/airlock_manager/terraform/workspace.tf b/templates/workspaces/airlock_manager/terraform/workspace.tf index f8bb69f33f..5dbeaeafb7 100644 --- a/templates/workspaces/airlock_manager/terraform/workspace.tf +++ b/templates/workspaces/airlock_manager/terraform/workspace.tf @@ -42,6 +42,7 @@ module "aad" { } module "airlock" { + count = var.enable_airlock ? 1 : 0 source = "./airlock" location = var.location tre_id = var.tre_id @@ -55,3 +56,23 @@ module "airlock" { module.network, ] } + + +module "azure_monitor" { + source = "./azure-monitor" + tre_id = var.tre_id + location = var.location + resource_group_name = azurerm_resource_group.ws.name + tre_resource_id = var.tre_resource_id + tre_workspace_tags = local.tre_workspace_tags + workspace_subnet_id = module.network.services_subnet_id + azure_monitor_dns_zone_id = module.network.azure_monitor_dns_zone_id + azure_monitor_oms_opinsights_dns_zone_id = module.network.azure_monitor_oms_opinsights_dns_zone_id + azure_monitor_ods_opinsights_dns_zone_id = module.network.azure_monitor_ods_opinsights_dns_zone_id + azure_monitor_agentsvc_dns_zone_id = module.network.azure_monitor_agentsvc_dns_zone_id + blob_core_dns_zone_id = module.network.blobcore_zone_id + enable_local_debugging = var.enable_local_debugging + depends_on = [ + module.network, + ] +} From 505a2aa3604f23177214c3006c3ec9cf1b120bef Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Thu, 25 Aug 2022 11:01:19 +0100 Subject: [PATCH 03/31] Change descriptions --- templates/workspaces/airlock_manager/parameters.json | 2 +- templates/workspaces/airlock_manager/porter.yaml | 4 ++-- templates/workspaces/airlock_manager/template_schema.json | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/templates/workspaces/airlock_manager/parameters.json b/templates/workspaces/airlock_manager/parameters.json index 42329886b4..f0a0b9e128 100755 --- a/templates/workspaces/airlock_manager/parameters.json +++ b/templates/workspaces/airlock_manager/parameters.json @@ -1,6 +1,6 @@ { "schemaVersion": "1.0.0-DRAFT+TODO", - "name": "base", + "name": "airlock_manager", "created": "2021-06-04T13:37:29.5071039+03:00", "modified": "2021-06-04T13:37:29.5071039+03:00", "parameters": [ diff --git a/templates/workspaces/airlock_manager/porter.yaml b/templates/workspaces/airlock_manager/porter.yaml index 38baf49370..e141ee74f9 100644 --- a/templates/workspaces/airlock_manager/porter.yaml +++ b/templates/workspaces/airlock_manager/porter.yaml @@ -1,7 +1,7 @@ --- -name: tre-workspace-base +name: tre-workspace-airlock-manager version: 0.3.25 -description: "A base Azure TRE workspace" +description: "An Airlock Manager workspace for Azure TRE" dockerfile: Dockerfile.tmpl registry: azuretre diff --git a/templates/workspaces/airlock_manager/template_schema.json b/templates/workspaces/airlock_manager/template_schema.json index db8f728f5a..3a8c116e49 100644 --- a/templates/workspaces/airlock_manager/template_schema.json +++ b/templates/workspaces/airlock_manager/template_schema.json @@ -1,9 +1,9 @@ { "$schema": "http://json-schema.org/draft-07/schema", - "$id": "https://github.com/microsoft/AzureTRE/templates/workspaces/base/template_schema.json", + "$id": "https://github.com/microsoft/AzureTRE/templates/workspaces/airlock_manager/template_schema.json", "type": "object", - "title": "Base Workspace", - "description": "This workspace template is the foundation for TRE workspaces and workspace services.", + "title": "Airlock Manager Workspace", + "description": "This workspace template is intended to conduct Airlock Data Import reviews from.", "required": [], "properties": { "shared_storage_quota": { From 628f8aea5743c769b8100b0086ac15b914923380 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Thu, 25 Aug 2022 11:17:23 +0100 Subject: [PATCH 04/31] remove unused module --- .../airlock_manager/terraform/azure-monitor/providers.tf | 4 ---- 1 file changed, 4 deletions(-) diff --git a/templates/workspaces/airlock_manager/terraform/azure-monitor/providers.tf b/templates/workspaces/airlock_manager/terraform/azure-monitor/providers.tf index 308d332af3..303382e106 100644 --- a/templates/workspaces/airlock_manager/terraform/azure-monitor/providers.tf +++ b/templates/workspaces/airlock_manager/terraform/azure-monitor/providers.tf @@ -5,9 +5,5 @@ terraform { source = "hashicorp/azurerm" version = ">= 3.8.0" } - local = { - source = "hashicorp/local" - version = "~> 2.2.0" - } } } From 7fbebb224761b1a5019096b26b71787943d12c0c Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Mon, 12 Sep 2022 13:49:15 +0100 Subject: [PATCH 05/31] WIP: reusing files from base workspace --- .../airlock_manager/Dockerfile.tmpl | 10 + .../terraform/.terraform.lock.hcl | 102 ------ .../airlock_manager/terraform/aad/aad.tf | 126 ------- .../airlock_manager/terraform/aad/outputs.tf | 23 -- .../terraform/aad/providers.tf | 17 - .../terraform/aad/variables.tf | 7 - .../airlock_manager/terraform/airlock/data.tf | 25 -- .../terraform/airlock/eventgrid_topics.tf | 209 ------------ .../terraform/airlock/locals.tf | 36 -- .../terraform/airlock/providers.tf | 9 - .../terraform/airlock/storage_accounts.tf | 317 ------------------ .../terraform/airlock/variables.tf | 8 - .../terraform/api-permissions.tf | 15 - .../terraform/appserviceplan.tf | 10 - .../terraform/azure-monitor/azure-monitor.tf | 135 -------- .../terraform/azure-monitor/locals.tf | 4 - .../terraform/azure-monitor/outputs.tf | 11 - .../terraform/azure-monitor/providers.tf | 9 - .../terraform/azure-monitor/variables.tf | 12 - .../airlock_manager/terraform/deploy.sh | 15 - .../airlock_manager/terraform/destroy.sh | 16 - .../airlock_manager/terraform/keyvault.tf | 123 ------- .../airlock_manager/terraform/locals.tf | 10 - .../airlock_manager/terraform/network/data.tf | 94 ------ .../terraform/network/dns_zones.tf | 84 ----- .../terraform/network/locals.tf | 9 - .../terraform/network/network.tf | 90 ----- .../terraform/network/outputs.tf | 35 -- .../terraform/network/providers.tf | 9 - .../terraform/network/security.tf | 271 --------------- .../terraform/network/variables.tf | 6 - .../terraform/network/zone_links.tf | 110 ------ .../airlock_manager/terraform/outputs.tf | 30 -- .../airlock_manager/terraform/providers.tf | 41 --- .../airlock_manager/terraform/storage.tf | 81 ----- .../airlock_manager/terraform/variables.tf | 116 ------- .../airlock_manager/terraform/workspace.tf | 78 ----- 37 files changed, 10 insertions(+), 2293 deletions(-) delete mode 100644 templates/workspaces/airlock_manager/terraform/.terraform.lock.hcl delete mode 100644 templates/workspaces/airlock_manager/terraform/aad/aad.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/aad/outputs.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/aad/providers.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/aad/variables.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/airlock/data.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/airlock/eventgrid_topics.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/airlock/locals.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/airlock/providers.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/airlock/storage_accounts.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/airlock/variables.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/api-permissions.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/appserviceplan.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/azure-monitor/azure-monitor.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/azure-monitor/locals.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/azure-monitor/outputs.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/azure-monitor/providers.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/azure-monitor/variables.tf delete mode 100755 templates/workspaces/airlock_manager/terraform/deploy.sh delete mode 100755 templates/workspaces/airlock_manager/terraform/destroy.sh delete mode 100644 templates/workspaces/airlock_manager/terraform/keyvault.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/locals.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/network/data.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/network/dns_zones.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/network/locals.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/network/network.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/network/outputs.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/network/providers.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/network/security.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/network/variables.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/network/zone_links.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/outputs.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/providers.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/storage.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/variables.tf delete mode 100644 templates/workspaces/airlock_manager/terraform/workspace.tf diff --git a/templates/workspaces/airlock_manager/Dockerfile.tmpl b/templates/workspaces/airlock_manager/Dockerfile.tmpl index bf77b0f459..d3b2bd1c76 100644 --- a/templates/workspaces/airlock_manager/Dockerfile.tmpl +++ b/templates/workspaces/airlock_manager/Dockerfile.tmpl @@ -3,11 +3,21 @@ FROM debian:buster-slim ARG BUNDLE_DIR +ARG AZURE_TRE_VERSION="0.4.2" + # Install jq RUN apt-get update && \ apt-get install -y jq="1.5+dfsg-2+b1" --no-install-recommends && \ apt-get clean -y && rm -rf /var/lib/apt/lists/* +WORKDIR $BUNDLE_DIR + +# Copy all files from base workspace (note: some of them will be overwritten with the following COPY command) +RUN curl -o azuretre.tar.gz -L "https://github.com/microsoft/AzureTRE/archive/refs/tags/v${AZURE_TRE_VERSION}.tar.gz" \ + && tar -xzf azuretre.tar.gz "AzureTRE-${AZURE_TRE_VERSION}/templates/workspaces/base" --strip-components=4 --skip-old-files \ + && patch TODO + && rm -rf azuretre.tar.gz + # This is a template Dockerfile for the bundle's invocation image # You can customize it to use different base images, install tools and copy configuration files. # diff --git a/templates/workspaces/airlock_manager/terraform/.terraform.lock.hcl b/templates/workspaces/airlock_manager/terraform/.terraform.lock.hcl deleted file mode 100644 index a03985c9c2..0000000000 --- a/templates/workspaces/airlock_manager/terraform/.terraform.lock.hcl +++ /dev/null @@ -1,102 +0,0 @@ -# This file is maintained automatically by "terraform init". -# Manual edits may be lost in future updates. - -provider "registry.terraform.io/hashicorp/azuread" { - version = "2.20.0" - constraints = ">= 2.20.0, 2.20.0" - hashes = [ - "h1:qKo6WfRyml6w4qcnqDoeTmlWCL/kzng4qOB/5/XAW9g=", - "zh:0262b33661825b54edc0c539415ebdc942ecb3e2cf90af75f7ef134a1f901816", - "zh:0b569b6427e0a1f6c38ad19dd50f036bf65d5b64751e8a083fb36df76337faba", - "zh:1c3e89cf19118fc07d7b04257251fc9897e722c16e0a0df7b07fcd261f8c12e7", - "zh:4f3d017077eb9264ad4047ea0eda87ae7bc76da119f98361d10df27654b5b01c", - "zh:5566a523690f75f5fd4577f24a3194c719ebd22c011bf8619b86594a352afc71", - "zh:6101be64bf464d763585d144ee2cafae4aad74eb2f7f5264340addc9a9f227f7", - "zh:632627f20e48ce7e47f3be86a4d5869eb8412bf8083b5770decbb1e3cc335a1c", - "zh:63e7fbf0a34d7be50a4b83853600be6116a7c1600484d2e7ff2f15cc98abcf6f", - "zh:7909a7a074440e50be426f57e616e920745f8c38288537220f37c2d1ec719452", - "zh:e4f20c9887062a9ae1edcd208112d4d90c12afb7577f943220b54b83de8f10b7", - "zh:eb76ecf86977cd310f3311bc8f0015763c0a91594172a6b2d4ddb3d981d9c28e", - "zh:ffe05338f3e98fcbc5ffcf8b19dab8463849558d2ee6284afc91cdf9636c3330", - ] -} - -provider "registry.terraform.io/hashicorp/azurerm" { - version = "3.16.0" - constraints = ">= 3.8.0, 3.16.0" - hashes = [ - "h1:cBZXnJ4WErrhAzoQ1IMUMkpRlUmr8KQ2a0vLKH6B2a8=", - "zh:02aecc67db3f7cf19bd39ed454824422c43a5dc9f18b44d9547bb79ba66e0beb", - "zh:1775b033e3a29395087d731387efc926251232c4469a6c262f7039669e2f3aed", - "zh:1b955c3134b8fa61486383fee609bc99e46883c9b5148cb8d3bdc3d6d25b1e5e", - "zh:1ca04c35917fcf9f15aa2f24ef52b823575efa213fcb6d241cd189fddb032268", - "zh:20663ca219acc95d1de2129aac941f08eca1093c61cd6775e9c0b239b70a573e", - "zh:28427df342789f106ce500a489c750d7971d67cb58c495274878dc55d52452fe", - "zh:2a2e0755b9ebedbb4dd55de53191ce02e0a5511648610bf816532cd1614f2d7a", - "zh:5cc4c086ff081379070ea8177025a92a53e3c7bec2eabbf8182efa146e05b371", - "zh:5df50ae712c2b6e850b5953d5b89a29aca98ef1ae5fac4cb9225080ac319207c", - "zh:944ec6ceac2a1af58b58c270db90992d5f32614714647f6086ebc42789fa0f15", - "zh:f1e2df2f7db13b234d2cfa5d7c70054df4039532829be6ce8ed11c6f99ba0cf5", - "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", - ] -} - -provider "registry.terraform.io/hashicorp/local" { - version = "2.2.3" - constraints = "~> 2.2.0" - hashes = [ - "h1:aWp5iSUxBGgPv1UnV5yag9Pb0N+U1I0sZb38AXBFO8A=", - "zh:04f0978bb3e052707b8e82e46780c371ac1c66b689b4a23bbc2f58865ab7d5c0", - "zh:6484f1b3e9e3771eb7cc8e8bab8b35f939a55d550b3f4fb2ab141a24269ee6aa", - "zh:78a56d59a013cb0f7eb1c92815d6eb5cf07f8b5f0ae20b96d049e73db915b238", - "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:8aa9950f4c4db37239bcb62e19910c49e47043f6c8587e5b0396619923657797", - "zh:996beea85f9084a725ff0e6473a4594deb5266727c5f56e9c1c7c62ded6addbb", - "zh:9a7ef7a21f48fabfd145b2e2a4240ca57517ad155017e86a30860d7c0c109de3", - "zh:a63e70ac052aa25120113bcddd50c1f3cfe61f681a93a50cea5595a4b2cc3e1c", - "zh:a6e8d46f94108e049ad85dbed60354236dc0b9b5ec8eabe01c4580280a43d3b8", - "zh:bb112ce7efbfcfa0e65ed97fa245ef348e0fd5bfa5a7e4ab2091a9bd469f0a9e", - "zh:d7bec0da5c094c6955efed100f3fe22fca8866859f87c025be1760feb174d6d9", - "zh:fb9f271b72094d07cef8154cd3d50e9aa818a0ea39130bc193132ad7b23076fd", - ] -} - -provider "registry.terraform.io/hashicorp/null" { - version = "3.1.1" - constraints = "~> 3.1.0" - hashes = [ - "h1:71sNUDvmiJcijsvfXpiLCz0lXIBSsEJjMxljt7hxMhw=", - "zh:063466f41f1d9fd0dd93722840c1314f046d8760b1812fa67c34de0afcba5597", - "zh:08c058e367de6debdad35fc24d97131c7cf75103baec8279aba3506a08b53faf", - "zh:73ce6dff935150d6ddc6ac4a10071e02647d10175c173cfe5dca81f3d13d8afe", - "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:8fdd792a626413502e68c195f2097352bdc6a0df694f7df350ed784741eb587e", - "zh:976bbaf268cb497400fd5b3c774d218f3933271864345f18deebe4dcbfcd6afa", - "zh:b21b78ca581f98f4cdb7a366b03ae9db23a73dfa7df12c533d7c19b68e9e72e5", - "zh:b7fc0c1615dbdb1d6fd4abb9c7dc7da286631f7ca2299fb9cd4664258ccfbff4", - "zh:d1efc942b2c44345e0c29bc976594cb7278c38cfb8897b344669eafbc3cddf46", - "zh:e356c245b3cd9d4789bab010893566acace682d7db877e52d40fc4ca34a50924", - "zh:ea98802ba92fcfa8cf12cbce2e9e7ebe999afbf8ed47fa45fc847a098d89468b", - "zh:eff8872458806499889f6927b5d954560f3d74bf20b6043409edf94d26cd906f", - ] -} - -provider "registry.terraform.io/hashicorp/random" { - version = "3.3.2" - constraints = "~> 3.3.0" - hashes = [ - "h1:H5V+7iXol/EHB2+BUMzGlpIiCOdV74H8YjzCxnSAWcg=", - "zh:038293aebfede983e45ee55c328e3fde82ae2e5719c9bd233c324cfacc437f9c", - "zh:07eaeab03a723d83ac1cc218f3a59fceb7bbf301b38e89a26807d1c93c81cef8", - "zh:427611a4ce9d856b1c73bea986d841a969e4c2799c8ac7c18798d0cc42b78d32", - "zh:49718d2da653c06a70ba81fd055e2b99dfd52dcb86820a6aeea620df22cd3b30", - "zh:5574828d90b19ab762604c6306337e6cd430e65868e13ef6ddb4e25ddb9ad4c0", - "zh:7222e16f7833199dabf1bc5401c56d708ec052b2a5870988bc89ff85b68a5388", - "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:b1b2d7d934784d2aee98b0f8f07a8ccfc0410de63493ae2bf2222c165becf938", - "zh:b8f85b6a20bd264fcd0814866f415f0a368d1123cd7879c8ebbf905d370babc8", - "zh:c3813133acc02bbebddf046d9942e8ba5c35fc99191e3eb057957dafc2929912", - "zh:e7a41dbc919d1de800689a81c240c27eec6b9395564630764ebb323ea82ac8a9", - "zh:ee6d23208449a8eaa6c4f203e33f5176fa795b4b9ecf32903dffe6e2574732c2", - ] -} diff --git a/templates/workspaces/airlock_manager/terraform/aad/aad.tf b/templates/workspaces/airlock_manager/terraform/aad/aad.tf deleted file mode 100644 index 0c35da6518..0000000000 --- a/templates/workspaces/airlock_manager/terraform/aad/aad.tf +++ /dev/null @@ -1,126 +0,0 @@ -data "azuread_client_config" "current" {} - -resource "random_uuid" "oauth2_user_impersonation_id" {} -resource "random_uuid" "app_role_workspace_owner_id" {} -resource "random_uuid" "app_role_workspace_researcher_id" {} -resource "random_uuid" "app_role_workspace_airlock_manager_id" {} - -resource "azuread_application" "workspace" { - display_name = var.workspace_resource_name_suffix - identifier_uris = ["api://${var.workspace_resource_name_suffix}"] - owners = [data.azuread_client_config.current.object_id] - - api { - mapped_claims_enabled = true - requested_access_token_version = 2 - - oauth2_permission_scope { - admin_consent_description = "Allow the app to access the Workspace API on behalf of the signed-in user." - admin_consent_display_name = "Access the Workspace API on behalf of signed-in user" - enabled = true - id = random_uuid.oauth2_user_impersonation_id.result - type = "User" - user_consent_description = "Allow the app to access the Workspace API on your behalf." - user_consent_display_name = "Access the Workspace API" - value = "user_impersonation" - } - } - - app_role { - allowed_member_types = ["User", "Application"] - description = "Provides workspace owners access to the Workspace." - display_name = "Workspace Owner" - enabled = true - id = random_uuid.app_role_workspace_owner_id.result - value = "WorkspaceOwner" - } - - app_role { - allowed_member_types = ["User", "Application"] - description = "Provides researchers access to the Workspace." - display_name = "Workspace Researcher" - enabled = true - id = random_uuid.app_role_workspace_researcher_id.result - value = "WorkspaceResearcher" - } - - app_role { - allowed_member_types = ["User", "Application"] - description = "Provides airlock managers access to the Workspace and ability to review airlock requests." - display_name = "Airlock Manager" - enabled = true - id = random_uuid.app_role_workspace_airlock_manager_id.result - value = "AirlockManager" - } - - feature_tags { - enterprise = true - } - - optional_claims { - id_token { - name = "ipaddr" - essential = false - } - - id_token { - name = "email" - essential = false - } - } - - required_resource_access { - resource_app_id = "00000003-0000-0000-c000-000000000000" # Microsoft Graph - - resource_access { - id = "64a6cdd6-aab1-4aaf-94b8-3cc8405e90d0" # Email - type = "Scope" # Delegated - } - resource_access { - id = "37f7f235-527c-4136-accd-4a02d197296e" # Openid - type = "Scope" # Delegated - } - resource_access { - id = "14dad69e-099b-42c9-810b-d002981feec1" # Profile - type = "Scope" # Delegated - } - } - - web { - redirect_uris = jsondecode(base64decode(var.aad_redirect_uris_b64))[*].value - } -} - -resource "azuread_service_principal" "workspace" { - application_id = azuread_application.workspace.application_id - app_role_assignment_required = false - owners = [data.azuread_client_config.current.object_id] - - feature_tags { - enterprise = true - } -} - -resource "azuread_service_principal_password" "workspace" { - service_principal_id = azuread_service_principal.workspace.object_id -} - -resource "azurerm_key_vault_secret" "client_id" { - name = "workspace-client-id" - value = azuread_application.workspace.application_id - key_vault_id = var.key_vault_id - tags = var.tre_workspace_tags -} - -resource "azurerm_key_vault_secret" "client_secret" { - name = "workspace-client-secret" - value = azuread_service_principal_password.workspace.value - key_vault_id = var.key_vault_id - tags = var.tre_workspace_tags -} - -resource "azuread_app_role_assignment" "workspace_owner" { - app_role_id = azuread_service_principal.workspace.app_role_ids["WorkspaceOwner"] - principal_object_id = var.workspace_owner_object_id - resource_object_id = azuread_service_principal.workspace.object_id -} diff --git a/templates/workspaces/airlock_manager/terraform/aad/outputs.tf b/templates/workspaces/airlock_manager/terraform/aad/outputs.tf deleted file mode 100644 index d233607652..0000000000 --- a/templates/workspaces/airlock_manager/terraform/aad/outputs.tf +++ /dev/null @@ -1,23 +0,0 @@ -output "app_role_workspace_owner_id" { - value = random_uuid.app_role_workspace_owner_id.result -} - -output "app_role_workspace_researcher_id" { - value = random_uuid.app_role_workspace_researcher_id.result -} - -output "app_role_workspace_airlock_manager_id" { - value = random_uuid.app_role_workspace_airlock_manager_id.result -} - -output "client_id" { - value = azuread_application.workspace.application_id -} - -output "scope_id" { - value = "api://${var.workspace_resource_name_suffix}" -} - -output "sp_id" { - value = azuread_service_principal.workspace.object_id -} diff --git a/templates/workspaces/airlock_manager/terraform/aad/providers.tf b/templates/workspaces/airlock_manager/terraform/aad/providers.tf deleted file mode 100644 index 5361d62965..0000000000 --- a/templates/workspaces/airlock_manager/terraform/aad/providers.tf +++ /dev/null @@ -1,17 +0,0 @@ -terraform { - # In modules we should only specify the min version - required_providers { - azurerm = { - source = "hashicorp/azurerm" - version = ">= 3.8.0" - } - azuread = { - source = "hashicorp/azuread" - version = ">= 2.20" - } - random = { - source = "hashicorp/random" - version = "~>3.3.0" - } - } -} diff --git a/templates/workspaces/airlock_manager/terraform/aad/variables.tf b/templates/workspaces/airlock_manager/terraform/aad/variables.tf deleted file mode 100644 index 83a5fc217c..0000000000 --- a/templates/workspaces/airlock_manager/terraform/aad/variables.tf +++ /dev/null @@ -1,7 +0,0 @@ -variable "key_vault_id" {} -variable "workspace_resource_name_suffix" {} -variable "workspace_owner_object_id" {} -variable "tre_workspace_tags" {} -variable "aad_redirect_uris_b64" { - type = string # list of objects like [{"name": "my uri 1", "value": "https://..."}, {}] -} diff --git a/templates/workspaces/airlock_manager/terraform/airlock/data.tf b/templates/workspaces/airlock_manager/terraform/airlock/data.tf deleted file mode 100644 index e36e3887b8..0000000000 --- a/templates/workspaces/airlock_manager/terraform/airlock/data.tf +++ /dev/null @@ -1,25 +0,0 @@ -data "azurerm_user_assigned_identity" "airlock_id" { - name = "id-airlock-${var.tre_id}" - resource_group_name = "rg-${var.tre_id}" -} - -data "azurerm_user_assigned_identity" "api_id" { - name = "id-api-${var.tre_id}" - resource_group_name = "rg-${var.tre_id}" -} - -data "azurerm_private_dns_zone" "blobcore" { - name = "privatelink.blob.core.windows.net" - resource_group_name = local.core_resource_group_name -} - -data "azurerm_servicebus_namespace" "airlock_sb" { - name = "sb-${var.tre_id}" - resource_group_name = local.core_resource_group_name -} - -data "azurerm_servicebus_topic" "blob_created" { - name = local.blob_created_topic_name - resource_group_name = local.core_resource_group_name - namespace_name = data.azurerm_servicebus_namespace.airlock_sb.name -} diff --git a/templates/workspaces/airlock_manager/terraform/airlock/eventgrid_topics.tf b/templates/workspaces/airlock_manager/terraform/airlock/eventgrid_topics.tf deleted file mode 100644 index 4297a48a38..0000000000 --- a/templates/workspaces/airlock_manager/terraform/airlock/eventgrid_topics.tf +++ /dev/null @@ -1,209 +0,0 @@ -# System topics - -# Below we assign a SYSTEM-assigned identity for the topics. note that a user-assigned identity will not work. - -resource "azurerm_eventgrid_system_topic" "import_approved_blob_created" { - name = local.import_approved_sys_topic_name - location = var.location - resource_group_name = var.ws_resource_group_name - source_arm_resource_id = azurerm_storage_account.sa_import_approved.id - topic_type = "Microsoft.Storage.StorageAccounts" - - identity { - type = "SystemAssigned" - } - - tags = merge( - var.tre_workspace_tags, - { - Publishers = "airlock;approved-import-sa" - } - ) - - depends_on = [ - azurerm_storage_account.sa_import_approved - ] - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_role_assignment" "servicebus_sender_import_approved_blob_created" { - scope = data.azurerm_servicebus_namespace.airlock_sb.id - role_definition_name = "Azure Service Bus Data Sender" - principal_id = azurerm_eventgrid_system_topic.import_approved_blob_created.identity.0.principal_id - - depends_on = [ - azurerm_eventgrid_system_topic.import_approved_blob_created - ] -} - -resource "azurerm_eventgrid_system_topic" "export_inprogress_blob_created" { - name = local.export_inprogress_sys_topic_name - location = var.location - resource_group_name = var.ws_resource_group_name - source_arm_resource_id = azurerm_storage_account.sa_export_inprogress.id - topic_type = "Microsoft.Storage.StorageAccounts" - - tags = merge( - var.tre_workspace_tags, - { - Publishers = "airlock;inprogress-export-sa" - } - ) - - identity { - type = "SystemAssigned" - } - - depends_on = [ - azurerm_storage_account.sa_export_inprogress, - ] - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_role_assignment" "servicebus_sender_export_inprogress_blob_created" { - scope = data.azurerm_servicebus_namespace.airlock_sb.id - role_definition_name = "Azure Service Bus Data Sender" - principal_id = azurerm_eventgrid_system_topic.export_inprogress_blob_created.identity.0.principal_id - - depends_on = [ - azurerm_eventgrid_system_topic.export_inprogress_blob_created - ] -} - -resource "azurerm_eventgrid_system_topic" "export_rejected_blob_created" { - name = local.export_rejected_sys_topic_name - location = var.location - resource_group_name = var.ws_resource_group_name - source_arm_resource_id = azurerm_storage_account.sa_export_rejected.id - topic_type = "Microsoft.Storage.StorageAccounts" - - tags = merge( - var.tre_workspace_tags, - { - Publishers = "airlock;rejected-export-sa" - } - ) - - identity { - type = "SystemAssigned" - } - - depends_on = [ - azurerm_storage_account.sa_export_rejected, - ] - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_role_assignment" "servicebus_sender_export_rejected_blob_created" { - scope = data.azurerm_servicebus_namespace.airlock_sb.id - role_definition_name = "Azure Service Bus Data Sender" - principal_id = azurerm_eventgrid_system_topic.export_rejected_blob_created.identity.0.principal_id - - depends_on = [ - azurerm_eventgrid_system_topic.export_rejected_blob_created - ] -} - -resource "azurerm_eventgrid_system_topic" "export_blocked_blob_created" { - name = local.export_blocked_sys_topic_name - location = var.location - resource_group_name = var.ws_resource_group_name - source_arm_resource_id = azurerm_storage_account.sa_export_blocked.id - topic_type = "Microsoft.Storage.StorageAccounts" - - tags = merge( - var.tre_workspace_tags, - { - Publishers = "airlock;export-blocked-sa" - } - ) - - identity { - type = "SystemAssigned" - } - - depends_on = [ - azurerm_storage_account.sa_export_blocked, - ] - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_role_assignment" "servicebus_sender_export_blocked_blob_created" { - scope = data.azurerm_servicebus_namespace.airlock_sb.id - role_definition_name = "Azure Service Bus Data Sender" - principal_id = azurerm_eventgrid_system_topic.export_blocked_blob_created.identity.0.principal_id - - depends_on = [ - azurerm_eventgrid_system_topic.export_blocked_blob_created - ] -} - - -## Subscriptions -resource "azurerm_eventgrid_event_subscription" "import_approved_blob_created" { - name = "import-approved-blob-created-${var.short_workspace_id}" - scope = azurerm_storage_account.sa_import_approved.id - - service_bus_topic_endpoint_id = data.azurerm_servicebus_topic.blob_created.id - - delivery_identity { - type = "SystemAssigned" - } - - depends_on = [ - azurerm_eventgrid_system_topic.import_approved_blob_created, - azurerm_role_assignment.servicebus_sender_import_approved_blob_created - ] -} - -resource "azurerm_eventgrid_event_subscription" "export_inprogress_blob_created" { - name = "export-inprogress-blob-created-${var.short_workspace_id}" - scope = azurerm_storage_account.sa_export_inprogress.id - - service_bus_topic_endpoint_id = data.azurerm_servicebus_topic.blob_created.id - - delivery_identity { - type = "SystemAssigned" - } - - depends_on = [ - azurerm_eventgrid_system_topic.export_inprogress_blob_created, - azurerm_role_assignment.servicebus_sender_export_inprogress_blob_created - ] -} - -resource "azurerm_eventgrid_event_subscription" "export_rejected_blob_created" { - name = "export-rejected-blob-created-${var.short_workspace_id}" - scope = azurerm_storage_account.sa_export_rejected.id - - service_bus_topic_endpoint_id = data.azurerm_servicebus_topic.blob_created.id - - delivery_identity { - type = "SystemAssigned" - } - - depends_on = [ - azurerm_eventgrid_system_topic.export_rejected_blob_created, - azurerm_role_assignment.servicebus_sender_export_rejected_blob_created - ] -} - -resource "azurerm_eventgrid_event_subscription" "export_blocked_blob_created" { - name = "export-blocked-blob-created-${var.short_workspace_id}" - scope = azurerm_storage_account.sa_export_blocked.id - - service_bus_topic_endpoint_id = data.azurerm_servicebus_topic.blob_created.id - - delivery_identity { - type = "SystemAssigned" - } - - depends_on = [ - azurerm_eventgrid_system_topic.export_blocked_blob_created, - azurerm_role_assignment.servicebus_sender_export_blocked_blob_created - ] -} diff --git a/templates/workspaces/airlock_manager/terraform/airlock/locals.tf b/templates/workspaces/airlock_manager/terraform/airlock/locals.tf deleted file mode 100644 index f6310739e0..0000000000 --- a/templates/workspaces/airlock_manager/terraform/airlock/locals.tf +++ /dev/null @@ -1,36 +0,0 @@ -locals { - core_resource_group_name = "rg-${var.tre_id}" - workspace_resource_name_suffix = "${var.tre_id}-ws-${var.short_workspace_id}" - - import_approved_sys_topic_name = "evgt-airlock-import-approved-${local.workspace_resource_name_suffix}" - export_inprogress_sys_topic_name = "evgt-airlock-export-inprog-${local.workspace_resource_name_suffix}" - export_rejected_sys_topic_name = "evgt-airlock-export-rejected-${local.workspace_resource_name_suffix}" - export_blocked_sys_topic_name = "evgt-airlock-export-blocked-${local.workspace_resource_name_suffix}" - - blob_created_topic_name = "airlock-blob-created" - - # STorage AirLock IMport APProved - import_approved_storage_name = lower(replace("stalimapp${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) - # STorage AirLock EXport INTernal - export_internal_storage_name = lower(replace("stalexint${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) - # STorage AirLock EXport InProgress - export_inprogress_storage_name = lower(replace("stalexip${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) - # STorage AirLock EXport REJected - export_rejected_storage_name = lower(replace("stalexrej${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) - # STorage AirLock EXport BLOCKED - export_blocked_storage_name = lower(replace("stalexblocked${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) - - airlock_blob_data_contributor = [ - azurerm_storage_account.sa_import_approved.id, - azurerm_storage_account.sa_export_internal.id, - azurerm_storage_account.sa_export_inprogress.id, - azurerm_storage_account.sa_export_rejected.id, - azurerm_storage_account.sa_export_blocked.id - ] - - api_sa_data_contributor = [ - azurerm_storage_account.sa_import_approved.id, - azurerm_storage_account.sa_export_internal.id, - azurerm_storage_account.sa_export_inprogress.id - ] -} diff --git a/templates/workspaces/airlock_manager/terraform/airlock/providers.tf b/templates/workspaces/airlock_manager/terraform/airlock/providers.tf deleted file mode 100644 index 303382e106..0000000000 --- a/templates/workspaces/airlock_manager/terraform/airlock/providers.tf +++ /dev/null @@ -1,9 +0,0 @@ -terraform { - # In modules we should only specify the min version - required_providers { - azurerm = { - source = "hashicorp/azurerm" - version = ">= 3.8.0" - } - } -} diff --git a/templates/workspaces/airlock_manager/terraform/airlock/storage_accounts.tf b/templates/workspaces/airlock_manager/terraform/airlock/storage_accounts.tf deleted file mode 100644 index d873e96b85..0000000000 --- a/templates/workspaces/airlock_manager/terraform/airlock/storage_accounts.tf +++ /dev/null @@ -1,317 +0,0 @@ -# 'Approved' storage account -resource "azurerm_storage_account" "sa_import_approved" { - name = local.import_approved_storage_name - location = var.location - resource_group_name = var.ws_resource_group_name - account_tier = "Standard" - account_replication_type = "LRS" - allow_nested_items_to_be_public = false - - # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. - # This is true ONLY when Hierarchical Namespace is DISABLED - is_hns_enabled = false - - network_rules { - default_action = var.enable_local_debugging ? "Allow" : "Deny" - bypass = ["AzureServices"] - } - - tags = merge( - var.tre_workspace_tags, - { - description = "airlock;import;approved" - } - ) - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_endpoint" "import_approved_pe" { - name = "pe-sa-import-approved-blob-${var.short_workspace_id}" - location = var.location - resource_group_name = var.ws_resource_group_name - subnet_id = var.services_subnet_id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } - - private_dns_zone_group { - name = "private-dns-zone-group-sa-import-approved" - private_dns_zone_ids = [data.azurerm_private_dns_zone.blobcore.id] - } - - private_service_connection { - name = "psc-sa-import-approved-${var.short_workspace_id}" - private_connection_resource_id = azurerm_storage_account.sa_import_approved.id - is_manual_connection = false - subresource_names = ["Blob"] - } -} - - -# 'Drop' location for export -resource "azurerm_storage_account" "sa_export_internal" { - name = local.export_internal_storage_name - location = var.location - resource_group_name = var.ws_resource_group_name - account_tier = "Standard" - account_replication_type = "LRS" - allow_nested_items_to_be_public = false - - # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. - # This is true ONLY when Hierarchical Namespace is DISABLED - is_hns_enabled = false - - network_rules { - default_action = var.enable_local_debugging ? "Allow" : "Deny" - bypass = ["AzureServices"] - } - - tags = merge( - var.tre_workspace_tags, - { - description = "airlock;export;internal" - } - ) - - lifecycle { ignore_changes = [tags] } -} - - -resource "azurerm_private_endpoint" "export_internal_pe" { - name = "pe-sa-export-int-blob-${var.short_workspace_id}" - location = var.location - resource_group_name = var.ws_resource_group_name - subnet_id = var.services_subnet_id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } - - private_dns_zone_group { - name = "private-dns-zone-group-sa-export-int" - private_dns_zone_ids = [data.azurerm_private_dns_zone.blobcore.id] - } - - private_service_connection { - name = "psc-sa-export-int-${var.short_workspace_id}" - private_connection_resource_id = azurerm_storage_account.sa_export_internal.id - is_manual_connection = false - subresource_names = ["Blob"] - } -} - -# 'In-progress' location for export -resource "azurerm_storage_account" "sa_export_inprogress" { - name = local.export_inprogress_storage_name - location = var.location - resource_group_name = var.ws_resource_group_name - account_tier = "Standard" - account_replication_type = "LRS" - allow_nested_items_to_be_public = false - - # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. - # This is true ONLY when Hierarchical Namespace is DISABLED - is_hns_enabled = false - - tags = merge( - var.tre_workspace_tags, - { - description = "airlock;export;inprogress" - } - ) - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_storage_account_network_rules" "sa_export_inprogress_rules" { - storage_account_id = azurerm_storage_account.sa_export_inprogress.id - - # When the Airlock procssor tried to copy data from the export in-progress SA to the Export approved SA, its not using the PE, as the destination is public, hence, allowing this subnet is mandatory - # It might be possible to add PE to this storage instead of opening the fw to this subnet: https://github.com/microsoft/AzureTRE/issues/2098 - virtual_network_subnet_ids = [var.airlock_processor_subnet_id] - - default_action = var.enable_local_debugging ? "Allow" : "Deny" - bypass = ["AzureServices"] -} - - -resource "azurerm_private_endpoint" "export_inprogress_pe" { - name = "pe-sa-ip-export-blob-${var.short_workspace_id}" - location = var.location - resource_group_name = var.ws_resource_group_name - subnet_id = var.services_subnet_id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } - - private_dns_zone_group { - name = "private-dns-zone-group-sa-export-ip" - private_dns_zone_ids = [data.azurerm_private_dns_zone.blobcore.id] - } - - private_service_connection { - name = "psc-sa-export-ip-${var.short_workspace_id}" - private_connection_resource_id = azurerm_storage_account.sa_export_inprogress.id - is_manual_connection = false - subresource_names = ["Blob"] - } -} - -# 'Rejected' location for export -resource "azurerm_storage_account" "sa_export_rejected" { - name = local.export_rejected_storage_name - location = var.location - resource_group_name = var.ws_resource_group_name - account_tier = "Standard" - account_replication_type = "LRS" - allow_nested_items_to_be_public = false - - # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. - # This is true ONLY when Hierarchical Namespace is DISABLED - is_hns_enabled = false - - network_rules { - default_action = var.enable_local_debugging ? "Allow" : "Deny" - bypass = ["AzureServices"] - } - - tags = merge( - var.tre_workspace_tags, - { - description = "airlock;export;rejected" - } - ) - - lifecycle { ignore_changes = [tags] } -} - - -resource "azurerm_private_endpoint" "export_rejected_pe" { - name = "pe-sa-export-rej-blob-${var.short_workspace_id}" - location = var.location - resource_group_name = var.ws_resource_group_name - subnet_id = var.services_subnet_id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } - - private_dns_zone_group { - name = "private-dns-zone-group-sa-export-rej" - private_dns_zone_ids = [data.azurerm_private_dns_zone.blobcore.id] - } - - private_service_connection { - name = "psc-sa-export-rej-${var.short_workspace_id}" - private_connection_resource_id = azurerm_storage_account.sa_export_rejected.id - is_manual_connection = false - subresource_names = ["Blob"] - } -} - -# 'Blocked' location for export -resource "azurerm_storage_account" "sa_export_blocked" { - name = local.export_blocked_storage_name - location = var.location - resource_group_name = var.ws_resource_group_name - account_tier = "Standard" - account_replication_type = "LRS" - allow_nested_items_to_be_public = false - - # Important! we rely on the fact that the blob craeted events are issued when the creation of the blobs are done. - # This is true ONLY when Hierarchical Namespace is DISABLED - is_hns_enabled = false - - network_rules { - default_action = var.enable_local_debugging ? "Allow" : "Deny" - bypass = ["AzureServices"] - } - - tags = merge( - var.tre_workspace_tags, - { - description = "airlock;export;blocked" - } - ) - - lifecycle { ignore_changes = [tags] } -} - - -resource "azurerm_private_endpoint" "export_blocked_pe" { - name = "pe-sa-export-blocked-blob-${var.short_workspace_id}" - location = var.location - resource_group_name = var.ws_resource_group_name - subnet_id = var.services_subnet_id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } - - private_dns_zone_group { - name = "private-dns-zone-group-sa-export-blocked" - private_dns_zone_ids = [data.azurerm_private_dns_zone.blobcore.id] - } - - private_service_connection { - name = "psc-sa-export-blocked-${var.short_workspace_id}" - private_connection_resource_id = azurerm_storage_account.sa_export_blocked.id - is_manual_connection = false - subresource_names = ["Blob"] - } -} - -resource "azurerm_role_assignment" "sa_import_approved" { - scope = azurerm_storage_account.sa_import_approved.id - role_definition_name = "Contributor" - principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id -} - - -resource "azurerm_role_assignment" "sa_export_internal" { - scope = azurerm_storage_account.sa_export_internal.id - role_definition_name = "Contributor" - principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id -} - -resource "azurerm_role_assignment" "sa_export_inprogress" { - scope = azurerm_storage_account.sa_export_inprogress.id - role_definition_name = "Contributor" - principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id -} - -resource "azurerm_role_assignment" "sa_export_rejected" { - scope = azurerm_storage_account.sa_export_rejected.id - role_definition_name = "Contributor" - principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id -} - -resource "azurerm_role_assignment" "sa_export_blocked" { - scope = azurerm_storage_account.sa_export_blocked.id - role_definition_name = "Contributor" - principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id -} - - -resource "azurerm_role_assignment" "sa_import_approved_reader" { - scope = azurerm_storage_account.sa_import_approved.id - role_definition_name = "Reader and Data Access" - principal_id = data.azurerm_user_assigned_identity.api_id.principal_id -} - - -resource "azurerm_role_assignment" "sa_export_internal_reader" { - scope = azurerm_storage_account.sa_export_internal.id - role_definition_name = "Reader and Data Access" - principal_id = data.azurerm_user_assigned_identity.api_id.principal_id -} - -resource "azurerm_role_assignment" "sa_export_inprogress_reader" { - scope = azurerm_storage_account.sa_export_inprogress.id - role_definition_name = "Reader and Data Access" - principal_id = data.azurerm_user_assigned_identity.api_id.principal_id -} - -resource "azurerm_role_assignment" "sa_export_rejected_reader" { - scope = azurerm_storage_account.sa_export_rejected.id - role_definition_name = "Reader and Data Access" - principal_id = data.azurerm_user_assigned_identity.api_id.principal_id -} diff --git a/templates/workspaces/airlock_manager/terraform/airlock/variables.tf b/templates/workspaces/airlock_manager/terraform/airlock/variables.tf deleted file mode 100644 index 4c6aa50b79..0000000000 --- a/templates/workspaces/airlock_manager/terraform/airlock/variables.tf +++ /dev/null @@ -1,8 +0,0 @@ -variable "location" {} -variable "tre_id" {} -variable "ws_resource_group_name" {} -variable "enable_local_debugging" {} -variable "services_subnet_id" {} -variable "airlock_processor_subnet_id" {} -variable "short_workspace_id" {} -variable "tre_workspace_tags" {} diff --git a/templates/workspaces/airlock_manager/terraform/api-permissions.tf b/templates/workspaces/airlock_manager/terraform/api-permissions.tf deleted file mode 100644 index 4bd6fe6aeb..0000000000 --- a/templates/workspaces/airlock_manager/terraform/api-permissions.tf +++ /dev/null @@ -1,15 +0,0 @@ -# The API needs permissions to stop/start VMs - -data "azurerm_user_assigned_identity" "api_id" { - name = "id-api-${var.tre_id}" - resource_group_name = "rg-${var.tre_id}" -} - - -# TODO: the assigned builtin role gives too wide permissions. -# https://github.com/microsoft/AzureTRE/issues/2389 -resource "azurerm_role_assignment" "api_vm_contributor" { - scope = azurerm_resource_group.ws.id - role_definition_name = "Virtual Machine Contributor" - principal_id = data.azurerm_user_assigned_identity.api_id.principal_id -} diff --git a/templates/workspaces/airlock_manager/terraform/appserviceplan.tf b/templates/workspaces/airlock_manager/terraform/appserviceplan.tf deleted file mode 100644 index 5cbafd84c6..0000000000 --- a/templates/workspaces/airlock_manager/terraform/appserviceplan.tf +++ /dev/null @@ -1,10 +0,0 @@ -resource "azurerm_service_plan" "workspace" { - count = var.deploy_app_service_plan ? 1 : 0 - - name = "plan-${var.tre_resource_id}" - location = azurerm_resource_group.ws.location - resource_group_name = azurerm_resource_group.ws.name - os_type = "Linux" - sku_name = var.app_service_plan_sku - tags = local.tre_workspace_tags -} diff --git a/templates/workspaces/airlock_manager/terraform/azure-monitor/azure-monitor.tf b/templates/workspaces/airlock_manager/terraform/azure-monitor/azure-monitor.tf deleted file mode 100644 index 246d307413..0000000000 --- a/templates/workspaces/airlock_manager/terraform/azure-monitor/azure-monitor.tf +++ /dev/null @@ -1,135 +0,0 @@ -resource "azurerm_log_analytics_workspace" "workspace" { - name = "log-${var.tre_id}-ws-${local.short_workspace_id}" - resource_group_name = var.resource_group_name - location = var.location - retention_in_days = 30 - sku = "PerGB2018" - tags = var.tre_workspace_tags - internet_ingestion_enabled = var.enable_local_debugging ? true : false - - lifecycle { ignore_changes = [tags] } -} - -# Storage account for Application Insights -# Because Private Link is enabled on Application Performance Management (APM), Bring Your Own Storage (BYOS) approach is required -resource "azurerm_storage_account" "app_insights" { - name = lower(replace("stai${var.tre_id}ws${local.short_workspace_id}", "-", "")) - resource_group_name = var.resource_group_name - location = var.location - account_kind = "StorageV2" - account_tier = "Standard" - account_replication_type = "LRS" - allow_nested_items_to_be_public = false - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_log_analytics_linked_storage_account" "workspace_storage_ingestion" { - data_source_type = "ingestion" - resource_group_name = var.resource_group_name - workspace_resource_id = azurerm_log_analytics_workspace.workspace.id - storage_account_ids = [azurerm_storage_account.app_insights.id] -} - -resource "azurerm_log_analytics_linked_storage_account" "workspace_storage_customlogs" { - data_source_type = "customlogs" - resource_group_name = var.resource_group_name - workspace_resource_id = azurerm_log_analytics_workspace.workspace.id - storage_account_ids = [azurerm_storage_account.app_insights.id] -} - -resource "azurerm_monitor_private_link_scope" "workspace" { - name = "ampls-${var.tre_id}-ws-${local.short_workspace_id}" - resource_group_name = var.resource_group_name - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_monitor_private_link_scoped_service" "ampls_log_anaytics" { - name = "ampls-log-anaytics-service" - resource_group_name = var.resource_group_name - scope_name = azurerm_monitor_private_link_scope.workspace.name - linked_resource_id = azurerm_log_analytics_workspace.workspace.id -} - - - -# Application Insights - -resource "azurerm_application_insights" "workspace" { - name = "appi-${var.tre_id}-ws-${local.short_workspace_id}" - location = var.location - resource_group_name = var.resource_group_name - workspace_id = azurerm_log_analytics_workspace.workspace.id - application_type = "web" - internet_ingestion_enabled = var.enable_local_debugging ? true : false - force_customer_storage_for_profiler = true - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_monitor_private_link_scoped_service" "ampls_app_insights" { - name = "ampls-app-insights-service" - resource_group_name = var.resource_group_name - scope_name = azurerm_monitor_private_link_scope.workspace.name - linked_resource_id = azurerm_application_insights.workspace.id -} - -resource "azurerm_private_endpoint" "azure_monitor_private_endpoint" { - name = "pe-ampls-${var.tre_id}-ws-${local.short_workspace_id}" - resource_group_name = var.resource_group_name - location = var.location - subnet_id = var.workspace_subnet_id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } - - private_service_connection { - private_connection_resource_id = azurerm_monitor_private_link_scope.workspace.id - name = "psc-ampls-${var.tre_id}-ws-${local.short_workspace_id}" - subresource_names = ["azuremonitor"] - is_manual_connection = false - } - - private_dns_zone_group { - name = "azure-monitor-private-dns-zone-group" - - private_dns_zone_ids = [ - var.azure_monitor_dns_zone_id, - var.azure_monitor_oms_opinsights_dns_zone_id, - var.azure_monitor_ods_opinsights_dns_zone_id, - var.azure_monitor_agentsvc_dns_zone_id, - var.blob_core_dns_zone_id, - ] - } - - depends_on = [ - azurerm_monitor_private_link_scoped_service.ampls_app_insights, - ] -} - -# We don't really need this, but if not present the RG will not be empty and won't be destroyed -# TODO: remove when this is resolved: https://github.com/hashicorp/terraform-provider-azurerm/issues/18026 -resource "azurerm_monitor_action_group" "failure_anomalies" { - name = "${azurerm_application_insights.workspace.name}-failure-anomalies-action-group" - resource_group_name = var.resource_group_name - short_name = "Failures" -} - -# We don't really need this, but if not present the RG will not be empty and won't be destroyed -# TODO: remove when this is resolved: https://github.com/hashicorp/terraform-provider-azurerm/issues/18026 -resource "azurerm_monitor_smart_detector_alert_rule" "failure_anomalies" { - name = "Failure Anomalies - ${local.app_insights_name}" - resource_group_name = var.resource_group_name - severity = "Sev3" - scope_resource_ids = [azurerm_application_insights.workspace.id] - frequency = "PT1M" - detector_type = "FailureAnomaliesDetector" - - action_group { - ids = [azurerm_monitor_action_group.failure_anomalies.id] - } -} diff --git a/templates/workspaces/airlock_manager/terraform/azure-monitor/locals.tf b/templates/workspaces/airlock_manager/terraform/azure-monitor/locals.tf deleted file mode 100644 index 7a5f06bdfe..0000000000 --- a/templates/workspaces/airlock_manager/terraform/azure-monitor/locals.tf +++ /dev/null @@ -1,4 +0,0 @@ -locals { - short_workspace_id = substr(var.tre_resource_id, -4, -1) - app_insights_name = "appi-${var.tre_id}-ws-${local.short_workspace_id}" -} diff --git a/templates/workspaces/airlock_manager/terraform/azure-monitor/outputs.tf b/templates/workspaces/airlock_manager/terraform/azure-monitor/outputs.tf deleted file mode 100644 index e09791912c..0000000000 --- a/templates/workspaces/airlock_manager/terraform/azure-monitor/outputs.tf +++ /dev/null @@ -1,11 +0,0 @@ -output "app_insights_connection_string" { - value = azurerm_application_insights.workspace.connection_string -} - -output "log_analytics_workspace_id" { - value = azurerm_log_analytics_workspace.workspace.id -} - -output "log_analytics_workspace_name" { - value = azurerm_log_analytics_workspace.workspace.name -} diff --git a/templates/workspaces/airlock_manager/terraform/azure-monitor/providers.tf b/templates/workspaces/airlock_manager/terraform/azure-monitor/providers.tf deleted file mode 100644 index 303382e106..0000000000 --- a/templates/workspaces/airlock_manager/terraform/azure-monitor/providers.tf +++ /dev/null @@ -1,9 +0,0 @@ -terraform { - # In modules we should only specify the min version - required_providers { - azurerm = { - source = "hashicorp/azurerm" - version = ">= 3.8.0" - } - } -} diff --git a/templates/workspaces/airlock_manager/terraform/azure-monitor/variables.tf b/templates/workspaces/airlock_manager/terraform/azure-monitor/variables.tf deleted file mode 100644 index 452d974f92..0000000000 --- a/templates/workspaces/airlock_manager/terraform/azure-monitor/variables.tf +++ /dev/null @@ -1,12 +0,0 @@ -variable "tre_id" {} -variable "location" {} -variable "resource_group_name" {} -variable "tre_workspace_tags" {} -variable "workspace_subnet_id" {} -variable "azure_monitor_dns_zone_id" {} -variable "azure_monitor_oms_opinsights_dns_zone_id" {} -variable "azure_monitor_ods_opinsights_dns_zone_id" {} -variable "azure_monitor_agentsvc_dns_zone_id" {} -variable "blob_core_dns_zone_id" {} -variable "tre_resource_id" {} -variable "enable_local_debugging" {} diff --git a/templates/workspaces/airlock_manager/terraform/deploy.sh b/templates/workspaces/airlock_manager/terraform/deploy.sh deleted file mode 100755 index df5663e9e5..0000000000 --- a/templates/workspaces/airlock_manager/terraform/deploy.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -set -e - -# This script is not used and is left here for you to debug the creation of the workspace -# at a Terraform level without having to interact with Porter - -# This script assumes you have created an .env from the sample and the variables -# will come from there. -# shellcheck disable=SC2154 -terraform init -reconfigure -input=false -backend=true \ - -backend-config="resource_group_name=${TF_VAR_mgmt_resource_group_name}" \ - -backend-config="storage_account_name=${TF_VAR_mgmt_storage_account_name}" \ - -backend-config="container_name=${TF_VAR_terraform_state_container_name}" \ - -backend-config="key=${TF_VAR_tre_id}-ws-${TF_VAR_tre_resource_id}" -terraform apply -auto-approve diff --git a/templates/workspaces/airlock_manager/terraform/destroy.sh b/templates/workspaces/airlock_manager/terraform/destroy.sh deleted file mode 100755 index 2414544669..0000000000 --- a/templates/workspaces/airlock_manager/terraform/destroy.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -set -e - -# This script is not used and is left here for you to debug the creation of the workspace -# at a Terraform level without having to interact with Porter - -# This script assumes you have created an .env from the sample and the variables -# will come from there. -# shellcheck disable=SC2154 -terraform init -reconfigure -input=false -backend=true \ - -backend-config="resource_group_name=${TF_VAR_mgmt_resource_group_name}" \ - -backend-config="storage_account_name=${TF_VAR_mgmt_storage_account_name}" \ - -backend-config="container_name=${TF_VAR_terraform_state_container_name}" \ - -backend-config="key=${TF_VAR_tre_id}-ws-${TF_VAR_tre_resource_id}" - -terraform destroy -auto-approve diff --git a/templates/workspaces/airlock_manager/terraform/keyvault.tf b/templates/workspaces/airlock_manager/terraform/keyvault.tf deleted file mode 100644 index 6fa723c55e..0000000000 --- a/templates/workspaces/airlock_manager/terraform/keyvault.tf +++ /dev/null @@ -1,123 +0,0 @@ -data "azurerm_client_config" "current" {} - -resource "azurerm_key_vault" "kv" { - name = local.keyvault_name - location = azurerm_resource_group.ws.location - resource_group_name = azurerm_resource_group.ws.name - sku_name = "standard" - purge_protection_enabled = true - tenant_id = data.azurerm_client_config.current.tenant_id - tags = local.tre_workspace_tags - - network_acls { - bypass = "AzureServices" - default_action = var.enable_local_debugging ? "Allow" : "Deny" - } - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_endpoint" "kvpe" { - name = "kvpe-${local.workspace_resource_name_suffix}" - location = azurerm_resource_group.ws.location - resource_group_name = azurerm_resource_group.ws.name - subnet_id = module.network.services_subnet_id - tags = local.tre_workspace_tags - - depends_on = [ - module.network, - ] - - lifecycle { ignore_changes = [tags] } - - private_dns_zone_group { - name = "private-dns-zone-group" - private_dns_zone_ids = [module.network.vaultcore_zone_id] - } - - private_service_connection { - name = "kvpescv-${local.workspace_resource_name_suffix}" - private_connection_resource_id = azurerm_key_vault.kv.id - is_manual_connection = false - subresource_names = ["Vault"] - } -} - -data "azurerm_user_assigned_identity" "resource_processor_vmss_id" { - name = "id-vmss-${var.tre_id}" - resource_group_name = "rg-${var.tre_id}" -} - -resource "azurerm_key_vault_access_policy" "resource_processor" { - key_vault_id = azurerm_key_vault.kv.id - tenant_id = data.azurerm_user_assigned_identity.resource_processor_vmss_id.tenant_id - object_id = data.azurerm_user_assigned_identity.resource_processor_vmss_id.principal_id - - secret_permissions = ["Get", "List", "Set", "Delete", "Purge", "Recover"] -} - -# If running the terraform locally -resource "azurerm_key_vault_access_policy" "deployer" { - count = var.enable_local_debugging ? 1 : 0 - key_vault_id = azurerm_key_vault.kv.id - tenant_id = data.azurerm_client_config.current.tenant_id - object_id = data.azurerm_client_config.current.object_id - - secret_permissions = ["Get", "List", "Set", "Delete", "Purge", "Recover"] -} - -resource "null_resource" "wait_for_dns_vault" { - provisioner "local-exec" { - command = "bash -c \"sleep 120s\"" - on_failure = fail - } - - triggers = { - always_run = azurerm_private_endpoint.kvpe.private_service_connection[0].private_ip_address # only wait on new/changed private IP address - } - - depends_on = [azurerm_private_endpoint.kvpe] - -} - -resource "azurerm_key_vault_secret" "aad_tenant_id" { - name = "auth-tenant-id" - value = var.auth_tenant_id - key_vault_id = azurerm_key_vault.kv.id - tags = local.tre_workspace_tags - depends_on = [ - azurerm_key_vault_access_policy.deployer, - azurerm_key_vault_access_policy.resource_processor, - null_resource.wait_for_dns_vault - ] -} - -# This secret only gets written if Terraform is not responsible for -# registering the AAD Application -resource "azurerm_key_vault_secret" "client_id" { - name = "workspace-client-id" - value = var.client_id - key_vault_id = azurerm_key_vault.kv.id - count = var.register_aad_application ? 0 : 1 - tags = local.tre_workspace_tags - depends_on = [ - azurerm_key_vault_access_policy.deployer, - azurerm_key_vault_access_policy.resource_processor, - null_resource.wait_for_dns_vault - ] -} - -# This secret only gets written if Terraform is not responsible for -# registering the AAD Application -resource "azurerm_key_vault_secret" "client_secret" { - name = "workspace-client-secret" - value = var.client_secret - key_vault_id = azurerm_key_vault.kv.id - count = var.register_aad_application ? 0 : 1 - tags = local.tre_workspace_tags - depends_on = [ - azurerm_key_vault_access_policy.deployer, - azurerm_key_vault_access_policy.resource_processor, - null_resource.wait_for_dns_vault - ] -} diff --git a/templates/workspaces/airlock_manager/terraform/locals.tf b/templates/workspaces/airlock_manager/terraform/locals.tf deleted file mode 100644 index 35d70e5e9e..0000000000 --- a/templates/workspaces/airlock_manager/terraform/locals.tf +++ /dev/null @@ -1,10 +0,0 @@ -locals { - short_workspace_id = substr(var.tre_resource_id, -4, -1) - workspace_resource_name_suffix = "${var.tre_id}-ws-${local.short_workspace_id}" - storage_name = lower(replace("stg${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) - keyvault_name = lower("kv-${substr(local.workspace_resource_name_suffix, -20, -1)}") - tre_workspace_tags = { - tre_id = var.tre_id - tre_workspace_id = var.tre_resource_id - } -} diff --git a/templates/workspaces/airlock_manager/terraform/network/data.tf b/templates/workspaces/airlock_manager/terraform/network/data.tf deleted file mode 100644 index 1e3efbb97d..0000000000 --- a/templates/workspaces/airlock_manager/terraform/network/data.tf +++ /dev/null @@ -1,94 +0,0 @@ -data "azurerm_virtual_network" "core" { - name = local.core_vnet - resource_group_name = local.core_resource_group_name -} - -data "azurerm_subnet" "core_webapps" { - name = "WebAppSubnet" - virtual_network_name = "vnet-${var.tre_id}" - resource_group_name = "rg-${var.tre_id}" -} - -data "azurerm_subnet" "shared" { - resource_group_name = local.core_resource_group_name - virtual_network_name = local.core_vnet - name = "SharedSubnet" -} - -data "azurerm_subnet" "bastion" { - resource_group_name = local.core_resource_group_name - virtual_network_name = local.core_vnet - name = "AzureBastionSubnet" -} - -data "azurerm_subnet" "resourceprocessor" { - resource_group_name = local.core_resource_group_name - virtual_network_name = local.core_vnet - name = "ResourceProcessorSubnet" -} - -data "azurerm_subnet" "airlockprocessor" { - resource_group_name = local.core_resource_group_name - virtual_network_name = local.core_vnet - name = "AirlockProcessorSubnet" -} - -data "azurerm_route_table" "rt" { - name = "rt-${var.tre_id}" - resource_group_name = local.core_resource_group_name -} - -data "azurerm_private_dns_zone" "azurewebsites" { - name = "privatelink.azurewebsites.net" - resource_group_name = local.core_resource_group_name -} - -data "azurerm_private_dns_zone" "filecore" { - name = "privatelink.file.core.windows.net" - resource_group_name = local.core_resource_group_name -} - -data "azurerm_private_dns_zone" "blobcore" { - name = "privatelink.blob.core.windows.net" - resource_group_name = local.core_resource_group_name -} - -data "azurerm_private_dns_zone" "vaultcore" { - name = "privatelink.vaultcore.azure.net" - resource_group_name = local.core_resource_group_name -} - -data "azurerm_private_dns_zone" "azurecr" { - name = "privatelink.azurecr.io" - resource_group_name = local.core_resource_group_name -} - -data "azurerm_private_dns_zone" "azureml" { - name = "privatelink.api.azureml.ms" - resource_group_name = local.core_resource_group_name -} - -data "azurerm_private_dns_zone" "azuremlcert" { - name = "privatelink.cert.api.azureml.ms" - resource_group_name = local.core_resource_group_name -} - -data "azurerm_private_dns_zone" "notebooks" { - name = "privatelink.notebooks.azure.net" - resource_group_name = local.core_resource_group_name -} - -data "azurerm_private_dns_zone" "mysql" { - name = "privatelink.mysql.database.azure.com" - resource_group_name = local.core_resource_group_name -} - -data "azurerm_private_dns_zone" "postgres" { - name = "privatelink.postgres.database.azure.com" - resource_group_name = local.core_resource_group_name -} - -data "azurerm_private_dns_zone" "nexus" { - name = "nexus-${var.tre_id}.${var.location}.cloudapp.azure.com" - resource_group_name = local.core_resource_group_name -} diff --git a/templates/workspaces/airlock_manager/terraform/network/dns_zones.tf b/templates/workspaces/airlock_manager/terraform/network/dns_zones.tf deleted file mode 100644 index 1b6451c252..0000000000 --- a/templates/workspaces/airlock_manager/terraform/network/dns_zones.tf +++ /dev/null @@ -1,84 +0,0 @@ -# For recommended Azure private DNS zone names see https://docs.microsoft.com/azure/private-link/private-endpoint-dns#azure-services-dns-zone-configuration - -# To enable connecting to Azure Monitor from within a workspace VNET (where traffic is restricted), we need to have an Azure Monitor Private Link Scope (AMPLS) that is connected to a Private Endpoint within the VNET. -# An AMPLS can be connected to multiple Private Endpoints and multiple Azure Monitor resources, but [an AMPLS can only connect to up to 10 Private Endpoints](https://docs.microsoft.com/en-us/azure/azure-monitor/logs/private-link-design#consider-ampls-limits) so the suggestion is to deploy an AMPLS per workspace for simplicity. -# Because there are some shared endpoints (i.e. not resource-specific), a [single AMPLS should be used for all VNETs that share the same DNS](https://docs.microsoft.com/en-us/azure/azure-monitor/logs/private-link-security#azure-monitor-private-links-rely-on-your-dns). Currently, we have separate VNETs for each workspace but each VNET is linked to the same, single private DNS Zone for Azure Monitor/App Insights. To enable an AMPLS per workspace, we need to update the private DNS Zones for Azure Monitor so that the existing zones are just used for the core VNET and deploy separate zones for each workspace. - - -# Azure Monitor requires 5 DNS zones: -# - privatelink.monitor.azure.com -# - privatelink.oms.opinsights.azure.com -# - privatelink.ods.opinsights.azure.com -# - privatelink.agentsvc.azure-automation.net -# - privatelink.blob.core.windows.net (used also by Storage module) -resource "azurerm_private_dns_zone" "azure_monitor" { - name = "privatelink.monitor.azure.com" - resource_group_name = var.ws_resource_group_name - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "azure_monitor" { - name = "azure-monitor-link" - resource_group_name = var.ws_resource_group_name - virtual_network_id = azurerm_virtual_network.ws.id - private_dns_zone_name = azurerm_private_dns_zone.azure_monitor.name - registration_enabled = false - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone" "azure_monitor_oms_opinsights" { - name = "privatelink.oms.opinsights.azure.com" - resource_group_name = var.ws_resource_group_name - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "azure_monitor_oms_opinsights" { - name = "azure-monitor-link" - resource_group_name = var.ws_resource_group_name - virtual_network_id = azurerm_virtual_network.ws.id - private_dns_zone_name = azurerm_private_dns_zone.azure_monitor_oms_opinsights.name - registration_enabled = false - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone" "azure_monitor_ods_opinsights" { - name = "privatelink.ods.opinsights.azure.com" - resource_group_name = var.ws_resource_group_name - tags = var.tre_workspace_tags - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "azure_monitor_ods_opinsights" { - name = "azure-monitor-link" - resource_group_name = var.ws_resource_group_name - virtual_network_id = azurerm_virtual_network.ws.id - private_dns_zone_name = azurerm_private_dns_zone.azure_monitor_ods_opinsights.name - registration_enabled = false - tags = var.tre_workspace_tags - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone" "azure_monitor_agentsvc" { - name = "privatelink.agentsvc.azure-automation.net" - resource_group_name = var.ws_resource_group_name - tags = var.tre_workspace_tags - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "azure_monitor_agentsvc" { - name = "azure-monitor-link" - resource_group_name = var.ws_resource_group_name - virtual_network_id = azurerm_virtual_network.ws.id - private_dns_zone_name = azurerm_private_dns_zone.azure_monitor_agentsvc.name - registration_enabled = false - tags = var.tre_workspace_tags - lifecycle { ignore_changes = [tags] } -} diff --git a/templates/workspaces/airlock_manager/terraform/network/locals.tf b/templates/workspaces/airlock_manager/terraform/network/locals.tf deleted file mode 100644 index f477e8bf9a..0000000000 --- a/templates/workspaces/airlock_manager/terraform/network/locals.tf +++ /dev/null @@ -1,9 +0,0 @@ -locals { - core_vnet = "vnet-${var.tre_id}" - short_workspace_id = substr(var.tre_resource_id, -4, -1) - core_resource_group_name = "rg-${var.tre_id}" - workspace_resource_name_suffix = "${var.tre_id}-ws-${local.short_workspace_id}" - vnet_subnets = cidrsubnets(var.address_space, 1, 1) - services_subnet_address_prefix = local.vnet_subnets[0] - webapps_subnet_address_prefix = local.vnet_subnets[1] -} diff --git a/templates/workspaces/airlock_manager/terraform/network/network.tf b/templates/workspaces/airlock_manager/terraform/network/network.tf deleted file mode 100644 index 1d146933e4..0000000000 --- a/templates/workspaces/airlock_manager/terraform/network/network.tf +++ /dev/null @@ -1,90 +0,0 @@ -resource "azurerm_virtual_network" "ws" { - name = "vnet-${local.workspace_resource_name_suffix}" - location = var.location - resource_group_name = var.ws_resource_group_name - address_space = [var.address_space] - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_subnet" "services" { - name = "ServicesSubnet" - virtual_network_name = azurerm_virtual_network.ws.name - resource_group_name = var.ws_resource_group_name - address_prefixes = [local.services_subnet_address_prefix] - # notice that private endpoints do not adhere to NSG rules - enforce_private_link_endpoint_network_policies = true - enforce_private_link_service_network_policies = true - - # Eventgrid CAN'T send messages over private endpoints, hence we need to allow service endpoints to the service bus - # We are using service endpoints + managed identity to send these messaages - # https://docs.microsoft.com/en-us/azure/event-grid/consume-private-endpoints - service_endpoints = ["Microsoft.ServiceBus"] -} - -resource "azurerm_subnet" "webapps" { - name = "WebAppsSubnet" - virtual_network_name = azurerm_virtual_network.ws.name - resource_group_name = var.ws_resource_group_name - address_prefixes = [local.webapps_subnet_address_prefix] - # notice that private endpoints do not adhere to NSG rules - enforce_private_link_endpoint_network_policies = true - enforce_private_link_service_network_policies = true - - delegation { - name = "delegation" - - service_delegation { - name = "Microsoft.Web/serverFarms" - actions = ["Microsoft.Network/virtualNetworks/subnets/action"] - } - } - - depends_on = [ - # meant to resolve AnotherOperation errors with one operation in the vnet at a time - azurerm_subnet.services - ] -} - -resource "azurerm_virtual_network_peering" "ws_core_peer" { - name = "ws-core-peer-${local.workspace_resource_name_suffix}" - resource_group_name = var.ws_resource_group_name - virtual_network_name = azurerm_virtual_network.ws.name - remote_virtual_network_id = data.azurerm_virtual_network.core.id -} - -moved { - from = azurerm_virtual_network_peering.ws-core-peer - to = azurerm_virtual_network_peering.ws_core_peer -} - -resource "azurerm_virtual_network_peering" "core_ws_peer" { - name = "core-ws-peer-${local.workspace_resource_name_suffix}" - resource_group_name = local.core_resource_group_name - virtual_network_name = local.core_vnet - remote_virtual_network_id = azurerm_virtual_network.ws.id -} - -moved { - from = azurerm_virtual_network_peering.core-ws-peer - to = azurerm_virtual_network_peering.core_ws_peer -} - -resource "azurerm_subnet_route_table_association" "rt_services_subnet_association" { - route_table_id = data.azurerm_route_table.rt.id - subnet_id = azurerm_subnet.services.id - depends_on = [ - # meant to resolve AnotherOperation errors with one operation in the vnet at a time - azurerm_subnet.webapps - ] -} - -resource "azurerm_subnet_route_table_association" "rt_webapps_subnet_association" { - route_table_id = data.azurerm_route_table.rt.id - subnet_id = azurerm_subnet.webapps.id - depends_on = [ - # meant to resolve AnotherOperation errors with one operation in the vnet at a time - azurerm_subnet_route_table_association.rt_services_subnet_association - ] -} diff --git a/templates/workspaces/airlock_manager/terraform/network/outputs.tf b/templates/workspaces/airlock_manager/terraform/network/outputs.tf deleted file mode 100644 index 99ddbbc28c..0000000000 --- a/templates/workspaces/airlock_manager/terraform/network/outputs.tf +++ /dev/null @@ -1,35 +0,0 @@ -output "services_subnet_id" { - value = azurerm_subnet.services.id -} - -output "vaultcore_zone_id" { - value = data.azurerm_private_dns_zone.vaultcore.id -} - -output "filecore_zone_id" { - value = data.azurerm_private_dns_zone.filecore.id -} - -output "blobcore_zone_id" { - value = data.azurerm_private_dns_zone.blobcore.id -} - -output "airlock_processor_subnet_id" { - value = data.azurerm_subnet.airlockprocessor.id -} - -output "azure_monitor_dns_zone_id" { - value = azurerm_private_dns_zone.azure_monitor.id -} - -output "azure_monitor_oms_opinsights_dns_zone_id" { - value = azurerm_private_dns_zone.azure_monitor_oms_opinsights.id -} - -output "azure_monitor_ods_opinsights_dns_zone_id" { - value = azurerm_private_dns_zone.azure_monitor_ods_opinsights.id -} - -output "azure_monitor_agentsvc_dns_zone_id" { - value = azurerm_private_dns_zone.azure_monitor_agentsvc.id -} diff --git a/templates/workspaces/airlock_manager/terraform/network/providers.tf b/templates/workspaces/airlock_manager/terraform/network/providers.tf deleted file mode 100644 index 303382e106..0000000000 --- a/templates/workspaces/airlock_manager/terraform/network/providers.tf +++ /dev/null @@ -1,9 +0,0 @@ -terraform { - # In modules we should only specify the min version - required_providers { - azurerm = { - source = "hashicorp/azurerm" - version = ">= 3.8.0" - } - } -} diff --git a/templates/workspaces/airlock_manager/terraform/network/security.tf b/templates/workspaces/airlock_manager/terraform/network/security.tf deleted file mode 100644 index 430b575561..0000000000 --- a/templates/workspaces/airlock_manager/terraform/network/security.tf +++ /dev/null @@ -1,271 +0,0 @@ -resource "azurerm_network_security_group" "ws" { - location = var.location - name = "nsg-ws" - resource_group_name = var.ws_resource_group_name - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_subnet_network_security_group_association" "services" { - network_security_group_id = azurerm_network_security_group.ws.id - subnet_id = azurerm_subnet.services.id - depends_on = [ - # meant to resolve AnotherOperation errors with one operation in the vnet at a time - azurerm_subnet_route_table_association.rt_webapps_subnet_association - ] -} - -resource "azurerm_subnet_network_security_group_association" "webapps" { - network_security_group_id = azurerm_network_security_group.ws.id - subnet_id = azurerm_subnet.webapps.id - depends_on = [ - # meant to resolve AnotherOperation errors with one operation in the vnet at a time - azurerm_subnet_network_security_group_association.webapps - ] -} - -resource "azurerm_network_security_rule" "deny_outbound_override" { - access = "Deny" - destination_address_prefix = "*" - destination_port_range = "*" - direction = "Outbound" - name = "deny-outbound-override" - network_security_group_name = azurerm_network_security_group.ws.name - priority = 4096 - protocol = "*" - resource_group_name = var.ws_resource_group_name - source_address_prefix = "*" - source_port_range = "*" -} - -resource "azurerm_network_security_rule" "deny_all_inbound_override" { - access = "Deny" - destination_address_prefix = "*" - destination_port_range = "*" - direction = "Inbound" - name = "deny-inbound-override" - network_security_group_name = azurerm_network_security_group.ws.name - priority = 900 - protocol = "*" - resource_group_name = var.ws_resource_group_name - source_address_prefix = "*" - source_port_range = "*" -} - -resource "azurerm_network_security_rule" "allow_inbound_within_services_subnet" { - access = "Allow" - destination_port_range = "*" - destination_address_prefixes = azurerm_subnet.services.address_prefixes - source_address_prefixes = azurerm_subnet.services.address_prefixes - direction = "Inbound" - name = "inbound-within-services-subnet" - network_security_group_name = azurerm_network_security_group.ws.name - priority = 100 - protocol = "*" - resource_group_name = var.ws_resource_group_name - source_port_range = "*" -} - -resource "azurerm_network_security_rule" "allow_outbound_within_services_subnet" { - access = "Allow" - destination_port_range = "*" - destination_address_prefixes = azurerm_subnet.services.address_prefixes - source_address_prefixes = azurerm_subnet.services.address_prefixes - direction = "Outbound" - name = "outbound-within-services-subnet" - network_security_group_name = azurerm_network_security_group.ws.name - priority = 100 - protocol = "*" - resource_group_name = var.ws_resource_group_name - source_port_range = "*" -} - -resource "azurerm_network_security_rule" "allow_outbound_to_shared_services" { - access = "Allow" - destination_address_prefixes = data.azurerm_subnet.shared.address_prefixes - destination_port_range = "*" - direction = "Outbound" - name = "to-shared-services" - network_security_group_name = azurerm_network_security_group.ws.name - priority = 110 - protocol = "*" - resource_group_name = var.ws_resource_group_name - source_address_prefix = "*" - source_port_range = "*" -} - - -resource "azurerm_network_security_rule" "allow_outbound_to_internet" { - access = "Allow" - destination_address_prefix = "INTERNET" - destination_port_range = "443" - direction = "Outbound" - name = "to-internet" - network_security_group_name = azurerm_network_security_group.ws.name - priority = 120 - protocol = "Tcp" - resource_group_name = var.ws_resource_group_name - source_address_prefix = "*" - source_port_range = "*" -} - - -resource "azurerm_network_security_rule" "allow_outbound_from_webapp_to_core_webapp" { - access = "Allow" - destination_port_range = "443" - destination_address_prefixes = data.azurerm_subnet.core_webapps.address_prefixes - source_address_prefixes = azurerm_subnet.webapps.address_prefixes - direction = "Outbound" - name = "outbound-workspace-webapps-to-tre-core-webapps" - network_security_group_name = azurerm_network_security_group.ws.name - priority = 130 - protocol = "Tcp" - resource_group_name = var.ws_resource_group_name - source_port_range = "*" -} - -resource "azurerm_network_security_rule" "allow_outbound_webapps_to_services" { - access = "Allow" - destination_port_ranges = [ - "80", - "443", - "445", - "3306", - "3389", - "5432", - ] - destination_address_prefixes = azurerm_subnet.services.address_prefixes - source_address_prefixes = azurerm_subnet.webapps.address_prefixes - direction = "Outbound" - name = "outbound-from-services-to-webapps-subnets" - network_security_group_name = azurerm_network_security_group.ws.name - priority = 140 - protocol = "Tcp" - resource_group_name = var.ws_resource_group_name - source_port_range = "*" -} - -resource "azurerm_network_security_rule" "allow_inbound_from_bastion" { - access = "Allow" - destination_address_prefixes = azurerm_subnet.services.address_prefixes - destination_port_ranges = [ - "22", - "3389", - ] - direction = "Inbound" - name = "allow-inbound-from-bastion" - network_security_group_name = azurerm_network_security_group.ws.name - priority = 110 - protocol = "Tcp" - resource_group_name = var.ws_resource_group_name - source_address_prefixes = [ - data.azurerm_subnet.bastion.address_prefix - ] - source_port_range = "*" -} - -resource "azurerm_network_security_rule" "allow_inbound_from_resourceprocessor" { - access = "Allow" - destination_address_prefixes = azurerm_subnet.services.address_prefixes - destination_port_range = "443" - direction = "Inbound" - name = "allow-inbound-from-resourceprocessor" - network_security_group_name = azurerm_network_security_group.ws.name - priority = 120 - protocol = "Tcp" - resource_group_name = var.ws_resource_group_name - source_address_prefixes = [ - data.azurerm_subnet.resourceprocessor.address_prefix - ] - source_port_range = "*" -} - - -resource "azurerm_network_security_rule" "allow_inbound_from_airlockprocessor" { - access = "Allow" - destination_address_prefixes = azurerm_subnet.services.address_prefixes - destination_port_range = "443" - direction = "Inbound" - name = "allow-inbound-from-airlockprocessor" - network_security_group_name = azurerm_network_security_group.ws.name - priority = 140 - protocol = "Tcp" - resource_group_name = var.ws_resource_group_name - source_address_prefixes = [ - data.azurerm_subnet.airlockprocessor.address_prefix - ] - source_port_range = "*" -} - -resource "azurerm_network_security_rule" "allow_inbound_from_webapp_to_services" { - access = "Allow" - destination_port_ranges = [ - "80", - "443", - "445", - "3306", - "3389", - "5432", - ] - destination_address_prefixes = azurerm_subnet.services.address_prefixes - source_address_prefixes = azurerm_subnet.webapps.address_prefixes - direction = "Inbound" - name = "inbound-from-webapps-to-services-subnets" - network_security_group_name = azurerm_network_security_group.ws.name - priority = 130 - protocol = "Tcp" - resource_group_name = var.ws_resource_group_name - source_port_range = "*" -} - - - -moved { - from = azurerm_network_security_rule.deny-outbound-overrid - to = azurerm_network_security_rule.deny_outbound_overrid -} -moved { - from = azurerm_network_security_rule.deny-all-inbound-override - to = azurerm_network_security_rule.deny_all_inbound_override -} -moved { - from = azurerm_network_security_rule.allow-inbound-within-services-subnet - to = azurerm_network_security_rule.allow_inbound_within_services_subnet -} -moved { - from = azurerm_network_security_rule.allow-outbound-within-services-subnet - to = azurerm_network_security_rule.allow_outbound_within_services_subnet -} -moved { - from = azurerm_network_security_rule.allow-outbound-to-shared-services - to = azurerm_network_security_rule.allow_outbound_to_shared_services -} -moved { - from = azurerm_network_security_rule.allow-outbound-to-internet - to = azurerm_network_security_rule.allow_outbound_to_internet -} -moved { - from = azurerm_network_security_rule.allow-outbound-from-webapp-to-core-webapp - to = azurerm_network_security_rule.allow_outbound_from_webapp_to_core_webapp -} -moved { - from = azurerm_network_security_rule.allow-outbound-webapps-to-services - to = azurerm_network_security_rule.allow_outbound_webapps_to_services -} -moved { - from = azurerm_network_security_rule.allow-inbound-from-bastion - to = azurerm_network_security_rule.allow_inbound_from_bastion -} -moved { - from = azurerm_network_security_rule.allow-inbound-from-resourceprocessor - to = azurerm_network_security_rule.allow_inbound_from_resourceprocessor -} -moved { - from = azurerm_network_security_rule.allow-inbound-from-airlockprocessor - to = azurerm_network_security_rule.allow_inbound_from_airlockprocessor -} -moved { - from = azurerm_network_security_rule.allow-inbound-from-webapp-to-services - to = azurerm_network_security_rule.allow_inbound_from_webapp_to_services -} diff --git a/templates/workspaces/airlock_manager/terraform/network/variables.tf b/templates/workspaces/airlock_manager/terraform/network/variables.tf deleted file mode 100644 index f27b3fb8a4..0000000000 --- a/templates/workspaces/airlock_manager/terraform/network/variables.tf +++ /dev/null @@ -1,6 +0,0 @@ -variable "location" {} -variable "tre_id" {} -variable "address_space" {} -variable "ws_resource_group_name" {} -variable "tre_workspace_tags" {} -variable "tre_resource_id" {} diff --git a/templates/workspaces/airlock_manager/terraform/network/zone_links.tf b/templates/workspaces/airlock_manager/terraform/network/zone_links.tf deleted file mode 100644 index 2e9e390973..0000000000 --- a/templates/workspaces/airlock_manager/terraform/network/zone_links.tf +++ /dev/null @@ -1,110 +0,0 @@ -resource "azurerm_private_dns_zone_virtual_network_link" "azurewebsites" { - name = "azurewebsites-link-${azurerm_virtual_network.ws.name}" - resource_group_name = local.core_resource_group_name - private_dns_zone_name = data.azurerm_private_dns_zone.azurewebsites.name - virtual_network_id = azurerm_virtual_network.ws.id - registration_enabled = false - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "filecorelink" { - name = "filecorelink-${local.workspace_resource_name_suffix}" - resource_group_name = local.core_resource_group_name - private_dns_zone_name = data.azurerm_private_dns_zone.filecore.name - virtual_network_id = azurerm_virtual_network.ws.id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "blobcorelink" { - name = "blobcorelink-${local.workspace_resource_name_suffix}" - resource_group_name = local.core_resource_group_name - private_dns_zone_name = data.azurerm_private_dns_zone.blobcore.name - virtual_network_id = azurerm_virtual_network.ws.id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "vaultcorelink" { - name = "vaultcorelink-${local.workspace_resource_name_suffix}" - resource_group_name = local.core_resource_group_name - private_dns_zone_name = data.azurerm_private_dns_zone.vaultcore.name - virtual_network_id = azurerm_virtual_network.ws.id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "azurecrlink" { - name = "azurecrlink-${local.workspace_resource_name_suffix}" - resource_group_name = local.core_resource_group_name - private_dns_zone_name = data.azurerm_private_dns_zone.azurecr.name - virtual_network_id = azurerm_virtual_network.ws.id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "azuremllink" { - name = "azuremllink-${local.workspace_resource_name_suffix}" - resource_group_name = local.core_resource_group_name - private_dns_zone_name = data.azurerm_private_dns_zone.azureml.name - virtual_network_id = azurerm_virtual_network.ws.id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "azuremlcertlink" { - name = "azuremlcertlink-${local.workspace_resource_name_suffix}" - resource_group_name = local.core_resource_group_name - private_dns_zone_name = data.azurerm_private_dns_zone.azuremlcert.name - virtual_network_id = azurerm_virtual_network.ws.id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "notebookslink" { - name = "notebookslink-${local.workspace_resource_name_suffix}" - resource_group_name = local.core_resource_group_name - private_dns_zone_name = data.azurerm_private_dns_zone.notebooks.name - virtual_network_id = azurerm_virtual_network.ws.id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "mysqllink" { - name = "mysqllink-${local.workspace_resource_name_suffix}" - resource_group_name = local.core_resource_group_name - private_dns_zone_name = data.azurerm_private_dns_zone.mysql.name - virtual_network_id = azurerm_virtual_network.ws.id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "postgreslink" { - name = "postgreslink-${local.workspace_resource_name_suffix}" - resource_group_name = local.core_resource_group_name - private_dns_zone_name = data.azurerm_private_dns_zone.postgres.name - virtual_network_id = azurerm_virtual_network.ws.id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_private_dns_zone_virtual_network_link" "nexuslink" { - name = "nexuslink-${local.workspace_resource_name_suffix}" - resource_group_name = local.core_resource_group_name - private_dns_zone_name = data.azurerm_private_dns_zone.nexus.name - virtual_network_id = azurerm_virtual_network.ws.id - tags = var.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} diff --git a/templates/workspaces/airlock_manager/terraform/outputs.tf b/templates/workspaces/airlock_manager/terraform/outputs.tf deleted file mode 100644 index b7b5e85157..0000000000 --- a/templates/workspaces/airlock_manager/terraform/outputs.tf +++ /dev/null @@ -1,30 +0,0 @@ -output "workspace_resource_name_suffix" { - value = local.workspace_resource_name_suffix -} - -# The following outputs are dependent on an Automatic AAD Workspace Application Registration. -# If we are not creating an App Reg we simple pass back the same values that were already created -# This is necessary so that we don't delete workspace properties -output "app_role_id_workspace_owner" { - value = var.register_aad_application ? module.aad[0].app_role_workspace_owner_id : var.app_role_id_workspace_owner -} - -output "app_role_id_workspace_researcher" { - value = var.register_aad_application ? module.aad[0].app_role_workspace_researcher_id : var.app_role_id_workspace_researcher -} - -output "app_role_id_workspace_airlock_manager" { - value = var.register_aad_application ? module.aad[0].app_role_workspace_airlock_manager_id : var.app_role_id_workspace_airlock_manager -} - -output "client_id" { - value = var.register_aad_application ? module.aad[0].client_id : var.client_id -} - -output "sp_id" { - value = var.register_aad_application ? module.aad[0].sp_id : var.sp_id -} - -output "scope_id" { - value = var.register_aad_application ? module.aad[0].scope_id : var.scope_id -} diff --git a/templates/workspaces/airlock_manager/terraform/providers.tf b/templates/workspaces/airlock_manager/terraform/providers.tf deleted file mode 100644 index 07233a4bcb..0000000000 --- a/templates/workspaces/airlock_manager/terraform/providers.tf +++ /dev/null @@ -1,41 +0,0 @@ -terraform { - required_providers { - azurerm = { - source = "hashicorp/azurerm" - version = "=3.16.0" - } - azuread = { - source = "hashicorp/azuread" - version = "=2.20.0" - } - null = { - source = "hashicorp/null" - version = "~>3.1.0" - } - } - - backend "azurerm" {} -} - -provider "azurerm" { - features { - key_vault { - # Don't purge on destroy (this would fail due to purge protection being enabled on keyvault) - purge_soft_delete_on_destroy = false - purge_soft_deleted_secrets_on_destroy = false - purge_soft_deleted_certificates_on_destroy = false - purge_soft_deleted_keys_on_destroy = false - # When recreating an environment, recover any previously soft deleted secrets - set to true by default - recover_soft_deleted_key_vaults = true - recover_soft_deleted_secrets = true - recover_soft_deleted_certificates = true - recover_soft_deleted_keys = true - } - } -} - -provider "azuread" { - client_id = var.auth_client_id - client_secret = var.auth_client_secret - tenant_id = var.auth_tenant_id -} diff --git a/templates/workspaces/airlock_manager/terraform/storage.tf b/templates/workspaces/airlock_manager/terraform/storage.tf deleted file mode 100644 index 26bb86f860..0000000000 --- a/templates/workspaces/airlock_manager/terraform/storage.tf +++ /dev/null @@ -1,81 +0,0 @@ -resource "azurerm_storage_account" "stg" { - name = local.storage_name - resource_group_name = azurerm_resource_group.ws.name - location = azurerm_resource_group.ws.location - account_tier = "Standard" - account_replication_type = "GRS" - tags = local.tre_workspace_tags - - lifecycle { ignore_changes = [tags] } -} - -resource "azurerm_storage_share" "shared_storage" { - name = "vm-shared-storage" - storage_account_name = azurerm_storage_account.stg.name - quota = var.shared_storage_quota - - depends_on = [ - azurerm_private_endpoint.stgfilepe, - azurerm_storage_account_network_rules.stgrules - ] -} - -resource "azurerm_storage_account_network_rules" "stgrules" { - storage_account_id = azurerm_storage_account.stg.id - - # When deploying from a local machine we need to "allow" - default_action = var.enable_local_debugging ? "Allow" : "Deny" - bypass = ["AzureServices"] -} - -resource "azurerm_private_endpoint" "stgfilepe" { - name = "stgfilepe-${local.workspace_resource_name_suffix}" - location = azurerm_resource_group.ws.location - resource_group_name = azurerm_resource_group.ws.name - subnet_id = module.network.services_subnet_id - tags = local.tre_workspace_tags - - depends_on = [ - module.network, - ] - - lifecycle { ignore_changes = [tags] } - - private_dns_zone_group { - name = "private-dns-zone-group" - private_dns_zone_ids = [module.network.filecore_zone_id] - } - - private_service_connection { - name = "stgfilepesc-${local.workspace_resource_name_suffix}" - private_connection_resource_id = azurerm_storage_account.stg.id - is_manual_connection = false - subresource_names = ["File"] - } -} - -resource "azurerm_private_endpoint" "stgblobpe" { - name = "stgblobpe-${local.workspace_resource_name_suffix}" - location = azurerm_resource_group.ws.location - resource_group_name = azurerm_resource_group.ws.name - subnet_id = module.network.services_subnet_id - tags = local.tre_workspace_tags - - depends_on = [ - module.network, - ] - - lifecycle { ignore_changes = [tags] } - - private_dns_zone_group { - name = "private-dns-zone-group" - private_dns_zone_ids = [module.network.blobcore_zone_id] - } - - private_service_connection { - name = "stgblobpesc-${local.workspace_resource_name_suffix}" - private_connection_resource_id = azurerm_storage_account.stg.id - is_manual_connection = false - subresource_names = ["Blob"] - } -} diff --git a/templates/workspaces/airlock_manager/terraform/variables.tf b/templates/workspaces/airlock_manager/terraform/variables.tf deleted file mode 100644 index c4a618cdbc..0000000000 --- a/templates/workspaces/airlock_manager/terraform/variables.tf +++ /dev/null @@ -1,116 +0,0 @@ -variable "tre_id" { - type = string - description = "Unique TRE ID" -} - -variable "tre_resource_id" { - type = string - description = "Resource ID" -} - -variable "shared_storage_quota" { - type = number - default = 50 - description = "Quota (in GB) to set for the VM Shared Storage." -} - -variable "location" { - type = string - description = "Azure location (region) for deployment of core TRE services" -} - -variable "address_space" { - type = string - description = "VNet address space for the workspace services" -} - -variable "deploy_app_service_plan" { - type = bool - default = true - description = "Deploy app service plan" -} - -variable "app_service_plan_sku" { - type = string - description = "App Service Plan SKU" -} - -variable "enable_local_debugging" { - type = bool - default = false - description = "This will allow storage account access over the internet. Set to true to allow deploying this from a local machine." -} - -variable "register_aad_application" { - type = bool - default = false - description = "Create an AAD application automatically for the Workspace." -} - -variable "enable_airlock" { - type = bool - description = "Controls the deployment of Airlock resources in the workspace." -} - -variable "aad_redirect_uris_b64" { - type = string # B64 encoded list of objects like [{"name": "my uri 1", "value": "https://..."}, {}] - default = "W10=" #b64 for [] -} - -variable "auth_tenant_id" { - type = string - description = "Used to authenticate into the AAD Tenant to create the AAD App" -} -variable "auth_client_id" { - type = string - description = "Used to authenticate into the AAD Tenant to create the AAD App" -} -variable "auth_client_secret" { - type = string - description = "Used to authenticate into the AAD Tenant to create the AAD App" -} - -# These variables are only passed in if you are not registering an AAD -# application as they need passing back out -variable "app_role_id_workspace_owner" { - type = string - default = "" - description = "The id of the application role WorkspaceOwner in the identity provider, this is passed in so that we may return it as an output." -} -variable "app_role_id_workspace_researcher" { - type = string - default = "" - description = "The id of the application role WorkspaceResearcher in the identity provider, this is passed in so that we may return it as an output." -} -variable "app_role_id_workspace_airlock_manager" { - type = string - default = "" - description = "The id of the application role AirlockManager in the identity provider, this is passed in so that we may return it as an output." -} -variable "client_id" { - type = string - default = "" - description = "The client id of the workspace in the identity provider, this is passed in so that we may return it as an output." -} -variable "client_secret" { - type = string - default = "" - description = "The client secret of the workspace in the identity provider, this is passed in so that we may return it as an output." -} -variable "sp_id" { - type = string - default = "" - description = "The Service Principal in the Identity provider to be able to get claims, this is passed in so that we may return it as an output." -} -variable "scope_id" { - type = string - default = "" - description = "The Service Principal Name or Identifier URI, this is passed in so that we may return it as an output." -} -variable "workspace_owner_object_id" { - type = string - default = "" - description = "The Object Id of the user that you wish to be the Workspace Owner. E.g. the TEST_AUTOMATION_ACCOUNT." -} - - diff --git a/templates/workspaces/airlock_manager/terraform/workspace.tf b/templates/workspaces/airlock_manager/terraform/workspace.tf deleted file mode 100644 index 5dbeaeafb7..0000000000 --- a/templates/workspaces/airlock_manager/terraform/workspace.tf +++ /dev/null @@ -1,78 +0,0 @@ -resource "azurerm_resource_group" "ws" { - location = var.location - name = "rg-${local.workspace_resource_name_suffix}" - tags = merge( - local.tre_workspace_tags, - { - project = "Azure Trusted Research Environment", - source = "https://github.com/microsoft/AzureTRE/" - }, - ) - - lifecycle { ignore_changes = [tags] } -} - -// Networking is causing dependencies issues when some parts are deployed from -// Azure, especially for storage shares. It became quite difficult to figure out the needed -// dependencies for each resource seperatly, so to make it easier we packed all network -// resources as a single module that should be depended on. -module "network" { - source = "./network" - location = var.location - tre_id = var.tre_id - address_space = var.address_space - ws_resource_group_name = azurerm_resource_group.ws.name - tre_resource_id = var.tre_resource_id - tre_workspace_tags = local.tre_workspace_tags -} - -module "aad" { - source = "./aad" - tre_workspace_tags = local.tre_workspace_tags - count = var.register_aad_application ? 1 : 0 - key_vault_id = azurerm_key_vault.kv.id - workspace_resource_name_suffix = local.workspace_resource_name_suffix - workspace_owner_object_id = var.workspace_owner_object_id - aad_redirect_uris_b64 = var.aad_redirect_uris_b64 - depends_on = [ - azurerm_key_vault_access_policy.deployer, - azurerm_key_vault_access_policy.resource_processor, - null_resource.wait_for_dns_vault - ] -} - -module "airlock" { - count = var.enable_airlock ? 1 : 0 - source = "./airlock" - location = var.location - tre_id = var.tre_id - tre_workspace_tags = local.tre_workspace_tags - ws_resource_group_name = azurerm_resource_group.ws.name - enable_local_debugging = var.enable_local_debugging - services_subnet_id = module.network.services_subnet_id - short_workspace_id = local.short_workspace_id - airlock_processor_subnet_id = module.network.airlock_processor_subnet_id - depends_on = [ - module.network, - ] -} - - -module "azure_monitor" { - source = "./azure-monitor" - tre_id = var.tre_id - location = var.location - resource_group_name = azurerm_resource_group.ws.name - tre_resource_id = var.tre_resource_id - tre_workspace_tags = local.tre_workspace_tags - workspace_subnet_id = module.network.services_subnet_id - azure_monitor_dns_zone_id = module.network.azure_monitor_dns_zone_id - azure_monitor_oms_opinsights_dns_zone_id = module.network.azure_monitor_oms_opinsights_dns_zone_id - azure_monitor_ods_opinsights_dns_zone_id = module.network.azure_monitor_ods_opinsights_dns_zone_id - azure_monitor_agentsvc_dns_zone_id = module.network.azure_monitor_agentsvc_dns_zone_id - blob_core_dns_zone_id = module.network.blobcore_zone_id - enable_local_debugging = var.enable_local_debugging - depends_on = [ - module.network, - ] -} From 42e48ef791c060bb27ad13cda20fac42b64b76ad Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Mon, 12 Sep 2022 15:21:24 +0100 Subject: [PATCH 06/31] Add patch file --- .../airlock_manager/Dockerfile.tmpl | 10 +-- .../airlock_manager/workspace_base.diff | 66 +++++++++++++++++++ 2 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 templates/workspaces/airlock_manager/workspace_base.diff diff --git a/templates/workspaces/airlock_manager/Dockerfile.tmpl b/templates/workspaces/airlock_manager/Dockerfile.tmpl index d3b2bd1c76..9588b2b899 100644 --- a/templates/workspaces/airlock_manager/Dockerfile.tmpl +++ b/templates/workspaces/airlock_manager/Dockerfile.tmpl @@ -5,17 +5,15 @@ ARG BUNDLE_DIR ARG AZURE_TRE_VERSION="0.4.2" -# Install jq -RUN apt-get update && \ - apt-get install -y jq="1.5+dfsg-2+b1" --no-install-recommends && \ - apt-get clean -y && rm -rf /var/lib/apt/lists/* +RUN apt-get update \ + && apt-get install --no-install-recommends jq ca-certificates curl patch -y \ + && apt-get clean -y && rm -rf /var/lib/apt/lists/* WORKDIR $BUNDLE_DIR # Copy all files from base workspace (note: some of them will be overwritten with the following COPY command) RUN curl -o azuretre.tar.gz -L "https://github.com/microsoft/AzureTRE/archive/refs/tags/v${AZURE_TRE_VERSION}.tar.gz" \ && tar -xzf azuretre.tar.gz "AzureTRE-${AZURE_TRE_VERSION}/templates/workspaces/base" --strip-components=4 --skip-old-files \ - && patch TODO && rm -rf azuretre.tar.gz # This is a template Dockerfile for the bundle's invocation image @@ -34,6 +32,8 @@ RUN curl -o azuretre.tar.gz -L "https://github.com/microsoft/AzureTRE/archive/r # Use the BUNDLE_DIR build argument to copy files into the bundle COPY . $BUNDLE_DIR +RUN patch -l terraform/airlock/storage_accounts.tf $BUNDLE_DIR/workspace_base.diff + # Mirror plugins to prevent network access at runtime # Remove when available from https://github.com/getporter/terraform-mixin/issues/90 WORKDIR $BUNDLE_DIR/terraform diff --git a/templates/workspaces/airlock_manager/workspace_base.diff b/templates/workspaces/airlock_manager/workspace_base.diff new file mode 100644 index 0000000000..8f42797c31 --- /dev/null +++ b/templates/workspaces/airlock_manager/workspace_base.diff @@ -0,0 +1,66 @@ +262,266c262,264 +< # we can't use for_each due to the data object +< resource "azurerm_role_assignment" "airlock_blob_data_contributor" { +< count = length(local.airlock_blob_data_contributor) +< scope = local.airlock_blob_data_contributor[count.index] +< role_definition_name = "Storage Blob Data Contributor" +--- +> resource "azurerm_role_assignment" "sa_import_approved" { +> scope = azurerm_storage_account.sa_import_approved.id +> role_definition_name = "Contributor" +270,275c268,315 +< # This might be considered redundent since we give Virtual Machine Contributor +< # at the subscription level, but best to be explicit. +< resource "azurerm_role_assignment" "api_sa_data_contributor" { +< count = length(local.api_sa_data_contributor) +< scope = local.api_sa_data_contributor[count.index] +< role_definition_name = "Storage Blob Data Contributor" +--- +> +> resource "azurerm_role_assignment" "sa_export_internal" { +> scope = azurerm_storage_account.sa_export_internal.id +> role_definition_name = "Contributor" +> principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id +> } +> +> resource "azurerm_role_assignment" "sa_export_inprogress" { +> scope = azurerm_storage_account.sa_export_inprogress.id +> role_definition_name = "Contributor" +> principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id +> } +> +> resource "azurerm_role_assignment" "sa_export_rejected" { +> scope = azurerm_storage_account.sa_export_rejected.id +> role_definition_name = "Contributor" +> principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id +> } +> +> resource "azurerm_role_assignment" "sa_export_blocked" { +> scope = azurerm_storage_account.sa_export_blocked.id +> role_definition_name = "Contributor" +> principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id +> } +> +> +> resource "azurerm_role_assignment" "sa_import_approved_reader" { +> scope = azurerm_storage_account.sa_import_approved.id +> role_definition_name = "Reader and Data Access" +> principal_id = data.azurerm_user_assigned_identity.api_id.principal_id +> } +> +> +> resource "azurerm_role_assignment" "sa_export_internal_reader" { +> scope = azurerm_storage_account.sa_export_internal.id +> role_definition_name = "Reader and Data Access" +> principal_id = data.azurerm_user_assigned_identity.api_id.principal_id +> } +> +> resource "azurerm_role_assignment" "sa_export_inprogress_reader" { +> scope = azurerm_storage_account.sa_export_inprogress.id +> role_definition_name = "Reader and Data Access" +> principal_id = data.azurerm_user_assigned_identity.api_id.principal_id +> } +> +> resource "azurerm_role_assignment" "sa_export_rejected_reader" { +> scope = azurerm_storage_account.sa_export_rejected.id +> role_definition_name = "Reader and Data Access" From acd50e939251c0c01d7cb387a32d0cfdba6b9252 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Mon, 12 Sep 2022 17:42:26 +0100 Subject: [PATCH 07/31] wip --- .../airlock_manager/Dockerfile.tmpl | 2 +- .../airlock_manager/workspace_base.diff | 177 +++++++++++------- 2 files changed, 112 insertions(+), 67 deletions(-) diff --git a/templates/workspaces/airlock_manager/Dockerfile.tmpl b/templates/workspaces/airlock_manager/Dockerfile.tmpl index 9588b2b899..c415f97c3e 100644 --- a/templates/workspaces/airlock_manager/Dockerfile.tmpl +++ b/templates/workspaces/airlock_manager/Dockerfile.tmpl @@ -32,7 +32,7 @@ RUN curl -o azuretre.tar.gz -L "https://github.com/microsoft/AzureTRE/archive/r # Use the BUNDLE_DIR build argument to copy files into the bundle COPY . $BUNDLE_DIR -RUN patch -l terraform/airlock/storage_accounts.tf $BUNDLE_DIR/workspace_base.diff +RUN patch -p0 < $BUNDLE_DIR/workspace_base.diff # Mirror plugins to prevent network access at runtime # Remove when available from https://github.com/getporter/terraform-mixin/issues/90 diff --git a/templates/workspaces/airlock_manager/workspace_base.diff b/templates/workspaces/airlock_manager/workspace_base.diff index 8f42797c31..541bb0cb05 100644 --- a/templates/workspaces/airlock_manager/workspace_base.diff +++ b/templates/workspaces/airlock_manager/workspace_base.diff @@ -1,66 +1,111 @@ -262,266c262,264 -< # we can't use for_each due to the data object -< resource "azurerm_role_assignment" "airlock_blob_data_contributor" { -< count = length(local.airlock_blob_data_contributor) -< scope = local.airlock_blob_data_contributor[count.index] -< role_definition_name = "Storage Blob Data Contributor" ---- -> resource "azurerm_role_assignment" "sa_import_approved" { -> scope = azurerm_storage_account.sa_import_approved.id -> role_definition_name = "Contributor" -270,275c268,315 -< # This might be considered redundent since we give Virtual Machine Contributor -< # at the subscription level, but best to be explicit. -< resource "azurerm_role_assignment" "api_sa_data_contributor" { -< count = length(local.api_sa_data_contributor) -< scope = local.api_sa_data_contributor[count.index] -< role_definition_name = "Storage Blob Data Contributor" ---- -> -> resource "azurerm_role_assignment" "sa_export_internal" { -> scope = azurerm_storage_account.sa_export_internal.id -> role_definition_name = "Contributor" -> principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id -> } -> -> resource "azurerm_role_assignment" "sa_export_inprogress" { -> scope = azurerm_storage_account.sa_export_inprogress.id -> role_definition_name = "Contributor" -> principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id -> } -> -> resource "azurerm_role_assignment" "sa_export_rejected" { -> scope = azurerm_storage_account.sa_export_rejected.id -> role_definition_name = "Contributor" -> principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id -> } -> -> resource "azurerm_role_assignment" "sa_export_blocked" { -> scope = azurerm_storage_account.sa_export_blocked.id -> role_definition_name = "Contributor" -> principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id -> } -> -> -> resource "azurerm_role_assignment" "sa_import_approved_reader" { -> scope = azurerm_storage_account.sa_import_approved.id -> role_definition_name = "Reader and Data Access" -> principal_id = data.azurerm_user_assigned_identity.api_id.principal_id -> } -> -> -> resource "azurerm_role_assignment" "sa_export_internal_reader" { -> scope = azurerm_storage_account.sa_export_internal.id -> role_definition_name = "Reader and Data Access" -> principal_id = data.azurerm_user_assigned_identity.api_id.principal_id -> } -> -> resource "azurerm_role_assignment" "sa_export_inprogress_reader" { -> scope = azurerm_storage_account.sa_export_inprogress.id -> role_definition_name = "Reader and Data Access" -> principal_id = data.azurerm_user_assigned_identity.api_id.principal_id -> } -> -> resource "azurerm_role_assignment" "sa_export_rejected_reader" { -> scope = azurerm_storage_account.sa_export_rejected.id -> role_definition_name = "Reader and Data Access" +diff -Naur ../base/terraform/airlock/storage_accounts.tf terraform/airlock/storage_accounts.tf +--- ../base/terraform/airlock/storage_accounts.tf 2022-08-17 12:09:06.000000000 +0100 ++++ terraform/airlock/storage_accounts.tf 2022-09-12 17:29:41.000000000 +0100 +@@ -259,19 +259,59 @@ + } + } + +-# we can't use for_each due to the data object +-resource "azurerm_role_assignment" "airlock_blob_data_contributor" { +- count = length(local.airlock_blob_data_contributor) +- scope = local.airlock_blob_data_contributor[count.index] +- role_definition_name = "Storage Blob Data Contributor" ++resource "azurerm_role_assignment" "sa_import_approved" { ++ scope = azurerm_storage_account.sa_import_approved.id ++ role_definition_name = "Contributor" + principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id + } + +-# This might be considered redundent since we give Virtual Machine Contributor +-# at the subscription level, but best to be explicit. +-resource "azurerm_role_assignment" "api_sa_data_contributor" { +- count = length(local.api_sa_data_contributor) +- scope = local.api_sa_data_contributor[count.index] +- role_definition_name = "Storage Blob Data Contributor" ++ ++resource "azurerm_role_assignment" "sa_export_internal" { ++ scope = azurerm_storage_account.sa_export_internal.id ++ role_definition_name = "Contributor" ++ principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id ++} ++ ++resource "azurerm_role_assignment" "sa_export_inprogress" { ++ scope = azurerm_storage_account.sa_export_inprogress.id ++ role_definition_name = "Contributor" ++ principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id ++} ++ ++resource "azurerm_role_assignment" "sa_export_rejected" { ++ scope = azurerm_storage_account.sa_export_rejected.id ++ role_definition_name = "Contributor" ++ principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id ++} ++ ++resource "azurerm_role_assignment" "sa_export_blocked" { ++ scope = azurerm_storage_account.sa_export_blocked.id ++ role_definition_name = "Contributor" ++ principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id ++} ++ ++ ++resource "azurerm_role_assignment" "sa_import_approved_reader" { ++ scope = azurerm_storage_account.sa_import_approved.id ++ role_definition_name = "Reader and Data Access" ++ principal_id = data.azurerm_user_assigned_identity.api_id.principal_id ++} ++ ++ ++resource "azurerm_role_assignment" "sa_export_internal_reader" { ++ scope = azurerm_storage_account.sa_export_internal.id ++ role_definition_name = "Reader and Data Access" ++ principal_id = data.azurerm_user_assigned_identity.api_id.principal_id ++} ++ ++resource "azurerm_role_assignment" "sa_export_inprogress_reader" { ++ scope = azurerm_storage_account.sa_export_inprogress.id ++ role_definition_name = "Reader and Data Access" ++ principal_id = data.azurerm_user_assigned_identity.api_id.principal_id ++} ++ ++resource "azurerm_role_assignment" "sa_export_rejected_reader" { ++ scope = azurerm_storage_account.sa_export_rejected.id ++ role_definition_name = "Reader and Data Access" + principal_id = data.azurerm_user_assigned_identity.api_id.principal_id + } +diff -Naur ../base/terraform/storage.tf terraform/storage.tf +--- ../base/terraform/storage.tf 2022-08-10 10:15:54.000000000 +0100 ++++ terraform/storage.tf 2022-09-12 17:29:41.000000000 +0100 +@@ -9,17 +9,6 @@ + lifecycle { ignore_changes = [tags] } + } + +-resource "azurerm_storage_share" "shared_storage" { +- name = "vm-shared-storage" +- storage_account_name = azurerm_storage_account.stg.name +- quota = var.shared_storage_quota +- +- depends_on = [ +- azurerm_private_endpoint.stgfilepe, +- azurerm_storage_account_network_rules.stgrules +- ] +-} +- + resource "azurerm_storage_account_network_rules" "stgrules" { + storage_account_id = azurerm_storage_account.stg.id + +diff -Naur ../base/terraform/variables.tf terraform/variables.tf +--- ../base/terraform/variables.tf 2022-08-12 19:02:29.000000000 +0100 ++++ terraform/variables.tf 2022-09-12 17:29:41.000000000 +0100 +@@ -8,12 +8,6 @@ + description = "Resource ID" + } + +-variable "shared_storage_quota" { +- type = number +- default = 50 +- description = "Quota (in GB) to set for the VM Shared Storage." +-} +- + variable "location" { + type = string + description = "Azure location (region) for deployment of core TRE services" From f39fbd9da380c009452a746d5d63d69bc3fb4369 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Mon, 12 Sep 2022 17:42:42 +0100 Subject: [PATCH 08/31] wip: add testing script --- templates/workspaces/airlock_manager/test.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100755 templates/workspaces/airlock_manager/test.sh diff --git a/templates/workspaces/airlock_manager/test.sh b/templates/workspaces/airlock_manager/test.sh new file mode 100755 index 0000000000..c30d8785ab --- /dev/null +++ b/templates/workspaces/airlock_manager/test.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +AZURE_TRE_VERSION="0.4.2" + +# apt-get update \ +# && apt-get install --no-install-recommends jq ca-certificates curl patch -y \ +# && apt-get clean -y && rm -rf /var/lib/apt/lists/* + +# WORKDIR $BUNDLE_DIR + +# Copy all files from base workspace (note: some of them will be overwritten with the following COPY command) +curl -o azuretre.tar.gz -L "https://github.com/microsoft/AzureTRE/archive/refs/tags/v${AZURE_TRE_VERSION}.tar.gz" \ + && tar -xzf azuretre.tar.gz "AzureTRE-${AZURE_TRE_VERSION}/templates/workspaces/base" --strip-components=4 --skip-old-files \ + && rm -rf azuretre.tar.gz + +echo DOWNLOADED + +patch -p0 < ./workspace_base.diff From c930577eb6559c777be09de8197383f89a7e0575 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Mon, 12 Sep 2022 17:42:51 +0100 Subject: [PATCH 09/31] wip: add testing makefile command --- Makefile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 9b3785d6c8..d0b8ab32a0 100644 --- a/Makefile +++ b/Makefile @@ -290,11 +290,7 @@ build-and-deploy-ui: && if [ "$${DEPLOY_UI}" != "false" ]; then ${MAKEFILE_DIR}/devops/scripts/build_deploy_ui.sh; else echo "UI Deploy skipped as DEPLOY_UI is false"; fi \ prepare-for-e2e: - $(call workspace_bundle,base) \ - && $(call workspace_service_bundle,guacamole) \ - && $(call shared_service_bundle,gitea) \ - && $(call user_resource_bundle,guacamole,guacamole-azure-windowsvm) \ - && $(call user_resource_bundle,guacamole,guacamole-azure-linuxvm) + $(call workspace_bundle,airlock_manager) test-e2e-smoke: $(call target_title, "Running E2E smoke tests") && \ From 062d43d59803d55fe07caff9e2f333e498f4a6e1 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Mon, 12 Sep 2022 18:05:06 +0100 Subject: [PATCH 10/31] wip --- .../airlock_manager/workspace_base.diff | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/templates/workspaces/airlock_manager/workspace_base.diff b/templates/workspaces/airlock_manager/workspace_base.diff index 541bb0cb05..28046151db 100644 --- a/templates/workspaces/airlock_manager/workspace_base.diff +++ b/templates/workspaces/airlock_manager/workspace_base.diff @@ -1,10 +1,10 @@ diff -Naur ../base/terraform/airlock/storage_accounts.tf terraform/airlock/storage_accounts.tf --- ../base/terraform/airlock/storage_accounts.tf 2022-08-17 12:09:06.000000000 +0100 -+++ terraform/airlock/storage_accounts.tf 2022-09-12 17:29:41.000000000 +0100 ++++ terraform/airlock/storage_accounts.tf 2022-09-12 17:42:55.000000000 +0100 @@ -259,19 +259,59 @@ } } - + -# we can't use for_each due to the data object -resource "azurerm_role_assignment" "airlock_blob_data_contributor" { - count = length(local.airlock_blob_data_contributor) @@ -15,7 +15,7 @@ diff -Naur ../base/terraform/airlock/storage_accounts.tf terraform/airlock/stora + role_definition_name = "Contributor" principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id } - + -# This might be considered redundent since we give Virtual Machine Contributor -# at the subscription level, but best to be explicit. -resource "azurerm_role_assignment" "api_sa_data_contributor" { @@ -74,11 +74,11 @@ diff -Naur ../base/terraform/airlock/storage_accounts.tf terraform/airlock/stora } diff -Naur ../base/terraform/storage.tf terraform/storage.tf --- ../base/terraform/storage.tf 2022-08-10 10:15:54.000000000 +0100 -+++ terraform/storage.tf 2022-09-12 17:29:41.000000000 +0100 ++++ terraform/storage.tf 2022-09-12 17:42:55.000000000 +0100 @@ -9,17 +9,6 @@ lifecycle { ignore_changes = [tags] } } - + -resource "azurerm_storage_share" "shared_storage" { - name = "vm-shared-storage" - storage_account_name = azurerm_storage_account.stg.name @@ -92,14 +92,14 @@ diff -Naur ../base/terraform/storage.tf terraform/storage.tf - resource "azurerm_storage_account_network_rules" "stgrules" { storage_account_id = azurerm_storage_account.stg.id - + diff -Naur ../base/terraform/variables.tf terraform/variables.tf --- ../base/terraform/variables.tf 2022-08-12 19:02:29.000000000 +0100 -+++ terraform/variables.tf 2022-09-12 17:29:41.000000000 +0100 ++++ terraform/variables.tf 2022-09-12 17:42:55.000000000 +0100 @@ -8,12 +8,6 @@ description = "Resource ID" } - + -variable "shared_storage_quota" { - type = number - default = 50 From 42e197ab8ed289384625377d7ff96216fbadc555 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Tue, 13 Sep 2022 10:37:28 +0100 Subject: [PATCH 11/31] Add empty terraform directory --- templates/workspaces/airlock_manager/terraform/empty.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 templates/workspaces/airlock_manager/terraform/empty.txt diff --git a/templates/workspaces/airlock_manager/terraform/empty.txt b/templates/workspaces/airlock_manager/terraform/empty.txt new file mode 100644 index 0000000000..c77897746a --- /dev/null +++ b/templates/workspaces/airlock_manager/terraform/empty.txt @@ -0,0 +1 @@ +The porter terraform mixin requires this directory to exist in the local build context. From daa25a5c726ee1c72ce9d58c6548b4db2f59689b Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Tue, 13 Sep 2022 10:37:40 +0100 Subject: [PATCH 12/31] remove testing script --- templates/workspaces/airlock_manager/test.sh | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100755 templates/workspaces/airlock_manager/test.sh diff --git a/templates/workspaces/airlock_manager/test.sh b/templates/workspaces/airlock_manager/test.sh deleted file mode 100755 index c30d8785ab..0000000000 --- a/templates/workspaces/airlock_manager/test.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -AZURE_TRE_VERSION="0.4.2" - -# apt-get update \ -# && apt-get install --no-install-recommends jq ca-certificates curl patch -y \ -# && apt-get clean -y && rm -rf /var/lib/apt/lists/* - -# WORKDIR $BUNDLE_DIR - -# Copy all files from base workspace (note: some of them will be overwritten with the following COPY command) -curl -o azuretre.tar.gz -L "https://github.com/microsoft/AzureTRE/archive/refs/tags/v${AZURE_TRE_VERSION}.tar.gz" \ - && tar -xzf azuretre.tar.gz "AzureTRE-${AZURE_TRE_VERSION}/templates/workspaces/base" --strip-components=4 --skip-old-files \ - && rm -rf azuretre.tar.gz - -echo DOWNLOADED - -patch -p0 < ./workspace_base.diff From 5c5de76b486cce8436316da3b65fde5b1670ad72 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Tue, 13 Sep 2022 10:38:06 +0100 Subject: [PATCH 13/31] revert makefile change --- Makefile | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index d0b8ab32a0..9bfc9702c8 100644 --- a/Makefile +++ b/Makefile @@ -11,13 +11,18 @@ LINTER_REGEX_INCLUDE?=all # regular expression used to specify which files to in target_title = @echo -e "\n\e[34m»»» 🧩 \e[96m$(1)\e[0m..." all: bootstrap mgmt-deploy images tre-deploy -tre-deploy: deploy-core build-and-deploy-ui firewall-install db-migrate show-core-output +tre-deploy: deploy-core build-and-deploy-ui deploy-shared-services db-migrate show-core-output images: build-and-push-api build-and-push-resource-processor build-and-push-airlock-processor build-and-push-api: build-api-image push-api-image build-and-push-resource-processor: build-resource-processor-vm-porter-image push-resource-processor-vm-porter-image build-and-push-airlock-processor: build-airlock-processor push-airlock-processor +deploy-shared-services: firewall-install + . ${MAKEFILE_DIR}/devops/scripts/load_env.sh ./templates/core/.env \ + && if [ "$${DEPLOY_GITEA}" == "true" ]; then $(MAKE) gitea-install; fi \ + && if [ "$${DEPLOY_NEXUS}" == "true" ]; then $(MAKE) nexus-install; fi + # to move your environment from the single 'core' deployment (which includes the firewall) # toward the shared services model, where it is split out - run the following make target before a tre-deploy # This will remove + import the resource state into a shared service @@ -102,10 +107,7 @@ prepare-tf-state: deploy-core: tre-start $(call target_title, "Deploying TRE") \ && . ${MAKEFILE_DIR}/devops/scripts/check_dependencies.sh nodocker,env,auth \ - && if [[ "$${TF_LOG}" == "DEBUG" ]]; \ - then echo "TF DEBUG set - output supressed - see tflogs container for log file" && cd ${MAKEFILE_DIR}/templates/core/terraform/ \ - && ./deploy.sh 1>/dev/null 2>/dev/null; \ - else cd ${MAKEFILE_DIR}/templates/core/terraform/ && ./deploy.sh; fi; + && if [[ "$${TF_LOG}" == "DEBUG" ]]; then echo "TF DEBUG set - output supressed - see tflogs container for log file" && cd ${MAKEFILE_DIR}/templates/core/terraform/ && ./deploy.sh 1>/dev/null 2>/dev/null; else cd ${MAKEFILE_DIR}/templates/core/terraform/ && ./deploy.sh; fi; letsencrypt: $(call target_title, "Requesting LetsEncrypt SSL certificate") \ @@ -166,11 +168,9 @@ lint: -e VALIDATE_BASH_EXEC=true \ -e VALIDATE_GITHUB_ACTIONS=true \ -e VALIDATE_DOCKERFILE_HADOLINT=true \ - -e VALIDATE_TSX=true \ - -e VALIDATE_TYPESCRIPT_ES=true \ -e FILTER_REGEX_INCLUDE=${LINTER_REGEX_INCLUDE} \ -v $${LOCAL_WORKSPACE_FOLDER}:/tmp/lint \ - github/super-linter:slim-v4.9.6 + github/super-linter:slim-v4.9.5 lint-docs: LINTER_REGEX_INCLUDE='./docs/.*\|./mkdocs.yml' $(MAKE) lint @@ -247,9 +247,7 @@ bundle-register: && az acr login --name $${ACR_NAME} \ && . ${MAKEFILE_DIR}/devops/scripts/get_access_token.sh \ && cd ${DIR} \ - && ${MAKEFILE_DIR}/devops/scripts/register_bundle_with_api.sh --acr-name "$${ACR_NAME}" --bundle-type "$${BUNDLE_TYPE}" \ - --current --insecure --tre_url "$${TRE_URL:-https://$${TRE_ID}.$${LOCATION}.cloudapp.azure.com}" --verify \ - --workspace-service-name "$${WORKSPACE_SERVICE_NAME}" + && ${MAKEFILE_DIR}/devops/scripts/register_bundle_with_api.sh --acr-name "$${ACR_NAME}" --bundle-type "$${BUNDLE_TYPE}" --current --insecure --tre_url "$${TRE_URL:-https://$${TRE_ID}.$${LOCATION}.cloudapp.azure.com}" --verify --workspace-service-name "$${WORKSPACE_SERVICE_NAME}" workspace_bundle = $(MAKE) bundle-build bundle-publish bundle-register \ DIR="${MAKEFILE_DIR}/templates/workspaces/$(1)" BUNDLE_TYPE=workspace @@ -275,6 +273,18 @@ firewall-install: $(MAKE) bundle-build bundle-publish bundle-register deploy-shared-service \ DIR=${MAKEFILE_DIR}/templates/shared_services/firewall/ BUNDLE_TYPE=shared_service +nexus-install: + $(MAKE) bundle-build bundle-publish bundle-register deploy-shared-service \ + DIR="${MAKEFILE_DIR}/templates/shared_services/certs" BUNDLE_TYPE=shared_service PROPS="--domain_prefix nexus --cert_name nexus-ssl" \ + && $(MAKE) bundle-build bundle-publish bundle-register deploy-shared-service \ + DIR=${MAKEFILE_DIR}/templates/shared_services/sonatype-nexus-vm/ BUNDLE_TYPE=shared_service PROPS="--ssl_cert_name nexus-ssl" + +gitea-install: + $(MAKE) bundle-build bundle-publish bundle-register deploy-shared-service DIR=${MAKEFILE_DIR}/templates/shared_services/gitea/ BUNDLE_TYPE=shared_service + +temp-do-upload: + $(MAKE) static-web-upload DIR=${MAKEFILE_DIR}/dummy + static-web-upload: $(call target_title, "Uploading to static website") \ && . ${MAKEFILE_DIR}/devops/scripts/check_dependencies.sh nodocker,env,auth \ @@ -287,10 +297,14 @@ build-and-deploy-ui: && . ${MAKEFILE_DIR}/devops/scripts/check_dependencies.sh nodocker,env,auth \ && pushd ${MAKEFILE_DIR}/templates/core/terraform/ > /dev/null && . ./outputs.sh && popd > /dev/null \ && . ${MAKEFILE_DIR}/devops/scripts/load_env.sh ${MAKEFILE_DIR}/templates/core/private.env \ - && if [ "$${DEPLOY_UI}" != "false" ]; then ${MAKEFILE_DIR}/devops/scripts/build_deploy_ui.sh; else echo "UI Deploy skipped as DEPLOY_UI is false"; fi \ + && if [ "$${DEPLOY_UI}" == "true" ]; then ${MAKEFILE_DIR}/devops/scripts/build_deploy_ui.sh; else echo "UI Deploy skipped as DEPLOY_UI not true"; fi \ prepare-for-e2e: - $(call workspace_bundle,airlock_manager) + $(call workspace_bundle,base) \ + && $(call workspace_service_bundle,guacamole) \ + && $(call shared_service_bundle,gitea) \ + && $(call user_resource_bundle,guacamole,guacamole-azure-windowsvm) \ + && $(call user_resource_bundle,guacamole,guacamole-azure-linuxvm) test-e2e-smoke: $(call target_title, "Running E2E smoke tests") && \ From f25918e0d4330a7331450a3d4d01d874513c9699 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Tue, 13 Sep 2022 10:40:19 +0100 Subject: [PATCH 14/31] update to latest main --- Makefile | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 9bfc9702c8..9b3785d6c8 100644 --- a/Makefile +++ b/Makefile @@ -11,18 +11,13 @@ LINTER_REGEX_INCLUDE?=all # regular expression used to specify which files to in target_title = @echo -e "\n\e[34m»»» 🧩 \e[96m$(1)\e[0m..." all: bootstrap mgmt-deploy images tre-deploy -tre-deploy: deploy-core build-and-deploy-ui deploy-shared-services db-migrate show-core-output +tre-deploy: deploy-core build-and-deploy-ui firewall-install db-migrate show-core-output images: build-and-push-api build-and-push-resource-processor build-and-push-airlock-processor build-and-push-api: build-api-image push-api-image build-and-push-resource-processor: build-resource-processor-vm-porter-image push-resource-processor-vm-porter-image build-and-push-airlock-processor: build-airlock-processor push-airlock-processor -deploy-shared-services: firewall-install - . ${MAKEFILE_DIR}/devops/scripts/load_env.sh ./templates/core/.env \ - && if [ "$${DEPLOY_GITEA}" == "true" ]; then $(MAKE) gitea-install; fi \ - && if [ "$${DEPLOY_NEXUS}" == "true" ]; then $(MAKE) nexus-install; fi - # to move your environment from the single 'core' deployment (which includes the firewall) # toward the shared services model, where it is split out - run the following make target before a tre-deploy # This will remove + import the resource state into a shared service @@ -107,7 +102,10 @@ prepare-tf-state: deploy-core: tre-start $(call target_title, "Deploying TRE") \ && . ${MAKEFILE_DIR}/devops/scripts/check_dependencies.sh nodocker,env,auth \ - && if [[ "$${TF_LOG}" == "DEBUG" ]]; then echo "TF DEBUG set - output supressed - see tflogs container for log file" && cd ${MAKEFILE_DIR}/templates/core/terraform/ && ./deploy.sh 1>/dev/null 2>/dev/null; else cd ${MAKEFILE_DIR}/templates/core/terraform/ && ./deploy.sh; fi; + && if [[ "$${TF_LOG}" == "DEBUG" ]]; \ + then echo "TF DEBUG set - output supressed - see tflogs container for log file" && cd ${MAKEFILE_DIR}/templates/core/terraform/ \ + && ./deploy.sh 1>/dev/null 2>/dev/null; \ + else cd ${MAKEFILE_DIR}/templates/core/terraform/ && ./deploy.sh; fi; letsencrypt: $(call target_title, "Requesting LetsEncrypt SSL certificate") \ @@ -168,9 +166,11 @@ lint: -e VALIDATE_BASH_EXEC=true \ -e VALIDATE_GITHUB_ACTIONS=true \ -e VALIDATE_DOCKERFILE_HADOLINT=true \ + -e VALIDATE_TSX=true \ + -e VALIDATE_TYPESCRIPT_ES=true \ -e FILTER_REGEX_INCLUDE=${LINTER_REGEX_INCLUDE} \ -v $${LOCAL_WORKSPACE_FOLDER}:/tmp/lint \ - github/super-linter:slim-v4.9.5 + github/super-linter:slim-v4.9.6 lint-docs: LINTER_REGEX_INCLUDE='./docs/.*\|./mkdocs.yml' $(MAKE) lint @@ -247,7 +247,9 @@ bundle-register: && az acr login --name $${ACR_NAME} \ && . ${MAKEFILE_DIR}/devops/scripts/get_access_token.sh \ && cd ${DIR} \ - && ${MAKEFILE_DIR}/devops/scripts/register_bundle_with_api.sh --acr-name "$${ACR_NAME}" --bundle-type "$${BUNDLE_TYPE}" --current --insecure --tre_url "$${TRE_URL:-https://$${TRE_ID}.$${LOCATION}.cloudapp.azure.com}" --verify --workspace-service-name "$${WORKSPACE_SERVICE_NAME}" + && ${MAKEFILE_DIR}/devops/scripts/register_bundle_with_api.sh --acr-name "$${ACR_NAME}" --bundle-type "$${BUNDLE_TYPE}" \ + --current --insecure --tre_url "$${TRE_URL:-https://$${TRE_ID}.$${LOCATION}.cloudapp.azure.com}" --verify \ + --workspace-service-name "$${WORKSPACE_SERVICE_NAME}" workspace_bundle = $(MAKE) bundle-build bundle-publish bundle-register \ DIR="${MAKEFILE_DIR}/templates/workspaces/$(1)" BUNDLE_TYPE=workspace @@ -273,18 +275,6 @@ firewall-install: $(MAKE) bundle-build bundle-publish bundle-register deploy-shared-service \ DIR=${MAKEFILE_DIR}/templates/shared_services/firewall/ BUNDLE_TYPE=shared_service -nexus-install: - $(MAKE) bundle-build bundle-publish bundle-register deploy-shared-service \ - DIR="${MAKEFILE_DIR}/templates/shared_services/certs" BUNDLE_TYPE=shared_service PROPS="--domain_prefix nexus --cert_name nexus-ssl" \ - && $(MAKE) bundle-build bundle-publish bundle-register deploy-shared-service \ - DIR=${MAKEFILE_DIR}/templates/shared_services/sonatype-nexus-vm/ BUNDLE_TYPE=shared_service PROPS="--ssl_cert_name nexus-ssl" - -gitea-install: - $(MAKE) bundle-build bundle-publish bundle-register deploy-shared-service DIR=${MAKEFILE_DIR}/templates/shared_services/gitea/ BUNDLE_TYPE=shared_service - -temp-do-upload: - $(MAKE) static-web-upload DIR=${MAKEFILE_DIR}/dummy - static-web-upload: $(call target_title, "Uploading to static website") \ && . ${MAKEFILE_DIR}/devops/scripts/check_dependencies.sh nodocker,env,auth \ @@ -297,7 +287,7 @@ build-and-deploy-ui: && . ${MAKEFILE_DIR}/devops/scripts/check_dependencies.sh nodocker,env,auth \ && pushd ${MAKEFILE_DIR}/templates/core/terraform/ > /dev/null && . ./outputs.sh && popd > /dev/null \ && . ${MAKEFILE_DIR}/devops/scripts/load_env.sh ${MAKEFILE_DIR}/templates/core/private.env \ - && if [ "$${DEPLOY_UI}" == "true" ]; then ${MAKEFILE_DIR}/devops/scripts/build_deploy_ui.sh; else echo "UI Deploy skipped as DEPLOY_UI not true"; fi \ + && if [ "$${DEPLOY_UI}" != "false" ]; then ${MAKEFILE_DIR}/devops/scripts/build_deploy_ui.sh; else echo "UI Deploy skipped as DEPLOY_UI is false"; fi \ prepare-for-e2e: $(call workspace_bundle,base) \ From 6d9f17107e33c28e4ddafe14d018580145be803e Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Tue, 13 Sep 2022 10:43:41 +0100 Subject: [PATCH 15/31] remove references to shared storage --- templates/workspaces/airlock_manager/.env.sample | 1 - templates/workspaces/airlock_manager/parameters.json | 6 ------ templates/workspaces/airlock_manager/porter.yaml | 6 ------ templates/workspaces/airlock_manager/template_schema.json | 6 ------ 4 files changed, 19 deletions(-) diff --git a/templates/workspaces/airlock_manager/.env.sample b/templates/workspaces/airlock_manager/.env.sample index e7793021f5..a65710cdc2 100644 --- a/templates/workspaces/airlock_manager/.env.sample +++ b/templates/workspaces/airlock_manager/.env.sample @@ -24,7 +24,6 @@ APP_ROLE_ID_WORKSPACE_OWNER="" APP_ROLE_ID_WORKSPACE_RESEARCHER="" APP_ROLE_ID_WORKSPACE_AIRLOCK_MANAGER="" ADDRESS_SPACE="10.2.8.0/24" -SHARED_STORAGE_QUOTA=50 ENABLE_LOCAL_DEBUGGING=true AAD_REDIRECT_URIS="W10=" diff --git a/templates/workspaces/airlock_manager/parameters.json b/templates/workspaces/airlock_manager/parameters.json index f0a0b9e128..54c58bfc82 100755 --- a/templates/workspaces/airlock_manager/parameters.json +++ b/templates/workspaces/airlock_manager/parameters.json @@ -46,12 +46,6 @@ "env": "MGMT_STORAGE_ACCOUNT_NAME" } }, - { - "name": "shared_storage_quota", - "source": { - "env": "SHARED_STORAGE_QUOTA" - } - }, { "name": "enable_local_debugging", "source": { diff --git a/templates/workspaces/airlock_manager/porter.yaml b/templates/workspaces/airlock_manager/porter.yaml index e141ee74f9..2aab69da74 100644 --- a/templates/workspaces/airlock_manager/porter.yaml +++ b/templates/workspaces/airlock_manager/porter.yaml @@ -49,9 +49,6 @@ parameters: - name: arm_use_msi type: boolean default: false - - name: shared_storage_quota - type: integer - default: 50 - name: enable_local_debugging type: boolean default: false @@ -145,7 +142,6 @@ install: tre_resource_id: "{{ bundle.parameters.id }}" location: "{{ bundle.parameters.azure_location }}" address_space: "{{ bundle.parameters.address_space }}" - shared_storage_quota: "{{ bundle.parameters.shared_storage_quota }}" enable_local_debugging: "{{ bundle.parameters.enable_local_debugging }}" register_aad_application: "{{ bundle.parameters.register_aad_application }}" auth_client_id: "{{ bundle.credentials.auth_client_id }}" @@ -184,7 +180,6 @@ upgrade: # tre_resource_id: "{{ bundle.parameters.id }}" # location: "{{ bundle.parameters.azure_location }}" # address_space: "{{ bundle.parameters.address_space }}" - # shared_storage_quota: "{{ bundle.parameters.shared_storage_quota }}" # enable_local_debugging: "{{ bundle.parameters.enable_local_debugging }}" # register_aad_application: "{{ bundle.parameters.register_aad_application }}" # auth_client_id: "{{ bundle.credentials.auth_client_id }}" @@ -238,7 +233,6 @@ uninstall: tre_resource_id: "{{ bundle.parameters.id }}" location: "{{ bundle.parameters.azure_location }}" address_space: "{{ bundle.parameters.address_space }}" - shared_storage_quota: "{{ bundle.parameters.shared_storage_quota }}" enable_local_debugging: "{{ bundle.parameters.enable_local_debugging }}" register_aad_application: "{{ bundle.parameters.register_aad_application }}" auth_client_id: "{{ bundle.credentials.auth_client_id }}" diff --git a/templates/workspaces/airlock_manager/template_schema.json b/templates/workspaces/airlock_manager/template_schema.json index 3a8c116e49..df5209c1c4 100644 --- a/templates/workspaces/airlock_manager/template_schema.json +++ b/templates/workspaces/airlock_manager/template_schema.json @@ -6,12 +6,6 @@ "description": "This workspace template is intended to conduct Airlock Data Import reviews from.", "required": [], "properties": { - "shared_storage_quota": { - "$id": "#/properties/shared_storage_quota", - "type": "integer", - "title": "Shared Storage Quota", - "description": "Quota (in GB) to set for the VM Shared Storage." - }, "aad_redirect_uris": { "$id": "#/properties/aad_redirect_uris", "type": "array", From c738bf1f03e48c9fa202c8713ff5bf750f7f759a Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Tue, 13 Sep 2022 16:47:54 +0100 Subject: [PATCH 16/31] Make mounting of shared storage optional depending on whether it's set in the config --- .../guacamole-azure-windowsvm/terraform/windowsvm.tf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf index 3a083a7113..76038a649a 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf @@ -95,7 +95,7 @@ data "template_file" "vm_config" { SharedStorageAccess = tobool(var.shared_storage_access) ? 1 : 0 StorageAccountName = data.azurerm_storage_account.stg.name StorageAccountKey = data.azurerm_storage_account.stg.primary_access_key - FileShareName = data.azurerm_storage_share.shared_storage.name + FileShareName = var.shared_storage_access ? data.azurerm_storage_share.shared_storage[0].name : "" CondaConfig = local.image_ref[var.image].conda_config ? 1 : 0 } } @@ -106,6 +106,7 @@ data "azurerm_storage_account" "stg" { } data "azurerm_storage_share" "shared_storage" { + count = var.shared_storage_access ? 1 : 0 name = var.shared_storage_name storage_account_name = data.azurerm_storage_account.stg.name } From 42b26ce8fb0f0726f3e17135faab7fe6fde64a07 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Wed, 14 Sep 2022 09:48:51 +0100 Subject: [PATCH 17/31] Update linuxvm to not depend on shared storage --- .../user_resources/guacamole-azure-linuxvm/porter.yaml | 2 +- .../guacamole-azure-linuxvm/terraform/linuxvm.tf | 3 ++- .../user_resources/guacamole-azure-windowsvm/porter.yaml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/porter.yaml b/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/porter.yaml index 50eb318ef5..c9cb558d84 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/porter.yaml +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/porter.yaml @@ -1,6 +1,6 @@ --- name: tre-service-guacamole-linuxvm -version: 0.4.14 +version: 0.4.15 description: "An Azure TRE User Resource Template for Guacamole (Linux)" dockerfile: Dockerfile.tmpl registry: azuretre diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/terraform/linuxvm.tf b/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/terraform/linuxvm.tf index 243cc28fb8..440e026ab2 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/terraform/linuxvm.tf +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/terraform/linuxvm.tf @@ -98,7 +98,7 @@ data "template_file" "vm_config" { STORAGE_ACCOUNT_NAME = data.azurerm_storage_account.stg.name STORAGE_ACCOUNT_KEY = data.azurerm_storage_account.stg.primary_access_key HTTP_ENDPOINT = data.azurerm_storage_account.stg.primary_file_endpoint - FILESHARE_NAME = data.azurerm_storage_share.shared_storage.name + FILESHARE_NAME = var.shared_storage_access ? data.azurerm_storage_share.shared_storage[0].name : "" NEXUS_PROXY_URL = local.nexus_proxy_url CONDA_CONFIG = local.image_ref[var.image].conda_config ? 1 : 0 } @@ -137,6 +137,7 @@ data "azurerm_storage_account" "stg" { } data "azurerm_storage_share" "shared_storage" { + count = var.shared_storage_access ? 1 : 0 name = var.shared_storage_name storage_account_name = data.azurerm_storage_account.stg.name } diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml index 64bd335141..452c95bbae 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml @@ -1,6 +1,6 @@ --- name: tre-service-guacamole-windowsvm -version: 0.4.8 +version: 0.4.9 description: "An Azure TRE User Resource Template for Guacamole (Windows 10)" dockerfile: Dockerfile.tmpl registry: azuretre From 353385830b46179951bb70595e3dad00318ec6e8 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Wed, 14 Sep 2022 15:18:14 +0100 Subject: [PATCH 18/31] wip: does not work --- .../user_resources/guacamole-azure-windowsvm/porter.yaml | 6 +++--- .../guacamole-azure-windowsvm/template_schema.json | 7 +++++++ .../guacamole-azure-windowsvm/terraform/variables.tf | 4 +++- .../guacamole-azure-windowsvm/terraform/windowsvm.tf | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml index 452c95bbae..e853d893d2 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml @@ -1,6 +1,6 @@ --- name: tre-service-guacamole-windowsvm -version: 0.4.9 +version: 0.4.11 description: "An Azure TRE User Resource Template for Guacamole (Windows 10)" dockerfile: Dockerfile.tmpl registry: azuretre @@ -50,8 +50,8 @@ parameters: type: string default: "2 CPU | 8GB RAM" - name: shared_storage_access - type: string - default: "true" + type: boolean + default: true - name: shared_storage_name type: string default: "vm-shared-storage" diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/template_schema.json b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/template_schema.json index f4eb91c241..2869aba071 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/template_schema.json +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/template_schema.json @@ -29,6 +29,13 @@ "16 CPU | 64GB RAM" ], "updateable": true + }, + "shared_storage_access": { + "$id": "#/properties/shared_storage_access", + "type": "boolean", + "title": "Shared storage", + "default": true, + "description": "Enable access to shared storage" } } } diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/variables.tf b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/variables.tf index a5038c01ef..2fdb0f77dd 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/variables.tf +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/variables.tf @@ -4,5 +4,7 @@ variable "parent_service_id" {} variable "tre_resource_id" {} variable "image" {} variable "vm_size" {} -variable "shared_storage_access" {} +variable "shared_storage_access" { + type = bool +} variable "shared_storage_name" {} diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf index 76038a649a..5b58cc4aed 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf @@ -92,7 +92,7 @@ data "template_file" "vm_config" { template = file("${path.module}/vm_config.ps1") vars = { nexus_proxy_url = local.nexus_proxy_url - SharedStorageAccess = tobool(var.shared_storage_access) ? 1 : 0 + SharedStorageAccess = var.shared_storage_access ? 1 : 0 StorageAccountName = data.azurerm_storage_account.stg.name StorageAccountKey = data.azurerm_storage_account.stg.primary_access_key FileShareName = var.shared_storage_access ? data.azurerm_storage_share.shared_storage[0].name : "" From 60c1789a867e6f4ccbb9af90d8ebec36b7864ec8 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Wed, 14 Sep 2022 15:18:23 +0100 Subject: [PATCH 19/31] Revert "wip: does not work" This reverts commit 353385830b46179951bb70595e3dad00318ec6e8. --- .../user_resources/guacamole-azure-windowsvm/porter.yaml | 6 +++--- .../guacamole-azure-windowsvm/template_schema.json | 7 ------- .../guacamole-azure-windowsvm/terraform/variables.tf | 4 +--- .../guacamole-azure-windowsvm/terraform/windowsvm.tf | 2 +- 4 files changed, 5 insertions(+), 14 deletions(-) diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml index e853d893d2..452c95bbae 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml @@ -1,6 +1,6 @@ --- name: tre-service-guacamole-windowsvm -version: 0.4.11 +version: 0.4.9 description: "An Azure TRE User Resource Template for Guacamole (Windows 10)" dockerfile: Dockerfile.tmpl registry: azuretre @@ -50,8 +50,8 @@ parameters: type: string default: "2 CPU | 8GB RAM" - name: shared_storage_access - type: boolean - default: true + type: string + default: "true" - name: shared_storage_name type: string default: "vm-shared-storage" diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/template_schema.json b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/template_schema.json index 2869aba071..f4eb91c241 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/template_schema.json +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/template_schema.json @@ -29,13 +29,6 @@ "16 CPU | 64GB RAM" ], "updateable": true - }, - "shared_storage_access": { - "$id": "#/properties/shared_storage_access", - "type": "boolean", - "title": "Shared storage", - "default": true, - "description": "Enable access to shared storage" } } } diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/variables.tf b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/variables.tf index 2fdb0f77dd..a5038c01ef 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/variables.tf +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/variables.tf @@ -4,7 +4,5 @@ variable "parent_service_id" {} variable "tre_resource_id" {} variable "image" {} variable "vm_size" {} -variable "shared_storage_access" { - type = bool -} +variable "shared_storage_access" {} variable "shared_storage_name" {} diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf index 5b58cc4aed..76038a649a 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf @@ -92,7 +92,7 @@ data "template_file" "vm_config" { template = file("${path.module}/vm_config.ps1") vars = { nexus_proxy_url = local.nexus_proxy_url - SharedStorageAccess = var.shared_storage_access ? 1 : 0 + SharedStorageAccess = tobool(var.shared_storage_access) ? 1 : 0 StorageAccountName = data.azurerm_storage_account.stg.name StorageAccountKey = data.azurerm_storage_account.stg.primary_access_key FileShareName = var.shared_storage_access ? data.azurerm_storage_share.shared_storage[0].name : "" From fc527e8e55b5629f48e0ade81d8e7554199c0025 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Wed, 14 Sep 2022 17:06:53 +0100 Subject: [PATCH 20/31] Change type of parameter to bool --- .../user_resources/guacamole-azure-windowsvm/porter.yaml | 6 +++--- .../guacamole-azure-windowsvm/template_schema.json | 7 +++++++ .../guacamole-azure-windowsvm/terraform/variables.tf | 4 +++- .../guacamole-azure-windowsvm/terraform/windowsvm.tf | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml index 452c95bbae..5d7092b635 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/porter.yaml @@ -1,6 +1,6 @@ --- name: tre-service-guacamole-windowsvm -version: 0.4.9 +version: 0.4.14 description: "An Azure TRE User Resource Template for Guacamole (Windows 10)" dockerfile: Dockerfile.tmpl registry: azuretre @@ -50,8 +50,8 @@ parameters: type: string default: "2 CPU | 8GB RAM" - name: shared_storage_access - type: string - default: "true" + type: boolean + default: true - name: shared_storage_name type: string default: "vm-shared-storage" diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/template_schema.json b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/template_schema.json index f4eb91c241..2869aba071 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/template_schema.json +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/template_schema.json @@ -29,6 +29,13 @@ "16 CPU | 64GB RAM" ], "updateable": true + }, + "shared_storage_access": { + "$id": "#/properties/shared_storage_access", + "type": "boolean", + "title": "Shared storage", + "default": true, + "description": "Enable access to shared storage" } } } diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/variables.tf b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/variables.tf index a5038c01ef..2fdb0f77dd 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/variables.tf +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/variables.tf @@ -4,5 +4,7 @@ variable "parent_service_id" {} variable "tre_resource_id" {} variable "image" {} variable "vm_size" {} -variable "shared_storage_access" {} +variable "shared_storage_access" { + type = bool +} variable "shared_storage_name" {} diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf index 76038a649a..5b58cc4aed 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-windowsvm/terraform/windowsvm.tf @@ -92,7 +92,7 @@ data "template_file" "vm_config" { template = file("${path.module}/vm_config.ps1") vars = { nexus_proxy_url = local.nexus_proxy_url - SharedStorageAccess = tobool(var.shared_storage_access) ? 1 : 0 + SharedStorageAccess = var.shared_storage_access ? 1 : 0 StorageAccountName = data.azurerm_storage_account.stg.name StorageAccountKey = data.azurerm_storage_account.stg.primary_access_key FileShareName = var.shared_storage_access ? data.azurerm_storage_share.shared_storage[0].name : "" From 4f4bd6328242dffd29003fb73d91380eea8882ec Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Wed, 14 Sep 2022 17:07:21 +0100 Subject: [PATCH 21/31] Add a forgotten private endpoint --- .../airlock_manager/workspace_base.diff | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/templates/workspaces/airlock_manager/workspace_base.diff b/templates/workspaces/airlock_manager/workspace_base.diff index 28046151db..5b14a0acb3 100644 --- a/templates/workspaces/airlock_manager/workspace_base.diff +++ b/templates/workspaces/airlock_manager/workspace_base.diff @@ -1,6 +1,32 @@ diff -Naur ../base/terraform/airlock/storage_accounts.tf terraform/airlock/storage_accounts.tf --- ../base/terraform/airlock/storage_accounts.tf 2022-08-17 12:09:06.000000000 +0100 +++ terraform/airlock/storage_accounts.tf 2022-09-12 17:42:55.000000000 +0100 +@@ -77,13 +76,34 @@ + lifecycle { ignore_changes = [tags] } + } + ++resource "azurerm_private_endpoint" "stg_import_inprogress_pe" { ++ name = "stg-ip-import-blob-${var.tre_id}-ws-${var.short_workspace_id}" ++ location = var.location ++ resource_group_name = var.ws_resource_group_name ++ subnet_id = var.services_subnet_id ++ ++ lifecycle { ignore_changes = [tags] } ++ ++ private_dns_zone_group { ++ name = "private-dns-zone-group-stg-import-ip" ++ private_dns_zone_ids = [data.azurerm_private_dns_zone.blobcore.id] ++ } ++ ++ private_service_connection { ++ name = "psc-stgipimport-${var.tre_id}" ++ private_connection_resource_id = data.azurerm_storage_account.sa_import_inprogress.id ++ is_manual_connection = false ++ subresource_names = ["Blob"] ++ } ++ ++ tags = var.tre_workspace_tags ++} @@ -259,19 +259,59 @@ } } From 5ee9919effdec5fd037501fa891ce45eed803d41 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Wed, 14 Sep 2022 17:07:26 +0100 Subject: [PATCH 22/31] Revert "remove testing script" This reverts commit daa25a5c726ee1c72ce9d58c6548b4db2f59689b. --- templates/workspaces/airlock_manager/test.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100755 templates/workspaces/airlock_manager/test.sh diff --git a/templates/workspaces/airlock_manager/test.sh b/templates/workspaces/airlock_manager/test.sh new file mode 100755 index 0000000000..c30d8785ab --- /dev/null +++ b/templates/workspaces/airlock_manager/test.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +AZURE_TRE_VERSION="0.4.2" + +# apt-get update \ +# && apt-get install --no-install-recommends jq ca-certificates curl patch -y \ +# && apt-get clean -y && rm -rf /var/lib/apt/lists/* + +# WORKDIR $BUNDLE_DIR + +# Copy all files from base workspace (note: some of them will be overwritten with the following COPY command) +curl -o azuretre.tar.gz -L "https://github.com/microsoft/AzureTRE/archive/refs/tags/v${AZURE_TRE_VERSION}.tar.gz" \ + && tar -xzf azuretre.tar.gz "AzureTRE-${AZURE_TRE_VERSION}/templates/workspaces/base" --strip-components=4 --skip-old-files \ + && rm -rf azuretre.tar.gz + +echo DOWNLOADED + +patch -p0 < ./workspace_base.diff From c3f91c4fea93c5519396d0b25c314c2555f27c0e Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Wed, 14 Sep 2022 17:47:03 +0100 Subject: [PATCH 23/31] fix diff --- .../airlock_manager/workspace_base.diff | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/templates/workspaces/airlock_manager/workspace_base.diff b/templates/workspaces/airlock_manager/workspace_base.diff index 5b14a0acb3..67b5001bb8 100644 --- a/templates/workspaces/airlock_manager/workspace_base.diff +++ b/templates/workspaces/airlock_manager/workspace_base.diff @@ -1,11 +1,13 @@ diff -Naur ../base/terraform/airlock/storage_accounts.tf terraform/airlock/storage_accounts.tf --- ../base/terraform/airlock/storage_accounts.tf 2022-08-17 12:09:06.000000000 +0100 -+++ terraform/airlock/storage_accounts.tf 2022-09-12 17:42:55.000000000 +0100 -@@ -77,13 +76,34 @@ - lifecycle { ignore_changes = [tags] } ++++ terraform/airlock/storage_accounts.tf 2022-09-14 17:42:52.000000000 +0100 +@@ -48,6 +48,30 @@ + } } - -+resource "azurerm_private_endpoint" "stg_import_inprogress_pe" { + ++# 'In progress' storage account ++ ++resource "azurerm_private_endpoint" "sa_import_inprogress_pe" { + name = "stg-ip-import-blob-${var.tre_id}-ws-${var.short_workspace_id}" + location = var.location + resource_group_name = var.ws_resource_group_name @@ -27,7 +29,10 @@ diff -Naur ../base/terraform/airlock/storage_accounts.tf terraform/airlock/stora + + tags = var.tre_workspace_tags +} -@@ -259,19 +259,59 @@ + + # 'Drop' location for export + resource "azurerm_storage_account" "sa_export_internal" { +@@ -259,19 +283,59 @@ } } @@ -38,6 +43,13 @@ diff -Naur ../base/terraform/airlock/storage_accounts.tf terraform/airlock/stora - role_definition_name = "Storage Blob Data Contributor" +resource "azurerm_role_assignment" "sa_import_approved" { + scope = azurerm_storage_account.sa_import_approved.id ++ role_definition_name = "Contributor" ++ principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id ++} ++ ++ ++resource "azurerm_role_assignment" "sa_export_internal" { ++ scope = azurerm_storage_account.sa_export_internal.id + role_definition_name = "Contributor" principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id } @@ -48,13 +60,6 @@ diff -Naur ../base/terraform/airlock/storage_accounts.tf terraform/airlock/stora - count = length(local.api_sa_data_contributor) - scope = local.api_sa_data_contributor[count.index] - role_definition_name = "Storage Blob Data Contributor" -+ -+resource "azurerm_role_assignment" "sa_export_internal" { -+ scope = azurerm_storage_account.sa_export_internal.id -+ role_definition_name = "Contributor" -+ principal_id = data.azurerm_user_assigned_identity.airlock_id.principal_id -+} -+ +resource "azurerm_role_assignment" "sa_export_inprogress" { + scope = azurerm_storage_account.sa_export_inprogress.id + role_definition_name = "Contributor" @@ -100,7 +105,7 @@ diff -Naur ../base/terraform/airlock/storage_accounts.tf terraform/airlock/stora } diff -Naur ../base/terraform/storage.tf terraform/storage.tf --- ../base/terraform/storage.tf 2022-08-10 10:15:54.000000000 +0100 -+++ terraform/storage.tf 2022-09-12 17:42:55.000000000 +0100 ++++ terraform/storage.tf 2022-09-14 17:11:00.000000000 +0100 @@ -9,17 +9,6 @@ lifecycle { ignore_changes = [tags] } } @@ -121,7 +126,7 @@ diff -Naur ../base/terraform/storage.tf terraform/storage.tf diff -Naur ../base/terraform/variables.tf terraform/variables.tf --- ../base/terraform/variables.tf 2022-08-12 19:02:29.000000000 +0100 -+++ terraform/variables.tf 2022-09-12 17:42:55.000000000 +0100 ++++ terraform/variables.tf 2022-09-14 17:11:00.000000000 +0100 @@ -8,12 +8,6 @@ description = "Resource ID" } From 226ef24508371b6e5f5ad4d825da25d596f69e15 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Wed, 14 Sep 2022 22:19:57 +0100 Subject: [PATCH 24/31] update diff --- .../airlock_manager/workspace_base.diff | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/templates/workspaces/airlock_manager/workspace_base.diff b/templates/workspaces/airlock_manager/workspace_base.diff index 67b5001bb8..490f471533 100644 --- a/templates/workspaces/airlock_manager/workspace_base.diff +++ b/templates/workspaces/airlock_manager/workspace_base.diff @@ -1,6 +1,18 @@ +diff -Naur ../base/terraform/airlock/data.tf terraform/airlock/data.tf +--- ../base/terraform/airlock/data.tf 2022-08-10 10:15:54.000000000 +0100 ++++ terraform/airlock/data.tf 2022-09-14 22:19:06.000000000 +0100 +@@ -23,3 +23,8 @@ + resource_group_name = local.core_resource_group_name + namespace_name = data.azurerm_servicebus_namespace.airlock_sb.name + } ++ ++data "azurerm_storage_account" "sa_import_inprogress" { ++ name = local.import_in_progress_storage_name ++ resource_group_name = local.core_resource_group_name ++} diff -Naur ../base/terraform/airlock/storage_accounts.tf terraform/airlock/storage_accounts.tf --- ../base/terraform/airlock/storage_accounts.tf 2022-08-17 12:09:06.000000000 +0100 -+++ terraform/airlock/storage_accounts.tf 2022-09-14 17:42:52.000000000 +0100 ++++ terraform/airlock/storage_accounts.tf 2022-09-14 22:18:19.000000000 +0100 @@ -48,6 +48,30 @@ } } @@ -105,7 +117,7 @@ diff -Naur ../base/terraform/airlock/storage_accounts.tf terraform/airlock/stora } diff -Naur ../base/terraform/storage.tf terraform/storage.tf --- ../base/terraform/storage.tf 2022-08-10 10:15:54.000000000 +0100 -+++ terraform/storage.tf 2022-09-14 17:11:00.000000000 +0100 ++++ terraform/storage.tf 2022-09-14 22:18:19.000000000 +0100 @@ -9,17 +9,6 @@ lifecycle { ignore_changes = [tags] } } @@ -126,7 +138,7 @@ diff -Naur ../base/terraform/storage.tf terraform/storage.tf diff -Naur ../base/terraform/variables.tf terraform/variables.tf --- ../base/terraform/variables.tf 2022-08-12 19:02:29.000000000 +0100 -+++ terraform/variables.tf 2022-09-14 17:11:00.000000000 +0100 ++++ terraform/variables.tf 2022-09-14 22:18:19.000000000 +0100 @@ -8,12 +8,6 @@ description = "Resource ID" } From e1bd50fc93eb6fcc84f41c7af53821b605371a3d Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Wed, 14 Sep 2022 23:57:30 +0100 Subject: [PATCH 25/31] update diff --- .../workspaces/airlock_manager/porter.yaml | 2 +- .../airlock_manager/workspace_base.diff | 45 +++++++++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/templates/workspaces/airlock_manager/porter.yaml b/templates/workspaces/airlock_manager/porter.yaml index 2aab69da74..24de642b04 100644 --- a/templates/workspaces/airlock_manager/porter.yaml +++ b/templates/workspaces/airlock_manager/porter.yaml @@ -1,6 +1,6 @@ --- name: tre-workspace-airlock-manager -version: 0.3.25 +version: 0.3.29 description: "An Airlock Manager workspace for Azure TRE" dockerfile: Dockerfile.tmpl registry: azuretre diff --git a/templates/workspaces/airlock_manager/workspace_base.diff b/templates/workspaces/airlock_manager/workspace_base.diff index 490f471533..a5d052ac87 100644 --- a/templates/workspaces/airlock_manager/workspace_base.diff +++ b/templates/workspaces/airlock_manager/workspace_base.diff @@ -1,6 +1,6 @@ diff -Naur ../base/terraform/airlock/data.tf terraform/airlock/data.tf --- ../base/terraform/airlock/data.tf 2022-08-10 10:15:54.000000000 +0100 -+++ terraform/airlock/data.tf 2022-09-14 22:19:06.000000000 +0100 ++++ terraform/airlock/data.tf 2022-09-14 23:46:54.000000000 +0100 @@ -23,3 +23,8 @@ resource_group_name = local.core_resource_group_name namespace_name = data.azurerm_servicebus_namespace.airlock_sb.name @@ -10,9 +10,46 @@ diff -Naur ../base/terraform/airlock/data.tf terraform/airlock/data.tf + name = local.import_in_progress_storage_name + resource_group_name = local.core_resource_group_name +} +diff -Naur ../base/terraform/airlock/locals.tf terraform/airlock/locals.tf +--- ../base/terraform/airlock/locals.tf 2022-08-17 12:09:06.000000000 +0100 ++++ terraform/airlock/locals.tf 2022-09-14 23:46:54.000000000 +0100 +@@ -1,4 +1,5 @@ + locals { ++ core_vnet = "vnet-${var.tre_id}" + core_resource_group_name = "rg-${var.tre_id}" + workspace_resource_name_suffix = "${var.tre_id}-ws-${var.short_workspace_id}" + +@@ -11,6 +12,8 @@ + + # STorage AirLock IMport APProved + import_approved_storage_name = lower(replace("stalimapp${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) ++ # STorage AirLock IMport InProgress ++ import_in_progress_storage_name = lower(replace("stalimip${var.tre_id}", "-", "")) + # STorage AirLock EXport INTernal + export_internal_storage_name = lower(replace("stalexint${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) + # STorage AirLock EXport InProgress +@@ -19,18 +22,4 @@ + export_rejected_storage_name = lower(replace("stalexrej${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) + # STorage AirLock EXport BLOCKED + export_blocked_storage_name = lower(replace("stalexblocked${substr(local.workspace_resource_name_suffix, -8, -1)}", "-", "")) +- +- airlock_blob_data_contributor = [ +- azurerm_storage_account.sa_import_approved.id, +- azurerm_storage_account.sa_export_internal.id, +- azurerm_storage_account.sa_export_inprogress.id, +- azurerm_storage_account.sa_export_rejected.id, +- azurerm_storage_account.sa_export_blocked.id +- ] +- +- api_sa_data_contributor = [ +- azurerm_storage_account.sa_import_approved.id, +- azurerm_storage_account.sa_export_internal.id, +- azurerm_storage_account.sa_export_inprogress.id +- ] + } diff -Naur ../base/terraform/airlock/storage_accounts.tf terraform/airlock/storage_accounts.tf --- ../base/terraform/airlock/storage_accounts.tf 2022-08-17 12:09:06.000000000 +0100 -+++ terraform/airlock/storage_accounts.tf 2022-09-14 22:18:19.000000000 +0100 ++++ terraform/airlock/storage_accounts.tf 2022-09-14 23:46:54.000000000 +0100 @@ -48,6 +48,30 @@ } } @@ -117,7 +154,7 @@ diff -Naur ../base/terraform/airlock/storage_accounts.tf terraform/airlock/stora } diff -Naur ../base/terraform/storage.tf terraform/storage.tf --- ../base/terraform/storage.tf 2022-08-10 10:15:54.000000000 +0100 -+++ terraform/storage.tf 2022-09-14 22:18:19.000000000 +0100 ++++ terraform/storage.tf 2022-09-14 23:46:54.000000000 +0100 @@ -9,17 +9,6 @@ lifecycle { ignore_changes = [tags] } } @@ -138,7 +175,7 @@ diff -Naur ../base/terraform/storage.tf terraform/storage.tf diff -Naur ../base/terraform/variables.tf terraform/variables.tf --- ../base/terraform/variables.tf 2022-08-12 19:02:29.000000000 +0100 -+++ terraform/variables.tf 2022-09-14 22:18:19.000000000 +0100 ++++ terraform/variables.tf 2022-09-14 23:46:54.000000000 +0100 @@ -8,12 +8,6 @@ description = "Resource ID" } From 25b9d81d5c23d4aece59f9434252d4656c9aa80c Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Thu, 15 Sep 2022 08:52:17 +0100 Subject: [PATCH 26/31] remove test script --- templates/workspaces/airlock_manager/test.sh | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100755 templates/workspaces/airlock_manager/test.sh diff --git a/templates/workspaces/airlock_manager/test.sh b/templates/workspaces/airlock_manager/test.sh deleted file mode 100755 index c30d8785ab..0000000000 --- a/templates/workspaces/airlock_manager/test.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -AZURE_TRE_VERSION="0.4.2" - -# apt-get update \ -# && apt-get install --no-install-recommends jq ca-certificates curl patch -y \ -# && apt-get clean -y && rm -rf /var/lib/apt/lists/* - -# WORKDIR $BUNDLE_DIR - -# Copy all files from base workspace (note: some of them will be overwritten with the following COPY command) -curl -o azuretre.tar.gz -L "https://github.com/microsoft/AzureTRE/archive/refs/tags/v${AZURE_TRE_VERSION}.tar.gz" \ - && tar -xzf azuretre.tar.gz "AzureTRE-${AZURE_TRE_VERSION}/templates/workspaces/base" --strip-components=4 --skip-old-files \ - && rm -rf azuretre.tar.gz - -echo DOWNLOADED - -patch -p0 < ./workspace_base.diff From 160b8b952c9922c745dc9e73a479c688052aa99c Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Thu, 15 Sep 2022 08:53:58 +0100 Subject: [PATCH 27/31] fix linuxvm --- Makefile | 6 +----- .../user_resources/guacamole-azure-linuxvm/porter.yaml | 4 ++-- .../guacamole-azure-linuxvm/template_schema.json | 7 +++++++ .../guacamole-azure-linuxvm/terraform/variables.tf | 4 +++- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 9b3785d6c8..d0b8ab32a0 100644 --- a/Makefile +++ b/Makefile @@ -290,11 +290,7 @@ build-and-deploy-ui: && if [ "$${DEPLOY_UI}" != "false" ]; then ${MAKEFILE_DIR}/devops/scripts/build_deploy_ui.sh; else echo "UI Deploy skipped as DEPLOY_UI is false"; fi \ prepare-for-e2e: - $(call workspace_bundle,base) \ - && $(call workspace_service_bundle,guacamole) \ - && $(call shared_service_bundle,gitea) \ - && $(call user_resource_bundle,guacamole,guacamole-azure-windowsvm) \ - && $(call user_resource_bundle,guacamole,guacamole-azure-linuxvm) + $(call workspace_bundle,airlock_manager) test-e2e-smoke: $(call target_title, "Running E2E smoke tests") && \ diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/porter.yaml b/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/porter.yaml index c9cb558d84..5e4b110ce5 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/porter.yaml +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/porter.yaml @@ -52,8 +52,8 @@ parameters: type: string default: "2 CPU | 8GB RAM" - name: shared_storage_access - type: string - default: "true" + type: boolean + default: true - name: shared_storage_name type: string default: "vm-shared-storage" diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/template_schema.json b/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/template_schema.json index 7e5027675f..a713fa9630 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/template_schema.json +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/template_schema.json @@ -29,6 +29,13 @@ "16 CPU | 64GB RAM" ], "updateable": true + }, + "shared_storage_access": { + "$id": "#/properties/shared_storage_access", + "type": "boolean", + "title": "Shared storage", + "default": true, + "description": "Enable access to shared storage" } } } diff --git a/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/terraform/variables.tf b/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/terraform/variables.tf index a5038c01ef..2fdb0f77dd 100644 --- a/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/terraform/variables.tf +++ b/templates/workspace_services/guacamole/user_resources/guacamole-azure-linuxvm/terraform/variables.tf @@ -4,5 +4,7 @@ variable "parent_service_id" {} variable "tre_resource_id" {} variable "image" {} variable "vm_size" {} -variable "shared_storage_access" {} +variable "shared_storage_access" { + type = bool +} variable "shared_storage_name" {} From 7dd0b2795e3e2babbc3932bc0a24c7d14f9a3130 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Thu, 15 Sep 2022 09:50:58 +0100 Subject: [PATCH 28/31] revert makefile changes --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d0b8ab32a0..9b3785d6c8 100644 --- a/Makefile +++ b/Makefile @@ -290,7 +290,11 @@ build-and-deploy-ui: && if [ "$${DEPLOY_UI}" != "false" ]; then ${MAKEFILE_DIR}/devops/scripts/build_deploy_ui.sh; else echo "UI Deploy skipped as DEPLOY_UI is false"; fi \ prepare-for-e2e: - $(call workspace_bundle,airlock_manager) + $(call workspace_bundle,base) \ + && $(call workspace_service_bundle,guacamole) \ + && $(call shared_service_bundle,gitea) \ + && $(call user_resource_bundle,guacamole,guacamole-azure-windowsvm) \ + && $(call user_resource_bundle,guacamole,guacamole-azure-linuxvm) test-e2e-smoke: $(call target_title, "Running E2E smoke tests") && \ From 5891e1adf6c5d51f603e77a33561551f0f4e3ca7 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Thu, 15 Sep 2022 12:04:06 +0100 Subject: [PATCH 29/31] Remove update_redirect_urls.sh --- .../airlock_manager/update_redirect_urls.sh | 82 ------------------- 1 file changed, 82 deletions(-) delete mode 100755 templates/workspaces/airlock_manager/update_redirect_urls.sh diff --git a/templates/workspaces/airlock_manager/update_redirect_urls.sh b/templates/workspaces/airlock_manager/update_redirect_urls.sh deleted file mode 100755 index 67380e1392..0000000000 --- a/templates/workspaces/airlock_manager/update_redirect_urls.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash - -set -o errexit -set -o pipefail -# Uncomment this line to see each command for debugging (careful: this will show secrets!) -# set -o xtrace - -function usage() { - cat < Date: Thu, 15 Sep 2022 12:04:19 +0100 Subject: [PATCH 30/31] Update Dockerfile --- templates/workspaces/airlock_manager/Dockerfile.tmpl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/templates/workspaces/airlock_manager/Dockerfile.tmpl b/templates/workspaces/airlock_manager/Dockerfile.tmpl index c415f97c3e..435dd51a8a 100644 --- a/templates/workspaces/airlock_manager/Dockerfile.tmpl +++ b/templates/workspaces/airlock_manager/Dockerfile.tmpl @@ -3,7 +3,7 @@ FROM debian:buster-slim ARG BUNDLE_DIR -ARG AZURE_TRE_VERSION="0.4.2" +ARG AZURE_TRE_VERSION="0.4.3" RUN apt-get update \ && apt-get install --no-install-recommends jq ca-certificates curl patch -y \ @@ -32,10 +32,12 @@ RUN curl -o azuretre.tar.gz -L "https://github.com/microsoft/AzureTRE/archive/r # Use the BUNDLE_DIR build argument to copy files into the bundle COPY . $BUNDLE_DIR +# Apply patch with the difference from the base workspace RUN patch -p0 < $BUNDLE_DIR/workspace_base.diff # Mirror plugins to prevent network access at runtime # Remove when available from https://github.com/getporter/terraform-mixin/issues/90 WORKDIR $BUNDLE_DIR/terraform RUN terraform init -backend=false \ + && rm -fr $BUNDLE_DIR/terraform/.terraform/providers \ && terraform providers mirror /usr/local/share/terraform/plugins From 9744321a412f5f02d7996457112134b8ca2d0e05 Mon Sep 17 00:00:00 2001 From: Tanya Borisova Date: Thu, 15 Sep 2022 12:04:31 +0100 Subject: [PATCH 31/31] Add doc page --- docs/tre-templates/workspaces/airlock_manager.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 docs/tre-templates/workspaces/airlock_manager.md diff --git a/docs/tre-templates/workspaces/airlock_manager.md b/docs/tre-templates/workspaces/airlock_manager.md new file mode 100644 index 0000000000..60bb3bf7fc --- /dev/null +++ b/docs/tre-templates/workspaces/airlock_manager.md @@ -0,0 +1,8 @@ +# Airlock Manager workspace + +**NOTE**: This feature is still in active development. More documentation will be added as the development progresses. + +Airlock Manager workspace is used as part of Review workflow for [Airlock](../../azure-tre-overview/airlock.md). +It allows to review Airlock Data Import requests from, by providing a workspace to spin up VMs in that then can access the in-progress storage account. + +The workspace is built upon the base workspace template. It adds a private endpoint to connect to import in-progress storage account, adds corresponding roles, and disables shared storage for VMs.