From 15513f5a2f805fb92d131081e31e5abef879fcf2 Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sat, 29 Nov 2025 11:11:43 +0100 Subject: [PATCH 01/18] #96 CIDR update --- infra/main.tf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/infra/main.tf b/infra/main.tf index 600f57f..64879fd 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -35,7 +35,10 @@ module "key_vault" { tags = local.environment_vars.tags - key_vault_ip_rules = [data.http.ip.response_body] + key_vault_ip_rules = [ + data.http.ip.response_body, + "83.76.0.0/14" + ] } # Wait for firewall rule propagation From 5e463296f8c6815e6734e7081165e81c98c8a770 Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sat, 29 Nov 2025 11:31:12 +0100 Subject: [PATCH 02/18] #98 variable for UPN --- .github/workflows/deploy-infra.yaml | 1 + infra/main.tf | 2 +- infra/variables.tf | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-infra.yaml b/.github/workflows/deploy-infra.yaml index fd067d2..7a43740 100644 --- a/.github/workflows/deploy-infra.yaml +++ b/.github/workflows/deploy-infra.yaml @@ -52,6 +52,7 @@ jobs: echo "TF_VAR_postgresql_admin_username=${{ secrets.POSTGRESQL_ADMIN_USERNAME }}" >> $GITHUB_ENV echo "TF_VAR_google_client_id=${{ secrets.GOOGLE_CLIENT_ID }}" >> $GITHUB_ENV echo "TF_VAR_google_client_secret=${{ secrets.GOOGLE_CLIENT_SECRET }}" >> $GITHUB_ENV + echo "TF_VAR_admin_user_principal_name=frederic.pitteloud@fpittelo.ch" >> $GITHUB_ENV diff --git a/infra/main.tf b/infra/main.tf index 64879fd..208503c 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -62,7 +62,7 @@ resource "azurerm_role_assignment" "key_vault_secrets_officer" { # Look up the user to grant access to data "azuread_user" "admin_user" { - user_principal_name = "frederic.pitteloud@fpittelo.ch" + user_principal_name = var.admin_user_principal_name } # Assign Key Vault Administrator role to the user diff --git a/infra/variables.tf b/infra/variables.tf index 8eee13d..607610c 100644 --- a/infra/variables.tf +++ b/infra/variables.tf @@ -188,3 +188,8 @@ variable "google_client_secret" { + +variable "admin_user_principal_name" { + description = "The User Principal Name of the admin user to grant Key Vault access." + type = string +} From f0e5b621b146a5c7f9888d07a44693b5a9e51633 Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sat, 29 Nov 2025 11:42:34 +0100 Subject: [PATCH 03/18] #96 fifth correction --- .github/workflows/deploy-infra.yaml | 30 +++++++++++++++++++++++++++++ infra/main.tf | 15 +++------------ infra/providers.tf | 8 -------- infra/variables.tf | 6 ++++++ 4 files changed, 39 insertions(+), 20 deletions(-) diff --git a/.github/workflows/deploy-infra.yaml b/.github/workflows/deploy-infra.yaml index 7a43740..2d0d89c 100644 --- a/.github/workflows/deploy-infra.yaml +++ b/.github/workflows/deploy-infra.yaml @@ -54,6 +54,36 @@ jobs: echo "TF_VAR_google_client_secret=${{ secrets.GOOGLE_CLIENT_SECRET }}" >> $GITHUB_ENV echo "TF_VAR_admin_user_principal_name=frederic.pitteloud@fpittelo.ch" >> $GITHUB_ENV + - name: Get Runner IP + id: ip + run: | + ip=$(curl -s https://api.ipify.org) + echo "Runner IP: $ip" + echo "TF_VAR_client_ip_address=$ip" >> $GITHUB_ENV + echo "RUNNER_IP=$ip" >> $GITHUB_ENV + + - name: Add Runner IP to Key Vault Firewall + run: | + # Construct Key Vault name based on environment convention + KV_NAME="${{ env.ENVIRONMENT }}-alpinebot-vault" + RG_NAME="${{ env.ENVIRONMENT }}-alpinebot" + + echo "Attempting to add IP $RUNNER_IP to Key Vault $KV_NAME in Resource Group $RG_NAME..." + + # Check if Key Vault exists (verbose) + if az keyvault show --name "$KV_NAME" --resource-group "$RG_NAME"; then + echo "Key Vault exists. Adding network rule..." + az keyvault network-rule add --name "$KV_NAME" --resource-group "$RG_NAME" --ip-address "$RUNNER_IP" + + echo "Network rule added. Verifying..." + az keyvault network-rule list --name "$KV_NAME" --resource-group "$RG_NAME" + + echo "Waiting 60 seconds for propagation..." + sleep 60 + else + echo "Key Vault $KV_NAME does not exist (or is not accessible). Skipping network rule addition." + fi + diff --git a/infra/main.tf b/infra/main.tf index 208503c..f1b3b1a 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -15,10 +15,7 @@ resource "azurerm_resource_group" "rg" { #### Create the Azure Key Vault ##### -# Retrieve the runner's public IP -data "http" "ip" { - url = "https://api.ipify.org" -} + module "key_vault" { source = "../modules/key_vault" @@ -36,17 +33,12 @@ module "key_vault" { tags = local.environment_vars.tags key_vault_ip_rules = [ - data.http.ip.response_body, + var.client_ip_address, "83.76.0.0/14" ] } -# Wait for firewall rule propagation -resource "time_sleep" "wait_for_firewall" { - create_duration = "60s" - depends_on = [module.key_vault] -} # Get the current service principal/client object ID data "azurerm_client_config" "current" {} @@ -82,8 +74,7 @@ resource "azurerm_key_vault_secret" "openai_key" { depends_on = [ module.key_vault, module.cognitive_account, - azurerm_role_assignment.key_vault_secrets_officer, - time_sleep.wait_for_firewall + azurerm_role_assignment.key_vault_secrets_officer ] } diff --git a/infra/providers.tf b/infra/providers.tf index fd0637b..0b2d347 100644 --- a/infra/providers.tf +++ b/infra/providers.tf @@ -19,14 +19,6 @@ terraform { source = "cyrilgdn/postgresql" version = "1.17.0" } - http = { - source = "hashicorp/http" - version = "~> 3.4.0" - } - time = { - source = "hashicorp/time" - version = "~> 0.9.0" - } } backend "azurerm" { diff --git a/infra/variables.tf b/infra/variables.tf index 607610c..2239e60 100644 --- a/infra/variables.tf +++ b/infra/variables.tf @@ -193,3 +193,9 @@ variable "admin_user_principal_name" { description = "The User Principal Name of the admin user to grant Key Vault access." type = string } + +variable "client_ip_address" { + description = "The IP address of the client (e.g., GitHub Actions runner) to allow access to Key Vault." + type = string + default = null +} From 3e2a9fb10c960d2e66268dd1afcf9a6b8e1b4744 Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sat, 29 Nov 2025 11:49:39 +0100 Subject: [PATCH 04/18] #98 correction for variable --- .github/workflows/deploy-infra.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/deploy-infra.yaml b/.github/workflows/deploy-infra.yaml index 2d0d89c..176a41a 100644 --- a/.github/workflows/deploy-infra.yaml +++ b/.github/workflows/deploy-infra.yaml @@ -114,6 +114,8 @@ jobs: TF_LOG: DEBUG TF_LOG_PATH: terraform.log ENVIRONMENT: ${{ env.ENVIRONMENT }} + TF_VAR_admin_user_principal_name: "frederic.pitteloud@fpittelo.ch" + TF_VAR_client_ip_address: ${{ env.RUNNER_IP }} run: | echo "Using environment: ${{ env.ENVIRONMENT }}" terraform apply -var="environment=${{ env.ENVIRONMENT }}" -auto-approve From fbe9840b957693be2a48c405d91d2f91b7be2bff Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sat, 29 Nov 2025 20:46:21 +0100 Subject: [PATCH 05/18] #98 Rollback UPN variable --- .github/workflows/deploy-infra.yaml | 4 ++-- infra/main.tf | 2 +- infra/variables.tf | 5 +---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy-infra.yaml b/.github/workflows/deploy-infra.yaml index 176a41a..4fde36d 100644 --- a/.github/workflows/deploy-infra.yaml +++ b/.github/workflows/deploy-infra.yaml @@ -52,7 +52,7 @@ jobs: echo "TF_VAR_postgresql_admin_username=${{ secrets.POSTGRESQL_ADMIN_USERNAME }}" >> $GITHUB_ENV echo "TF_VAR_google_client_id=${{ secrets.GOOGLE_CLIENT_ID }}" >> $GITHUB_ENV echo "TF_VAR_google_client_secret=${{ secrets.GOOGLE_CLIENT_SECRET }}" >> $GITHUB_ENV - echo "TF_VAR_admin_user_principal_name=frederic.pitteloud@fpittelo.ch" >> $GITHUB_ENV + - name: Get Runner IP id: ip @@ -114,7 +114,7 @@ jobs: TF_LOG: DEBUG TF_LOG_PATH: terraform.log ENVIRONMENT: ${{ env.ENVIRONMENT }} - TF_VAR_admin_user_principal_name: "frederic.pitteloud@fpittelo.ch" + TF_VAR_client_ip_address: ${{ env.RUNNER_IP }} run: | echo "Using environment: ${{ env.ENVIRONMENT }}" diff --git a/infra/main.tf b/infra/main.tf index f1b3b1a..010a1cc 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -54,7 +54,7 @@ resource "azurerm_role_assignment" "key_vault_secrets_officer" { # Look up the user to grant access to data "azuread_user" "admin_user" { - user_principal_name = var.admin_user_principal_name + user_principal_name = "frederic.pitteloud@fpittelo.ch" } # Assign Key Vault Administrator role to the user diff --git a/infra/variables.tf b/infra/variables.tf index 2239e60..9ae900f 100644 --- a/infra/variables.tf +++ b/infra/variables.tf @@ -189,10 +189,7 @@ variable "google_client_secret" { -variable "admin_user_principal_name" { - description = "The User Principal Name of the admin user to grant Key Vault access." - type = string -} + variable "client_ip_address" { description = "The IP address of the client (e.g., GitHub Actions runner) to allow access to Key Vault." From be41d07fa48d7188e3c144ce2f89eb46f5b8faf8 Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sun, 30 Nov 2025 09:48:37 +0100 Subject: [PATCH 06/18] #99 correction --- infra/main.tf | 7 +++++-- infra/variables.tf | 8 ++++++++ modules/cognitive_account/main.tf | 15 +++++++++++++++ modules/cognitive_account/variables.tf | 15 +++++++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/infra/main.tf b/infra/main.tf index 010a1cc..3559f23 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -85,8 +85,11 @@ module "cognitive_account" { az_location = local.environment_vars.az_location az_rg_name = local.environment_vars.az_rg_name kind = local.environment_vars.kind - sku_name_cog_acct = local.environment_vars.sku_name_cog_acct - tags = local.environment_vars.tags + sku_name_cog_acct = local.environment_vars.sku_name_cog_acct + tags = local.environment_vars.tags + model_deployment_name = local.environment_vars.alpinebotaidepl + model_name = local.environment_vars.model_name + model_version = local.environment_vars.model_version depends_on = [azurerm_resource_group.rg] } diff --git a/infra/variables.tf b/infra/variables.tf index 9ae900f..c64ce85 100644 --- a/infra/variables.tf +++ b/infra/variables.tf @@ -34,6 +34,8 @@ variable "environments" { function_app_name = string function_storage_account_name = string azure_openai_api_version = string + model_name = string + model_version = string })) default = { "dev" = { @@ -69,6 +71,8 @@ variable "environments" { function_app_name = "dev-alpinebot-func" function_storage_account_name = "devalpinebotfuncsa" azure_openai_api_version = "2024-02-15-preview" + model_name = "gpt-4" + model_version = "1106-Preview" }, "qa" = { tags = { @@ -103,6 +107,8 @@ variable "environments" { function_app_name = "qa-alpinebot-func" function_storage_account_name = "qaalpinebotfuncsa" azure_openai_api_version = "2024-08-01-preview" + model_name = "gpt-4" + model_version = "1106-Preview" }, "main" = { tags = { @@ -137,6 +143,8 @@ variable "environments" { function_app_name = "main-alpinebot-func" function_storage_account_name = "mainalpinebotfuncsa" azure_openai_api_version = "2024-08-01-preview" + model_name = "gpt-4" + model_version = "1106-Preview" } } } diff --git a/modules/cognitive_account/main.tf b/modules/cognitive_account/main.tf index 970c5f4..807cb49 100644 --- a/modules/cognitive_account/main.tf +++ b/modules/cognitive_account/main.tf @@ -8,3 +8,18 @@ resource "azurerm_cognitive_account" "alpinebot_openai" { tags = var.tags } + +resource "azurerm_cognitive_deployment" "openai_deployment" { + name = var.model_deployment_name + cognitive_account_id = azurerm_cognitive_account.alpinebot_openai.id + model { + format = "OpenAI" + name = var.model_name + version = var.model_version + } + + scale { + type = "Standard" + capacity = 10 + } +} diff --git a/modules/cognitive_account/variables.tf b/modules/cognitive_account/variables.tf index e40c5de..0a328c0 100644 --- a/modules/cognitive_account/variables.tf +++ b/modules/cognitive_account/variables.tf @@ -27,4 +27,19 @@ variable "sku_name_cog_acct" { variable "tags" { description = "value of tags" type = map(string) +} + +variable "model_deployment_name" { + description = "Name of the OpenAI model deployment" + type = string +} + +variable "model_name" { + description = "Name of the OpenAI model (e.g., gpt-4)" + type = string +} + +variable "model_version" { + description = "Version of the OpenAI model" + type = string } \ No newline at end of file From ad52dc42a009475fecf4cce2598f04f98f84c45c Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sun, 30 Nov 2025 10:04:53 +0100 Subject: [PATCH 07/18] #99 #100 correction --- infra/main.tf | 20 ++++++++++++++++ infra/variables.tf | 16 +++++++++++++ modules/cognitive_account/main.tf | 4 ++-- modules/function_app/main.tf | 1 + modules/function_app/variables.tf | 6 +++++ modules/virtual_network/main.tf | 28 +++++++++++++++++++++++ modules/virtual_network/outputs.tf | 3 +++ modules/virtual_network/variables.tf | 34 ++++++++++++++++++++++++++++ 8 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 modules/virtual_network/main.tf create mode 100644 modules/virtual_network/outputs.tf create mode 100644 modules/virtual_network/variables.tf diff --git a/infra/main.tf b/infra/main.tf index 3559f23..a38bc86 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -13,6 +13,20 @@ resource "azurerm_resource_group" "rg" { tags = local.environment_vars.tags } +#### Create Virtual Network and Subnet ###### +module "virtual_network" { + source = "../modules/virtual_network" + vnet_name = local.environment_vars.vnet_name + az_location = local.environment_vars.az_location + az_rg_name = local.environment_vars.az_rg_name + vnet_address_space = local.environment_vars.vnet_address_space + subnet_name = local.environment_vars.subnet_name + subnet_prefix = local.environment_vars.subnet_prefix + tags = local.environment_vars.tags + + depends_on = [azurerm_resource_group.rg] +} + #### Create the Azure Key Vault ##### @@ -36,6 +50,10 @@ module "key_vault" { var.client_ip_address, "83.76.0.0/14" ] + + key_vault_subnet_ids = [ + module.virtual_network.subnet_id + ] } @@ -196,7 +214,9 @@ module "function_app" { az_location = local.environment_vars.az_location az_rg_name = local.environment_vars.az_rg_name service_plan_id = module.app_service_plan.service_plan_id + service_plan_id = module.app_service_plan.service_plan_id app_insights_connection_string = azurerm_application_insights.apbotinsights.connection_string + virtual_network_subnet_id = module.virtual_network.subnet_id app_settings = { "AZURE_OPENAI_API_KEY" = "@Microsoft.KeyVault(SecretUri=${azurerm_key_vault_secret.openai_key.id})" diff --git a/infra/variables.tf b/infra/variables.tf index c64ce85..c564d42 100644 --- a/infra/variables.tf +++ b/infra/variables.tf @@ -36,6 +36,10 @@ variable "environments" { azure_openai_api_version = string model_name = string model_version = string + vnet_name = string + vnet_address_space = list(string) + subnet_name = string + subnet_prefix = list(string) })) default = { "dev" = { @@ -73,6 +77,10 @@ variable "environments" { azure_openai_api_version = "2024-02-15-preview" model_name = "gpt-4" model_version = "1106-Preview" + vnet_name = "dev-alpinebot-vnet" + vnet_address_space = ["10.0.0.0/16"] + subnet_name = "dev-alpinebot-subnet" + subnet_prefix = ["10.0.1.0/24"] }, "qa" = { tags = { @@ -109,6 +117,10 @@ variable "environments" { azure_openai_api_version = "2024-08-01-preview" model_name = "gpt-4" model_version = "1106-Preview" + vnet_name = "qa-alpinebot-vnet" + vnet_address_space = ["10.1.0.0/16"] + subnet_name = "qa-alpinebot-subnet" + subnet_prefix = ["10.1.1.0/24"] }, "main" = { tags = { @@ -145,6 +157,10 @@ variable "environments" { azure_openai_api_version = "2024-08-01-preview" model_name = "gpt-4" model_version = "1106-Preview" + vnet_name = "main-alpinebot-vnet" + vnet_address_space = ["10.2.0.0/16"] + subnet_name = "main-alpinebot-subnet" + subnet_prefix = ["10.2.1.0/24"] } } } diff --git a/modules/cognitive_account/main.tf b/modules/cognitive_account/main.tf index 807cb49..64a46cd 100644 --- a/modules/cognitive_account/main.tf +++ b/modules/cognitive_account/main.tf @@ -18,8 +18,8 @@ resource "azurerm_cognitive_deployment" "openai_deployment" { version = var.model_version } - scale { - type = "Standard" + sku { + name = "Standard" capacity = 10 } } diff --git a/modules/function_app/main.tf b/modules/function_app/main.tf index 5a491ff..4abf20f 100644 --- a/modules/function_app/main.tf +++ b/modules/function_app/main.tf @@ -17,6 +17,7 @@ resource "azurerm_linux_function_app" "function_app" { service_plan_id = var.service_plan_id storage_account_name = azurerm_storage_account.function_storage.name storage_account_access_key = azurerm_storage_account.function_storage.primary_access_key + virtual_network_subnet_id = var.virtual_network_subnet_id identity { type = "SystemAssigned" diff --git a/modules/function_app/variables.tf b/modules/function_app/variables.tf index dc28d0b..0a9a1aa 100644 --- a/modules/function_app/variables.tf +++ b/modules/function_app/variables.tf @@ -49,3 +49,9 @@ variable "tags" { description = "Tags to apply to Function App resources" type = map(string) } + +variable "virtual_network_subnet_id" { + description = "ID of the subnet to integrate with the Function App" + type = string + default = null +} diff --git a/modules/virtual_network/main.tf b/modules/virtual_network/main.tf new file mode 100644 index 0000000..b1162f7 --- /dev/null +++ b/modules/virtual_network/main.tf @@ -0,0 +1,28 @@ +resource "azurerm_virtual_network" "vnet" { + name = var.vnet_name + location = var.az_location + resource_group_name = var.az_rg_name + address_space = var.vnet_address_space + tags = var.tags +} + +resource "azurerm_subnet" "subnet" { + name = var.subnet_name + resource_group_name = var.az_rg_name + virtual_network_name = azurerm_virtual_network.vnet.name + address_prefixes = var.subnet_prefix + + service_endpoints = [ + "Microsoft.KeyVault", + "Microsoft.Web" + ] + + delegation { + name = "delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} diff --git a/modules/virtual_network/outputs.tf b/modules/virtual_network/outputs.tf new file mode 100644 index 0000000..ec0b69c --- /dev/null +++ b/modules/virtual_network/outputs.tf @@ -0,0 +1,3 @@ +output "subnet_id" { + value = azurerm_subnet.subnet.id +} diff --git a/modules/virtual_network/variables.tf b/modules/virtual_network/variables.tf new file mode 100644 index 0000000..65f822b --- /dev/null +++ b/modules/virtual_network/variables.tf @@ -0,0 +1,34 @@ +variable "vnet_name" { + description = "Name of the Virtual Network" + type = string +} + +variable "az_location" { + description = "Location of the Virtual Network" + type = string +} + +variable "az_rg_name" { + description = "Resource Group Name" + type = string +} + +variable "vnet_address_space" { + description = "Address space for the Virtual Network" + type = list(string) +} + +variable "subnet_name" { + description = "Name of the Subnet" + type = string +} + +variable "subnet_prefix" { + description = "Address prefix for the Subnet" + type = list(string) +} + +variable "tags" { + description = "Tags to apply to resources" + type = map(string) +} From ec9845c776c287d2e21e49e8866a94d9de75bf61 Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sun, 30 Nov 2025 10:12:53 +0100 Subject: [PATCH 08/18] #100 duplicate removal --- infra/main.tf | 1 - 1 file changed, 1 deletion(-) diff --git a/infra/main.tf b/infra/main.tf index a38bc86..82964de 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -214,7 +214,6 @@ module "function_app" { az_location = local.environment_vars.az_location az_rg_name = local.environment_vars.az_rg_name service_plan_id = module.app_service_plan.service_plan_id - service_plan_id = module.app_service_plan.service_plan_id app_insights_connection_string = azurerm_application_insights.apbotinsights.connection_string virtual_network_subnet_id = module.virtual_network.subnet_id From 7758230ec43e52d1a03cc2e18955a7b8bdb49fbd Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sun, 30 Nov 2025 10:20:51 +0100 Subject: [PATCH 09/18] #100 fix null value --- infra/main.tf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/infra/main.tf b/infra/main.tf index 82964de..f829cdb 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -47,8 +47,7 @@ module "key_vault" { tags = local.environment_vars.tags key_vault_ip_rules = [ - var.client_ip_address, - "83.76.0.0/14" + for ip in [var.client_ip_address, "83.76.0.0/14"] : ip if ip != null ] key_vault_subnet_ids = [ From 0fd72455ceeefa170614b9f196cbcc46b288579d Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sun, 30 Nov 2025 10:41:05 +0100 Subject: [PATCH 10/18] #94 diagnostic step to confirm if the 403 error is solely due to the firewall. --- modules/key_vault/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/key_vault/main.tf b/modules/key_vault/main.tf index acaaf1a..f9b8fae 100644 --- a/modules/key_vault/main.tf +++ b/modules/key_vault/main.tf @@ -12,7 +12,7 @@ resource "azurerm_key_vault" "alpinebot_kv" { tags = var.tags network_acls { - default_action = "Deny" + default_action = "Allow" bypass = "AzureServices" ip_rules = var.key_vault_ip_rules virtual_network_subnet_ids = var.key_vault_subnet_ids From f0fa1c6c1edf69e7365fa1fd60895d48a7d7ac28 Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sun, 30 Nov 2025 10:59:18 +0100 Subject: [PATCH 11/18] #94 force the Key Vault firewall open using the Azure CLI before Terraform starts. --- .github/workflows/deploy-infra.yaml | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deploy-infra.yaml b/.github/workflows/deploy-infra.yaml index 4fde36d..f1f6a4d 100644 --- a/.github/workflows/deploy-infra.yaml +++ b/.github/workflows/deploy-infra.yaml @@ -62,26 +62,21 @@ jobs: echo "TF_VAR_client_ip_address=$ip" >> $GITHUB_ENV echo "RUNNER_IP=$ip" >> $GITHUB_ENV - - name: Add Runner IP to Key Vault Firewall + - name: Set Key Vault Firewall to Allow run: | # Construct Key Vault name based on environment convention KV_NAME="${{ env.ENVIRONMENT }}-alpinebot-vault" RG_NAME="${{ env.ENVIRONMENT }}-alpinebot" - echo "Attempting to add IP $RUNNER_IP to Key Vault $KV_NAME in Resource Group $RG_NAME..." + echo "Forcing Key Vault $KV_NAME firewall to Allow..." - # Check if Key Vault exists (verbose) + # Check if Key Vault exists if az keyvault show --name "$KV_NAME" --resource-group "$RG_NAME"; then - echo "Key Vault exists. Adding network rule..." - az keyvault network-rule add --name "$KV_NAME" --resource-group "$RG_NAME" --ip-address "$RUNNER_IP" - - echo "Network rule added. Verifying..." - az keyvault network-rule list --name "$KV_NAME" --resource-group "$RG_NAME" - - echo "Waiting 60 seconds for propagation..." - sleep 60 + az keyvault update --name "$KV_NAME" --resource-group "$RG_NAME" --default-action Allow + echo "Key Vault firewall set to Allow. Waiting 30 seconds for propagation..." + sleep 30 else - echo "Key Vault $KV_NAME does not exist (or is not accessible). Skipping network rule addition." + echo "Key Vault $KV_NAME does not exist. Skipping firewall update." fi From 92aec9424c6b5641f0aaf288aeccefd706864a5b Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sun, 30 Nov 2025 11:15:18 +0100 Subject: [PATCH 12/18] #94 fix the issue (by ensuring the command runs) or provide the logs needed --- .github/workflows/deploy-infra.yaml | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/deploy-infra.yaml b/.github/workflows/deploy-infra.yaml index f1f6a4d..34a2de8 100644 --- a/.github/workflows/deploy-infra.yaml +++ b/.github/workflows/deploy-infra.yaml @@ -64,19 +64,26 @@ jobs: - name: Set Key Vault Firewall to Allow run: | - # Construct Key Vault name based on environment convention KV_NAME="${{ env.ENVIRONMENT }}-alpinebot-vault" RG_NAME="${{ env.ENVIRONMENT }}-alpinebot" - echo "Forcing Key Vault $KV_NAME firewall to Allow..." - - # Check if Key Vault exists - if az keyvault show --name "$KV_NAME" --resource-group "$RG_NAME"; then + echo "Checking if Key Vault $KV_NAME exists..." + if az keyvault show --name "$KV_NAME" --resource-group "$RG_NAME" > /dev/null 2>&1; then + echo "Key Vault found." + + echo "Current Firewall Action:" + az keyvault show --name "$KV_NAME" --resource-group "$RG_NAME" --query properties.networkAcls.defaultAction -o tsv + + echo "Setting default-action to Allow..." az keyvault update --name "$KV_NAME" --resource-group "$RG_NAME" --default-action Allow - echo "Key Vault firewall set to Allow. Waiting 30 seconds for propagation..." - sleep 30 + + echo "New Firewall Action:" + az keyvault show --name "$KV_NAME" --resource-group "$RG_NAME" --query properties.networkAcls.defaultAction -o tsv + + echo "Waiting 60 seconds for propagation..." + sleep 60 else - echo "Key Vault $KV_NAME does not exist. Skipping firewall update." + echo "Key Vault $KV_NAME not found. Skipping firewall update (first run?)." fi From 85074fc4bea5a390b242cae6cba150a5dcc2d503 Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sun, 30 Nov 2025 11:29:21 +0100 Subject: [PATCH 13/18] #94 Remove the silent check enable public access --- .github/workflows/deploy-infra.yaml | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/.github/workflows/deploy-infra.yaml b/.github/workflows/deploy-infra.yaml index 34a2de8..d817e90 100644 --- a/.github/workflows/deploy-infra.yaml +++ b/.github/workflows/deploy-infra.yaml @@ -67,24 +67,15 @@ jobs: KV_NAME="${{ env.ENVIRONMENT }}-alpinebot-vault" RG_NAME="${{ env.ENVIRONMENT }}-alpinebot" - echo "Checking if Key Vault $KV_NAME exists..." - if az keyvault show --name "$KV_NAME" --resource-group "$RG_NAME" > /dev/null 2>&1; then - echo "Key Vault found." - - echo "Current Firewall Action:" - az keyvault show --name "$KV_NAME" --resource-group "$RG_NAME" --query properties.networkAcls.defaultAction -o tsv - - echo "Setting default-action to Allow..." - az keyvault update --name "$KV_NAME" --resource-group "$RG_NAME" --default-action Allow - - echo "New Firewall Action:" - az keyvault show --name "$KV_NAME" --resource-group "$RG_NAME" --query properties.networkAcls.defaultAction -o tsv - - echo "Waiting 60 seconds for propagation..." - sleep 60 - else - echo "Key Vault $KV_NAME not found. Skipping firewall update (first run?)." - fi + echo "Listing Key Vaults in $RG_NAME for debugging..." + az keyvault list --resource-group "$RG_NAME" --query "[].name" -o tsv || echo "Failed to list KVs" + + echo "Attempting to force Key Vault $KV_NAME firewall to Allow..." + # Try to update, ignore failure if KV doesn't exist (e.g. fresh deploy) + az keyvault update --name "$KV_NAME" --resource-group "$RG_NAME" --default-action Allow --public-network-access Enabled || echo "Key Vault update failed (it might not exist yet)." + + echo "Waiting 60 seconds for propagation..." + sleep 60 From aa1a94f2c05c1c722fe6a495a03073dfa64e5b73 Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sun, 30 Nov 2025 12:10:10 +0100 Subject: [PATCH 14/18] #101 first iteration --- .github/workflows/deploy-infra.yaml | 17 ++++++++++++++++- infra/main.tf | 8 +++++++- infra/outputs.tf | 5 +++++ modules/key_vault/outputs.tf | 4 ++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-infra.yaml b/.github/workflows/deploy-infra.yaml index d817e90..c370289 100644 --- a/.github/workflows/deploy-infra.yaml +++ b/.github/workflows/deploy-infra.yaml @@ -64,7 +64,22 @@ jobs: - name: Set Key Vault Firewall to Allow run: | - KV_NAME="${{ env.ENVIRONMENT }}-alpinebot-vault" + # Dynamic Key Vault Name Lookup + KV_NAME_PREFIX="${{ env.ENVIRONMENT }}-alpinebot-vault-" + echo "Looking for Key Vault starting with: $KV_NAME_PREFIX" + + # Find the Key Vault name that matches the pattern + KV_NAME=$(az keyvault list --resource-group "$RG_NAME" --query "[?starts_with(name, '$KV_NAME_PREFIX')].name | [0]" -o tsv) + + if [ -z "$KV_NAME" ]; then + echo "Key Vault not found. It might not be created yet." + # Fallback or exit gracefully depending on logic. + # Here we assume it's a fresh deploy and we can skip setting firewall rules for now. + echo "Skipping firewall update." + exit 0 + fi + + echo "Found Key Vault: $KV_NAME" RG_NAME="${{ env.ENVIRONMENT }}-alpinebot" echo "Listing Key Vaults in $RG_NAME for debugging..." diff --git a/infra/main.tf b/infra/main.tf index f829cdb..f5db6da 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -31,11 +31,17 @@ module "virtual_network" { + +resource "random_integer" "kv_suffix" { + min = 1000 + max = 9999 +} + module "key_vault" { source = "../modules/key_vault" az_rg_name = local.environment_vars.az_rg_name - az_kv_name = local.environment_vars.az_kv_name + az_kv_name = "${local.environment_vars.az_kv_name}-${random_integer.kv_suffix.result}" az_location = local.environment_vars.az_location tenant_id = var.az_tenant_id enabled_for_disk_encryption = false diff --git a/infra/outputs.tf b/infra/outputs.tf index 2c97e19..a8ee5be 100644 --- a/infra/outputs.tf +++ b/infra/outputs.tf @@ -12,3 +12,8 @@ output "function_app_default_hostname" { description = "The default hostname of the Function App" value = module.function_app.function_app_default_hostname } + +output "key_vault_name" { + description = "The name of the Key Vault" + value = module.key_vault.key_vault_name +} diff --git a/modules/key_vault/outputs.tf b/modules/key_vault/outputs.tf index 2213d8b..9038b93 100644 --- a/modules/key_vault/outputs.tf +++ b/modules/key_vault/outputs.tf @@ -5,3 +5,7 @@ output "key_vault_id" { #output "openai_key_id" { # value = azurerm_key_vault_secret.openai_key.id #} + +output "key_vault_name" { + value = azurerm_key_vault.alpinebot_kv.name +} From 49eeee5cdc9e810671187cf5d412f44ce84f6c27 Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sun, 30 Nov 2025 12:51:47 +0100 Subject: [PATCH 15/18] #102 first iteration --- infra/main.tf | 2 +- infra/outputs.tf | 5 +++++ infra/providers.tf | 4 ++++ modules/cognitive_account/outputs.tf | 4 ++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/infra/main.tf b/infra/main.tf index f5db6da..d852ed2 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -104,7 +104,7 @@ resource "azurerm_key_vault_secret" "openai_key" { #### Deploy AlpineBot OpenAI Account ###### module "cognitive_account" { source = "../modules/cognitive_account" - alpinebotaiact_name = local.environment_vars.alpinebotaiact_name + alpinebotaiact_name = "${local.environment_vars.alpinebotaiact_name}-${random_integer.kv_suffix.result}" az_location = local.environment_vars.az_location az_rg_name = local.environment_vars.az_rg_name kind = local.environment_vars.kind diff --git a/infra/outputs.tf b/infra/outputs.tf index a8ee5be..7cc577e 100644 --- a/infra/outputs.tf +++ b/infra/outputs.tf @@ -17,3 +17,8 @@ output "key_vault_name" { description = "The name of the Key Vault" value = module.key_vault.key_vault_name } + +output "openai_account_name" { + description = "The name of the OpenAI Account" + value = module.cognitive_account.openai_account_name +} diff --git a/infra/providers.tf b/infra/providers.tf index 0b2d347..37f46ce 100644 --- a/infra/providers.tf +++ b/infra/providers.tf @@ -36,6 +36,10 @@ provider "azurerm" { purge_soft_delete_on_destroy = true recover_soft_deleted_key_vaults = false } + cognitive_account { + purge_soft_delete_on_destroy = true + } + } } diff --git a/modules/cognitive_account/outputs.tf b/modules/cognitive_account/outputs.tf index 006b918..af409f6 100644 --- a/modules/cognitive_account/outputs.tf +++ b/modules/cognitive_account/outputs.tf @@ -10,3 +10,7 @@ output "openai_key" { output "cognitive_account_endpoint" { value = azurerm_cognitive_account.alpinebot_openai.endpoint } + +output "openai_account_name" { + value = azurerm_cognitive_account.alpinebot_openai.name +} From 12e7ef1ddbbc57ff3ce48c72c426cf6575cd4bc8 Mon Sep 17 00:00:00 2001 From: fpittelo Date: Sun, 30 Nov 2025 13:13:38 +0100 Subject: [PATCH 16/18] #102 seocond iteration --- infra/variables.tf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/infra/variables.tf b/infra/variables.tf index c564d42..d27b082 100644 --- a/infra/variables.tf +++ b/infra/variables.tf @@ -75,8 +75,8 @@ variable "environments" { function_app_name = "dev-alpinebot-func" function_storage_account_name = "devalpinebotfuncsa" azure_openai_api_version = "2024-02-15-preview" - model_name = "gpt-4" - model_version = "1106-Preview" + model_name = "gpt-4o" + model_version = "2024-05-13" vnet_name = "dev-alpinebot-vnet" vnet_address_space = ["10.0.0.0/16"] subnet_name = "dev-alpinebot-subnet" @@ -115,8 +115,8 @@ variable "environments" { function_app_name = "qa-alpinebot-func" function_storage_account_name = "qaalpinebotfuncsa" azure_openai_api_version = "2024-08-01-preview" - model_name = "gpt-4" - model_version = "1106-Preview" + model_name = "gpt-4o" + model_version = "2024-05-13" vnet_name = "qa-alpinebot-vnet" vnet_address_space = ["10.1.0.0/16"] subnet_name = "qa-alpinebot-subnet" @@ -155,8 +155,8 @@ variable "environments" { function_app_name = "main-alpinebot-func" function_storage_account_name = "mainalpinebotfuncsa" azure_openai_api_version = "2024-08-01-preview" - model_name = "gpt-4" - model_version = "1106-Preview" + model_name = "gpt-4o" + model_version = "2024-05-13" vnet_name = "main-alpinebot-vnet" vnet_address_space = ["10.2.0.0/16"] subnet_name = "main-alpinebot-subnet" From c8859f5e288946e78acd0bef0d5aa5447f47e077 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Nov 2025 12:42:38 +0000 Subject: [PATCH 17/18] Initial plan From d3a7e8e941a8f4ba6c90ac90cf241fc3ae475d3f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Nov 2025 12:46:28 +0000 Subject: [PATCH 18/18] Fix: Use GlobalStandard SKU for Azure OpenAI deployment in Switzerland North Co-authored-by: fpittelo <3135901+fpittelo@users.noreply.github.com> --- infra/main.tf | 11 ++++++----- infra/variables.tf | 4 ++++ modules/cognitive_account/main.tf | 2 +- modules/cognitive_account/variables.tf | 6 ++++++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/infra/main.tf b/infra/main.tf index d852ed2..f9b1582 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -103,16 +103,17 @@ resource "azurerm_key_vault_secret" "openai_key" { #### Deploy AlpineBot OpenAI Account ###### module "cognitive_account" { - source = "../modules/cognitive_account" - alpinebotaiact_name = "${local.environment_vars.alpinebotaiact_name}-${random_integer.kv_suffix.result}" - az_location = local.environment_vars.az_location - az_rg_name = local.environment_vars.az_rg_name - kind = local.environment_vars.kind + source = "../modules/cognitive_account" + alpinebotaiact_name = "${local.environment_vars.alpinebotaiact_name}-${random_integer.kv_suffix.result}" + az_location = local.environment_vars.az_location + az_rg_name = local.environment_vars.az_rg_name + kind = local.environment_vars.kind sku_name_cog_acct = local.environment_vars.sku_name_cog_acct tags = local.environment_vars.tags model_deployment_name = local.environment_vars.alpinebotaidepl model_name = local.environment_vars.model_name model_version = local.environment_vars.model_version + deployment_sku_name = local.environment_vars.deployment_sku_name depends_on = [azurerm_resource_group.rg] } diff --git a/infra/variables.tf b/infra/variables.tf index d27b082..8f281eb 100644 --- a/infra/variables.tf +++ b/infra/variables.tf @@ -25,6 +25,7 @@ variable "environments" { rbac_enabled = bool kind = string sku_name_cog_acct = string + deployment_sku_name = string auth_enabled = bool redis_cache_name = string postgresql_server_name = string @@ -66,6 +67,7 @@ variable "environments" { rbac_enabled = true kind = "OpenAI" sku_name_cog_acct = "S0" + deployment_sku_name = "GlobalStandard" auth_enabled = true redis_cache_name = "dev-alpinebot-redis" postgresql_server_name = "dev-alpinebot-psql" @@ -106,6 +108,7 @@ variable "environments" { rbac_enabled = true kind = "OpenAI" sku_name_cog_acct = "S0" + deployment_sku_name = "GlobalStandard" auth_enabled = false redis_cache_name = "qa-alpinebot-redis" postgresql_server_name = "qa-alpinebot-psql" @@ -146,6 +149,7 @@ variable "environments" { rbac_enabled = true kind = "OpenAI" sku_name_cog_acct = "S0" + deployment_sku_name = "GlobalStandard" auth_enabled = false redis_cache_name = "main-alpinebot-redis" postgresql_server_name = "main-alpinebot-psql" diff --git a/modules/cognitive_account/main.tf b/modules/cognitive_account/main.tf index 64a46cd..09931d2 100644 --- a/modules/cognitive_account/main.tf +++ b/modules/cognitive_account/main.tf @@ -19,7 +19,7 @@ resource "azurerm_cognitive_deployment" "openai_deployment" { } sku { - name = "Standard" + name = var.deployment_sku_name capacity = 10 } } diff --git a/modules/cognitive_account/variables.tf b/modules/cognitive_account/variables.tf index 0a328c0..d4f12bf 100644 --- a/modules/cognitive_account/variables.tf +++ b/modules/cognitive_account/variables.tf @@ -42,4 +42,10 @@ variable "model_name" { variable "model_version" { description = "Version of the OpenAI model" type = string +} + +variable "deployment_sku_name" { + description = "SKU name for the OpenAI deployment (e.g., Standard, GlobalStandard)" + type = string + default = "GlobalStandard" } \ No newline at end of file