---
title: "RenovateでTerraformを自動更新する設定｜lockファイルとrangeStrategyの実際の挙動"
url: "https://www.issoh.co.jp/tech/details/12321/"
published: 2026-06-01
updated: 2026-10-09
categories: ["IaC"]
publisher: "株式会社一創"
---

# RenovateでTerraformを自動更新する設定｜lockファイルとrangeStrategyの実際の挙動

Renovateは、Terraformのprovider・module・Terraform本体のバージョンを検知して更新PRを作り、`.terraform.lock.hcl`のハッシュも自分で書き換えます。ただ、既定設定のままだと「制約の範囲内ならlockファイルだけが更新される」「`required_version = ">= 1.9.0"`には更新PRが出ない」など、設定ファイルの見た目からは予想しにくい動きをします。この記事では、Renovate 44.148.0（2026年10月8日公開）を手元のTerraformリポジトリに対して実行した結果をもとに、どの設定で何が変わるのかを整理します。

## まとめ：RenovateでTerraformを更新するときの要点

- **対象**：`**/*.tf`と`**/*.tofu`を自動で走査し、`required_providers`・`module`・`required_version`などを依存として拾います。ディレクトリごとの登録は不要です。
- **既定の更新方法**：`rangeStrategy`の既定値`auto`は、Terraformでは`update-lockfile`として動きます。`~> 3.5`の範囲内の新版は`.terraform.lock.hcl`だけを更新し、範囲外のメジャー版が出たときは`~> 2.1`を`~> 3.0`のように制約ごと書き換えます。
- **Terraform本体**：`>= 1.9.0`のような下限だけの制約は既定ではPRが出ません。追いかけるなら`required_version`だけ`rangeStrategy: "bump"`にします。
- **lockファイル**：Renovateはハッシュを自分で計算・取得して書き込むので、Terraform CLIは要りません。定期的に全providerを更新する`lockFileMaintenance`は既定で無効です。
- **落とし穴**：`minimumReleaseAge`を設定すると、公開日時を返さない`git-tags`で取得するmodule（GitLabなどの`git::`ソース）は、更新PRが保留されたまま解けません。
- **Dependabotとの差**：Dependabotは`required_version`を依存として扱わず、Terraformのセキュリティアップデートにも対応していません。Terraformを中心に据えるならRenovateが有利です。

以下、検知範囲→既定設定での実測→設定の変え方→運用上の落とし穴の順に説明します。

## RenovateのTerraform対応範囲

### terraform managerが拾う依存と取得元

Renovateの`terraform` managerは、`.tf`と`.tofu`の中身を解析し、依存の種類ごとに`depType`を付けます。`depType`は、後述の`packageRules`で「Terraform本体だけ設定を変える」といった絞り込みに使う名前です。

| 記述                                | depType             | バージョンの取得元                            |
| --------------------------------- | ------------------- | ------------------------------------ |
| required\_providersのprovider      | `required_provider` | Terraform Registry                   |
| providerブロックのversion              | `provider`          | Terraform Registry                   |
| moduleのsourceとversion             | `module`            | Registry／GitHubタグ／Gitタグ              |
| terraformブロックのrequired\_version   | `required_version`  | GitHub Releases（hashicorp/terraform） |
| tfe\_workspaceのterraform\_version | `tfe_workspace`     | HCP Terraform向け                      |
| helm\_releaseのchart               | `helm_release`      | Helmリポジトリ・OCI                        |
| docker\_\*・kubernetes\_\*のimage   | `docker_image`など    | コンテナレジストリ                            |

`required_version`の新版はGitHubのhashicorp/terraformリポジトリから引くため、セルフホストで動かす場合はGitHubのトークン（`RENOVATE_GITHUB_COM_TOKEN`）が必要です。トークンなしで実行すると「GitHub token is required for some dependencies」という警告が出て、Terraform本体の更新だけが止まりました。

