[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M7B1S6CF3XPYXMXP6WQVC0AX":3,"skill-same:01M7B1S6CF3XPYXMXP6WQVC0AX":59},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":27,"commitSha":28,"skillDirectory":29,"forksCount":14,"repositoryHtmlUrl":30,"repositoryHomepageUrl":6,"ownerHtmlUrl":31,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":32,"install":33,"resources":46},"01M7B1S6CF3XPYXMXP6WQVC0AX","terraform-azure",null,"Provision Azure infrastructure with Terraform. Configure providers, manage state, and deploy resources. Use when implementing IaC for Azure.","aeroalgo\u002Fdev-hub","aeroalgo","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F71006969?v=4","01M7B06910BBQC29R55C0V7XYW","Андрей","01M7B0691R77MY9Q3YXE7W683M",0,"MIT","https:\u002F\u002Fgithub.com\u002Faeroalgo\u002Fdev-hub\u002Fblob\u002Fmaster\u002Fharness\u002Fskills\u002Fterraform-azure\u002FSKILL.md",[],[],"2026-11-15 14:19:17",false,"---\nname: terraform-azure\ndescription: Provision Azure infrastructure with Terraform. Configure providers, manage state, and deploy resources. Use when implementing IaC for Azure.\nlicense: MIT\nmetadata:\n  author: devops-skills\n  version: \"1.0\"\n---\n\n# Terraform Azure\n\nProvision and manage Azure infrastructure with Terraform using the AzureRM provider. Covers provider configuration, remote state, resource groups, VNets, AKS, Key Vault, complete .tf file examples, and production workflows.\n\n## When to Use\n\n- You need multi-cloud or cloud-agnostic Infrastructure as Code.\n- Your team standardizes on Terraform across AWS, Azure, and GCP.\n- You need plan\u002Fapply workflows with change preview before deployment.\n- You want modular, reusable infrastructure components.\n- You need state locking and drift detection for production infrastructure.\n\n## Prerequisites\n\n```bash\n# Install Terraform\nwget -O- https:\u002F\u002Fapt.releases.hashicorp.com\u002Fgpg | sudo gpg --dearmor -o \u002Fusr\u002Fshare\u002Fkeyrings\u002Fhashicorp-archive-keyring.gpg\necho \"deb [signed-by=\u002Fusr\u002Fshare\u002Fkeyrings\u002Fhashicorp-archive-keyring.gpg] https:\u002F\u002Fapt.releases.hashicorp.com $(lsb_release -cs) main\" | sudo tee \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fhashicorp.list\nsudo apt update && sudo apt install terraform\n\n# Verify installation\nterraform version\n\n# Install Azure CLI and login\ncurl -sL https:\u002F\u002Faka.ms\u002FInstallAzureCLIDeb | sudo bash\naz login\naz account set --subscription \"my-subscription-id\"\n\n# Create storage account for remote state\naz group create --name tfstate-rg --location eastus\naz storage account create \\\n  --name tfstate$(openssl rand -hex 4) \\\n  --resource-group tfstate-rg \\\n  --sku Standard_LRS \\\n  --encryption-services blob\naz storage container create \\\n  --name tfstate \\\n  --account-name tfstateXXXXXXXX\n```\n\n## Provider Configuration\n\n### providers.tf\n\n```hcl\nterraform {\n  required_version = \">= 1.5.0\"\n\n  required_providers {\n    azurerm = {\n      source  = \"hashicorp\u002Fazurerm\"\n      version = \"~> 3.80\"\n    }\n    azuread = {\n      source  = \"hashicorp\u002Fazuread\"\n      version = \"~> 2.47\"\n    }\n    random = {\n      source  = \"hashicorp\u002Frandom\"\n      version = \"~> 3.6\"\n    }\n  }\n\n  backend \"azurerm\" {\n    resource_group_name  = \"tfstate-rg\"\n    storage_account_name = \"tfstate12345abc\"\n    container_name       = \"tfstate\"\n    key                  = \"prod.terraform.tfstate\"\n  }\n}\n\nprovider \"azurerm\" {\n  features {\n    key_vault {\n      purge_soft_delete_on_destroy    = false\n      recover_soft_deleted_key_vaults = true\n    }\n    resource_group {\n      prevent_deletion_if_contains_resources = true\n    }\n  }\n  # Optional: use a specific subscription\n  # subscription_id = var.subscription_id\n}\n\nprovider \"azuread\" {}\n```\n\n### variables.tf\n\n```hcl\nvariable \"environment\" {\n  description = \"Environment name (dev, staging, prod)\"\n  type        = string\n  validation {\n    condition     = contains([\"dev\", \"staging\", \"prod\"], var.environment)\n    error_message = \"Environment must be dev, staging, or prod.\"\n  }\n}\n\nvariable \"location\" {\n  description = \"Azure region for all resources\"\n  type        = string\n  default     = \"eastus\"\n}\n\nvariable \"project_name\" {\n  description = \"Project name used in resource naming\"\n  type        = string\n  default     = \"myapp\"\n}\n\nvariable \"tags\" {\n  description = \"Tags applied to all resources\"\n  type        = map(string)\n  default     = {}\n}\n\nvariable \"sql_admin_password\" {\n  description = \"SQL Server admin password\"\n  type        = string\n  sensitive   = true\n}\n\nvariable \"aks_admin_group_id\" {\n  description = \"Azure AD group ID for AKS admin access\"\n  type        = string\n}\n\nlocals {\n  name_prefix = \"${var.project_name}-${var.environment}\"\n  common_tags = merge(var.tags, {\n    environment = var.environment\n    project     = var.project_name\n    managed_by  = \"terraform\"\n  })\n}\n```\n\n### terraform.tfvars (per environment)\n\n```hcl\n# terraform.prod.tfvars\nenvironment        = \"prod\"\nlocation           = \"eastus\"\nproject_name       = \"myapp\"\naks_admin_group_id = \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"\n\ntags = {\n  cost_center = \"engineering\"\n  owner       = \"platform-team\"\n}\n```\n\n## Resource Group\n\n### resource-group.tf\n\n```hcl\nresource \"azurerm_resource_group\" \"main\" {\n  name     = \"${local.name_prefix}-rg\"\n  location = var.location\n  tags     = local.common_tags\n}\n```\n\n## Virtual Network\n\n### network.tf\n\n```hcl\nresource \"azurerm_virtual_network\" \"main\" {\n  name                = \"${local.name_prefix}-vnet\"\n  location            = azurerm_resource_group.main.location\n  resource_group_name = azurerm_resource_group.main.name\n  address_space       = [\"10.0.0.0\u002F16\"]\n  tags                = local.common_tags\n}\n\nresource \"azurerm_subnet\" \"aks\" {\n  name                 = \"aks-subnet\"\n  resource_group_name  = azurerm_resource_group.main.name\n  virtual_network_name = azurerm_virtual_network.main.name\n  address_prefixes     = [\"10.0.1.0\u002F22\"]\n}\n\nresource \"azurerm_subnet\" \"app\" {\n  name                 = \"app-subnet\"\n  resource_group_name  = azurerm_resource_group.main.name\n  virtual_network_name = azurerm_virtual_network.main.name\n  address_prefixes     = [\"10.0.8.0\u002F24\"]\n}\n\nresource \"azurerm_subnet\" \"data\" {\n  name                 = \"data-subnet\"\n  resource_group_name  = azurerm_resource_group.main.name\n  virtual_network_name = azurerm_virtual_network.main.name\n  address_prefixes     = [\"10.0.9.0\u002F24\"]\n\n  private_endpoint_network_policies_enabled = true\n}\n\nresource \"azurerm_network_security_group\" \"app\" {\n  name                = \"${local.name_prefix}-app-nsg\"\n  location            = azurerm_resource_group.main.location\n  resource_group_name = azurerm_resource_group.main.name\n\n  security_rule {\n    name                       = \"AllowHTTPS\"\n    priority                   = 100\n    direction                  = \"Inbound\"\n    access                     = \"Allow\"\n    protocol                   = \"Tcp\"\n    source_port_range          = \"*\"\n    destination_port_range     = \"443\"\n    source_address_prefix      = \"*\"\n    destination_address_prefix = \"*\"\n  }\n\n  tags = local.common_tags\n}\n\nresource \"azurerm_subnet_network_security_group_association\" \"app\" {\n  subnet_id                 = azurerm_subnet.app.id\n  network_security_group_id = azurerm_network_security_group.app.id\n}\n```\n\n## AKS Cluster\n\n### aks.tf\n\n```hcl\nresource \"azurerm_log_analytics_workspace\" \"aks\" {\n  name                = \"${local.name_prefix}-law\"\n  location            = azurerm_resource_group.main.location\n  resource_group_name = azurerm_resource_group.main.name\n  sku                 = \"PerGB2018\"\n  retention_in_days   = 30\n  tags                = local.common_tags\n}\n\nresource \"azurerm_kubernetes_cluster\" \"main\" {\n  name                = \"${local.name_prefix}-aks\"\n  location            = azurerm_resource_group.main.location\n  resource_group_name = azurerm_resource_group.main.name\n  dns_prefix          = \"${var.project_name}-${var.environment}\"\n  kubernetes_version  = \"1.28\"\n\n  default_node_pool {\n    name                = \"system\"\n    vm_size             = \"Standard_D4s_v5\"\n    enable_auto_scaling = true\n    min_count           = 2\n    max_count           = 5\n    zones               = [1, 2, 3]\n    vnet_subnet_id      = azurerm_subnet.aks.id\n    os_disk_size_gb     = 128\n    os_disk_type        = \"Managed\"\n    max_pods            = 50\n\n    node_labels = {\n      role = \"system\"\n    }\n  }\n\n  identity {\n    type = \"SystemAssigned\"\n  }\n\n  network_profile {\n    network_plugin    = \"azure\"\n    network_policy    = \"calico\"\n    service_cidr      = \"10.1.0.0\u002F16\"\n    dns_service_ip    = \"10.1.0.10\"\n    load_balancer_sku = \"standard\"\n  }\n\n  azure_active_directory_role_based_access_control {\n    managed                = true\n    azure_rbac_enabled     = true\n    admin_group_object_ids = [var.aks_admin_group_id]\n  }\n\n  oms_agent {\n    log_analytics_workspace_id = azurerm_log_analytics_workspace.aks.id\n  }\n\n  key_vault_secrets_provider {\n    secret_rotation_enabled  = true\n    secret_rotation_interval = \"2m\"\n  }\n\n  tags = local.common_tags\n}\n\nresource \"azurerm_kubernetes_cluster_node_pool\" \"app\" {\n  name                  = \"app\"\n  kubernetes_cluster_id = azurerm_kubernetes_cluster.main.id\n  vm_size               = \"Standard_D8s_v5\"\n  enable_auto_scaling   = true\n  min_count             = 2\n  max_count             = 20\n  zones                 = [1, 2, 3]\n  vnet_subnet_id        = azurerm_subnet.aks.id\n  max_pods              = 50\n\n  node_labels = {\n    workload = \"app\"\n  }\n\n  node_taints = [\n    \"dedicated=app:NoSchedule\"\n  ]\n\n  tags = local.common_tags\n}\n```\n\n## Key Vault\n\n### keyvault.tf\n\n```hcl\ndata \"azurerm_client_config\" \"current\" {}\n\nresource \"azurerm_key_vault\" \"main\" {\n  name                        = \"${var.project_name}-${var.environment}-kv\"\n  location                    = azurerm_resource_group.main.location\n  resource_group_name         = azurerm_resource_group.main.name\n  tenant_id                   = data.azurerm_client_config.current.tenant_id\n  sku_name                    = \"standard\"\n  soft_delete_retention_days  = 90\n  purge_protection_enabled    = true\n  enabled_for_disk_encryption = true\n\n  network_acls {\n    default_action = \"Deny\"\n    bypass         = \"AzureServices\"\n    ip_rules       = var.allowed_ip_ranges\n    virtual_network_subnet_ids = [\n      azurerm_subnet.app.id,\n      azurerm_subnet.aks.id,\n    ]\n  }\n\n  tags = local.common_tags\n}\n\nresource \"azurerm_key_vault_access_policy\" \"terraform\" {\n  key_vault_id = azurerm_key_vault.main.id\n  tenant_id    = data.azurerm_client_config.current.tenant_id\n  object_id    = data.azurerm_client_config.current.object_id\n\n  secret_permissions = [\n    \"Get\", \"List\", \"Set\", \"Delete\", \"Purge\", \"Recover\"\n  ]\n\n  key_permissions = [\n    \"Get\", \"List\", \"Create\", \"Delete\", \"Purge\", \"Recover\",\n    \"WrapKey\", \"UnwrapKey\"\n  ]\n}\n\nresource \"azurerm_key_vault_access_policy\" \"aks\" {\n  key_vault_id = azurerm_key_vault.main.id\n  tenant_id    = data.azurerm_client_config.current.tenant_id\n  object_id    = azurerm_kubernetes_cluster.main.key_vault_secrets_provider[0].secret_identity[0].object_id\n\n  secret_permissions = [\"Get\", \"List\"]\n}\n\nresource \"azurerm_key_vault_secret\" \"sql_password\" {\n  name         = \"sql-admin-password\"\n  value        = var.sql_admin_password\n  key_vault_id = azurerm_key_vault.main.id\n\n  depends_on = [azurerm_key_vault_access_policy.terraform]\n}\n```\n\n## SQL Database\n\n### database.tf\n\n```hcl\nresource \"azurerm_mssql_server\" \"main\" {\n  name                         = \"${local.name_prefix}-sql\"\n  resource_group_name          = azurerm_resource_group.main.name\n  location                     = azurerm_resource_group.main.location\n  version                      = \"12.0\"\n  administrator_login          = \"sqladmin\"\n  administrator_login_password = var.sql_admin_password\n  minimum_tls_version          = \"1.2\"\n\n  azuread_administrator {\n    login_username = \"SQL Admins\"\n    object_id      = var.aks_admin_group_id\n  }\n\n  tags = local.common_tags\n}\n\nresource \"azurerm_mssql_database\" \"main\" {\n  name         = \"${var.project_name}-db\"\n  server_id    = azurerm_mssql_server.main.id\n  collation    = \"SQL_Latin1_General_CP1_CI_AS\"\n  sku_name     = var.environment == \"prod\" ? \"BC_Gen5_4\" : \"GP_S_Gen5_2\"\n  max_size_gb  = var.environment == \"prod\" ? 256 : 32\n  zone_redundant = var.environment == \"prod\"\n\n  short_term_retention_policy {\n    retention_days = var.environment == \"prod\" ? 14 : 7\n  }\n\n  tags = local.common_tags\n}\n\nresource \"azurerm_private_endpoint\" \"sql\" {\n  name                = \"${local.name_prefix}-sql-pe\"\n  location            = azurerm_resource_group.main.location\n  resource_group_name = azurerm_resource_group.main.name\n  subnet_id           = azurerm_subnet.data.id\n\n  private_service_connection {\n    name                           = \"sql-connection\"\n    private_connection_resource_id = azurerm_mssql_server.main.id\n    subresource_names              = [\"sqlServer\"]\n    is_manual_connection           = false\n  }\n\n  tags = local.common_tags\n}\n```\n\n## Outputs\n\n### outputs.tf\n\n```hcl\noutput \"resource_group_name\" {\n  value = azurerm_resource_group.main.name\n}\n\noutput \"aks_cluster_name\" {\n  value = azurerm_kubernetes_cluster.main.name\n}\n\noutput \"aks_kube_config\" {\n  value     = azurerm_kubernetes_cluster.main.kube_config_raw\n  sensitive = true\n}\n\noutput \"key_vault_uri\" {\n  value = azurerm_key_vault.main.vault_uri\n}\n\noutput \"sql_server_fqdn\" {\n  value = azurerm_mssql_server.main.fully_qualified_domain_name\n}\n\noutput \"vnet_id\" {\n  value = azurerm_virtual_network.main.id\n}\n```\n\n## Terraform Workflow Commands\n\n```bash\n# Initialize (download providers, configure backend)\nterraform init\n\n# Validate configuration syntax\nterraform validate\n\n# Format all .tf files\nterraform fmt -recursive\n\n# Plan changes for a specific environment\nterraform plan \\\n  -var-file=\"terraform.prod.tfvars\" \\\n  -var=\"sql_admin_password=$(az keyvault secret show --vault-name ops-vault --name sql-pass --query value -o tsv)\" \\\n  -out=tfplan\n\n# Apply the saved plan\nterraform apply tfplan\n\n# Apply with auto-approve (CI\u002FCD pipelines only)\nterraform apply \\\n  -var-file=\"terraform.prod.tfvars\" \\\n  -auto-approve\n\n# Destroy infrastructure (careful!)\nterraform plan -destroy -var-file=\"terraform.prod.tfvars\" -out=destroyplan\nterraform apply destroyplan\n\n# Import existing resources into state\nterraform import azurerm_resource_group.main \u002Fsubscriptions\u002F{sub}\u002FresourceGroups\u002Fmyapp-prod-rg\n\n# Show current state\nterraform state list\nterraform state show azurerm_kubernetes_cluster.main\n\n# Move resources in state (renaming)\nterraform state mv azurerm_resource_group.old azurerm_resource_group.new\n\n# Refresh state from real infrastructure\nterraform refresh -var-file=\"terraform.prod.tfvars\"\n\n# Unlock stuck state\nterraform force-unlock LOCK_ID\n\n# Use workspaces for environment isolation\nterraform workspace new prod\nterraform workspace select prod\nterraform workspace list\n```\n\n## Module Structure\n\n```\nproject\u002F\n  modules\u002F\n    networking\u002F\n      main.tf\n      variables.tf\n      outputs.tf\n    aks\u002F\n      main.tf\n      variables.tf\n      outputs.tf\n    database\u002F\n      main.tf\n      variables.tf\n      outputs.tf\n  environments\u002F\n    dev\u002F\n      main.tf\n      terraform.tfvars\n      backend.tf\n    prod\u002F\n      main.tf\n      terraform.tfvars\n      backend.tf\n```\n\n### Using Modules\n\n```hcl\n# environments\u002Fprod\u002Fmain.tf\nmodule \"networking\" {\n  source = \"..\u002F..\u002Fmodules\u002Fnetworking\"\n\n  environment   = var.environment\n  location      = var.location\n  project_name  = var.project_name\n  address_space = [\"10.0.0.0\u002F16\"]\n}\n\nmodule \"aks\" {\n  source = \"..\u002F..\u002Fmodules\u002Faks\"\n\n  environment         = var.environment\n  location            = var.location\n  project_name        = var.project_name\n  resource_group_name = module.networking.resource_group_name\n  subnet_id           = module.networking.aks_subnet_id\n  admin_group_id      = var.aks_admin_group_id\n}\n\nmodule \"database\" {\n  source = \"..\u002F..\u002Fmodules\u002Fdatabase\"\n\n  environment         = var.environment\n  location            = var.location\n  project_name        = var.project_name\n  resource_group_name = module.networking.resource_group_name\n  subnet_id           = module.networking.data_subnet_id\n  admin_password      = var.sql_admin_password\n}\n```\n\n## Troubleshooting\n\n| Symptom | Cause | Fix |\n|---------|-------|-----|\n| `Error acquiring state lock` | Previous run crashed or concurrent access | Run `terraform force-unlock LOCK_ID` after confirming no other run is active |\n| `Provider version constraint error` | Version conflict in required_providers | Run `terraform init -upgrade` to fetch compatible versions |\n| `Resource already exists` | Resource created outside Terraform | Import with `terraform import` to bring it under management |\n| `Cycle detected` in plan | Circular dependency between resources | Restructure references or use `depends_on` carefully |\n| State file corruption | Concurrent writes or manual edits | Restore from state backup in the storage account versioning |\n| `AuthorizationFailed` during apply | Service principal lacks RBAC permissions | Assign Contributor role on subscription or resource group |\n| Plan shows unexpected changes | Drift from manual portal changes | Run `terraform refresh` then `terraform plan` to reconcile |\n| Module source not found | Incorrect relative path or registry reference | Verify path in `source` attribute; run `terraform init` again |\n\n## Related Skills\n\n- `arm-templates` -- Azure-native IaC alternative with Bicep.\n- `azure-aks` -- AKS cluster details and kubectl operations.\n- `azure-networking` -- VNet and NSG design referenced in Terraform configs.\n- `azure-sql` -- Database provisioning and security configurations.\n- `azure-vms` -- VM sizing and scale set configurations.\n","# Terraform Azure\n\nProvision and manage Azure infrastructure with Terraform using the AzureRM provider. Covers provider configuration, remote state, resource groups, VNets, AKS, Key Vault, complete .tf file examples, and production workflows.\n\n## When to Use\n\n- You need multi-cloud or cloud-agnostic Infrastructure as Code.\n- Your team standardizes on Terraform across AWS, Azure, and GCP.\n- You need plan\u002Fapply workflows with change preview before deployment.\n- You want modular, reusable infrastructure components.\n- You need state locking and drift detection for production infrastructure.\n\n## Prerequisites\n\n```bash\n# Install Terraform\nwget -O- https:\u002F\u002Fapt.releases.hashicorp.com\u002Fgpg | sudo gpg --dearmor -o \u002Fusr\u002Fshare\u002Fkeyrings\u002Fhashicorp-archive-keyring.gpg\necho \"deb [signed-by=\u002Fusr\u002Fshare\u002Fkeyrings\u002Fhashicorp-archive-keyring.gpg] https:\u002F\u002Fapt.releases.hashicorp.com $(lsb_release -cs) main\" | sudo tee \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fhashicorp.list\nsudo apt update && sudo apt install terraform\n\n# Verify installation\nterraform version\n\n# Install Azure CLI and login\ncurl -sL https:\u002F\u002Faka.ms\u002FInstallAzureCLIDeb | sudo bash\naz login\naz account set --subscription \"my-subscription-id\"\n\n# Create storage account for remote state\naz group create --name tfstate-rg --location eastus\naz storage account create \\\n  --name tfstate$(openssl rand -hex 4) \\\n  --resource-group tfstate-rg \\\n  --sku Standard_LRS \\\n  --encryption-services blob\naz storage container create \\\n  --name tfstate \\\n  --account-name tfstateXXXXXXXX\n```\n\n## Provider Configuration\n\n### providers.tf\n\n```hcl\nterraform {\n  required_version = \">= 1.5.0\"\n\n  required_providers {\n    azurerm = {\n      source  = \"hashicorp\u002Fazurerm\"\n      version = \"~> 3.80\"\n    }\n    azuread = {\n      source  = \"hashicorp\u002Fazuread\"\n      version = \"~> 2.47\"\n    }\n    random = {\n      source  = \"hashicorp\u002Frandom\"\n      version = \"~> 3.6\"\n    }\n  }\n\n  backend \"azurerm\" {\n    resource_group_name  = \"tfstate-rg\"\n    storage_account_name = \"tfstate12345abc\"\n    container_name       = \"tfstate\"\n    key                  = \"prod.terraform.tfstate\"\n  }\n}\n\nprovider \"azurerm\" {\n  features {\n    key_vault {\n      purge_soft_delete_on_destroy    = false\n      recover_soft_deleted_key_vaults = true\n    }\n    resource_group {\n      prevent_deletion_if_contains_resources = true\n    }\n  }\n  # Optional: use a specific subscription\n  # subscription_id = var.subscription_id\n}\n\nprovider \"azuread\" {}\n```\n\n### variables.tf\n\n```hcl\nvariable \"environment\" {\n  description = \"Environment name (dev, staging, prod)\"\n  type        = string\n  validation {\n    condition     = contains([\"dev\", \"staging\", \"prod\"], var.environment)\n    error_message = \"Environment must be dev, staging, or prod.\"\n  }\n}\n\nvariable \"location\" {\n  description = \"Azure region for all resources\"\n  type        = string\n  default     = \"eastus\"\n}\n\nvariable \"project_name\" {\n  description = \"Project name used in resource naming\"\n  type        = string\n  default     = \"myapp\"\n}\n\nvariable \"tags\" {\n  description = \"Tags applied to all resources\"\n  type        = map(string)\n  default     = {}\n}\n\nvariable \"sql_admin_password\" {\n  description = \"SQL Server admin password\"\n  type        = string\n  sensitive   = true\n}\n\nvariable \"aks_admin_group_id\" {\n  description = \"Azure AD group ID for AKS admin access\"\n  type        = string\n}\n\nlocals {\n  name_prefix = \"${var.project_name}-${var.environment}\"\n  common_tags = merge(var.tags, {\n    environment = var.environment\n    project     = var.project_name\n    managed_by  = \"terraform\"\n  })\n}\n```\n\n### terraform.tfvars (per environment)\n\n```hcl\n# terraform.prod.tfvars\nenvironment        = \"prod\"\nlocation           = \"eastus\"\nproject_name       = \"myapp\"\naks_admin_group_id = \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"\n\ntags = {\n  cost_center = \"engineering\"\n  owner       = \"platform-team\"\n}\n```\n\n## Resource Group\n\n### resource-group.tf\n\n```hcl\nresource \"azurerm_resource_group\" \"main\" {\n  name     = \"${local.name_prefix}-rg\"\n  location = var.location\n  tags     = local.common_tags\n}\n```\n\n## Virtual Network\n\n### network.tf\n\n```hcl\nresource \"azurerm_virtual_network\" \"main\" {\n  name                = \"${local.name_prefix}-vnet\"\n  location            = azurerm_resource_group.main.location\n  resource_group_name = azurerm_resource_group.main.name\n  address_space       = [\"10.0.0.0\u002F16\"]\n  tags                = local.common_tags\n}\n\nresource \"azurerm_subnet\" \"aks\" {\n  name                 = \"aks-subnet\"\n  resource_group_name  = azurerm_resource_group.main.name\n  virtual_network_name = azurerm_virtual_network.main.name\n  address_prefixes     = [\"10.0.1.0\u002F22\"]\n}\n\nresource \"azurerm_subnet\" \"app\" {\n  name                 = \"app-subnet\"\n  resource_group_name  = azurerm_resource_group.main.name\n  virtual_network_name = azurerm_virtual_network.main.name\n  address_prefixes     = [\"10.0.8.0\u002F24\"]\n}\n\nresource \"azurerm_subnet\" \"data\" {\n  name                 = \"data-subnet\"\n  resource_group_name  = azurerm_resource_group.main.name\n  virtual_network_name = azurerm_virtual_network.main.name\n  address_prefixes     = [\"10.0.9.0\u002F24\"]\n\n  private_endpoint_network_policies_enabled = true\n}\n\nresource \"azurerm_network_security_group\" \"app\" {\n  name                = \"${local.name_prefix}-app-nsg\"\n  location            = azurerm_resource_group.main.location\n  resource_group_name = azurerm_resource_group.main.name\n\n  security_rule {\n    name                       = \"AllowHTTPS\"\n    priority                   = 100\n    direction                  = \"Inbound\"\n    access                     = \"Allow\"\n    protocol                   = \"Tcp\"\n    source_port_range          = \"*\"\n    destination_port_range     = \"443\"\n    source_address_prefix      = \"*\"\n    destination_address_prefix = \"*\"\n  }\n\n  tags = local.common_tags\n}\n\nresource \"azurerm_subnet_network_security_group_association\" \"app\" {\n  subnet_id                 = azurerm_subnet.app.id\n  network_security_group_id = azurerm_network_security_group.app.id\n}\n```\n\n## AKS Cluster\n\n### aks.tf\n\n```hcl\nresource \"azurerm_log_analytics_workspace\" \"aks\" {\n  name                = \"${local.name_prefix}-law\"\n  location            = azurerm_resource_group.main.location\n  resource_group_name = azurerm_resource_group.main.name\n  sku                 = \"PerGB2018\"\n  retention_in_days   = 30\n  tags                = local.common_tags\n}\n\nresource \"azurerm_kubernetes_cluster\" \"main\" {\n  name                = \"${local.name_prefix}-aks\"\n  location            = azurerm_resource_group.main.location\n  resource_group_name = azurerm_resource_group.main.name\n  dns_prefix          = \"${var.project_name}-${var.environment}\"\n  kubernetes_version  = \"1.28\"\n\n  default_node_pool {\n    name                = \"system\"\n    vm_size             = \"Standard_D4s_v5\"\n    enable_auto_scaling = true\n    min_count           = 2\n    max_count           = 5\n    zones               = [1, 2, 3]\n    vnet_subnet_id      = azurerm_subnet.aks.id\n    os_disk_size_gb     = 128\n    os_disk_type        = \"Managed\"\n    max_pods            = 50\n\n    node_labels = {\n      role = \"system\"\n    }\n  }\n\n  identity {\n    type = \"SystemAssigned\"\n  }\n\n  network_profile {\n    network_plugin    = \"azure\"\n    network_policy    = \"calico\"\n    service_cidr      = \"10.1.0.0\u002F16\"\n    dns_service_ip    = \"10.1.0.10\"\n    load_balancer_sku = \"standard\"\n  }\n\n  azure_active_directory_role_based_access_control {\n    managed                = true\n    azure_rbac_enabled     = true\n    admin_group_object_ids = [var.aks_admin_group_id]\n  }\n\n  oms_agent {\n    log_analytics_workspace_id = azurerm_log_analytics_workspace.aks.id\n  }\n\n  key_vault_secrets_provider {\n    secret_rotation_enabled  = true\n    secret_rotation_interval = \"2m\"\n  }\n\n  tags = local.common_tags\n}\n\nresource \"azurerm_kubernetes_cluster_node_pool\" \"app\" {\n  name                  = \"app\"\n  kubernetes_cluster_id = azurerm_kubernetes_cluster.main.id\n  vm_size               = \"Standard_D8s_v5\"\n  enable_auto_scaling   = true\n  min_count             = 2\n  max_count             = 20\n  zones                 = [1, 2, 3]\n  vnet_subnet_id        = azurerm_subnet.aks.id\n  max_pods              = 50\n\n  node_labels = {\n    workload = \"app\"\n  }\n\n  node_taints = [\n    \"dedicated=app:NoSchedule\"\n  ]\n\n  tags = local.common_tags\n}\n```\n\n## Key Vault\n\n### keyvault.tf\n\n```hcl\ndata \"azurerm_client_config\" \"current\" {}\n\nresource \"azurerm_key_vault\" \"main\" {\n  name                        = \"${var.project_name}-${var.environment}-kv\"\n  location                    = azurerm_resource_group.main.location\n  resource_group_name         = azurerm_resource_group.main.name\n  tenant_id                   = data.azurerm_client_config.current.tenant_id\n  sku_name                    = \"standard\"\n  soft_delete_retention_days  = 90\n  purge_protection_enabled    = true\n  enabled_for_disk_encryption = true\n\n  network_acls {\n    default_action = \"Deny\"\n    bypass         = \"AzureServices\"\n    ip_rules       = var.allowed_ip_ranges\n    virtual_network_subnet_ids = [\n      azurerm_subnet.app.id,\n      azurerm_subnet.aks.id,\n    ]\n  }\n\n  tags = local.common_tags\n}\n\nresource \"azurerm_key_vault_access_policy\" \"terraform\" {\n  key_vault_id = azurerm_key_vault.main.id\n  tenant_id    = data.azurerm_client_config.current.tenant_id\n  object_id    = data.azurerm_client_config.current.object_id\n\n  secret_permissions = [\n    \"Get\", \"List\", \"Set\", \"Delete\", \"Purge\", \"Recover\"\n  ]\n\n  key_permissions = [\n    \"Get\", \"List\", \"Create\", \"Delete\", \"Purge\", \"Recover\",\n    \"WrapKey\", \"UnwrapKey\"\n  ]\n}\n\nresource \"azurerm_key_vault_access_policy\" \"aks\" {\n  key_vault_id = azurerm_key_vault.main.id\n  tenant_id    = data.azurerm_client_config.current.tenant_id\n  object_id    = azurerm_kubernetes_cluster.main.key_vault_secrets_provider[0].secret_identity[0].object_id\n\n  secret_permissions = [\"Get\", \"List\"]\n}\n\nresource \"azurerm_key_vault_secret\" \"sql_password\" {\n  name         = \"sql-admin-password\"\n  value        = var.sql_admin_password\n  key_vault_id = azurerm_key_vault.main.id\n\n  depends_on = [azurerm_key_vault_access_policy.terraform]\n}\n```\n\n## SQL Database\n\n### database.tf\n\n```hcl\nresource \"azurerm_mssql_server\" \"main\" {\n  name                         = \"${local.name_prefix}-sql\"\n  resource_group_name          = azurerm_resource_group.main.name\n  location                     = azurerm_resource_group.main.location\n  version                      = \"12.0\"\n  administrator_login          = \"sqladmin\"\n  administrator_login_password = var.sql_admin_password\n  minimum_tls_version          = \"1.2\"\n\n  azuread_administrator {\n    login_username = \"SQL Admins\"\n    object_id      = var.aks_admin_group_id\n  }\n\n  tags = local.common_tags\n}\n\nresource \"azurerm_mssql_database\" \"main\" {\n  name         = \"${var.project_name}-db\"\n  server_id    = azurerm_mssql_server.main.id\n  collation    = \"SQL_Latin1_General_CP1_CI_AS\"\n  sku_name     = var.environment == \"prod\" ? \"BC_Gen5_4\" : \"GP_S_Gen5_2\"\n  max_size_gb  = var.environment == \"prod\" ? 256 : 32\n  zone_redundant = var.environment == \"prod\"\n\n  short_term_retention_policy {\n    retention_days = var.environment == \"prod\" ? 14 : 7\n  }\n\n  tags = local.common_tags\n}\n\nresource \"azurerm_private_endpoint\" \"sql\" {\n  name                = \"${local.name_prefix}-sql-pe\"\n  location            = azurerm_resource_group.main.location\n  resource_group_name = azurerm_resource_group.main.name\n  subnet_id           = azurerm_subnet.data.id\n\n  private_service_connection {\n    name                           = \"sql-connection\"\n    private_connection_resource_id = azurerm_mssql_server.main.id\n    subresource_names              = [\"sqlServer\"]\n    is_manual_connection           = false\n  }\n\n  tags = local.common_tags\n}\n```\n\n## Outputs\n\n### outputs.tf\n\n```hcl\noutput \"resource_group_name\" {\n  value = azurerm_resource_group.main.name\n}\n\noutput \"aks_cluster_name\" {\n  value = azurerm_kubernetes_cluster.main.name\n}\n\noutput \"aks_kube_config\" {\n  value     = azurerm_kubernetes_cluster.main.kube_config_raw\n  sensitive = true\n}\n\noutput \"key_vault_uri\" {\n  value = azurerm_key_vault.main.vault_uri\n}\n\noutput \"sql_server_fqdn\" {\n  value = azurerm_mssql_server.main.fully_qualified_domain_name\n}\n\noutput \"vnet_id\" {\n  value = azurerm_virtual_network.main.id\n}\n```\n\n## Terraform Workflow Commands\n\n```bash\n# Initialize (download providers, configure backend)\nterraform init\n\n# Validate configuration syntax\nterraform validate\n\n# Format all .tf files\nterraform fmt -recursive\n\n# Plan changes for a specific environment\nterraform plan \\\n  -var-file=\"terraform.prod.tfvars\" \\\n  -var=\"sql_admin_password=$(az keyvault secret show --vault-name ops-vault --name sql-pass --query value -o tsv)\" \\\n  -out=tfplan\n\n# Apply the saved plan\nterraform apply tfplan\n\n# Apply with auto-approve (CI\u002FCD pipelines only)\nterraform apply \\\n  -var-file=\"terraform.prod.tfvars\" \\\n  -auto-approve\n\n# Destroy infrastructure (careful!)\nterraform plan -destroy -var-file=\"terraform.prod.tfvars\" -out=destroyplan\nterraform apply destroyplan\n\n# Import existing resources into state\nterraform import azurerm_resource_group.main \u002Fsubscriptions\u002F{sub}\u002FresourceGroups\u002Fmyapp-prod-rg\n\n# Show current state\nterraform state list\nterraform state show azurerm_kubernetes_cluster.main\n\n# Move resources in state (renaming)\nterraform state mv azurerm_resource_group.old azurerm_resource_group.new\n\n# Refresh state from real infrastructure\nterraform refresh -var-file=\"terraform.prod.tfvars\"\n\n# Unlock stuck state\nterraform force-unlock LOCK_ID\n\n# Use workspaces for environment isolation\nterraform workspace new prod\nterraform workspace select prod\nterraform workspace list\n```\n\n## Module Structure\n\n```\nproject\u002F\n  modules\u002F\n    networking\u002F\n      main.tf\n      variables.tf\n      outputs.tf\n    aks\u002F\n      main.tf\n      variables.tf\n      outputs.tf\n    database\u002F\n      main.tf\n      variables.tf\n      outputs.tf\n  environments\u002F\n    dev\u002F\n      main.tf\n      terraform.tfvars\n      backend.tf\n    prod\u002F\n      main.tf\n      terraform.tfvars\n      backend.tf\n```\n\n### Using Modules\n\n```hcl\n# environments\u002Fprod\u002Fmain.tf\nmodule \"networking\" {\n  source = \"..\u002F..\u002Fmodules\u002Fnetworking\"\n\n  environment   = var.environment\n  location      = var.location\n  project_name  = var.project_name\n  address_space = [\"10.0.0.0\u002F16\"]\n}\n\nmodule \"aks\" {\n  source = \"..\u002F..\u002Fmodules\u002Faks\"\n\n  environment         = var.environment\n  location            = var.location\n  project_name        = var.project_name\n  resource_group_name = module.networking.resource_group_name\n  subnet_id           = module.networking.aks_subnet_id\n  admin_group_id      = var.aks_admin_group_id\n}\n\nmodule \"database\" {\n  source = \"..\u002F..\u002Fmodules\u002Fdatabase\"\n\n  environment         = var.environment\n  location            = var.location\n  project_name        = var.project_name\n  resource_group_name = module.networking.resource_group_name\n  subnet_id           = module.networking.data_subnet_id\n  admin_password      = var.sql_admin_password\n}\n```\n\n## Troubleshooting\n\n| Symptom | Cause | Fix |\n|---------|-------|-----|\n| `Error acquiring state lock` | Previous run crashed or concurrent access | Run `terraform force-unlock LOCK_ID` after confirming no other run is active |\n| `Provider version constraint error` | Version conflict in required_providers | Run `terraform init -upgrade` to fetch compatible versions |\n| `Resource already exists` | Resource created outside Terraform | Import with `terraform import` to bring it under management |\n| `Cycle detected` in plan | Circular dependency between resources | Restructure references or use `depends_on` carefully |\n| State file corruption | Concurrent writes or manual edits | Restore from state backup in the storage account versioning |\n| `AuthorizationFailed` during apply | Service principal lacks RBAC permissions | Assign Contributor role on subscription or resource group |\n| Plan shows unexpected changes | Drift from manual portal changes | Run `terraform refresh` then `terraform plan` to reconcile |\n| Module source not found | Incorrect relative path or registry reference | Verify path in `source` attribute; run `terraform init` again |\n\n## Related Skills\n\n- `arm-templates` -- Azure-native IaC alternative with Bicep.\n- `azure-aks` -- AKS cluster details and kubectl operations.\n- `azure-networking` -- VNet and NSG design referenced in Terraform configs.\n- `azure-sql` -- Database provisioning and security configurations.\n- `azure-vms` -- VM sizing and scale set configurations.\n",{"name":5,"license":15,"metadata":24,"description":7},{"author":25,"version":26},"devops-skills","1.0","master","6afd82404843540f5a44d929a8738661d4ee1a46","harness\u002Fskills\u002Fterraform-azure","https:\u002F\u002Fgithub.com\u002Faeroalgo\u002Fdev-hub","https:\u002F\u002Fgithub.com\u002Faeroalgo","2026-10-30 21:15:25",{"source":8,"skillName":5,"commands":34,"prompt":44,"zipAvailable":45},[35,38,41],{"tool":36,"command":37},"npx","npx skills add aeroalgo\u002Fdev-hub --skill terraform-azure",{"tool":39,"command":40},"bunx","bunx skills add aeroalgo\u002Fdev-hub --skill terraform-azure",{"tool":42,"command":43},"pnpm","pnpm dlx skills add aeroalgo\u002Fdev-hub --skill terraform-azure","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Faeroalgo\u002Fdev-hub\u002Fblob\u002Fmaster\u002Fharness\u002Fskills\u002Fterraform-azure\u002FSKILL.md",true,[47,53],{"path":48,"resourceType":49,"resourceTypeDesc":50,"sizeBytes":51,"sourceHtmlUrl":52},"assets\u002Fvnet-module.tf","ASSET","资产文件",2354,"https:\u002F\u002Fgithub.com\u002Faeroalgo\u002Fdev-hub\u002Fblob\u002Fmaster\u002Fharness\u002Fskills\u002Fterraform-azure\u002Fassets\u002Fvnet-module.tf",{"path":54,"resourceType":55,"resourceTypeDesc":56,"sizeBytes":57,"sourceHtmlUrl":58},"scripts\u002Ftf-init-azure.sh","SCRIPT","脚本",2561,"https:\u002F\u002Fgithub.com\u002Faeroalgo\u002Fdev-hub\u002Fblob\u002Fmaster\u002Fharness\u002Fskills\u002Fterraform-azure\u002Fscripts\u002Ftf-init-azure.sh",[60,68,75,82,89,96],{"skillNo":61,"name":62,"nameZh":6,"description":63,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":64,"licenseFileUrl":6,"sourceHtmlUrl":65,"categories":66,"keywords":67,"publishedAt":19},"01M7B1WAEEY273S87Y9A8WT0EN","your-skill-name","Replace with a clear description of what this skill does. Use when \u003Cthe situations that should trigger it>.","CC-BY-4.0","https:\u002F\u002Fgithub.com\u002Faeroalgo\u002Fdev-hub\u002Fblob\u002Fmaster\u002Fharness\u002Fskills\u002Fyour-skill-name\u002FSKILL.md",[],[],{"skillNo":69,"name":70,"nameZh":6,"description":71,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":72,"categories":73,"keywords":74,"publishedAt":19},"01M7B1W0HKXX2J9R6NSFBFPB12","websocket-engineer","Use when building real-time communication systems with WebSockets or Socket.IO. Invoke for bidirectional messaging, horizontal scaling with Redis, presence tracking, room management.","https:\u002F\u002Fgithub.com\u002Faeroalgo\u002Fdev-hub\u002Fblob\u002Fmaster\u002Fharness\u002Fskills\u002Fwebsocket-engineer\u002FSKILL.md",[],[],{"skillNo":76,"name":77,"nameZh":6,"description":78,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":64,"licenseFileUrl":6,"sourceHtmlUrl":79,"categories":80,"keywords":81,"publishedAt":19},"01M7B1VXEW7V2QJWBYWTYGDZ4Z","web-security-review","Review web applications against the OWASP Top 10 for Web Applications (2021). Use when auditing web apps, reviewing server-side code, or assessing web frameworks for the classic OWASP Top 10 risks including injection, broken auth, and XSS.","https:\u002F\u002Fgithub.com\u002Faeroalgo\u002Fdev-hub\u002Fblob\u002Fmaster\u002Fharness\u002Fskills\u002Fweb-security-review\u002FSKILL.md",[],[],{"skillNo":83,"name":84,"nameZh":6,"description":85,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":88,"publishedAt":19},"01M7B1V47JB0TAGPE3FJPG0F0V","vercel-react-view-transitions","Guide for implementing smooth, native-feeling animations using React's View Transition API (`\u003CViewTransition>` component, `addTransitionType`, and CSS view transition pseudo-elements). Use this skill whenever the user wants to add page transitions, animate route changes, create shared element animations, animate enter\u002Fexit of components, animate list reorder, implement directional (forward\u002Fback) navigation animations, or integrate view transitions in Next.js. Also use when the user mentions view transitions, `startViewTransition`, `ViewTransition`, transition types, or asks about animating between UI states in React without third-party animation libraries.","https:\u002F\u002Fgithub.com\u002Faeroalgo\u002Fdev-hub\u002Fblob\u002Fmaster\u002Fharness\u002Fskills\u002Fvercel-react-view-transitions\u002FSKILL.md",[],[],{"skillNo":90,"name":91,"nameZh":6,"description":92,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":95,"publishedAt":19},"01M7B1TZS9MNJKTKTFNPRCEB0C","vercel-react-native-skills","React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.","https:\u002F\u002Fgithub.com\u002Faeroalgo\u002Fdev-hub\u002Fblob\u002Fmaster\u002Fharness\u002Fskills\u002Fvercel-react-native-skills\u002FSKILL.md",[],[],{"skillNo":97,"name":98,"nameZh":6,"description":99,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":100,"categories":101,"keywords":102,"publishedAt":19},"01M7B1TT4SA56VD9Z32HKBHGZK","vercel-react-best-practices","React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React\u002FNext.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.","https:\u002F\u002Fgithub.com\u002Faeroalgo\u002Fdev-hub\u002Fblob\u002Fmaster\u002Fharness\u002Fskills\u002Fvercel-react-best-practices\u002FSKILL.md",[],[]]