import-infrastructure-as-code

import-infrastructure-as-code

熱門

使用 Azure CLI 探索與 Azure Verified Modules (AVM),將現有 Azure 資源匯入 Terraform。當需要逆向工程現有 Azure 基礎架構、從現有訂閱/資源群組/資源 ID 產生基礎架構即程式碼、對應相依性、從下載的模組原始碼推導精確匯入位址、防止配置漂移,以及產出可供驗證與規劃的 AVM 型 Terraform 檔案時使用。

3.7萬星標
4572分支
更新於 2026/7/14
SKILL.md
readonlyread-only
name
import-infrastructure-as-code
description

使用 Azure CLI 探索與 Azure Verified Modules (AVM),將現有 Azure 資源匯入 Terraform。當需要逆向工程現有 Azure 基礎架構、從現有訂閱/資源群組/資源 ID 產生基礎架構即程式碼、對應相依性、從下載的模組原始碼推導精確匯入位址、防止配置漂移,以及產出可供驗證與規劃的 AVM 型 Terraform 檔案時使用。

將基礎架構匯入為程式碼 (Azure -> Terraform with AVM)

使用探索資料與 Azure Verified Modules,將現有 Azure 基礎架構轉換為可維護的 Terraform 程式碼。

何時使用此技能

當使用者要求以下事項時使用此技能:

  • 將現有 Azure 資源匯入 Terraform
  • 從現有 Azure 環境產生 IaC
  • 處理 AVM 支援的所有 Azure 資源類型(並記錄合理的非 AVM 替代方案)
  • 從訂閱或資源群組重建基礎架構
  • 對應已探索 Azure 資源之間的相依性
  • 使用 AVM 模組而非手寫的 azurerm_* 資源

先決條件

  • 已安裝 Azure CLI 並通過驗證 (az login)
  • 可存取目標訂閱或資源群組
  • 已安裝 Terraform CLI
  • 可連線至 Terraform Registry 與 AVM 索引來源

輸入參數

參數 必要 預設值 說明
subscription-id 使用中 CLI 內容 用於訂閱範圍探索與內容設定的 Azure 訂閱
resource-group-name 用於資源群組範圍探索的 Azure 資源群組
resource-id 用於特定資源範圍探索的一或多個 Azure ARM 資源 ID

至少需要提供 subscription-idresource-group-nameresource-id 其中之一。

逐步工作流程

1) 收集必要範圍(強制)

在執行探索指令前,要求提供以下其中一個範圍:

  • 訂閱範圍:<subscription-id>
  • 資源群組範圍:<resource-group-name>
  • 特定資源範圍:一或多個 <resource-id>

範圍處理規則:

  • 將 Azure ARM 資源 ID(例如 /subscriptions/.../providers/...)視為雲端資源識別碼,而非本機檔案系統路徑。
  • 僅將資源 ID 用於 Azure CLI 的 --ids 參數(例如 az resource show --ids <resource-id>)。
  • 除非使用者明確表示為本機檔案路徑,否則切勿將資源 ID 傳遞給檔案讀取指令(catlsread_file、glob 搜尋)。
  • 若使用者已提供一個有效的範圍,除非指令因缺少必要資訊而失敗,否則不要要求額外的範圍輸入。
  • 不要詢問可從已提供範圍值回答的後續問題。

若缺少範圍,請明確要求並停止。

2) 驗證並設定內容

僅執行所選範圍所需的指令。

對於訂閱範圍:

az login
az account set --subscription <subscription-id>
az account show --query "{subscriptionId:id, name:name, tenantId:tenantId}" -o json

預期輸出:包含 subscriptionIdnametenantId 的 JSON 物件。

對於資源群組或特定資源範圍,仍需要 az login,但如果使用中內容已正確,則 az account set 為選用。

使用特定資源範圍時,優先使用直接基於 --ids 的指令,除非具體指令需要,否則避免額外的訂閱或資源群組探索提示。

3) 執行探索指令

使用所選範圍探索資源。確保取得所有必要資訊以準確產生 Terraform。

# 訂閱範圍
az resource list --subscription <subscription-id> -o json

# 資源群組範圍
az resource list --resource-group <resource-group-name> -o json

# 特定資源範圍
az resource show --ids <resource-id-1> <resource-id-2> ... -o json

預期輸出:包含 Azure 資源中繼資料(idtypenamelocationtagsproperties)的 JSON 物件或陣列。

4) 在產生程式碼前解析相依性

解析匯出的 JSON 並對應:

  • 父子關係(例如:NIC -> Subnet -> VNet)
  • properties 中的跨資源參考
  • Terraform 建立的順序

