Terraform 狀態管理是維護基礎設施定義與實際狀態同步的關鍵。理解其運作機制,包含工作區的運用、狀態鎖定避免衝突、後端驗證確儲存取安全,以及遠端狀態儲存提升協作效率,對於穩定可靠的基礎設施管理至關重要。搭配正確的後端組態策略,可以有效保護敏感資訊,避免安全風險。實務上,變數與輸出值的運用,結合資料結構與內建函式,能讓組態更具彈性與可維護性。瞭解如何讀取、生成和修改組態,並遵循安全最佳實務,才能有效運用 Terraform 管理基礎設施。

Terraform 狀態管理實務與安全機制解析

Terraform 的狀態管理是其運作的核心之一,涉及如何儲存、管理和保護基礎設施的狀態資料。本文將探討 Terraform 的狀態管理機制,包括工作區管理、狀態鎖定、後端驗證方法以及遠端狀態儲存機制。

工作區管理與狀態儲存

Terraform 允許使用工作區(workspace)來管理不同的基礎設施狀態。每個工作區都有自己的狀態檔案,這些檔案儲存在 .terraform/terraform.tfstate.d/ 目錄下。例如,當前目錄結構可能如下所示:

1 ├── .terraform
2 ├── main.tf
3 ├── terraform.tfstate
4 └── terraform.tfstate.d
5 └── development
6 └── terraform.tfstate

在上述結構中,terraform.tfstate.d 目錄包含了不同工作區的狀態檔案。預設工作區的狀態檔案則儲存在根目錄下的 terraform.tfstate

內容解密:

  1. .terraform 目錄:Terraform 的內部工作目錄,用於儲存外掛和其他內部資料。
  2. main.tf:主要的 Terraform 組態檔案。
  3. terraform.tfstate:預設工作區的狀態檔案。
  4. terraform.tfstate.d:包含各個工作區狀態檔案的目錄。
  5. development:特定工作區的目錄,其中包含該工作區的狀態檔案 terraform.tfstate

狀態鎖定機制

為了防止多個 Terraform 程式同時修改狀態檔案,Terraform 提供了狀態鎖定機制。任何可能修改狀態的操作都會先嘗試鎖定狀態檔案。如果無法獲得鎖定,該操作將會被終止。

可以使用 -lock=false 引數來停用鎖定,但這並不建議,因為它可能導致狀態檔案損壞。此外,-lock-timeout 引數可用於設定取得鎖定的超時時間。

內容解密:

  • 狀態鎖定是為了防止平行操作導致的狀態檔案損壞。
  • 大多數後端都支援狀態鎖定,但仍需查閱特定後端的檔案以確認其支援情況。

後端驗證方法

許多遠端後端需要驗證資訊才能存取狀態資料。例如,Azure Storage 後端需要存取金鑰。這些資訊可以直接寫在組態檔案中,但這樣做並不安全,因為敏感資訊可能會被意外地提交到版本控制系統中。

1 terraform {
2 backend "azurerm" {
3 storage_account_name = "arthurdent42"
4 container_name = "tfstate"
5 key = "terraform.tfstate"
6 access_key = "qwertyuiop12345678..."
7 }
8 }

上述範例直接在組態檔案中寫入了 access_key,這並不是一個好的做法。建議使用部分後端組態,並在執行時提供剩餘的資訊。

內容解密:

  1. 使用部分後端組態可以避免將敏感資訊直接寫入組態檔案。
  2. 在執行時提供驗證資訊可以增加安全性,避免敏感資訊被提交到版本控制系統。

遠端狀態儲存機制

預設情況下,Terraform 使用本地檔案後端儲存狀態資料。然而,這種方式不適合團隊協作或大規模專案。遠端後端允許將狀態資料儲存在遠端分享位置,從而提供更好的資料保護和協作能力。

Terraform 的後端分為兩類別:

  • 標準後端:提供狀態管理和鎖定功能。
  • 增強後端:除了標準功能外,還支援遠端操作,如 Terraform Cloud 和 Terraform Enterprise。

內容解密:

  • 遠端後端提供更好的資料保護和協作能力。
  • 狀態資料儲存在遠端,不會寫入本地磁碟,從而增加安全性。

實作與維護 Terraform 狀態

在 Terraform 中,狀態的管理對於團隊協作和基礎設施的管理至關重要。除了將狀態儲存在安全的位置外,使用遠端狀態還可以讓其他團隊成員存取或修改狀態,或將其用作資料來源。

遠端狀態的優勢

