Skip to content

aztfexport - 從既有環境導出 Azure 資源狀態

A tool to bring existing Azure resources under Terraform's management

因為這個 Microsoft Azure Export for Terraform 小工具是以 Resource Group 為最大範圍而 Resource 為最小範圍 Export,而不是以 Subscription,所以在用的時候要先切換到對應的 Subscription

微軟官網文件有專門的頁面在介紹怎麼用 Microsoft Learn - 適用於 Terraform 的 Azure 導出概觀

獲得當前 Azure 資源狀態

當初看到這個工具的時候,我一開始覺得他適合拿來當作每週基礎狀態備份之用,但後來抓了好幾個資源後,覺得反而比較適合下列 2 個情境

  1. 轉換部署模式: 當你想要將資源部署模式轉成以 Terraform 為主的 IaC 的模式`,這個我猜應該是比較少見...
  2. 研究當前狀態: 對於一個剛接觸到的環境,完全不知道在幹嘛的時候,可以先透過這程式抓當前資源狀態研究,廠商做案子的時候可以考慮出首先使用,不用慢慢點滑鼠
get-azure-tfstate.sh
#!/usr/bin/env bash
SUBSCRIPTION_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
RG_NAME="rg-azure-openai"
TF_DIRNAME="tfstate-${RG_NAME}-$(date +%Y%m%d)"

mkdir $TF_DIRNAME
az account set --subscription ${SUBSCRIPTION_ID}
aztfexport resource-group --non-interactive --continue --subscription-id ${SUBSCRIPTION_ID} --provider-version 3.89.0 --plain-ui --output-dir ${TF_DIRNAME} ${RG_NAME}
tar -zcvf ${TF_DIRNAME}.tar.gz ${TF_DIRNAME}

檢視特定資源狀態,以 Azure OpenAI 為例

下面是用 terraform 來檢視特定資源狀態,但實際上你可以直接開 vim 或 vscode 來檢視,也是很方便

順便一提,其實 Azure OpenAI 這個服務是算在 Microsoft.CognitiveServices/accounts 資源範圍內,如果要分辨是不是 OpenAI 的資源,可以看 kind 的欄位

$ cd tfstate-rg-azure-openai-20240126
$ terraform init
$ terraform state list
azurerm_cognitive_account.res-1
azurerm_cognitive_account.res-6
azurerm_cognitive_deployment.res-2
azurerm_cognitive_deployment.res-3
azurerm_resource_group.res-0
azurerm_search_service.res-7

#
# Display the current state of Azure OpenAI resource
#
$ terraform state show azurerm_cognitive_account.res-1
# azurerm_cognitive_account.res-1:
resource "azurerm_cognitive_account" "res-1" {
    custom_subdomain_name              = "pichuang"
    dynamic_throttling_enabled         = false
    endpoint                           = "https://pichuang.openai.azure.com/"
    fqdns                              = []
    id                                 = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rg-azure-openai/providers/Microsoft.CognitiveServices/accounts/pichuang"
    kind                               = "OpenAI"
    local_auth_enabled                 = true
    location                           = "eastus2"
    name                               = "pichuang"
    outbound_network_access_restricted = false
    primary_access_key                 = (sensitive value)
    public_network_access_enabled      = true
    resource_group_name                = "rg-azure-openai"
    secondary_access_key               = (sensitive value)
    sku_name                           = "S0"
    tags                               = {
        "Environment" = "production"
    }

    network_acls {
        default_action = "Allow"
        ip_rules       = []
    }
}

回復特定 Azure 資源狀態

有時候需要把資源狀態以特定時機點蓋回去,這時候你就要透過 terraform plan 來檢視差異,然後再透過 terraform apply 來回復狀態

基於 How Azure Export for Terraform Works - Limitations 所述,這工具對於 Write-only 屬性的參數都不會被匯出或者是被顯示,譬如像是密碼不會被匯出,你得要自己紀錄.此外如果有服務剛好不在 Terraform Azure Provider 所定義的範圍內,那麼這個服務也不會被匯出.因為有可能剛好該服務還沒有實踐到 Terraform Azure Provider 上

結論來說,要緊急恢復資源狀態,平時要排除對於 terraform plan 已知資源的差異,要能快速辨識議題和手動修復,不然遇到會很麻煩

#
# Found Error
#
$ terraform plan
 Error: Missing required argument
   with azurerm_cognitive_account.res-6,
   on main.tf line 56, in resource "azurerm_cognitive_account" "res-6":
   56: resource "azurerm_cognitive_account" "res-6" {
 "network_acls": all of `custom_subdomain_name,network_acls` must be specified

#
# Before
#
$ cd tfstate-rg-azure-openai-20240124
$ terraform state show azurerm_cognitive_account.res-6
# azurerm_cognitive_account.res-6:
resource "azurerm_cognitive_account" "res-6" {
    dynamic_throttling_enabled         = false
    endpoint                           = "https://japaneast.api.cognitive.microsoft.com/"
    fqdns                              = []
    id                                 = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rg-azure-openai/providers/Microsoft.CognitiveServices/accounts/stt-pichuang"
    kind                               = "SpeechServices"
    local_auth_enabled                 = true
    location                           = "japaneast"
    name                               = "stt-pichuang"
    outbound_network_access_restricted = false
    primary_access_key                 = (sensitive value)
    public_network_access_enabled      = true
    resource_group_name                = "rg-azure-openai"
    secondary_access_key               = (sensitive value)
    sku_name                           = "F0"
    tags                               = {
        "Environment" = "production"
    }

    network_acls {
        default_action = "Allow"
        ip_rules       = []
    }
}

#
# After
#
# Fix the error from above and re-run `terraform plan`
# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/cognitive_account
#
$ terraform plan
Terraform will perform the following actions:
  # azurerm_cognitive_account.res-6 will be updated in-place
  ~ resource "azurerm_cognitive_account" "res-6" {
        id                                 = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rg-azure-openai/providers/Microsoft.CognitiveServices/accounts/stt-pichuang"
        name                               = "stt-pichuang"
        tags                               = {
            "Environment" = "production"
        }
        # (12 unchanged attributes hidden)

      - network_acls {
          - default_action = "Allow" -> null
          - ip_rules       = [] -> null
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Q&A

Q1: 使用經驗如何?

不是每一個 Resource 都倒的出來,匯出來後,要真的要 Import 還是要一個一個修補缺少的內容,凡舉不知道為什麼缺欄位、密碼、或者是不在 Terraform Azure Provider 所定義的範圍內的服務,都需要被處理

Q2: 我可以拿來當 tfstate 檔案的常規備份用嗎?

傾向不要,當然如果你的資源不具備 Nested Resource Group 之類的特性,可以考慮試試看,但如果像 Azure Kubernetes Service 或者是 Azure Red Hat OpenShift 建立服務的時候都會額外再建立一個 Resource Group 放置一堆資源的話,那可能在 aztfexport 的時候會有問題,估計要手動一個一個下 terraform import 修補

文後廢言

這幾天天氣太冷了,已經冷到點香氛蠟燭取暖上班了

References

Comments