重要:產生以下文件並儲存至專案根目錄的 docs 資料夾。

  • exported-resources.json:包含所有探索到的資源及其中繼資料,包括相依性和參考。
  • EXPORTED-ARCHITECTURE.MD:根據探索到的資源及其關係,提供人類可讀的架構概覽。

5) 選擇 Azure Verified Modules(必要)

對每種資源類型使用最新的 AVM 版本。

Terraform Registry

  • 搜尋 "avm" + 資源名稱
  • 透過 "Partner" 標籤篩選以找到官方 AVM 模組
  • 範例:搜尋 "avm storage account" → 篩選 Partner

官方 AVM 索引

注意: 以下連結始終指向主分支上最新版本的 CSV 檔案。這意味著檔案可能會隨時間變更。如果您需要特定時間點的版本,請考慮在 URL 中使用特定的發行標籤。

  • Terraform Resource Moduleshttps://raw.githubusercontent.com/Azure/Azure-Verified-Modules/refs/heads/main/docs/static/module-indexes/TerraformResourceModules.csv
  • Terraform Pattern Moduleshttps://raw.githubusercontent.com/Azure/Azure-Verified-Modules/refs/heads/main/docs/static/module-indexes/TerraformPatternModules.csv
  • Terraform Utility Moduleshttps://raw.githubusercontent.com/Azure/Azure-Verified-Modules/refs/heads/main/docs/static/module-indexes/TerraformUtilityModules.csv

個別模組資訊

如果 .terraform 資料夾中沒有本機可用的模組資訊,請使用 web 工具或其他合適的 MCP 方法取得模組資訊。

使用 AVM 來源:

  • Registry:https://registry.terraform.io/modules/Azure/<module>/azurerm/latest
  • GitHub:https://github.com/Azure/terraform-azurerm-avm-res-<service>-<resource>

當 AVM 模組存在時,優先使用 AVM 模組而非手寫的 azurerm_* 資源。

從 GitHub 儲存庫取得模組資訊時,儲存庫根目錄中的 README.md 檔案通常包含模組的所有詳細資訊,例如:https://raw.githubusercontent.com/Azure/terraform-azurerm-avm-res-<service>-<resource>/refs/heads/main/README.md

5a) 在撰寫任何程式碼前閱讀模組 README(強制)

此步驟不可省略。 在為模組撰寫任何一行 HCL 之前,請先取得並閱讀該模組的完整 README。不要依賴對原始 azurerm provider 的知識或先前使用其他 AVM 模組的經驗。

對於每個選定的 AVM 模組,取得其 README:

https://raw.githubusercontent.com/Azure/terraform-azurerm-avm-res-<service>-<resource>/refs/heads/main/README.md

或者,如果模組已在 terraform init 後下載:

cat .terraform/modules/<module_key>/README.md

從 README 中,在撰寫程式碼前提取並記錄以下內容:

  1. 必要輸入 — 模組所需的每個輸入。此處列出的任何子資源(NIC、擴充功能、子網路、公用 IP)均由模組內部管理。請不要為這些資源建立獨立的模組區塊。
  2. 選用輸入 — 確切的 Terraform 變數名稱及其宣告的 type。不要假設它們與原始 azurerm provider 的參數名稱或區塊形狀相符。
  3. 使用範例 — 檢查使用的資源群組識別碼(parent_idresource_group_name)、子資源的表達方式(內聯 map 與獨立模組),以及每個輸入預期的語法。
將模組規則視為模式,而非假設

使用以下教訓作為導致匯入失敗的常見不匹配類型的範例。不要假設這些確切名稱適用於每個 AVM 模組。務必驗證每個選定模組的 README 和 variables.tf

avm-res-compute-virtualmachine(任何版本)

  • network_interfaces必要輸入。NIC 由 VM 模組擁有。切勿在 VM 模組旁建立獨立的 avm-res-network-networkinterface 模組 — 在 network_interfaces 下內聯定義每個 NIC。
  • TrustedLaunch 透過頂層布林值 secure_boot_enabled = truevtpm_enabled = true 表達。security_type 參數僅存在於 os_disk 下,用於機密 VM 磁碟加密,不得用於 TrustedLaunch。
  • boot_diagnosticsbool,而非物件。使用 boot_diagnostics = true;如果需要儲存體 URI,請使用單獨的 boot_diagnostics_storage_account_uri 變數。
  • 擴充功能透過 extensions map 在模組內部管理。請勿建立獨立的擴充功能資源。

