diff --git a/.gitignore b/.gitignore index 9491a2f..cb4864c 100644 --- a/.gitignore +++ b/.gitignore @@ -360,4 +360,18 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file +FodyWeavers.xsd + +# Terraform +*.tfstate +*.tfstate.* +.terraform/ +crash.log +*.tfvars +*.auto.tfvars +override.tf +override.tf.json +*_override.tf +*_override.tf.json +.terraformrc +terraform.rc diff --git a/devops/infra/.terraform.lock.hcl b/devops/infra/.terraform.lock.hcl new file mode 100644 index 0000000..1145315 --- /dev/null +++ b/devops/infra/.terraform.lock.hcl @@ -0,0 +1,22 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/azurerm" { + version = "3.117.1" + constraints = "~> 3.100" + hashes = [ + "h1:01r5mJ5Izv/aeJHEZAxnJYSuGWM9M8u4h073YwEj8DY=", + "zh:0c513676836e3c50d004ece7d2624a8aff6faac14b833b96feeac2e4bc2c1c12", + "zh:50ea01ada95bae2f187db9e926e463f45d860767a85ebc59160414e00e76c35d", + "zh:52c2a9edacc06b3f72153f5ef6daca0761c6292158815961fe37f60bc576a3d7", + "zh:618eed2a06b19b1a025b45b05891846d570a6a1cca4d23f4942f5a99e1f747ae", + "zh:61cde5d3165d7e5ec311d5d89486819cd605c1b2d54611b5c97bd4e97dba2762", + "zh:6a873358d5031fc222f5e05f029d1237f3dce8345c767665f393283dfa2627f6", + "zh:afdd80064b2a04da311856feb4ed45f77ff4df6c356e8c2b10afb51fe7e61c70", + "zh:b09113df7e0e8c8959539bd22bae6c39faeb269ba3c4cd948e742f5cf58c35fb", + "zh:d340db7973109761cfc27d52aa02560363337c908b2c99b3628adc5a70a99d5b", + "zh:d5a577226ebc8c65e8f19384878a86acc4b51ede4b4a82d37c3b331b0efcd4a7", + "zh:e2962b147f9e71732df8dbc74940c10d20906f3c003cbfaa1eb9fabbf601a9f0", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} diff --git a/devops/infra/main.tf b/devops/infra/main.tf new file mode 100644 index 0000000..c34edaa --- /dev/null +++ b/devops/infra/main.tf @@ -0,0 +1,171 @@ +terraform { + required_version = ">= 1.6.0" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.100" + } + } +} + +provider "azurerm" { + features {} +} + +# ------------------------ +# 1. Resource Group +# ------------------------ +resource "azurerm_resource_group" "rg" { + name = var.resource_group_name + location = var.location +} + +# ------------------------ +# 2. Storage Account (Blob) +# ------------------------ +resource "azurerm_storage_account" "storage" { + name = var.storage_account_name + resource_group_name = azurerm_resource_group.rg.name + location = azurerm_resource_group.rg.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_storage_container" "docs" { + name = "documents" + storage_account_name = azurerm_storage_account.storage.name + container_access_type = "private" +} + +# ------------------------ +# 3. Azure SQL Database +# ------------------------ +resource "azurerm_sql_server" "sql" { + name = var.sql_server_name + resource_group_name = azurerm_resource_group.rg.name + location = azurerm_resource_group.rg.location + version = "12.0" + administrator_login = var.sql_admin_user + administrator_login_password = var.sql_admin_password +} + +resource "azurerm_sql_database" "db" { + name = var.sql_db_name + resource_group_name = azurerm_resource_group.rg.name + location = azurerm_resource_group.rg.location + server_name = azurerm_sql_server.sql.name + requested_service_objective_name = "S0" +} + +# ------------------------ +# 4. Azure Key Vault +# ------------------------ +resource "azurerm_key_vault" "kv" { + name = var.key_vault_name + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + tenant_id = var.tenant_id + sku_name = "standard" + purge_protection_enabled = true + soft_delete_retention_days = 7 +} + +# ------------------------ +# 4b. Key Vault Access Policy +# ------------------------ + +resource "azurerm_key_vault_access_policy" "kv_policy" { + key_vault_id = azurerm_key_vault.kv.id + tenant_id = var.tenant_id + object_id = var.kv_admin_object_id + + # Permissions for secrets + secret_permissions = [ + "Get", + "List", + "Set", + "Delete" + ] + + # Optional: Permissions for keys and certificates + key_permissions = [ + "Get", + "List" + ] + + certificate_permissions = [ + "Get", + "List" + ] +} + + +# ------------------------ +# 5. Application Insights +# ------------------------ +resource "azurerm_application_insights" "appinsights" { + name = "${var.project_name}-ai" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + application_type = "web" +} + +# ------------------------ +# 6. Azure Cognitive Services (Document Intelligence, Language Studio, OpenAI) +# ------------------------ + +# Document Intelligence +resource "azurerm_cognitive_account" "doc_intel" { + name = "${var.project_name}-docintel" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + kind = "FormRecognizer" + sku_name = "F0" # Free tier +} + +# Language Studio (NER) +resource "azurerm_cognitive_account" "language" { + name = "${var.project_name}-language" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + kind = "TextAnalytics" + sku_name = "F0" # Free tier +} + +# Azure OpenAI (⚠️ Free tier doesn't exist — provision basic, keep disabled if not needed daily) +resource "azurerm_cognitive_account" "openai" { + name = "${var.project_name}-openai" + location = "East US" # Required for OpenAI + resource_group_name = azurerm_resource_group.rg.name + kind = "OpenAI" + sku_name = "S0" # Cheapest available +} + +# ------------------------ +# 7. Outputs +# ------------------------ +output "storage_account_name" { + value = azurerm_storage_account.storage.name +} + +output "sql_connection_string" { + value = "Server=tcp:${azurerm_sql_server.sql.name}.database.windows.net;Database=${azurerm_sql_database.db.name};User ID=${var.sql_admin_user};Password=${var.sql_admin_password};Encrypt=true" + sensitive = true +} + +output "key_vault_uri" { + value = azurerm_key_vault.kv.vault_uri +} + +output "doc_intel_endpoint" { + value = azurerm_cognitive_account.doc_intel.endpoint +} + +output "language_endpoint" { + value = azurerm_cognitive_account.language.endpoint +} + +output "openai_endpoint" { + value = azurerm_cognitive_account.openai.endpoint +} \ No newline at end of file diff --git a/devops/infra/variables.tf b/devops/infra/variables.tf new file mode 100644 index 0000000..d6e129b --- /dev/null +++ b/devops/infra/variables.tf @@ -0,0 +1,53 @@ +variable "location" { + default = "Australia East" + description = "Azure location" +} + +variable "project_name" { + default = "iacs" + description = "Project short name" +} + +variable "resource_group_name" { + default = "rg-iacs" + description = "Resource Group name" +} + +variable "storage_account_name" { + default = "iacsstorageacct" + description = "Globally unique storage account name" +} + +variable "sql_server_name" { + default = "iacssqlserver" + description = "SQL Server name" +} + +variable "sql_db_name" { + default = "iacsdb" + description = "SQL DB name" +} + +variable "sql_admin_user" { + default = "sqladminuser" + description = "SQL admin username" +} + +variable "sql_admin_password" { + description = "SQL admin password" + sensitive = true +} + +variable "key_vault_name" { + default = "iacsvault" + description = "Key Vault name" +} + +variable "tenant_id" { + description = "Azure Tenant ID" +} + +variable "kv_admin_object_id" { + description = "Object ID of the user or service principal to grant access to Key Vault" +} +