diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 9d49130458..8d4eefdebf 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -29,7 +29,7 @@ // Mount docker socket for docker builds "type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock", // Mounts the github cli login details from the host machine to the container (~/.config/gh/hosts.yml) - "type=bind,source=${env:HOME}${env:USERPROFILE}/.config,target=/home/vscode/.config", + "type=bind,source=${env:HOME}${env:USERPROFILE}/.config,target=/home/vscode/.config" ], "remoteUser": "vscode", "containerEnv": { @@ -277,6 +277,8 @@ "ms-python.pylance", "hashicorp.terraform", "github.vscode-pull-request-github", + "gitHub.copilot", + "github.copilot-chat", "getporter.porter-vscode", "davidanson.vscode-markdownlint", "editorconfig.editorconfig", @@ -291,5 +293,6 @@ 8000 ], // Run commands after the container is created. - "postCreateCommand": "./.devcontainer/scripts/post-create.sh" + "postCreateCommand": "./.devcontainer/scripts/post-create.sh", + "initializeCommand": "mkdir -p $HOME/.azure $HOME/.config || true" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 39010572e3..f9f9e38c9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ ENHANCEMENTS: * Allow enablement of Secure Boot and vTPM for Guacamole VMs ([#4235](https://github.com/microsoft/AzureTRE/issues/4235)) * Surface the server-layout parameter of Guacamole [server-layout](https://guacamole.apache.org/doc/gug/configuring-guacamole.html#session-settings) ([#4234](https://github.com/microsoft/AzureTRE/issues/4234)) * Add encryption at host for VMs ([#4263](https://github.com/microsoft/AzureTRE/pull/4263)) +* Downgrade certs shared service App Gateway to Basic SKU ([#4300](https://github.com/microsoft/AzureTRE/issues/4300)) +* Airlock function host storage to use the user-assigned managed identity ([#4276](https://github.com/microsoft/AzureTRE/issues/4276)) BUG FIXES: * Update KeyVault references in API to use the version so Terraform cascades the update ([#4112](https://github.com/microsoft/AzureTRE/pull/4112)) @@ -55,6 +57,7 @@ BUG FIXES: * Fix public exposure in Guacamole service ([[#4199](https://github.com/microsoft/AzureTRE/issues/4199)]) * Fix Azure ML network tags to use name rather than ID ([[#4151](https://github.com/microsoft/AzureTRE/issues/4151)]) * Certs shared service: Secret nexus-ssl-password is currently in a deleted but recoverable state ([#4294](https://github.com/microsoft/AzureTRE/issues/4294)]) +* Recreate tre_output.json if empty. ([[#4292](https://github.com/microsoft/AzureTRE/issues/4292)]) COMPONENTS: diff --git a/core/terraform/airlock/airlock_processor.tf b/core/terraform/airlock/airlock_processor.tf index 80a6968e97..a95bf54eaa 100644 --- a/core/terraform/airlock/airlock_processor.tf +++ b/core/terraform/airlock/airlock_processor.tf @@ -21,9 +21,8 @@ resource "azurerm_storage_account" "sa_airlock_processor_func_app" { allow_nested_items_to_be_public = false cross_tenant_replication_enabled = false local_user_enabled = false - # Function Host Storage doesn't seem to be able to use a User Managed ID, which is why we continue to use a key. - shared_access_key_enabled = true - tags = var.tre_core_tags + shared_access_key_enabled = false + tags = var.tre_core_tags dynamic "identity" { for_each = var.enable_cmk_encryption ? [1] : [] @@ -57,9 +56,7 @@ resource "azurerm_linux_function_app" "airlock_function_app" { ftp_publish_basic_authentication_enabled = false webdeploy_publish_basic_authentication_enabled = false storage_account_name = azurerm_storage_account.sa_airlock_processor_func_app.name - - # Function Host Storage doesn't seem to be able to use a User Managed ID, which is why we continue to use a key. - storage_account_access_key = azurerm_storage_account.sa_airlock_processor_func_app.primary_access_key + storage_uses_managed_identity = true tags = var.tre_core_tags @@ -86,6 +83,8 @@ resource "azurerm_linux_function_app" "airlock_function_app" { "TRE_ID" = var.tre_id "WEBSITE_CONTENTOVERVNET" = 1 "STORAGE_ENDPOINT_SUFFIX" = module.terraform_azurerm_environment_configuration.storage_suffix + "AzureWebJobsStorage__clientId" = azurerm_user_assigned_identity.airlock_id.client_id + "AzureWebJobsStorage__credential" = "managedidentity" } site_config { diff --git a/core/terraform/airlock/identity.tf b/core/terraform/airlock/identity.tf index 9711f19ab6..7f452ebdbb 100644 --- a/core/terraform/airlock/identity.tf +++ b/core/terraform/airlock/identity.tf @@ -52,3 +52,11 @@ resource "azurerm_role_assignment" "api_sa_data_contributor" { role_definition_name = "Storage Blob Data Contributor" principal_id = var.api_principal_id } + +# Permissions needed for the Function Host to work correctly. +resource "azurerm_role_assignment" "function_host_storage" { + for_each = toset(["Storage Account Contributor", "Storage Blob Data Owner", "Storage Queue Data Contributor"]) + scope = azurerm_storage_account.sa_airlock_processor_func_app.id + role_definition_name = each.value + principal_id = azurerm_user_assigned_identity.airlock_id.principal_id +} diff --git a/core/terraform/outputs.sh b/core/terraform/outputs.sh old mode 100755 new mode 100644 index e00090bbc1..078b20be53 --- a/core/terraform/outputs.sh +++ b/core/terraform/outputs.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -if [ ! -f ../tre_output.json ]; then +if [ ! -f ../tre_output.json ] || [ ! -s ../tre_output.json ]; then # Connect to the remote backend of Terraform export TF_LOG="" # shellcheck disable=SC2154 diff --git a/core/version.txt b/core/version.txt index 318bf6c824..3c85494aac 100644 --- a/core/version.txt +++ b/core/version.txt @@ -1 +1 @@ -__version__ = "0.11.19" +__version__ = "0.11.21" diff --git a/e2e_tests/config.py b/e2e_tests/config.py index cd43a78181..31ccb34c37 100644 --- a/e2e_tests/config.py +++ b/e2e_tests/config.py @@ -1,11 +1,9 @@ +import warnings from starlette.config import Config +warnings.filterwarnings("ignore", message="Config file '.env' not found.") -try: - config = Config('.env') -# Workaround needed until FastAPI uses Starlette >= 3.7.1 -except FileNotFoundError: - config = Config() +config = Config('.env') # Resource Info RESOURCE_LOCATION: str = config("RESOURCE_LOCATION", default="") diff --git a/e2e_tests/conftest.py b/e2e_tests/conftest.py index 7195a14588..39589e1696 100644 --- a/e2e_tests/conftest.py +++ b/e2e_tests/conftest.py @@ -12,23 +12,13 @@ LOGGER = logging.getLogger(__name__) -pytestmark = pytest.mark.asyncio +pytestmark = pytest.mark.asyncio(loop_scope="session") def pytest_addoption(parser): parser.addoption("--verify", action="store", default="true") -@pytest.fixture(scope="session") -def event_loop(): - try: - loop = asyncio.get_running_loop() - except RuntimeError: - loop = asyncio.new_event_loop() - yield loop - loop.close() - - @pytest.fixture(scope="session") def verify(pytestconfig): if pytestconfig.getoption("verify").lower() == "true": diff --git a/e2e_tests/pytest.ini b/e2e_tests/pytest.ini index 72fe2d3414..3e3cf490e3 100644 --- a/e2e_tests/pytest.ini +++ b/e2e_tests/pytest.ini @@ -10,6 +10,7 @@ markers = workspace_services asyncio_mode = auto +asyncio_default_fixture_loop_scope = session log_cli = 1 log_cli_level = INFO diff --git a/e2e_tests/test_airlock.py b/e2e_tests/test_airlock.py index 43e2df71bb..051a5c9d81 100644 --- a/e2e_tests/test_airlock.py +++ b/e2e_tests/test_airlock.py @@ -14,7 +14,7 @@ from helpers import get_admin_token -pytestmark = pytest.mark.asyncio +pytestmark = pytest.mark.asyncio(loop_scope="session") LOGGER = logging.getLogger(__name__) BLOB_FILE_PATH = "./test_airlock_sample.txt" BLOB_NAME = os.path.basename(BLOB_FILE_PATH) diff --git a/e2e_tests/test_performance.py b/e2e_tests/test_performance.py index 6c6d836d9d..f6e7637fe2 100644 --- a/e2e_tests/test_performance.py +++ b/e2e_tests/test_performance.py @@ -8,7 +8,7 @@ from helpers import get_admin_token -pytestmark = pytest.mark.asyncio +pytestmark = pytest.mark.asyncio(loop_scope="session") @pytest.mark.performance diff --git a/e2e_tests/test_provisioned_health_api.py b/e2e_tests/test_provisioned_health_api.py index 01c3cbeecc..92636d12dc 100644 --- a/e2e_tests/test_provisioned_health_api.py +++ b/e2e_tests/test_provisioned_health_api.py @@ -5,7 +5,7 @@ from resources import strings -pytestmark = pytest.mark.asyncio +pytestmark = pytest.mark.asyncio(loop_scope="session") @pytest.mark.smoke diff --git a/e2e_tests/test_ui.py b/e2e_tests/test_ui.py index 6e34da518b..8d71827fdb 100644 --- a/e2e_tests/test_ui.py +++ b/e2e_tests/test_ui.py @@ -4,7 +4,7 @@ import config -pytestmark = pytest.mark.asyncio +pytestmark = pytest.mark.asyncio(loop_scope="session") @pytest.mark.smoke diff --git a/e2e_tests/test_workspace_service_templates.py b/e2e_tests/test_workspace_service_templates.py index 34545d9af1..8ea70e6368 100644 --- a/e2e_tests/test_workspace_service_templates.py +++ b/e2e_tests/test_workspace_service_templates.py @@ -8,7 +8,7 @@ from resources import strings from helpers import get_admin_token -pytestmark = pytest.mark.asyncio +pytestmark = pytest.mark.asyncio(loop_scope="session") workspace_service_templates = [ (strings.AZUREML_SERVICE), diff --git a/e2e_tests/test_workspace_services.py b/e2e_tests/test_workspace_services.py index cd48910817..3013fef370 100644 --- a/e2e_tests/test_workspace_services.py +++ b/e2e_tests/test_workspace_services.py @@ -5,7 +5,7 @@ from resources.resource import get_resource, post_resource from resources import strings -pytestmark = pytest.mark.asyncio +pytestmark = pytest.mark.asyncio(loop_scope="session") workspace_services = [ strings.AZUREML_SERVICE, diff --git a/e2e_tests/test_workspace_templates.py b/e2e_tests/test_workspace_templates.py index d0ccb1f64e..1fed11daaa 100644 --- a/e2e_tests/test_workspace_templates.py +++ b/e2e_tests/test_workspace_templates.py @@ -11,7 +11,7 @@ from helpers import get_admin_token -pytestmark = pytest.mark.asyncio +pytestmark = pytest.mark.asyncio(loop_scope="session") workspace_templates = [ diff --git a/templates/shared_services/certs/terraform/.terraform.lock.hcl b/templates/shared_services/certs/terraform/.terraform.lock.hcl index 6e8b87ea6b..41771bac4d 100644 --- a/templates/shared_services/certs/terraform/.terraform.lock.hcl +++ b/templates/shared_services/certs/terraform/.terraform.lock.hcl @@ -2,21 +2,21 @@ # Manual edits may be lost in future updates. provider "registry.terraform.io/hashicorp/azurerm" { - version = "3.117.0" - constraints = "3.117.0" + version = "4.17.0" + constraints = "4.17.0" hashes = [ - "h1:Ynfg+Iy7x6K8M6W1AhqXCe3wkoiqIQhROlca7C3KC3w=", - "zh:2e25f47492366821a786762369f0e0921cc9452d64bfd5075f6fdfcf1a9c6d70", - "zh:41eb34f2f7469bf3eb1019dfb0e7fc28256f809824016f4f8b9d691bf473b2ac", - "zh:48bb9c87b3d928da1abc1d3db75453c9725de4674c612daf3800160cc7145d30", - "zh:5d6b0de0bbd78943fcc65c53944ef4496329e247f434c6eab86ed051c5cea67b", - "zh:78c9f6fdb1206a89cf0e6706b4f46178169a93b6c964a4cad8a321058ccbd9b4", - "zh:793b702c352589d4360b580d4a1cf654a7439d2ad6bdb7bfea91de07bc4b0fac", - "zh:7ed687ff0a5509463a592f97431863574fe5cc80a34e395be06766215b8c6285", - "zh:955ba18789bd15592824eb426a8d0f38595bd09fffc6939c1c58933489c1a71e", - "zh:bf5949a55be0714cd9c8815d472eae4baa48ba06d0f6bf2b96775869acda8a54", - "zh:da5d31f635abd2c645ffc76d6176d73f646128e73720cc368247cc424975c127", - "zh:eed5a66d59883c9c56729b0a964a2b60d758ea7489ef3e920a6fbd48518ce5f5", + "h1:gpFgaBSkRTxhavgPAuqQcElHJqmRJ1RpQGr1K0dvVW8=", + "zh:163b81a3bf29c8f161a1c100a48164b1bd1af434cd564b44596cb71a6c33f03d", + "zh:2996b107d3c05a9db14458b32b6f22f8cde0adb96263196d82d3dc302907a257", + "zh:361abd84b6e73016ebebb9ef9cd14c237d8b1e4500ea75f73243ff0534e5e4fb", + "zh:4872445dcb109fe8bbaba439d3dffaaef849a92645df3f8a854d3a40ac962f68", + "zh:61974eb7379acadbceb47b001ae1de2cdefe8cf078a15fff3a6fcc753cd24273", + "zh:75c60ca6e7851fe1d52fe9f5a0ae3d219e300ee5aa63bc8f807e3e0cab569ff0", + "zh:7c79305cff7849e6c5d9d60fe570510f95fb2e2bd5ae801da0281702f21dd779", + "zh:964b7da03f2dc55583cda3c277fef3511824b183a3a88344ae4ff9823af79109", + "zh:cad1593d364eb22b68578a1da4fd4d84749dc81f20e6591b27c6cb1eed9d2072", + "zh:db1a2ca17aae78813e8e0676bb9ef941e1a1e32d9fc6e1b239c24661605a8425", + "zh:e3a65d2f6f5a63cd1beeeb60a23e7e6b7328ebbd46ffe994792aaac6738186c3", "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", ] } diff --git a/templates/shared_services/certs/terraform/appgateway.tf b/templates/shared_services/certs/terraform/appgateway.tf index 909b3cb784..69d2b08db3 100644 --- a/templates/shared_services/certs/terraform/appgateway.tf +++ b/templates/shared_services/certs/terraform/appgateway.tf @@ -26,8 +26,8 @@ resource "azurerm_application_gateway" "agw" { tags = local.tre_shared_service_tags sku { - name = "Standard_v2" - tier = "Standard_v2" + name = "Basic" + tier = "Basic" capacity = 1 } diff --git a/templates/shared_services/certs/terraform/main.tf b/templates/shared_services/certs/terraform/main.tf index 001ccd9042..9f483e7251 100644 --- a/templates/shared_services/certs/terraform/main.tf +++ b/templates/shared_services/certs/terraform/main.tf @@ -3,7 +3,7 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "=3.117.0" + version = "=4.17.0" } } diff --git a/templates/workspaces/airlock-import-review/porter.yaml b/templates/workspaces/airlock-import-review/porter.yaml index 7e4330cd30..56f90dbc70 100644 --- a/templates/workspaces/airlock-import-review/porter.yaml +++ b/templates/workspaces/airlock-import-review/porter.yaml @@ -1,7 +1,7 @@ --- schemaVersion: 1.0.0 name: tre-workspace-airlock-import-review -version: 0.14.1 +version: 0.14.2 description: "A workspace to do Airlock Data Import Reviews for Azure TRE" dockerfile: Dockerfile.tmpl registry: azuretre diff --git a/templates/workspaces/airlock-import-review/template_schema.json b/templates/workspaces/airlock-import-review/template_schema.json index e05a0d87e7..180e360abc 100644 --- a/templates/workspaces/airlock-import-review/template_schema.json +++ b/templates/workspaces/airlock-import-review/template_schema.json @@ -16,6 +16,7 @@ "description": "The SKU that will be used when deploying an Azure App Service Plan.", "default": "P1v3", "enum": [ + "P0v3", "P1v3", "P1v2", "S1" diff --git a/templates/workspaces/base/porter.yaml b/templates/workspaces/base/porter.yaml index 89be17e3de..a7e09fa692 100644 --- a/templates/workspaces/base/porter.yaml +++ b/templates/workspaces/base/porter.yaml @@ -1,7 +1,7 @@ --- schemaVersion: 1.0.0 name: tre-workspace-base -version: 1.9.1 +version: 1.9.2 description: "A base Azure TRE workspace" dockerfile: Dockerfile.tmpl registry: azuretre diff --git a/templates/workspaces/base/template_schema.json b/templates/workspaces/base/template_schema.json index 77049d7f1c..b456b5f044 100644 --- a/templates/workspaces/base/template_schema.json +++ b/templates/workspaces/base/template_schema.json @@ -28,6 +28,7 @@ "description": "The SKU that will be used when deploying an Azure App Service Plan.", "default": "P1v3", "enum": [ + "P0v3", "P1v3", "P1v2", "S1" diff --git a/templates/workspaces/unrestricted/porter.yaml b/templates/workspaces/unrestricted/porter.yaml index 5d1cc8cfa1..b8bd2becae 100644 --- a/templates/workspaces/unrestricted/porter.yaml +++ b/templates/workspaces/unrestricted/porter.yaml @@ -1,7 +1,7 @@ --- schemaVersion: 1.0.0 name: tre-workspace-unrestricted -version: 0.13.1 +version: 0.13.2 description: "A base Azure TRE workspace" dockerfile: Dockerfile.tmpl registry: azuretre diff --git a/templates/workspaces/unrestricted/template_schema.json b/templates/workspaces/unrestricted/template_schema.json index 3fbaa16a3a..f9c8a807f1 100644 --- a/templates/workspaces/unrestricted/template_schema.json +++ b/templates/workspaces/unrestricted/template_schema.json @@ -28,6 +28,7 @@ "description": "The SKU that will be used when deploying an Azure App Service Plan.", "default": "P1v3", "enum": [ + "P0v3", "P1v3", "P1v2", "S1"