providerとmoduleは、レジストリの指定がなければ`registry.terraform.io`から取得します。OpenTofuのレジストリを使う場合は、`packageRules`で`matchDatasources: ["terraform-provider", "terraform-module"]`に`registryUrls: ["https://registry.opentofu.org"]`を指定します。

### terragrunt・.terraform-version・TFLintプラグインは別manager

Terraformの周辺ファイルは、それぞれ別のmanagerが担当します。どれも既定で有効なので、ファイルがあれば自動的に対象になります。

- `terragrunt`：`terragrunt.hcl`の`terraform { source = ... }`を更新します（[Terragruntの基本](/tech/details/12477/)で扱う構成）。
- `terraform-version`：tfenvなどが読む`.terraform-version`を、hashicorp/terraformのGitHub Releasesから更新します。
- `terragrunt-version`：`.terragrunt-version`を更新します。
- `tflint-plugin`：`.tflint.hcl`の`plugin`ブロックの版を更新します（[TFLintの導入と設定](/tech/details/3393/)で使うAWSルールセットなど）。

## 既定設定で検出される更新候補の実測

Renovate 44.148.0をnpmで入れ、`config:recommended`だけを書いた`renovate.json`を置いたリポジトリに対して`renovate --platform=local`（更新候補の検出までを行い、PRは作らないモード）を実行しました。対象の`main.tf`は次のとおりで、`.terraform.lock.hcl`はrandom 3.5.1とnull 2.1.2を記録した状態です。

```
terraform {
  required_version = ">= 1.9.0"
  required_providers {
    random = {
      source  = "hashicorp/random"
      version = "~> 3.5"
    }
    null = {
      source  = "hashicorp/null"
      version = "~> 2.1"
    }
  }
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.0.0"
}
```

2026年10月9日時点で検出された更新は次の4ブランチでした。

| 依存                | 現在の値                | 更新後            | ブランチ名                                      |
| ----------------- | ------------------- | -------------- | ------------------------------------------ |
| random            | \~> 3.5（lock 3.5.1） | lockのみ3.9.1    | renovate/random-3.x-lockfile               |
| null              | \~> 2.1（lock 2.1.2） | \~> 3.0（3.3.2） | renovate/null-3.x                          |
| vpcモジュール          | 5.0.0               | 5.21.0         | renovate/terraform-aws-modules-vpc-aws-5.x |
| vpcモジュール          | 5.0.0               | 6.7.3          | renovate/terraform-aws-modules-vpc-aws-6.x |
| required\_version | \>= 1.9.0           | PRなし           | なし                                         |

読み取れることは3つあります。1つ目は、randomのように制約の範囲内に新版があると、`main.tf`は変えずにlockファイルだけを3.9.1へ上げることです。制約の文字列を見てPRを待っていると「更新が来ない」と誤解しやすいところです。2つ目は、nullのように範囲外のメジャー版が出ると制約を`~> 3.0`へ置き換えることです。3つ目は、moduleのマイナー版とメジャー版が別のPRに分かれることで、これは`separateMajorMinor`の既定値が`true`だからです。