avm-res-network-virtualnetwork(任何版本)

  • 此模組由 AzAPI provider 支援,而非 azurerm。使用 parent_id(完整的資源群組資源 ID 字串)來指定資源群組,而非 resource_group_name
  • README 中的每個範例都顯示 parent_id;沒有範例顯示 resource_group_name

所有 AVM 模組的通用結論:

  • 在建立同級模組之前,從必要輸入確定子資源的歸屬。
  • 選用輸入variables.tf 確定接受的變數名稱和類型。
  • 從 README 使用範例確定識別碼樣式和輸入形狀。
  • 不要從原始 azurerm_* 資源推斷參數名稱。

6) 產生 Terraform 檔案

在撰寫 Import 區塊前 — 檢查模組原始碼(強制)

terraform init 下載模組後,在撰寫任何 import {} 區塊前,檢查每個模組的原始碼以確定確切的 Terraform 資源位址。切勿憑記憶撰寫匯入位址。

步驟 A — 識別 provider 和資源標籤
grep "^resource" .terraform/modules/<module_key>/main*.tf

這會顯示模組使用的是 azurerm_* 還是 azapi_resource 標籤。例如,avm-res-network-virtualnetwork 暴露的是 azapi_resource "vnet",而非 azurerm_virtual_network "this"

步驟 B — 識別子模組和巢狀路徑
grep "^module" .terraform/modules/<module_key>/main*.tf

如果子資源在子模組中管理(子網路、擴充功能等),匯入位址必須包含每個中間模組標籤:

module.<root_module_key>.module.<child_module_key>["<map_key>"].<resource_type>.<label>[<index>]
步驟 C — 檢查 countfor_each
grep -n "count\|for_each" .terraform/modules/<module_key>/main*.tf

任何使用 count 的資源都需要在匯入位址中包含索引。當 count = 1(例如,條件式 Linux 與 Windows 選擇)時,位址必須以 [0] 結尾。使用 for_each 的資源使用字串鍵,而非數字索引。

已知匯入位址模式(來自經驗教訓的範例)

這些僅為範例。將它們用作推理的模板,然後從目前匯入中模組的下載原始碼推導確切位址。

資源 正確的匯入 to 位址模式
AzAPI 支援的 VNet module.<vnet_key>.azapi_resource.vnet
子網路(巢狀,基於 count) module.<vnet_key>.module.subnet["<subnet_name>"].azapi_resource.subnet[0]
Linux VM(基於 count) module.<vm_key>.azurerm_linux_virtual_machine.this[0]
VM NIC module.<vm_key>.azurerm_network_interface.virtualmachine_network_interfaces["<nic_key>"]
VM 擴充功能(預設 deploy_sequence=5) module.<vm_key>.module.extension["<ext_name>"].azurerm_virtual_machine_extension.this
VM 擴充功能(deploy_sequence=1–4) module.<vm_key>.module.extension_<n>["<ext_name>"].azurerm_virtual_machine_extension.this
NSG-NIC 關聯 module.<vm_key>.azurerm_network_interface_security_group_association.this["<nic_key>-<nsg_key>"]

產出:

  • providers.tf:包含 azurerm provider 和必要的版本限制
  • main.tf:包含 AVM 模組區塊和明確的相依性
  • variables.tf:用於環境特定值
  • outputs.tf:用於金鑰 ID 和端點
  • terraform.tfvars.example:包含佔位符值

比較即時屬性與模組預設值(強制)

在撰寫初始配置後,將每個探索到的即時資源的每個非零屬性與對應 AVM 模組 variables.tf 中宣告的預設值進行比較。任何即時值與模組預設值不同的屬性都必須在 Terraform 配置中明確設定。

