Files
azure-production/main.tf
2025-06-22 02:54:36 +00:00

459 lines
13 KiB
HCL

# Full Terraform Config for Azure Demo Infra - Fixed for Free Tier
terraform {
required_version = ">= 1.3"
required_providers {
azurerm = { source = "hashicorp/azurerm", version = ">= 3.50" }
random = { source = "hashicorp/random" }
azuread = { source = "hashicorp/azuread" }
time = { source = "hashicorp/time" }
}
}
provider "azurerm" {
features {}
subscription_id = "1d363cb6-5669-42c2-98d3-5b9a1604b797"
}
provider "random" {}
provider "azuread" {}
data "azurerm_client_config" "current" {}
locals {
default_tags = {
environment = "Demo"
owner = "Linux Lenape"
purpose = "Technical-Demo"
}
}
# Resource Group
resource "azurerm_resource_group" "core" {
name = "Prod-Native-American-Empires"
location = var.location
tags = local.default_tags
}
# Key Vault
resource "azurerm_key_vault" "vault" {
name = var.key_vault_name
location = var.location
resource_group_name = azurerm_resource_group.core.name
tenant_id = data.azurerm_client_config.current.tenant_id
sku_name = "standard"
purge_protection_enabled = false
public_network_access_enabled = true
soft_delete_retention_days = 7
tags = local.default_tags
access_policy {
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = data.azurerm_client_config.current.object_id
key_permissions = [
"Get",
]
secret_permissions = [
"Get", "Set", "Delete", "List"
]
storage_permissions = [
"Get",
]
}
}
# Generate VM admin password
resource "random_password" "vm_admin" {
length = 16
special = true
}
# Store VM admin password in Key Vault
resource "azurerm_key_vault_secret" "vm_admin_password" {
name = "vm-admin-password"
value = random_password.vm_admin.result
key_vault_id = azurerm_key_vault.vault.id
depends_on = [azurerm_key_vault.vault]
}
# Networking
resource "azurerm_virtual_network" "vnet" {
name = "vnet-prod"
location = var.location
resource_group_name = azurerm_resource_group.core.name
address_space = ["10.0.0.0/16"]
tags = local.default_tags
}
resource "azurerm_subnet" "subnet" {
name = "subnet-prod"
resource_group_name = azurerm_resource_group.core.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.1.0/24"]
}
resource "azurerm_network_security_group" "nsg" {
name = "nsg-prod"
location = var.location
resource_group_name = azurerm_resource_group.core.name
tags = local.default_tags
security_rule {
name = "RDP"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "3389"
source_address_prefix = "*"
destination_address_prefix = "*"
}
security_rule {
name = "SSH"
priority = 1002
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
resource "azurerm_subnet_network_security_group_association" "nsg_assoc" {
subnet_id = azurerm_subnet.subnet.id
network_security_group_id = azurerm_network_security_group.nsg.id
}
# Public IPs
resource "azurerm_public_ip" "win_pip1" {
name = "pip-okeus"
resource_group_name = azurerm_resource_group.core.name
location = var.location
allocation_method = "Static"
sku = "Standard"
tags = local.default_tags
}
resource "azurerm_public_ip" "linux_pip" {
name = "pip-kokopelli"
resource_group_name = azurerm_resource_group.core.name
location = var.location
allocation_method = "Static"
sku = "Standard"
tags = local.default_tags
}
# Network Interfaces
resource "azurerm_network_interface" "win_nic1" {
name = "nic-okeus"
location = var.location
resource_group_name = azurerm_resource_group.core.name
ip_configuration {
name = "ipconfig1"
subnet_id = azurerm_subnet.subnet.id
public_ip_address_id = azurerm_public_ip.win_pip1.id
private_ip_address_allocation = "Dynamic"
}
tags = local.default_tags
}
resource "azurerm_network_interface" "linux_nic" {
name = "nic-kokopelli"
location = var.location
resource_group_name = azurerm_resource_group.core.name
ip_configuration {
name = "ipconfig1"
subnet_id = azurerm_subnet.subnet.id
public_ip_address_id = azurerm_public_ip.linux_pip.id
private_ip_address_allocation = "Dynamic"
}
tags = local.default_tags
}
# Virtual Machines - Reduced to 2 VMs for free tier
resource "azurerm_windows_virtual_machine" "okeus" {
name = "okeus"
resource_group_name = azurerm_resource_group.core.name
location = var.location
network_interface_ids = [azurerm_network_interface.win_nic1.id]
size = "Standard_B1s" # Free tier eligible
admin_username = var.vm_admin_username
admin_password = random_password.vm_admin.result
os_disk {
name = "okeus-osdisk"
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2022-Datacenter"
version = "latest"
}
tags = local.default_tags
}
resource "azurerm_linux_virtual_machine" "kokopelli" {
name = "kokopelli"
resource_group_name = azurerm_resource_group.core.name
location = var.location
network_interface_ids = [azurerm_network_interface.linux_nic.id]
size = "Standard_B1s" # Free tier eligible
admin_username = var.vm_admin_username
admin_password = random_password.vm_admin.result
disable_password_authentication = false
os_disk {
name = "kokopelli-osdisk"
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "0001-com-ubuntu-server-focal"
sku = "20_04-lts-gen2"
version = "latest"
}
tags = local.default_tags
}
# Azure SQL - Fixed resource names
resource "random_integer" "sqlsuffix" {
min = 1000
max = 9999
}
resource "random_password" "sql_admin" {
length = 16
special = true
}
resource "azurerm_mssql_server" "sqlsvr" {
name = "sqlsrv${random_integer.sqlsuffix.result}"
resource_group_name = azurerm_resource_group.core.name
location = var.location
version = "12.0"
administrator_login = "sqladmin"
administrator_login_password = random_password.sql_admin.result
tags = local.default_tags
}
resource "azurerm_mssql_database" "hoporenkv" {
name = "Hoporenkv"
server_id = azurerm_mssql_server.sqlsvr.id
sku_name = "Basic" # Free tier has 32MB limit, Basic is cheapest paid option
tags = local.default_tags
}
resource "azurerm_key_vault_secret" "sql_admin_secret" {
name = "sql-admin-password"
value = random_password.sql_admin.result
key_vault_id = azurerm_key_vault.vault.id
depends_on = [azurerm_key_vault.vault]
}
# AAD Users - 10 users as requested
resource "random_password" "demo_user_passwords" {
count = 10
length = 16
special = true
}
resource "azuread_user" "demo_users" {
count = 10
user_principal_name = "demo-user-${count.index + 1}@${var.tenant_domain}"
display_name = "Demo User ${count.index + 1}"
mail_nickname = "demo-user-${count.index + 1}"
password = random_password.demo_user_passwords[count.index].result
force_password_change = false
}
resource "azurerm_key_vault_secret" "demo_user_secrets" {
count = 10
name = "demo-user-${count.index + 1}-password"
value = random_password.demo_user_passwords[count.index].result
key_vault_id = azurerm_key_vault.vault.id
depends_on = [azurerm_key_vault.vault]
}
resource "azurerm_role_assignment" "demo_user_roles" {
count = 10
principal_id = azuread_user.demo_users[count.index].object_id
role_definition_name = "Reader"
scope = azurerm_resource_group.core.id
}
# Monitoring - Fixed diagnostic settings
resource "azurerm_log_analytics_workspace" "law_vm" {
name = "demo-law-vm"
location = var.location
resource_group_name = azurerm_resource_group.core.name
sku = "PerGB2018"
retention_in_days = 30
tags = local.default_tags
}
# Budget
resource "azurerm_consumption_budget_subscription" "demo_budget" {
name = "demo-budget"
amount = 200 # Increased to match your budget
time_grain = "Monthly"
subscription_id = "/subscriptions/${data.azurerm_client_config.current.subscription_id}"
time_period {
start_date = formatdate("YYYY-MM-01'T'00:00:00Z", timestamp())
}
notification {
enabled = true
operator = "GreaterThan"
threshold = 80
contact_emails = [var.admin_email]
}
notification {
enabled = true
operator = "GreaterThan"
threshold = 100
contact_emails = [var.admin_email]
}
}
# ACR & Container App - Simplified for free tier
resource "random_integer" "rand" {
min = 1000
max = 9999
}
resource "azurerm_container_registry" "acr" {
name = "demoacr${random_integer.rand.result}"
resource_group_name = azurerm_resource_group.core.name
location = var.location
sku = "Basic"
admin_enabled = true
tags = local.default_tags
}
resource "azurerm_log_analytics_workspace" "law_app" {
name = "demo-law-app"
location = var.location
resource_group_name = azurerm_resource_group.core.name
sku = "PerGB2018"
retention_in_days = 30
tags = local.default_tags
}
resource "azurerm_container_app_environment" "env" {
name = "demo-env"
location = var.location
resource_group_name = azurerm_resource_group.core.name
log_analytics_workspace_id = azurerm_log_analytics_workspace.law_app.id
tags = local.default_tags
}
# Add wait time to ensure container environment is fully provisioned
resource "time_sleep" "wait_for_container_env" {
depends_on = [azurerm_container_app_environment.env]
create_duration = "60s"
}
# FIXED: Container App with proper dependencies and public image
resource "azurerm_container_app" "skennen" {
name = "skennen"
container_app_environment_id = azurerm_container_app_environment.env.id
resource_group_name = azurerm_resource_group.core.name
revision_mode = "Single"
# More explicit dependency management
depends_on = [
time_sleep.wait_for_container_env,
azurerm_container_app_environment.env,
azurerm_log_analytics_workspace.law_app,
azurerm_container_registry.acr
]
secret {
name = "acr-password"
value = azurerm_container_registry.acr.admin_password
}
registry {
server = azurerm_container_registry.acr.login_server
username = azurerm_container_registry.acr.admin_username
password_secret_name = "acr-password"
}
template {
container {
name = "skennen"
image = "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest" # Use a public image initially
cpu = 0.25
memory = "0.5Gi"
}
revision_suffix = "initial"
}
ingress {
external_enabled = true
target_port = 80
traffic_weight {
latest_revision = true
percentage = 100
}
}
tags = local.default_tags
}
# Static Web App - Fixed deprecated resource
resource "azurerm_static_web_app" "landing" {
name = "plan-jacquesingram"
resource_group_name = azurerm_resource_group.core.name
location = var.location
sku_tier = "Free"
sku_size = "Free"
tags = local.default_tags
}
# Outputs
output "windows_vm_ip" {
value = azurerm_public_ip.win_pip1.ip_address
}
output "linux_vm_ip" {
value = azurerm_public_ip.linux_pip.ip_address
}
output "container_registry_url" {
value = azurerm_container_registry.acr.login_server
}
output "key_vault_uri" {
value = azurerm_key_vault.vault.vault_uri
}
output "static_site_url" {
value = azurerm_static_web_app.landing.default_host_name
}
output "sql_server_fqdn" {
value = azurerm_mssql_server.sqlsvr.fully_qualified_domain_name
}
output "vm_admin_password" {
value = random_password.vm_admin.result
sensitive = true
}
output "container_app_url" {
value = azurerm_container_app.skennen.latest_revision_fqdn
description = "The URL of the container app"
}