假設你正在與網路管理員 Joan 合作進行網路組態。兩人都可以更新本地組態副本,然後將其推播到版本控制系統。當需要更新實際環境時,執行 terraform planterraform apply。在更新過程中,遠端狀態會被鎖定,因此 Joan 無法進行任何更改。當 Joan 下次執行 terraform plan 時,將使用你最近一次 apply 後更新的遠端狀態資料。

狀態作為資料來源

在組態中定義的任何輸出都可以使用狀態檔案作為資料來源進行存取。例如,假設應用團隊需要查詢有關網路組態的資訊。你可以授予他們對網路狀態的唯讀存取許可權,並確保所需的資訊透過輸出公開。應用團隊然後可以在其組態中將網路狀態定義為資料來源,並直接參照輸出。

補充資訊

重點整理

Terraform 可以將狀態資料儲存在支援協作和狀態作為資料來源的遠端位置。

Terraform Refresh 對狀態的影響

儲存在狀態中的資料需要反映 Terraform 管理的基礎設施的實際狀態。terraform refresh 指令會檢查目標環境中資源的屬性,並將其與狀態中儲存的值進行比較。Terraform 不會在 refresh 操作期間更改目標基礎設施,但會更新狀態以準確反映目標環境。

重點整理

Terraform 可以從受管理的基礎設施的實際狀態重新整理狀態檔案的內容。

後端區塊組態與部分組態的最佳實踐

Terraform 後端的組態是在根模組的 terraform 區塊內定義的。巢狀的 backend 區塊定義了所使用的後端型別以及該後端所需的和可選的屬性。每個組態只能指定一個後端。你無法將狀態儲存在兩個不同的後端中,或將狀態分散在兩個不同的後端中。

後端組態範例

terraform {
  backend "azurerm" {
    storage_account_name = "arthurdent42"
    container_name       = "tfstate"
    key                  = "terraform.tfstate"
    access_key           = "qwertyuiop12345678..."
  }
}

部分組態

由於 Terraform 不允許在後端組態區塊中使用變數或任何其他插值,因此可以省略希望動態組態的設定,並在執行時提供它們。

terraform {
  backend "azurerm" {
    container_name = "tfstate"
    key            = "terraform.tfstate"
  }
}

storage_account_nameaccess_key 的值可以透過以下三種方式之一提供:

  1. 在執行 terraform init 時在命令列上互動式地提供
  2. 透過 -backend-config 旗標提供一組鍵/值對
  3. 透過 -backend-config 旗標提供包含鍵/值對的檔案路徑

某些後端的引數也可以從環境變數中取得。例如,使用 Azure 的 Managed Security Identity (MSI) 可以透過設定 ARM_USE_MSItrue 來組態。

重點整理

  • 後端組態定義了 Terraform 狀態的儲存位置。
  • 部分組態允許動態設定後端屬性。
  • 後端資訊儲存在 .terraform 目錄下的本地檔案中,該目錄應被排除在版本控制之外。

最佳實踐

  • 使用 .gitignore 檔案排除 .terraform 目錄、terraform.tfvarsterraform.tfstate 等檔案。
  • 確保敏感資料(如身份驗證憑證)不被提交到版本控制系統中。

內容解密:

此章節主要闡述了 Terraform 狀態的管理和後端組態的最佳實踐。首先介紹了遠端狀態的優勢,包括支援團隊協作和將狀態作為資料來源。接著講解了 terraform refresh 指令對狀態的影響,包括如何更新狀態以反映目標環境的實際狀態。最後詳細介紹了後端區塊的組態和部分組態的最佳實踐,包括如何動態設定後端屬性和保護敏感資料。

Terraform 狀態管理與組態修改

在前一章中,我們探討了 Terraform 的狀態管理,包括預設的本地後端、狀態鎖定、後端驗證方法、遠端狀態儲存機制以及敏感資料的管理。現在,我們將進一步深入 Terraform 的組態世界,學習如何讀取、生成和修改組態,以滿足不同的基礎設施需求。

8A: 變數與輸出的使用

輸入變數

在 Terraform 中,變數是用來注入資訊到組態中的重要工具。你可以在組態中定義變數,並在執行時提供值,或者為變數設定預設值。如果沒有為變數設定預設值,Terraform 將要求你在執行時提供一個值,否則相關命令將會報錯。

variable "aws_region" {
  type        = string
  default     = "us-east-1"
  description = "The AWS region to use for this configuration"
}

內容解密:

  1. variable "aws_region":定義了一個名為 aws_region 的變數。
  2. type = string:指定了變數的資料型別為字串。
  3. default = "us-east-1":為變數設定了預設值 "us-east-1"
  4. description = "The AWS region to use for this configuration":提供了對變數的描述,有助於其他使用者理解該變數的用途。

