Terraform Policyは、Terraformの設定と同じHCLでガバナンスのルールを書き、init・plan・applyの各段階でリソースやプロバイダー、モジュールを検査するHashiCorpのPolicy as Codeです。2026年10月21日公開のTerraform 1.17.0で一般提供になり、plan・apply・queryの-policiesフラグが実験版ビルドなしで使えるようになりました。本記事では、.policy.hclの書き方とtfpolicyによるテスト手順、HCP Terraformでの適用とローカル実行の違い、SentinelやOPAから移るかどうかの判断基準を、2026年10月28日時点の公式ドキュメントとterraform本体のソースをもとに整理します。
まとめ:Terraformと同じHCLで書き、ダウンロード前とapply後まで検査できる仕組み
Terraform Policyのポリシーは.policy.hclという拡張子のファイルに書きます。resource_policy・provider_policy・module_policyの3種類のブロックで対象を決め、enforceブロックのconditionが偽になれば違反です。テストは.policytest.hclにモックの属性を書き、tfpolicy testで合否を確かめます。
SentinelやOPAとの違いは、各ルールを評価するタイミングです。プロバイダーとモジュールはダウンロード前に止められ、ARNやIDのようにapplyの後で決まる値も検査できます。関連するリソースやデータソースを関数で引けるため、「S3バケットに対応するACLがprivateか」といった複数リソースにまたがる条件も短く書けます。
本番での強制はHCP Terraformのポリシーセットが担います。HCP Terraformで新しくガバナンスを組むなら、Terraform Policyを第一候補にしてよい段階です。一方、OpenTofuを使う組織や、Regoのポリシー資産をHCP Terraformの外でも使い回している組織は、今の時点で移る理由が薄いと判断します。
Terraform Policyの仕組み:1.17.0で一般提供になった範囲と評価の3段階
最初に、1.17.0で何が変わったかと、ポリシーがどの時点で評価されるかを押さえます。Terraform本体の版ごとの変更点はTerraformの最新バージョンは1.17|terraform versionでの確認とアップグレード手順・新機能にまとめています。
1.17.0のCHANGELOGで一般提供になった範囲と-policiesフラグ
Terraform v1.17.0のリリースノートは、新機能の項に「Terraform Policy is now generally available」と書いています。1.16系では-policiesが実験的な機能の扱いで、実験版ビルドか-allow-experimental-featuresフラグが必要でした。1.17.0からはどちらも不要です。
同じ版で、terraform queryのlistブロックが見つけた既存リソースにもポリシーを当てられるようになりました。結果は人が読む形式とJSONで出ます。ディレクトリでないパスをterraform query -policiesに渡すとエラーで止まる修正も入っています。ポリシーの置き場所はファイルでなくディレクトリで指定する、と覚えておけば迷いません。
init中・plan後・apply後の3段階で評価されるタイミングと止められるもの
Terraform policyの概要ページは、評価の段階を次の3つに分けています。
| 段階 | 評価する対象 | 違反したときの動き |
|---|---|---|
| セットアップ(init) | プロバイダーとモジュールの取得元・版 | ダウンロードの前に止まる |
| plan | 参照する属性がplanで分かるリソース | インフラを変える前に止まる |
| apply後 | ARN・ID・ポート番号など作成後に決まる値 | applyは完了済み。違反はエラーとして表示 |
apply後の評価は「作ってしまった後に気づく」仕組みです。違反を見つけたら手で直して再デプロイする必要があるため、止めたいルールはplanの段階で判定できる属性で書くのが基本です。apply後の評価は、作成後にしか分からない値の監査用と割り切って使います。
違反時の警告・上書き・停止を使い分ける3つの強制レベルと判断基準
強制の強さはenforcement_levelで決めます。resource_policyのリファレンスによると、省略時の既定値はmandatoryです。
mandatory:条件を満たさなければ処理を止める(既定値)mandatory_overridable:処理を止めるが、権限のあるユーザーが上書きして続けられるadvisory:処理は続け、警告だけを出す
導入の初期は、既存の構成が大量に違反するのが普通です。新しいルールはまずadvisoryで入れて違反件数を数え、直し終えたらmandatoryへ上げる順番にすると、本番の変更が止まる事故を避けられます。
Terraform Policyを試す手順:tfpolicyの導入からテスト実行まで
ここからは手元でポリシーを書き、テストを通すまでの流れです。コードは公式のPolicy examplesの構文に合わせています。
tfpolicy CLIのインストールと前提になるTerraformのバージョン
ポリシーの構文チェックとテストにはtfpolicyというCLIを使います。インストールのページの手順は、HashiCorpのリリースサイトからOSに合うzipを取ってPATHに置く方法と、macOSのHomebrewの2通りです。
# macOS の場合(Homebrew)
brew tap hashicorp/tap
brew install hashicorp/tap/tfpolicy
# 版を確かめる
tfpolicy version
2026年10月28日時点のリリース一覧で最新は0.5.0系です。CLIが持つコマンドはtest・validate・versionの3つだけで、ポリシーを本物のplanに当てる機能は持っていません。前提のTerraformの版は、インストールのページが1.16以降、HCP TerraformのVCS連携のページが1.17以降と書いています。HCP Terraformで動かす前提なら1.17系にそろえておきます。
policiesとtestsのディレクトリを分けるリポジトリ構成
VCS連携の設定ページが示す標準の構成は、ポリシー・テスト・プラグインをディレクトリで分ける形です。
./
├── policies/
│ └── ebs.policy.hcl
├── tests/
│ └── ebs.policytest.hcl
└── plugins/ # Go で書く独自関数を使う場合だけ
├── src/
└── bin/
ポリシーファイルは.policy.hcl、テストファイルは.policytest.hclで終わる名前にする決まりです。独自関数のプラグインを使う場合、HCP Terraformで実行させるにはビルド済みのバイナリもリポジトリに入れます。プラグインは1つにつき1バイナリしか置けないため、HCP Terraformのエージェントプールでx86とArmが混ざっていると、合わない側で接続エラーになります。
resource_policyでEBSボリュームの暗号化を必須にするコード
ポリシーファイルには、対象のプロバイダーを宣言するpolicyブロックが必要です。policyブロックのリファレンスの形でrequired_providersを書き、その下にresource_policyを並べます。
# policies/ebs.policy.hcl
policy {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 6.0.0, < 7.0.0"
}
}
}
# 暗号化していない EBS ボリュームは作らせない
resource_policy "aws_ebs_volume" "encryption_required" {
enforcement_level = "mandatory"
enforce {
condition = attrs.encrypted == true
error_message = "EBS ボリュームは encrypted = true が必須です。"
}
}
# 既存ボリュームの縮小を止める(更新時だけ評価)
resource_policy "aws_ebs_volume" "prevent_downsize" {
operations = ["update"]
enforce {
condition = attrs.size >= prior_attrs.size
error_message = "EBS ボリュームを ${prior_attrs.size}GB から ${attrs.size}GB に縮小できません。"
}
}
attrsは変更後の属性、prior_attrsは変更前の属性です。prior_attrsを参照するポリシーはoperationsを明示しないとエラーになり、createとは同じリストに入れられません。置き換え(replace)は削除と作成の2つの操作として評価されるので、置き換えを止めたい場合はポリシーを2つに分けて書きます。
policytest.hclでモックを渡しtfpolicy testで合否を確かめる
テストでは、リソースの属性を手で書いた「モック」をポリシーに通し、期待どおりに合格と違反が分かれるかを見ます。違反を期待するケースに付ける指定は、expect_failure = trueです。書き方はテストの書き方のページにあります。
# tests/ebs.policytest.hcl
policytest {
targets = ["../policies/ebs.policy.hcl"]
}
resource "aws_ebs_volume" "pass" {
attrs = {
availability_zone = "ap-northeast-1a"
size = 20
encrypted = true
}
}
resource "aws_ebs_volume" "fail_not_encrypted" {
expect_failure = true
attrs = {
availability_zone = "ap-northeast-1a"
size = 20
encrypted = false
}
}
構文の確認とテストの実行は、ポリシーとテストの場所をそれぞれ渡します。
tfpolicy validate --policies=policies/
tfpolicy test --policies=policies/ --tests=tests/
公式の例では、成功するとリソースごとにpassが並び、最後にテストファイル単位のpassが出ます。expect_failureを付けたケースは「期待どおり違反した」のでpassと表示される点に注意してください。ポリシーのinputで値を切り替える場合は、TFPOLICY_INPUT_<名前>の環境変数でテスト時の値を上書きできます。
init時にプロバイダーとモジュールのダウンロードを止める実装例
Terraform Policyだけが持つ機能が、プロバイダーとモジュールのダウンロード前の検査です。公式の例と同じ形で、取得元とモジュールの版を縛るポリシーを書きます。
# policies/supply_chain.policy.hcl(policy ブロックは ebs.policy.hcl と同じ)
provider_policy "aws" "official_source" {
enforce {
condition = meta.source == "registry.terraform.io/hashicorp/aws"
error_message = "AWS プロバイダーは HashiCorp 公式のものだけを使えます。"
}
}
module_policy "aws_vpc" "registry_check" {
enforcement_level = "advisory"
enforce {
condition = core::startswith(meta.source, "app.terraform.io/my-org/")
error_message = "VPC モジュールは社内のプライベートレジストリから取得してください。"
}
enforce {
condition = core::semverconstraint(meta.version, ">= 2.0.0")
error_message = "VPC モジュールは 2.0.0 以上を使ってください。"
}
}
terraform v1.17.0のmeta_policy.goを読むと、プロバイダーの版が決まった時点とモジュールの取得元が解決した時点にフックがあり、違反すると「Provider download blocked due to policy violations」でインストールを中断します。ただし、advisoryのポリシーは違反しても止めません。版の上限と下限の決め方そのものはterraform providerのバージョン制約とalias設計|lockファイルの運用判断で扱っています。
HCP Terraformでの適用とローカルの-policies実行の違い
書いたポリシーを本番の実行に効かせる場所は2つあります。HCP Terraformのポリシーセットと、手元のTerraform CLIの-policiesフラグです。両者は手間も保証の強さも違います。
VCS連携のポリシーセットをプロジェクト・ワークスペースへ割り当てる
HCP Terraformでは、.policy.hclを置いたリポジトリをVCS連携のポリシーセットとして登録し、対象をプロジェクト単位・ワークスペース単位・タグ単位のいずれかで指定します。ポリシーセットはいくつ作ってもかまいません。policyブロックのterraform_configにrequired_versionを書けば、ポリシーが前提にするTerraformの版も固定できます。
無料の範囲には上限があります。ワークスペースのポリシー適用のページによると、Freeエディションで使えるのは1つのポリシーセットに5つのポリシーまでです。ポリシーセットをVCSに接続したり、APIで版を作ったりするのはStandardとPremiumのエディションです。HCP Terraform自体の料金体系と無料枠はHCP Terraformとは?旧Terraform Cloudの料金・無料枠500リソースと自前運用との違いで整理しています。
ローカルのplan実行には別配布のtfpolicy-pluginが必要
Terraform CLIの-policiesは、ポリシーを評価するエンジンを本体に持っていません。v1.17.0のinternal/policy/client.goは、環境変数TF_POLICY_PLUGINで指定したプログラムか、PATH上のtfpolicy-pluginを別プロセスで起動し、gRPCで評価を依頼する作りです。tfpolicy-pluginはリリースサイトでtfpolicyとは別に配られています。
# tfpolicy-plugin を PATH に置かない場合は場所を指定する
export TF_POLICY_PLUGIN=/opt/tfpolicy/tfpolicy-plugin
# ポリシーはファイルでなくディレクトリで渡す(複数回指定できる)
terraform init -policies=./policies
terraform plan -policies=./policies
terraform apply -policies=./policies
見落としやすいのはライセンスです。tfpolicyとtfpolicy-pluginの0.5.0のzipには、OSSのライセンスではなくHashiCorpのEULA(EULA.txt)と評価版の利用条件(TermsOfEvaluation.txt)が入っています。また、ソースのbackendPolicyEntitlementは、cloudかremoteのbackendのときだけHCP Terraformのホスト・トークン・組織を評価エンジンへ渡し、ローカルのbackendでは何も渡しません。ローカル実行の位置づけは開発者が手元で先に違反を見つけるための補助で、強制の正本はHCP Terraform側に置く、と考えるのが安全です。業務のCIでローカル実行を組む場合は、事前に利用条件を法務と確認してください。
CIに組み込むならtfpolicy testをplanより先に回す順番
プルリクエストのCIで最初に回すべきなのは、本物のplanではなくtfpolicy validateとtfpolicy testです。クラウドの認証情報が要らず、ポリシー自体の書き間違いを数秒で見つけられます。ポリシーのリポジトリと構成のリポジトリを分けている場合は、ポリシー側のCIでこの2つを必須にし、構成側のCIでは従来どおりfmt・validate・planを回します。パイプライン全体の組み方はTerraformのCI導入ガイド|fmt・validate・planを自動化するパイプライン設計とツールの選び方を参照してください。
Sentinel・OPAとの違いとTerraform Policyへ移るかの判断基準
HCP TerraformはTerraform PolicyのほかにSentinelとOPAも扱えます。どれを選ぶかは、言語の好みより「どこで評価できるか」と「既存の資産」で決まります。
採用判断に使う言語・強制レベル・データソース参照・評価時点の比較表
公式の比較ページの記載を、判断に効く行だけ抜き出しました。
| 観点 | Terraform Policy | Sentinel | OPA(HCP Terraform) |
|---|---|---|---|
| 言語 | HCL | Sentinel言語 | Rego |
| 強制レベル | 3段階(advisory〜mandatory) | 3:advisory〜hard-mandatory | 合格と不合格の2値 |
| データソースの参照 | 評価時に関数で引ける | 引けない | 引けない |
| init時の評価 | ダウンロード前 | ダウンロード後 | ダウンロード後 |
| apply後の評価 | できる | できない | できない |
差が大きいのはデータソースの参照です。SentinelとOPAは静的なplanのスナップショットを見るため、「承認済みのKMSキーか」を判定するには承認済みの値をポリシー側に書いて同期し続ける必要があります。Terraform Policyはcore::getdatasource()で評価時に値を引けるので、その同期作業が不要になる仕組みです。OPAそのものの仕組みはOpen Policy Agent(OPA)とは?Policy as Codeを実現する汎用ポリシーエンジンを解説、Regoの書き方はRegoとは?OPA 1.0(Rego v1)の書き方とv0コード移行・テストの実装ガイドで解説しています。
採用する条件:HCP Terraformで新しくガバナンスを組む組織
次の条件に当てはまる組織は、Terraform Policyで始めてかまいません。
- Terraformの実行をHCP Terraformに集めている、または集める予定がある
- ポリシーを書くのがインフラ担当で、Regoや独自言語を新しく覚える余力が無い
- 非公式のプロバイダーや社外のモジュールを取り込ませたくない(init時に止めたい)
- KMSキーやAMIの承認リストが頻繁に変わり、ポリシー側の値の同期が負担になっている
特に3つ目は、SentinelでもOPAでもできない領域です。サプライチェーンの対策として取得元を縛りたい組織にとって、移る理由として十分です。Terraformの環境構築やHCP Terraformへの集約から相談したい場合は、一創のインフラ構築(AWS・Google Cloud・Azure)で受け付けています。
見送る条件:OpenTofu併用・HCP外の実行基盤・Rego資産を持つ組織
逆に、次の組織は今は移らない判断を勧めます。
1つ目はOpenTofuを使っている、または移行を考えている組織です。OpenTofuのplanコマンドのドキュメントには-policiesの記載が無く、評価エンジンもHashiCorpのEULAで配られています。OpenTofuとの違いはOpenTofuとは?Terraformとのライセンス・機能差と移行判断を実装視点で解説を参照してください。
2つ目は、AtlantisでTerraformをPR運用する構成のように、HCP Terraformの外でplanとapplyを回している組織です。強制の正本を置く場所が無く、ローカル実行は前の章のとおり補助にとどまります。
3つ目は、Kubernetesのアドミッション制御などでRegoのポリシーを既に書いている組織です。OPAはApache-2.0のOSSで、Terraform以外にも同じルールを使い回せます。Terraform Policyに移すと構文を書き直すことになり、比較ページでも、移行は構文と動作の両面で大きな転換になるという説明です。Terraformだけのために資産を二重に持つ意味は薄いと考えます。
Terraform Policyの導入前によく受ける質問と回答
検討の段階で出やすい疑問を、公式の記載をもとにまとめました。
Terraform PolicyはHCP Terraformが無くても使えますか?
書くこととテストすることは、HCP Terraformが無くてもできます。tfpolicy validateとtfpolicy testは、どちらも手元だけで完結するコマンドです。Terraform CLIの-policiesでplanに当てることもできますが、別配布のtfpolicy-pluginが必要で、利用条件はEULAに従います。ポリシーセットの管理、対象の指定、強制レベルに基づく実行の停止と上書きは、HCP Terraform側の機能です。
既存のSentinelポリシーはそのまま移せますか?
そのままでは移せません。言語がSentinelからHCLに変わるため、ポリシーは書き直しになります。強制レベルも名前が違い、Sentinelのsoft-mandatoryに当たるのがmandatory_overridable、hard-mandatoryに当たるのがmandatoryです。HCP TerraformはSentinelのサポートを続けているので、全部を一度に移す必要はありません。新しいルールからTerraform Policyで書き、既存のSentinelは更新のタイミングで置き換える進め方が現実的です。
TFLintやterraform testとはどう使い分けますか?
見る対象が違います。TFLintはコードの静的解析で、存在しないインスタンスタイプや命名規則の違反を書いた時点で見つけます。terraform testはモジュールが期待どおりのリソースを作るかを確かめる機能テストです。Terraform Policyは組織のルールに反する変更を実行の時点で止める仕組みで、3つは置き換えではなく併用します。
Terraform Policyは無料で使えますか?
HCP TerraformのFreeエディションでも、1つのポリシーセットに5つのポリシーまでは使えます。ポリシーセットをVCSのリポジトリに接続して運用するには、StandardかPremiumのエディションが必要です。tfpolicyのCLI自体はリリースサイトから取得できますが、OSSではなくHashiCorpのEULAで配られている点は、ほかのOSSツールと扱いが違います。
mandatory_overridableの違反は誰が上書きできますか?
HCP Terraformで上書きの権限を持つユーザーです。公式の例では、公開を意図した監査ログ用のバケットのように、例外を承認したうえで通したい場面にmandatory_overridableを使っています。例外が出るたびにルールをadvisoryへ下げると、ほかの違反まで素通りになるため、例外以外にも影響する変更です。例外がまれに出るルールはmandatory_overridableにして、上書きできる人を絞る運用にします。
関連記事
- Terraformの最新バージョンは1.17|terraform versionでの確認とアップグレード手順・新機能:Terraform Policyが一般提供になった1.17系への上げ方を確認できます。
- Open Policy Agent(OPA)とは?Policy as Codeを実現する汎用ポリシーエンジンを解説:Terraform以外にも使える汎用のポリシーエンジンと比べる場合の入口です。
- HCP Terraformとは?旧Terraform Cloudの料金・無料枠500リソースと自前運用との違い:ポリシーを強制する側のHCP Terraformの料金と仕組みです。
- Regoとは?OPA 1.0(Rego v1)の書き方とv0コード移行・テストの実装ガイド:OPAで同じルールを書いた場合の書き方を比べられます。
- TerraformのCI導入ガイド|fmt・validate・planを自動化するパイプライン設計とツールの選び方:tfpolicy testを組み込むCIの全体像です。