特別注意以下屬性類別,這些是無聲配置漂移的常見來源:

  • 逾時值(例如,公用 IP idle_timeout_in_minutes 預設為 4;實際部署通常使用 30
  • 網路原則旗標(例如,子網路 private_endpoint_network_policies 預設為 "Enabled";現有子網路通常為 "Disabled"
  • SKU 與配置(例如,公用 IP skuallocation_method
  • 可用區域(例如,VM 區域、公用 IP 區域)
  • 儲存體與資料庫資源的備援與複寫設定

使用明確的 az 指令取得完整的即時屬性,例如:

az network public-ip show --ids <resource_id> --query "{idleTimeout:idleTimeoutInMinutes, sku:sku.name, zones:zones}" -o json
az network vnet subnet show --ids <resource_id> --query "{privateEndpointPolicies:privateEndpointNetworkPolicies, delegation:delegations}" -o json

不要僅依賴 az resource list 的輸出,因為它可能省略巢狀或計算屬性。

明確鎖定模組版本:

module "example" {
	source  = "Azure/<module>/azurerm"
	version = "<latest-compatible-version>"
}

7) 驗證產生的程式碼

執行:

terraform init
terraform fmt -recursive
terraform validate
terraform plan

預期輸出:無語法錯誤、無驗證錯誤,且計劃與探索到的基礎架構意圖相符。

疑難排解

問題 可能原因 處理方式
az 指令因授權錯誤失敗 錯誤的租用戶/訂閱或缺少 RBAC 角色 重新執行 az login,驗證訂閱內容,確認所需權限
探索輸出為空 範圍不正確或範圍內無資源 重新檢查範圍輸入,再次執行範圍 list/show 指令
找不到資源類型的 AVM 模組 資源類型尚未被 AVM 涵蓋 對該類型使用原生 azurerm_* 資源,並記錄此缺口
terraform validate 失敗 缺少變數或未解析的相依性 新增必要的變數和明確的相依性,然後重新執行驗證
未知的參數或模組中找不到變數 AVM 變數名稱與 azurerm provider 參數名稱不同 閱讀模組 README 的 variables.tf 或選用輸入區段以取得正確名稱
Import 區塊失敗 — 在位址找不到資源 錯誤的 provider 標籤(azurerm_azapi_)、缺少子模組路徑或缺少 [0] 索引 執行 grep "^resource" .terraform/modules/<key>/main*.tfgrep "^module" 以找到確切位址
terraform plan 顯示已匯入資源有非預期的 ~ update 即時值與 AVM 模組預設值不同 使用 az <resource> show 取得即時屬性,與模組預設值比較,新增明確值
子資源模組出現 "provider configuration not present" 子資源被宣告為獨立模組,但父模組擁有它們 檢查 README 中的必要輸入,移除不正確的獨立模組,並使用父模組記錄的輸入結構來建模子資源
巢狀子資源匯入失敗,出現 "resource not found" 缺少中間模組路徑、錯誤的 map 鍵或缺少索引 檢查原始碼中的模組區塊和 count/for_each;建立完整的巢狀匯入位址,包含所有模組區段和必要的鍵/索引
工具嘗試將 ARM 資源 ID 讀取為檔案路徑,或重複詢問範圍問題 資源 ID 未被視為 --ids 輸入,或代理未信任已提供的範圍 嚴格將 ARM ID 視為雲端識別碼,使用 az ... --ids ...,一旦存在一個有效範圍就停止重新提示

回應合約

回傳結果時,提供:

  1. 使用的範圍(訂閱、資源群組或資源 ID)
  2. 建立的探索檔案
  3. 偵測到的資源類型
  4. 選取的 AVM 模組及其版本
  5. 產生或更新的 Terraform 檔案
  6. 驗證指令結果
  7. 需要使用者輸入的開放缺口(若有)

代理執行規則

  • 若缺少範圍,請勿繼續。
  • 未列出探索到的檔案和驗證輸出前,請勿聲稱匯入成功。
  • 在產生 Terraform 前,請勿跳過相依性對應。
  • 優先使用 AVM 模組;明確說明每個非 AVM 替代方案的理由。
  • 在撰寫程式碼前,閱讀每個 AVM 模組的 README。 必要輸入可識別模組擁有的子資源。選用輸入記錄了確切的變數名稱和類型。使用範例顯示 provider 特定的慣例(parent_idresource_group_name)。跳過 README 是 AVM 匯入中最常見的程式碼錯誤原因。
  • 切勿假設 NIC、擴充功能或公用 IP 資源是獨立的。 對於任何 AVM 模組,除非 README 明確指出需要獨立模組,否則將子資源視為父模組擁有。在建立同級模組前檢查必要輸入。
  • 切勿憑記憶撰寫匯入位址。terraform init 後,使用 grep 檢查下載的模組原始碼,以發現實際的 provider(azurermazapi)、資源標籤、子模組巢狀結構以及 countfor_each 的使用情況,然後再撰寫任何 import {} 區塊。
  • 切勿將 ARM 資源 ID 視為檔案路徑。 資源 ID 應放在 Azure CLI 的 --ids 參數和 API 查詢中,而非檔案 IO 工具。僅在提供實際工作區路徑時才讀取本機檔案。
  • 當範圍已知時,最小化提示。 如果已提供訂閱、資源群組或特定資源 ID,請直接執行指令,僅在指令因缺少必要內容而失敗時才提出後續問題。
  • terraform plan 顯示 0 個銷毀和 0 個非預期變更之前,請勿宣告匯入完成。 可接受 + create 資源。任何對實際基礎架構資源的 ~ update- destroy 都必須解決。

參考資料