Terraform 中的資料結構與內建函式

Terraform 支援多種資料結構,如列表(list)、對映(map)和物件(object)。你可以使用內建函式和迴圈結構來操作這些資料結構,以實作更複雜的組態邏輯。

依賴引擎

Terraform 的依賴引擎會檢查組態以確定操作的順序。這確保了資源的建立和更新按照正確的順序進行,避免了因依賴關係不明確而導致的錯誤。

Terraform 設定檔的讀取、生成與修改

Terraform 0.13 版本引入了變數驗證的新功能!使用變數驗證時,您需要在變數區塊中新增一個驗證區塊,該區塊必須評估為 true 或 false。深入瞭解變數驗證超出了本的範圍,但瞭解該功能的存在是有益的。

變數值的提交方式

那麼,這些變數的值是如何提交的呢?好問題!這些值在執行時透過多種方式提交。以下是您可選擇的方法:

  1. 設定環境變數,變數名稱字首為 TF_VAR_,後面跟著變數名稱
  2. 在設定檔相同的目錄中放置 terraform.tfvarsterraform.tfvars.json 檔案
  3. 在設定檔相同的目錄中放置以 .auto.tfvars.auto.tfvars.json 結尾的檔案
  4. 使用 -var-file 旗標指定包含鍵/值對的檔案路徑
  5. 使用 -var 旗標指定鍵/值對(例如 aws_region=us-west-1
  6. 在命令列提示時輸入變數值

Terraform 對評估提交的值有優先順序,恰好與上述列表的順序相符。後面的選項優先於前面的選項,因此如果您在環境變數中定義了變數值,並使用 -var 旗標為同一個變數提交了不同的值,則使用 -var 旗標提交的值將獲勝。在命令列層級,最後提交的值獲勝。

輸出值

成功佈署設定後,Terraform 可以提供輸出值。根模組(即主設定檔)建立的輸出值會作為控制檯輸出一部分印出,並且可以使用 terraform output 命令查詢。這看起來似乎不是特別有用,但輸出值在子模組和 Terraform 狀態資料來源中有兩種非常有用的情況。

子模組中的輸出值

當您在 Terraform 中呼叫子模組時,您可以存取該模組建立的一些屬性或資源。子模組中的輸出值決定了哪些資訊可供呼叫模組使用。這意味著子模組可以根據需要建立變數和資源,只要它為呼叫模組提供了一致的輸出值集合。

在 Terraform 0.12 之前,輸出值僅限於字串。您無法將複雜的資料型別作為輸出值傳回,這通常需要使用內建函式將該字串輸出轉換為列表或對映等資料型別。現在支援複雜的資料型別,這意味著您可以將整個資源及其所有屬性作為輸出值傳回。

Terraform 狀態資料來源中的輸出值

Terraform 狀態可以被另一個設定檔作為資料來源使用。從該資料來源可用的屬性僅限於透過輸出值公開的內容。假設您的網路團隊使用 Terraform 為您的應用程式團隊建立了網路環境,應用程式團隊可以在其設定檔中使用網路狀態檔案作為資料來源,並查詢目標網路環境的相關資訊。網路團隊可以透過在設定中建立適當的輸出值來決定哪些資訊可用。

建立輸出值

在設定檔中建立輸出值的格式很簡單。輸出值需要名稱和值。

output "vpc_id" {
  value       = module.vpc.vpc_id
  description = "The VPC ID for your application"
}

輸出區塊可以有兩個額外的引數:sensitivedepends_on。如果輸出值的 sensitive 設定為 true,Terraform 將不會在 CLI 中列印輸出值。depends_on 引數接受輸出值所依賴的資源列表,然後再呈現。通常,Terraform 可以自行判斷依賴關係,但在某些特殊情況下,依賴鏈並不明顯。

輸出值的渲染

輸出值在執行 terraform apply 時被渲染。如果您更改了現有的輸出值或新增了新的輸出值,即使設定檔中沒有其他更改,您也需要再次執行 apply

補充資訊

重點整理

  • 變數是用於向 Terraform 設定檔提交值的方法。有多種提交值的方法,並且有評估順序,後面的值優先。
  • 輸出值主要用於將子模組中的資訊暴露給呼叫模組,或透過遠端狀態暴露資訊。輸出值在 apply 期間被渲染,可以是複雜的資料型別。

內容解密:

此段落主要介紹了 Terraform 中的變數和輸出值的用法。首先講解了如何透過多種方式向 Terraform 設定檔提交變數值,包括環境變數、檔案和命令列引數等,並說明瞭 Terraform 對這些值的評估順序。接著介紹了輸出值的概念,包括如何在子模組和 Terraform 狀態資料來源中使用輸出值,以及如何建立和渲染輸出值。最後提供了補充資訊和重點整理,幫助讀者更好地理解相關內容。

安全地處理敏感資料與 Terraform 組態

在進行 Terraform 組態時,處理敏感資料是一項重要的任務。敏感資料包括應用程式密碼、API 權杖、使用者名稱和密碼等,這些資訊需要被妥善保護以避免洩露。

安全處理敏感資料的最佳實踐

  1. 避免在 .tfvars 檔案中儲存敏感資料:Terraform 不提供對變數檔案的加密或安全保護,因此將敏感資料儲存在 .tfvars 檔案中可能會導致資料洩露,尤其是當這些檔案被提交到原始碼控制系統中時。

  2. 使用環境變數:將敏感資料載入到環境變數中是一種更安全的做法。可以使用 TF_VAR_ 字首加上變數名稱來定義環境變數。這樣可以避免在命令列中直接暴露敏感資料。

    export TF_VAR_sensitive_data="your_sensitive_data_here"
    
  3. 使用秘密生命週期管理器:像 HashiCorp Vault、AWS Key Management Service 或 Azure Key Vault 這樣的秘密生命週期管理器,可以安全地儲存和管理敏感資料。Terraform 可以透過資料來源使用儲存在這些位置的敏感資訊。

  4. 保護 Terraform 狀態檔案:Terraform 狀態檔案中可能包含敏感資料。因此,應該將狀態檔案儲存在支援靜態加密的安全後端。如果使用本地檔案後端,請確保它被排除在原始碼控制之外。

瞭解 Terraform 中的集合和結構型別

Terraform 0.12 版本引入了明確的資料結構定義。主要包括三種原始資料型別:字串(string)、數字(number)和布林值(boolean)。此外,還有集合型別和結構型別。

集合型別

集合型別允許儲存多個值,並且這些值必須是同一種原始型別。主要的集合型別包括:

  • 列表(list):一個有序的值列表,值由其在列表中的位置標識。
  • 對映(map):一個由唯一鍵標識的值集合,鍵是字串型別。
  • 集合(set):一個無序且無重複值的集合。
variable "my_list" {
  type = list(string)
}

variable "my_map" {
  type = map(number)
}

結構型別

結構型別允許建立更複雜的物件,其中可以包含不同型別的多個值。主要包括:

  • 物件(object):類別似於對映,但每個值可以是不同的型別。
  • 元組(tuple):類別似於列表,但每個值可以是不同的型別。
variable "network_info" {
  type = object({
    network_name = string
    cidr_ranges   = list(string)
    subnet_count  = number
    subnet_mask   = number
    nat_enabled   = boolean
  })
}

variable "pi_tuple" {
  type = tuple([string, number, boolean, list(number)])
}
此圖示顯示了敏感資料處理和 Terraform 資料型別的關聯
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Terraform 狀態管理與安全機制

package "安全架構" {
    package "網路安全" {
        component [防火牆] as firewall
        component [WAF] as waf
        component [DDoS 防護] as ddos
    }

    package "身份認證" {
        component [OAuth 2.0] as oauth
        component [JWT Token] as jwt
        component [MFA] as mfa
    }

    package "資料安全" {
        component [加密傳輸 TLS] as tls
        component [資料加密] as encrypt
        component [金鑰管理] as kms
    }

    package "監控審計" {
        component [日誌收集] as log
        component [威脅偵測] as threat
        component [合規審計] as audit
    }
}

firewall --> waf : 過濾流量
waf --> oauth : 驗證身份
oauth --> jwt : 簽發憑證
jwt --> tls : 加密傳輸
tls --> encrypt : 資料保護
log --> threat : 異常分析
threat --> audit : 報告生成

@enduml

內容解密:

此圖示闡述了兩大主題:安全處理敏感資料的最佳實踐以及 Terraform 中的資料型別分類別。左側部分展示了安全處理敏感資料的兩種主要方法:使用環境變數和秘密生命週期管理器。右側部分則展示了 Terraform 中的資料型別,包括集合型別(列表、對映、集合)和結構型別(物件、元組)。這張圖幫助讀者理解如何在 Terraform 組態中妥善管理敏感資訊以及如何選擇適當的資料型別來滿足基礎設施即程式碼的需求。