この挙動の理由は[Renovate 44.148.0のgetRangeStrategy実装](https://github.com/renovatebot/renovate/blob/44.148.0/lib/modules/manager/index.ts)にあります。`rangeStrategy`が`auto`のとき、managerがlockファイルの部分更新（`updateLockedDependency`）を実装していれば`update-lockfile`、そうでなければ`replace`に解決されます。terraform managerはこれを実装しているため`update-lockfile`になります。公式ドキュメントも`update-lockfile`の対応managerに`terraform`を挙げています。

## rangeStrategyの選び方

同じリポジトリで`"rangeStrategy": "bump"`にすると、結果は次のように変わりました。

| 依存                | auto（既定）    | bump          |
| ----------------- | ----------- | ------------- |
| random（範囲内）       | lockのみ3.9.1 | \~> 3.9 に書き換え |
| null（範囲外）         | \~> 3.0     | \~> 3.3       |
| required\_version | PRなし        | \>= 1.16.5    |

providerは既定の`auto`のままにするのが無難です。`~> 3.5`で互換範囲を宣言し、実際に使う版はlockファイルで固定するというTerraform本来の分担と一致するからです。`bump`にすると下限が毎回上がるため、同じproviderを使う共有モジュールの利用側と制約が衝突しやすくなります（制約の書き方の判断は[providerのバージョン制約とlockファイルの運用判断](/tech/details/16540/)を参照）。

Terraform本体だけは事情が違います。`required_version`はlockファイルに記録されないので、`auto`では範囲内の新版を反映する先がなく、PRが出ません。実行を許可するTerraformの下限を新しい版に合わせて引き上げたいなら、`required_version`に限って`bump`を指定します。ただし`required_version`は制約にすぎず、CIにインストールされるTerraformは変わりません。CIの実行版はtfenvなどが読む`.terraform-version`（`terraform-version` manager）で追いかけ、両方を同じPRで上げるようにします。実測ではhashicorp/terraformが`config:recommended`に含まれる`group:monorepos`に該当し、ブランチ名は`renovate/terraform-monorepo`になりました。最新版の確認方法は[Terraformの最新バージョンとアップグレード手順](/tech/details/8928/)にまとめています。

moduleを`version = "5.0.0"`のように完全一致で書いている場合は、`auto`でも`bump`でも新しい版番号へ置き換わります。例外は`in-range-only`で、設定ファイルを書き換えないためmoduleの版も更新されません。

## .terraform.lock.hclの更新とlockFileMaintenance

### Renovateがハッシュを計算する仕組み

Renovateは`terraform init`や`terraform providers lock`を呼びません。Terraform Registryのproviderを更新するときは、対象版の全プラットフォームのzipをダウンロードして`h1:`ハッシュを計算し、`SHA256SUMS`から`zh:`ハッシュを取り、重複を除いて並べ替えて書き込みます（[lockfile/hash.ts](https://github.com/renovatebot/renovate/blob/44.148.0/lib/modules/manager/terraform/lockfile/hash.ts)）。OpenTofu Registryではpackages APIが返すハッシュを優先し、取れない場合だけzipから計算します。hashicorp/random 3.9.1で同じ処理を呼び出すと、h1が12件、zhが13件返りました。

このハッシュで作ったlockファイルに対してTerraform 1.16.5（darwin\_amd64）で`terraform init`を実行しても、lockファイルの内容は変わりませんでした。`terraform providers lock -platform=linux_arm64`も「found no need for changes」で終わり、ハッシュは追加されていません（検証用に手で組んだファイルには先頭の自動管理コメントが無かったため、その2行だけが付け足されました）。全プラットフォーム分のh1がそろっているので、macOSで作業する開発者とLinuxのCIが混在していても、ハッシュの追記による差分は起きません。

注意点は2つです。lockファイルが無いディレクトリでは何も更新しないので、`.terraform.lock.hcl`はコミットしておきます。また、lockファイルを書き換える対象は`required_provider`と`provider`だけで、moduleはlockファイルに関係しません。

### lockFileMaintenanceによるproviderの定期一括更新

通常の更新PRは、制約の範囲内で新版が出たproviderを1つずつ扱います。`lockFileMaintenance`を有効にすると、lockファイル内の全providerを制約の範囲内の最新版へまとめて上げるPRが別に作られます。既定値は無効で、有効にした場合のスケジュールは`before 4am on monday`、ブランチ名は`renovate/lock-file-maintenance`です。

```
{
  "lockFileMaintenance": { "enabled": true }
}
```

複数providerの更新が1つのPRに混ざるので、`terraform plan`で差分が出たときの原因の切り分けには手間がかかります。

## PRの数と実行タイミングの制御

導入直後は、溜まっていた更新がまとめて検出されます。Renovateの既定値は`prHourlyLimit`が1時間あたり2件、`prConcurrentLimit`が同時に開いておけるPR 10件で、`branchConcurrentLimit`は未指定なら`prConcurrentLimit`と同じ値を引き継ぎます。上限を超えた分は、`config:recommended`で有効になるDependency Dashboard（Issue）に一覧されます。

PRの数を減らす手段は、件数の上限より`groupName`でまとめる方が効きます。次の設定は、providerのマイナー・パッチ更新を1本にまとめ、メジャー版は個別のPRに残す例です。`schedule:earlyMondays`は新しいブランチを作る時間帯を月曜0時〜3時台に限るプリセットで、`timezone`を指定しないとUTC基準になります。Renovate自体の起動間隔はこれとは別に決め、既存ブランチのリベースなどは既定（`updateNotScheduled: true`）では時間外にも行われます。

```
{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:recommended", "schedule:earlyMondays"],
  "timezone": "Asia/Tokyo",
  "prHourlyLimit": 4,
  "prConcurrentLimit": 8,
  "lockFileMaintenance": { "enabled": true },
  "packageRules": [
    {
      "matchManagers": ["terraform"],
      "matchDepTypes": ["required_version"],
      "rangeStrategy": "bump"
    },
    {
      "matchManagers": ["terraform"],
      "matchDepTypes": ["required_provider"],
      "matchUpdateTypes": ["minor", "patch"],
      "groupName": "terraform providers (non-major)"
    },
    {
      "matchFileNames": ["envs/dev/**"],
      "additionalBranchPrefix": "dev-"
    },
    {
      "matchFileNames": ["envs/prod/**"],
      "additionalBranchPrefix": "prod-"
    },
    {
      "matchFileNames": ["envs/dev/**"],
      "matchUpdateTypes": ["minor", "patch"],
      "automerge": true
    }
  ]
}
```

範囲内のlockファイル更新も`matchUpdateTypes`上は`minor`や`patch`として扱われるので、このグループに入ります（設定は`renovate-config-validator`で検証済み）。

## 環境別ディレクトリを分けて扱うmatchFileNames

`envs/dev`と`envs/prod`のように環境ごとにディレクトリを分けている場合、Renovateは両方を自動で検知します。検知のために`matchFileNames`を書く必要はありません。

問題になるのは、同じproviderの同じ版の更新が**1つのブランチにまとまる**ことです。上の例から`additionalBranchPrefix`のルールを外して実行すると、devとprodのrandom更新はどちらも`renovate/terraform-providers-(non-major)`という同じブランチに入りました。この状態でdevだけ自動マージにしようとしても、PRは1本しかないため、devとprodを別々に適用できません。

`matchFileNames`で環境のディレクトリを指定し、`additionalBranchPrefix`に`dev-`と`prod-`を付けると、ブランチが`renovate/dev-terraform-providers-(non-major)`と`renovate/prod-terraform-providers-(non-major)`に分かれました。上の設定そのもので実行した結果は、null・providerグループ・Terraform本体・lockFileMaintenanceが環境ごとに分かれた8ブランチです。接頭辞を`{{parentDir}}-`で自動にする書き方もありますが、`envs/dev/app/main.tf`のように階層が深いとdevもprodも`app`になって分離できないため、環境名を固定で書く方が確実です。devのPRだけ自動マージし、prodは人がplanを確認してから適用する、という運用はここまで分けて初めて成り立ちます。PR上でplanを確認する仕組みには、[Atlantis](/tech/details/16549/)や[TerraformのCIパイプライン](/tech/details/6528/)を組み合わせます。

自動マージは、`terraform plan`をCIの必須チェックにしていないリポジトリでは使わない方が安全です。Renovateが見るのはCIの成否だけなので、planが走らなければ、providerのメジャー版で属性が変わるような破壊的変更もそのまま取り込まれます。planは削除や再作成を含む計画でも成功するため、自動マージを許すなら、`terraform show -json`で出したplanの`resource_changes`に`delete`が含まれたらCIを失敗させる条件まで組み込みます。

## minimumReleaseAgeとinternalChecksFilterの落とし穴

`minimumReleaseAge`は、公開から一定期間が過ぎた版だけを更新対象にする設定です。既定は未設定（待機なし）で、`"3 days"`のように指定します。Renovate 42からは、公開日時を取得できない版を「まだ期間を満たしていない」とみなす挙動（`minimumReleaseAgeBehaviour`の既定値`timestamp-required`）に変わりました。

Terraformでは、この公開日時を返す取得元と返さない取得元があります。

| 取得元                                    | 公開日時  |
| -------------------------------------- | ----- |
| registry.terraform.io（provider・module） | 全版あり  |
| registry.opentofu.org                  | 全版あり  |
| app.terraform.io（HCP Terraformのmodule） | 最新版のみ |
| その他のprivate providerレジストリ              | なし    |
| git::https://github.com/…（github-tags） | あり    |
| git-tagsで取得するgit::ソース（GitLabなど）        | なし    |

GitLab上のリポジトリを`git::https://gitlab.com/...?ref=v17.0.0`で参照するmoduleを置き、`minimumReleaseAge: "3 days"`で実行したところ、ログに「Marking 45 release(s) as pending, as they do not have a releaseTimestamp」と出て、更新は保留扱いになりました。git-tagsでは公開日時が取得できないので、この設定のままでは何日待っても保留は解けません。なお、Bitbucketの`git::`ソースは`bitbucket-tags`として扱われ、こちらは公開日時を取得できます。

保留中の版をどう扱うかを決めるのが`internalChecksFilter`です。既定値の`strict`では保留中の版のPRを作らず、Dependency Dashboardにだけ表示します。`flexible`は全版が保留中のときに最新の保留版でPRを作りますが、期間を満たした古い版へPRが差し戻される「ばたつき」が起きると公式ドキュメントが注意しています。社内Gitのmoduleを使うなら、そのmoduleだけ`minimumReleaseAge`を外すのが確実です。

```
{
  "minimumReleaseAge": "3 days",
  "packageRules": [
    {
      "matchDatasources": ["git-tags"],
      "minimumReleaseAge": null
    }
  ]
}
```

## プライベートレジストリの認証と実行環境

実行方法は、GitHubにMend Renovate App（GitHub App）を入れる方法と、自分で動かすセルフホスト（GitHub Action・Docker・npmのCLI）に分かれます。HCP Terraformのprivate registryや社内Gitのmoduleを参照するなら、トークンを自社のSecretsで管理できるセルフホストが扱いやすくなります。

認証は`hostRules`で、`matchHost`に対象ホスト、`token`に認証情報を指定します。トークンを`renovate.json`に直接書くとリポジトリに残るので、セルフホストのグローバル設定（`config.js`）で環境変数から読み込みます。

```
// renovate-config.js（セルフホストのグローバル設定）
module.exports = {
  platform: 'github',
  repositories: ['example-org/infra'],
  hostRules: [
    { matchHost: 'app.terraform.io', token: process.env.TFE_TOKEN },
  ],
};
```

GitHub Actionの`renovatebot/github-action`（v46.3.7、既定のRenovateは44系）は、Renovateをコンテナで起動し、`RENOVATE_`で始まる環境変数など決まったものだけをコンテナへ渡します。`TFE_TOKEN`のような独自名の変数は`additional-env-list`で明示しないと届かず、認証エラーになります。

```
- uses: renovatebot/github-action@v46.3.7
  with:
    configurationFile: renovate-config.js
    token: ${{ secrets.RENOVATE_TOKEN }}
    additional-env-list: |
      TFE_TOKEN
  env:
    TFE_TOKEN: ${{ secrets.TFE_TOKEN }}
    RENOVATE_GITHUB_COM_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

Actionのバージョンをタグで書くかコミットSHAで固定するかは、[SHA Pinningの考え方](/tech/details/10238/)に従って決めます。

## DependabotとのTerraform対応の違い

GitHub Docs（2026年10月時点）とDependabotのソース（dependabot-coreのTerraformパーサー）で確認した、Terraformに関する範囲の違いです。両ツールの一般的な比較や`dependabot.yml`の書き方は[Dependabotの設定とRenovateとの違い](/tech/details/6796/)で扱っています。

| 項目                             | Renovate           | Dependabot  |
| ------------------------------ | ------------------ | ----------- |
| provider・module                | 対応                 | 対応          |
| .terraform.lock.hcl            | 対応                 | 対応          |
| required\_version              | 対応                 | 抽出しない       |
| .terraform-version・TFLintプラグイン | 対応                 | 非対応         |
| 対応Terraformの版（公式表記）            | 記載なし               | 0.13〜1.15.x |
| GitHub以外のプラットフォーム              | GitLab・Bitbucketなど | GitHub      |

[Dependabotのパーサー](https://github.com/dependabot/dependabot-core/blob/main/terraform/lib/dependabot/terraform/file%5Fparser.rb)は`module`と`required_providers`だけを依存として取り出し、`required_version`を読む処理を持っていません。[GitHub Docsの対応表](https://docs.github.com/en/code-security/reference/supply-chain-security/supported-ecosystems-and-repositories)でも、Terraformは「Version updates」のみ対応で「Security updates」は非対応です。

判断の目安として、provider数本とRegistryのmoduleだけを使う小さなGitHubリポジトリなら、設定が少なく済むDependabotで足ります。Terraform本体の版を揃えたい、環境ごとに自動マージの扱いを変えたい、GitLabでも同じ運用をしたい、のどれかに当てはまるならRenovateを選びます。両方を同じリポジトリで動かすと同じ更新のPRが二重に開くので、どちらか一方に寄せてください。

## よくある質問

### Renovateのrangestrategyをbumpにするとproviderはどう変わりますか？

範囲内の新版でも制約の下限を書き換えます。`~> 3.5`で3.9.1が出ると、既定の`auto`はlockファイルだけを更新しますが、`bump`は`~> 3.9`に変えます。providerは`auto`のまま、`required_version`だけ`bump`にする使い分けが扱いやすい構成です。

### prHourlyLimitの既定値はいくつですか？

1時間あたり2件です。同時に開いておけるPRの上限`prConcurrentLimit`の既定値は10件です。上限で止まった更新はDependency Dashboardに表示されます。

### RenovateとDependabotの違いはTerraformでは何ですか？

大きな違いは`required_version`の扱いです。RenovateはTerraform本体の版を更新できますが、Dependabotは依存として抽出しません。`.terraform-version`やTFLintプラグインの更新もRenovateだけが対応しています。

### Renovateが更新したlockファイルでterraform initすると差分が出ますか？

Renovate 44.148.0とTerraform 1.16.5の組み合わせでは、版・制約・ハッシュとも変わりませんでした。Renovateが全プラットフォーム分のh1ハッシュを書き込むためです。差分が出る場合は、lockファイルのprovider版と`required_providers`の制約が食い違っていないかを確認します。

### internalChecksFilterとは何ですか？

`minimumReleaseAge`で保留中になった版をPRにするかどうかを決める設定です。既定値の`strict`は保留中の版のPRを作らず、`none`は保留を無視して最新版でPRを作ります。

## 関連記事

- [terraform providerのバージョン制約とalias設計｜lockファイルの運用判断](/tech/details/16540/)
- [Dependabotとは｜dependabot.ymlの設定・料金・Renovateとの違いを解説](/tech/details/6796/)
- [Terraformの最新バージョンは1.16｜terraform versionでの確認とアップグレード手順・新機能](/tech/details/8928/)
- [TerraformのCI導入ガイド｜fmt・validate・planを自動化するパイプライン設計とツールの選び方](/tech/details/6528/)
- [AtlantisでTerraformをPR運用する構成と権限設計｜採用条件を解説](/tech/details/16549/)

---

出典: [RenovateでTerraformを自動更新する設定｜lockファイルとrangeStrategyの実際の挙動](<https://www.issoh.co.jp/tech/details/12321/>)（株式会社一創）
