Terraformで複数人の開発や複数環境(dev・staging・prod)の管理を始めると、プロバイダーのバージョン管理のズレが原因でこうした問題が起きます。TerraformのAWSプロバイダーは本体とは独立して頻繁に更新されるため、バージョン指定を適切に設計していないと静かに環境差異が生まれます。
この記事では、
required_providers ブロックによるバージョン制約の設計と、terraform.lock.hcl を使ったチーム全体での環境固定方法を解説します。バージョン制約演算子の使い分け・複数プロバイダーの設定・provider alias による複数リージョン構成と、よくあるエラーの対処法も合わせて説明します。動作確認環境: RHEL 9.4 / Ubuntu 24.04 LTS + Terraform v1.9.x + hashicorp/aws v5.x
この記事のポイント
・required_providers でプロバイダーのsource・バージョン制約を必ず明示するのが基本
・~> 演算子でメジャーバージョンを固定しつつセキュリティパッチを自動取り込みできる
・terraform.lock.hcl は必ずGitにコミットしてチーム全体の環境を固定する
・provider alias で複数リージョン・クロスアカウント構成を1コードベースで扱える
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜプロバイダーのバージョン管理が崩れやすいのか
Terraformのプロバイダー(AWSの場合はhashicorp/aws)はTerraform本体とは独立して更新されます。AWS Providerは月に数回マイナーバージョンがリリースされ、新しいリソース属性の追加だけでなく既存の動作に影響するバグ修正も含まれます。バージョン管理が崩れやすい典型的なパターンを3つ挙げます。
・バージョン制約なし:
terraform init を実行するたびにその時点での最新プロバイダーがダウンロードされます。1週間後に別のメンバーが terraform init すると異なるバージョンが入り、挙動の差異が生まれます・バージョンを完全固定しすぎ:
= 5.31.0 のように完全固定すると、セキュリティパッチを含む更新が一切取り込まれません。毎回手動でバージョンを書き換える運用負荷が発生します・lock.hclをGitignoreしている:チームメンバーそれぞれが独自のバージョンで作業し、CIパイプラインではまた別のバージョンが使われます。「自分のPCでは動く」問題の最大原因がこれです
プロバイダーのバージョン管理には「制約の設計(required_providers)」と「固定の仕組み(lock.hcl)」の両輪が必要です。どちらか一方だけでは不十分です。
required_providersブロックの書き方
1. 基本構文とsource指定
required_providers は terraform ブロックの中に記述します。required_version でTerraform本体のバージョン制約と合わせて管理するのが標準的なパターンです。# versions.tf(専用ファイルに分離するのが慣習) terraform { required_version = ">= 1.5.0" required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } } # provider.tf(リージョン・認証設定) provider "aws" { region = "ap-northeast-1" }
source の形式は <名前空間>/<プロバイダー名> です。HashiCorp公式プロバイダーは hashicorp/aws のように書きます。source を省略するとデフォルトで hashicorp/<プロバイダー名> と解釈されますが、コミュニティプロバイダー(例: integrations/github)を使う場合は省略できません。習慣として常に明示しておくことをお勧めします。required_providers は versions.tf という専用ファイルに分離するチームが多く、Terraform公式ドキュメントでも推奨されています。「どのプロバイダーが使われているか」を一か所で確認できる利点があります。2. バージョン制約の演算子を使い分ける
Terraformのバージョン制約には5種類の演算子があります。実務で特に重要な3つを押さえておきましょう。| 演算子 | 意味 | 許容範囲の例 | 用途 |
|---|---|---|---|
= 5.31.0 |
完全一致 | 5.31.0 のみ | 再現性が最優先の場合 |
>= 5.0 |
以上 | 5.0以上すべて(6.xも含む) | 下限だけ指定したい場合 |
~> 5.0 |
悲観的制約(マイナーを許容) | 5.0以上かつ6.0未満 | 実務の標準パターン |
~> 5.1.0 |
悲観的制約(パッチのみ許容) | 5.1.0以上かつ5.2.0未満 | 安定性を最優先する本番環境 |
!= 5.2.1 |
除外 | 5.2.1以外のすべて | バグのある特定バージョンを回避 |
~> 5.0 のように最右の数値を1つだけ持つ悲観的制約(チルダアロー)です。「5.x系の最新マイナーを許容するが6.0以上は使わない」という意味になります。マイナーバージョンは後方互換性が保たれることが多く、セキュリティパッチや新リソースの追加が含まれます。メジャーバージョンはAPIの破壊的変更が含まれるため、意図的な確認のうえでアップグレードしたいケースに
~> 5.0 の制約が有効です。~> 5.1.0(パッチのみ許容)はより安定性を重視した設定です。本番環境への影響を最小化したい場合はこちらを選びます。ただしマイナーバージョンアップは手動での書き換えが必要になるため、長期的な運用負荷が増えます。3. 複数プロバイダーを同時に使う
AWSリソース以外にnull プロバイダーや random プロバイダーを組み合わせるのは標準的なパターンです。terraform { required_version = ">= 1.5.0" required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } null = { source = "hashicorp/null" version = "~> 3.0" } random = { source = "hashicorp/random" version = "~> 3.0" } } }
null_resource でローカルスクリプトの実行やリソース間の依存関係制御に使います。EC2インスタンス作成後にAnsibleプレイブックを呼び出すトリガーとして利用できます・randomプロバイダー:
random_id でリソース名のユニークなサフィックスを生成します。S3バケット名のようにグローバルユニークが要求される場合に ${random_id.suffix.hex} を使いますterraform.lock.hclの役割とチーム運用
1. lock.hclの構造を読む
terraform init を実行すると .terraform.lock.hcl が自動生成または更新されます。バージョン制約の範囲内で実際にインストールされたバージョンと、プロバイダーバイナリのハッシュ値を記録するファイルです。# .terraform.lock.hcl の実際の内容例(ハッシュ値はマスク済み) provider "registry.terraform.io/hashicorp/aws" { version = "5.84.0" constraints = "~> 5.0" hashes = [ "h1:Ab1Cd2Ef3Gh4Ij5Kl6Mn7Op8Qr9St0Uv1Wx2Yz3AA=", "zh:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c...", ] }
・version:バージョン制約の中で実際にインストールされたバージョン
・constraints:
required_providers で指定した制約(記録用、変更不可)・hashes:プロバイダーバイナリの整合性チェック用ハッシュ。次回の
terraform init でこのハッシュと一致するバイナリのみを受け入れ、改ざんやサプライチェーン攻撃を検知しますh1: で始まるハッシュはディレクトリハッシュ(zip内のファイル構成を含む)、zh: はzipファイル全体のハッシュです。Terraform 1.4以降は zh: ハッシュが優先されます。2. Gitにコミットすべき理由
.terraform.lock.hcl は .gitignore に追加せず、必ずリポジトリにコミットします。コミットが必要な理由は3つあります。
・チームの環境統一:lock.hcl をコミットしておくと、別のメンバーが
terraform init したときに同じバージョンが自動でダウンロードされます。「自分のPCでは動く」問題を根本から排除できます・CIパイプラインの再現性:GitHub ActionsなどのCIでも lock.hcl に記録されたバージョンが使われるため、ローカルとCIで動作が一致します
・サプライチェーン保護:ハッシュ値が記録されているため、Registry上のプロバイダーが改ざんされた場合に
terraform init がエラーで止まります.terraform/ ディレクトリ(プロバイダーバイナリ本体)は .gitignore で除外しますが、.terraform.lock.hcl だけは例外として必ずコミット対象にします。3. terraform init -upgradeでバージョンを更新する
lock.hcl に記録されたバージョンを更新するにはterraform init -upgrade を使います。バージョン制約の範囲内で最新のプロバイダーをダウンロードし、lock.hcl を書き換えます。# バージョン制約の範囲内で最新にアップグレード $ terraform init -upgrade Initializing the backend... Initializing provider plugins... - Finding hashicorp/aws versions matching "~> 5.0"... - Installing hashicorp/aws v5.84.0... - Installed hashicorp/aws v5.84.0 (signed by HashiCorp) Terraform has been successfully initialized! # lock.hcl が更新されたことを確認してコミットする $ git diff .terraform.lock.hcl $ git add .terraform.lock.hcl $ git commit -m "chore: upgrade hashicorp/aws to v5.84.0"
-upgrade なしの terraform init は lock.hcl に記録済みのバージョンを優先し、最新版があっても更新しません。セキュリティパッチの取り込みが必要な場合や新しいリソース属性を使いたい場合に限って -upgrade を実行し、terraform plan で既存リソースへの影響がないことを確認してから lock.hcl をコミットします。
>> Terraform実践セミナーの詳細はこちら
provider aliasで複数リージョン・複数アカウントを扱う
1. aliasの基本設定
同じプロバイダーを異なる設定(別リージョン、別AWSアカウント)で使いたい場合はalias を使います。alias なしのプロバイダーブロックがデフォルトになり、alias を付けたものを特定のリソースやモジュールに明示的に割り当てます。# デフォルトプロバイダー(alias なし = ap-northeast-1) provider "aws" { region = "ap-northeast-1" } # エイリアスプロバイダー(us-east-1 用) provider "aws" { alias = "us_east" region = "us-east-1" } # クロスアカウント例(別IAMロールを assume する) provider "aws" { alias = "dev_account" region = "ap-northeast-1" assume_role { role_arn = "arn:aws:iam::012345678901:role/TerraformCrossAccountRole" } }
alias が必要になる代表的なケースとして、CloudFrontのACM証明書があります。CloudFrontに紐づける証明書はus-east-1にしか作成できないため、東京リージョンのALB用証明書(ap-northeast-1)とCloudFront用証明書(us-east-1)を同一コードで管理する場合に alias が必要です。2. リソースへのalias適用
alias を設定したプロバイダーはリソースブロックで provider 引数を使って明示的に指定します。指定しないリソースはすべてデフォルトプロバイダー(alias なし)が使われます。# デフォルト(ap-northeast-1)に作るS3バケット resource "aws_s3_bucket" "logs_tokyo" { bucket = "my-logs-ap-northeast-1-abcd1234" # provider 指定なし → デフォルトプロバイダーが使われる } # us-east-1 に作るACM証明書(CloudFront用) resource "aws_acm_certificate" "cloudfront_cert" { domain_name = "example.com" validation_method = "DNS" provider = aws.us_east # エイリアスを明示 }
alias プロバイダーを渡す場合は、モジュール呼び出し側で providers 引数を使います。# モジュール呼び出し側(呼び出し元の root module) module "cdn_setup" { source = "./modules/cdn" providers = { aws = aws # デフォルトを渡す aws.us_east = aws.us_east # エイリアスも渡す } }
aws.us_east を使っている場合、呼び出し側で providers を渡さないと「provider configuration not present」エラーが発生します。モジュールを作成する際は required_providers に configuration_aliases を追記してaliasを宣言しておくことをお勧めします。よくあるエラーと対処法
「Failed to install provider」エラー
Terraform Registryへの接続が失敗した場合に発生します。$ terraform init │ Error: Failed to install provider │ │ Error while installing hashicorp/aws v5.84.0: could not query provider │ registry for registry.terraform.io/hashicorp/aws: failed to retrieve │ authentication checksums for provider: ...
・プロキシ環境の場合:
HTTPS_PROXY 環境変数を設定して実行します# プロキシ経由でterraform initを実行する $ HTTPS_PROXY=http://proxy.company.internal:8080 terraform init
--plugin-dir で指定します。社内にTerraformプロバイダーミラーを構築するか、HCP TerraformのPrivate Registryを使う選択肢もあります「Incompatible provider version」エラー
lock.hcl が異なるOS/CPUアーキテクチャで作成された場合に発生します。M1/M2 MacのエンジニアがいるチームでLinux(amd64)上で lock.hcl が作成されていると起きやすいエラーです。$ terraform init │ Error: Incompatible provider version │ │ Provider registry.terraform.io/hashicorp/aws v5.84.0 does not have a │ package available for your current platform, darwin_arm64.
terraform providers lock コマンドで複数プラットフォームのハッシュを追加します。# linux_amd64(CIサーバー)とdarwin_arm64(M1/M2 Mac)のハッシュを追加 $ terraform providers lock -platform=linux_amd64 -platform=darwin_arm64 Providers are now locked to specific checksums using a hash function that is supported by all versions of Terraform.
terraform init が成功します。lock.hclのGitコンフリクト
複数のメンバーが同時にterraform init -upgrade を実行してプッシュするとコンフリクトが発生します。ハッシュ値の構造上、マージエディタで手動解決しようとすると整合性が壊れます。安全な対処手順は「削除して再生成」です。# コンフリクトした lock.hcl を削除して再生成する $ rm .terraform.lock.hcl $ terraform init $ git add .terraform.lock.hcl $ git commit -m "chore: regenerate lock.hcl after merge conflict"
本記事のまとめ
Terraformのプロバイダー設定とバージョン管理の要点をまとめます。| 設定・操作 | 役割 | 実務でのポイント |
|---|---|---|
required_providers |
source・バージョン制約を宣言する | ~> 演算子でメジャー固定・マイナー許容が基本 |
terraform.lock.hcl |
実際のバージョンとハッシュを記録する | 必ずGitにコミットする(.gitignore 禁止) |
terraform init -upgrade |
制約範囲内で最新バージョンに更新する | plan確認後にlock.hclをコミットする手順で |
provider alias |
複数リージョン・複数アカウントを扱う | CloudFront用ACM証明書(us-east-1)などに必須 |
terraform providers lock |
複数プラットフォームのハッシュを追加する | M1 Mac + Linux CIの混在チームで必要 |
・
required_providers にはsource・version(~> 5.0 形式)を必ず明示する・
.terraform.lock.hcl は .gitignore に追加せず、必ずリポジトリにコミットする・プロバイダーのアップグレードは
terraform init -upgrade → terraform plan 確認 → lock.hclをコミットの手順で行う・M1/M2 MacとLinux CIが混在するチームは
terraform providers lock -platform=... でマルチプラットフォーム対応する関連記事もあわせてご覧ください。
・Terraformのtfstate管理とS3バックエンド設定|チーム運用で壊さないための基礎
・TerraformのHCL変数設計|variable・locals・output・data sourceで構成を整理する方法
・Terraformのlifecycleブロックで本番リソースを誤削除から守る方法
>> Terraform実践セミナーの詳細はこちら
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
- 前のページへ:Terraformのlifecycleブロックで本番リソースを誤削除から守る方法|prevent_destroyとignore_changesの実践設計
- この記事の属するカテゴリ:Terraformへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます