[IAC] 把本地的 Terraform state 改存到 AWS S3

記錄把本地 Terraform State 文件轉移到 AWS S3 的過程與注意事項

 

 

 

前言

最近我在玩 Terraform 與 AWS,一開始在手動建置 Terraform 時 state 沒有上 Git,是先存在 local,但隨著我後來將建置流程改交由 GitHub Actions 自動化後,state 就不能繼續放在 local 了,必須要找個 remote 來存放,才有辦法讓 GitHub Actions 使用。

(在實務情境中,公司也會因為需多人協作開發而有轉存 remote 的需求)

 

對於 state 存放 remote 的問題,Terraform 官方有一個設定方式 — Backend,以下我會分享如何將 loacl 的 state 文件轉交由 Terraform Backend 存放的過程。

 

 

Terraform Backend

Terraform Backend 是 Terraform 用來儲存與管理 state file 的機制

於 local 第一次運行 terraform apply 時,如果沒有特別指定要儲存在哪裏的話,他會 Default 於當前目錄 Create 一個 terraform.tfstate 文件

 

terraform.tfstate 文件是用來記錄 Terraform 管理之設施的當前狀態,會隨著每次 apply 更新設施狀態後更改文件內容

因為他裡面有可能會包含很多敏感的資訊,所以不能 push 上 Git 存放

如果你是個人專案,並且只有自己一個人管理 Terraform,存在 local 沒問題

若一旦須交由其他人管理 ( GitHub Actions 或是團隊其他人 ) ,存在 local 就會難以共享,此時就須要考慮 remote 的解決方案了

 

Terraform 有支援多種 Backend,這裡列出幾個比較知名的

 local (Default)ConsulS3AzurermGCS
remote
儲存位置當前目錄HashiCorp 
Consul KV
AWS S3Azure Blob StorageGCP Cloud Storage
lock 支援
lock 機制---Session locks3 原生 state lockBlob leaseObject generation lock

表格中可以看到,除了 local 以外,大多數其他 remote backend 都有支援 lock

 

lock 機制是為了防止多人同時編輯同一個文件造成衝突

有支援 lock 機制的,terraform 在執行時,會先檢查有無 lock 才會繼續往下做

有 lock 住的話,若沒有設置超時等待,在執行 terraform plan 會出現這種異常訊息 Error acquiring the state lock

 

上述的各種 remote backend 實作方式可參考官方教學:

 

因為我最近都在玩 AWS,所以這裡我會採用 AWS 的解決方案 — 使用 AWS S3 當作 state 的 remote 存放點

 

⚠️

網路上會看到很多 AWS S3 的 Terraform Backend 教學會加上 DynamoDB,不過從 Terraform v1.10 以後就已經不需要使用 DynamoDB 了喔~

更多詳情可參考:Terraform S3 Native State Locking — No DynamoDB Needed | by Pankaj Dhande | Medium

 

 

Create state 儲存用的 S3

這裡選擇一般用途就好,並輸入你想要取的 S3 Name

 

其他設定大多都使用 Default 就好不用更改~

 

不過在 Terraform 官方文件中,建議 S3 要開啟版本控制

 

所以這裡要選擇「啟用」

 

設定好後就可以 Create 了

 

 

編寫 Terraform 腳本

就參照 Terraform 官方文件說的寫就好了


terraform {
  backend "s3" {
    bucket       = "my-terraform-state"
    key          = "my-project/terraform.tfstate"
    region       = "us-east-1"
    use_lockfile = true
    encrypt      = true
  }
}
  

比較需要注意的是

 

🔶 啟用 lock 機制

設定 use_lockfile = true 才能夠啟用 S3 原生的 lock 機制,要能 lock 的話一定要設置

 

🔶 啟用檔案加密

因為 state 文件裡面有可能夾帶很多敏感資料,建議一定要加密

AWS 解決方案的加密方式有 3 種:

  1. SSE-S3 (Default):由 S3 自動管理加密的 Key
  2. KMS:自行添加 KMS Key 管理,能做更多 Policy 的存取設定
  3. SSE-C:設定客戶自己的 Key,這個 Key 不會由 AWS 管理,由客戶自己管

設定 encrypt = true 可以啟用檔案加密,預設的話會是用 S3 的 SSE-S3 方式加密

如果要用 KMS 加密的話,要再多設定 kms_key_id = "your-key"

 

ℹ️

因為從 2026/04 開始,S3 預設不支援 SSE-C 加密,需再額外設定開通,所以這裡我就不多做說明了,有興趣的夥伴可以前往 AWS 部落格文章

Advanced notice: Amazon S3 to disable the use of SSE-C encryption by default for all new buckets and select existing buckets in April 2026 | AWS Storage Blog

 

🔶 不能使用 variables 填充這裡的內容

這裡跟其他 Terraform 設定比較不一樣的是,在 backend 區塊中,是不能用 variables 的

因為 backend 是在 terraform init 階段初始化的,而 variables 是在之後的 plan、apply 階段才解析

ex:bucket  = var.bucket_name  不可以❌❌

 

 

執行 Terraform 命令搬移

開始執行 terraform init

 

此時,你會看到在 S3 隨即被添加了一個 lock 檔案

 

在添加 backend.tf 更改 state 儲存位置前,若有先執行過 terraform apply 命令,此時 local 會有一份既有的 state 文件,記錄著當前的最新狀態

所以他會跳出這個對話訊息

問你要不要將 local 的 state 文件複製到 S3,你就回 yes 就好

接下來他就會開始複製 state

 

看到綠色這段提示,代表 backend s3 設定沒有問題

 

init 執行完後,state 即同步過去了(lock 檔案隨即被刪除)

 

之後的每一次 Terraform 資源異動,都會改存取 S3 裡面的 state 文件了~~

 

END