🛡️

HCP TerraformでPolicy as Code

2024/12/17に公開

想定読者

  • HCP Terraform Plus をご利用の方。
    • 本記事では HCP Terraform Plus で利用可能な機能(Versioned Policy Sets)を使いますが、Free / Standard でも Sentinel 自体は利用可能です。
  • HCP Terraform の基本的な使い方を理解している方。
  • HCP Terraform をより高度に使うためにポリシーとか設定したいなあ。。。と思っている方。

はじめに - Sentinel とは?

本ブログでは、HCP Terraform上でSentinelを使ってPolicy as Codeを実現する方法について簡単にご紹介いたします。

HCP TerraformはIaCのデファクトであるTerraformを大規模に使う際に便利な機能を提供してくれるサービスですが、IaCを大規模に活用するにあたっては、コードの変更のレビューなどの人力の作業をいかに自動化できるかが鍵になります。
この「自社のガイドに従ったクラウドの利用がなされているか?」「セキュリティ上問題はないか?」などのレビューの自動化を行うための仕組みとして、Policy as Code (PaC) があります。
ポリシー定義によるガバナンス・セキュリティの強化はエンタープライズでIaCを活用する上での重要な要素の一つですが、それを実現するフレームワークとしてHCP TerraformではSentinelとOPAを利用することができます。
(Sentinelの基礎的な使い方については こちら もご参照ください。)
HCP Terraformで利用できるポリシーの種類

ポリシーの実装にあたってSentinelを使うかOPAを使うかについては、特に機能に差分があるわけでもないので慣れている方を利用することをおすすめします。

  • Sentinelを使った方が良さそうな方
    • OPAを使っていない。
    • HashiCorp Vaultなど、HCP Terraform以外のHashiCorp製品を導入しており、そちらにもSentinelの利用をしている・考えている。
  • OPAを使った方が良さそうな方
    • OPAをすでに別のプロダクトで活用している。

また、HCP Terraformには三つのエディションがあり、それぞれポリシーの機能自体は備わっているのですが、PlusのみがVerioned Policy Setsに対応しており、Policy as Codeの実現には実質Plusが必要です。
HCP Terraformのエディションと利用できる機能の比較

Free / Standardではポリシーのコードを直接HCP TerraformのUIに書き込むか、 tfe プロバイダを用いて Terraform のコードの中にポリシーのコードをベタ打ちすることで一応 Policy as Code を実現することはできますが、管理が煩雑になりがちです。
Plusではポリシーのコードを独立したリポジトリで管理することができ、Terraformコードの運用とは別に管理することができます。この、リポジトリに格納されたポリシーを利用することをVersioned Policy Setsと呼んでいます。

スクリーンショットが一部でわかりにくいですが、Versioned Policy Setsは下記のようにリポジトリを紐づけて設定するのに対し、
Versioned Policy Sets

Versionedではない手動設定のポリシーは以下のようにコードを直接入力して設定します。
VersionedではないPolicy Sets

本記事では、HCP Terraform Plusで利用可能なVersioned Policy Setsに絞って、どのようにポリシーを利用できるのかを簡単に紹介したいと思います。

それでは、早速ポリシーがどのように動作するのか見ていきましょう。

サンプルポリシーを使ってみよう!

HCP Terraformでは、自分でコードを書いてポリシーを設定することももちろんできますが、サンプルとなるポリシーや、すぐに使い始められる事前定義済みのポリシーもあります。
まずはこちらを見てみましょう。

サンプルポリシー

サンプルのSentinelポリシーがGitHub上に公開されており、利用することができます。
https://github.com/hashicorp/terraform-sentinel-policies

このリポジトリをForkし、HCP TerraformのVersioned Policy Setsに登録してみます。
登録する際に、利用しているクラウドプロバイダに合わせて Policies path を指定しておきます。
例えば、AWSを利用している場合には aws と入れておきます。
サンプルポリシーの登録

お試しなので、ここでは適用先のワークスペースを絞っておきます。
ポリシー適用のスコープ

これでとりあえず動きを確認してみます。
先ほど設定したワークスペースで + New run からRunを実行します。
お試しポリシー実行

Planの次のステップで、いろいろなポリシーが適用されていることがわかります。

中身を見てみる

さて、順番が逆な気がしますが、先ほどのポリシーの中身を見てみましょう。
aws ディレクトリの中には多くの *.sentinel ファイルと sentinel.hcl ファイルがありますが、前者がポリシーの定義(本体)で、後者がポリシーの設定になります。

Sentinelの設定ファイル

sentinel.hcl は、ポリシーの設定を記述するファイルです。
以下のように、 module ブロックや policy ブロックでポリシーの設定を行います。

# moduleは、terraformと同様に、サブディレクトリにある.sentinelファイルを読み
# 込むための設定になります。
# このサンプルの中には多くのヘルパーモジュールがあり、それを読み込んでいます。
module "tfplan-functions" {
  source = "../common-functions/tfplan-functions/tfplan-functions.sentinel"
}

module "tfstate-functions" {
  source = "../common-functions/tfstate-functions/tfstate-functions.sentinel"
}

~~~(中略)~~~

# ここから始まる policy ブロックで、ポリシーの設定を行っています。
policy "check-ec2-environment-tag" {
  source = "./check-ec2-environment-tag.sentinel"
  enforcement_level = "advisory"
}

policy "enforce-mandatory-tags" {
  source = "./enforce-mandatory-tags.sentinel"
  enforcement_level = "advisory"
}

~~~(以下略)~~~

重要なのは、 policy ブロックです。
これによりポリシー定義ファイルとしてどれを利用するか( source )、そのポリシーの当て方をどうするか ( enforcement_level ) を指定することができます。

enforcement_level としては advisory, soft-mandatory, hard-mandatory の三つが選択できます。
advisoryに指定されたポリシーでは、違反があった場合に警告が表示されるだけで、実行が止まることはありません。
soft-mandatoryに指定されたポリシーで違反があった場合、実行は止まりますが、特定の権限を持ったユーザーによって実行を継続することもできます。
hard-mandatoryに指定されたポリシーで違反があった場合には、問答無用で実行が停止されます。

上記の例ではすべてのポリシーが advisory が指定されているため、実行が止まることはなく、Applyの手前まで進むことができています。
Advisory Policy

ポリシーの運用を始める際には、まずは advisory で運用を始め、徐々に強制度を上げていくことをおすすめします。

この sentinel.hcl の中で利用しないポリシーをコメントアウトしたり、ポリシーの強制度を変更することで、自分の環境に合わせたポリシーの運用を行うことができます。
(もちろん、ポリシーを一部変更し、より組織にあったものに変更することもできます。)

ポリシーの定義ファイル(*.sentinel)

SentinelポリシーをVersioned Policy Setsとして登録する際には、最低でも一つの *.sentinel ファイルが必要です。
ポリシー本体を追いかけるのは大変ですが、雰囲気をつかむために、ここでは enforce-mandatory-tags.sentinel を見てみましょう。

# This policy uses the Sentinel tfplan/v2 import to require that
# specified AWS resources have all mandatory tags

# Import common-functions/tfplan-functions/tfplan-functions.sentinel
# with alias "plan"
import "tfplan-functions" as plan

# Import aws-functions/aws-functions.sentinel
# with alias "aws"
import "aws-functions" as aws

# List of resources that are required to have name/value tags
param resource_types default [
  "aws_s3_bucket",
  "aws_instance",
]

# List of mandatory tags
# Note that the tags here are for internal HashiCorp usage
# You should assign your own tags in a "mandatory_tags" parameter in your policy set
# Or change the tags here in the policy.
param mandatory_tags default ["Name", "ttl", "owner", "se-region", "purpose", "terraform"]

# Get all AWS Resources with standard tags
allAWSResourcesWithStandardTags =
                          aws.find_resources_with_standard_tags(resource_types)

# Filter to AWS resources with violations
# Warnings will be printed for all violations since the last parameter is true
violatingAWSResources =
        plan.filter_attribute_not_contains_list(allAWSResourcesWithStandardTags,
                        "tags", mandatory_tags, true)

# Main rule
main = rule {
  length(violatingAWSResources["messages"]) is 0
}

ヘルパーを多用しているものの、全体の動きは比較的わかりやすいのではないでしょうか?
このポリシーでは resource_types に指定されたリソースに対して、 mandatory_tags に指定されたタグが付与されているかをチェックし、準拠していないリソース数が0でない場合に警告を出すようになっています。

すべての詳細を理解する必要はありませんが、本番適用する前には一度なんとなく眺めて動きをさらっておくとよいかなと思います。

事前定義済みのポリシー

サンプルポリシーと何が違うんだ?という感じですが、本記事では先ほどのサンプルポリシーと区別する意味で、Terraform Registryに公開されているポリシーのことを事前定義済みのポリシーと呼んでいます。

事前定義済みのポリシーにアクセスするには、Terraform Registryにアクセスし、 Browse Sentinel Policies をクリックします。
Terraform Registry

ここから、様々なポリシーを探索し、利用することができるようになっています。
Policy Libraries

事前定義済みのポリシーを使ってみる

毎度AWSで恐縮ですが、ここでもAWSのポリシーを試しに見てみます。
先ほどの画面で、左ペインのProviderでAWSを選択してから、少し下にスクロールすると、 (Beta) で始まるポリシーがいくつかあります。
この中で、 (Beta) Pre-written Sentinel Policies for Center for Internet Security(CIS) AWS EC2 Foundations Benchmark を選択してみます。
CIS AWS EC2 Foundations Benchmark

細かい説明はPolicyのReadmeに書かれていますのでここでは省略します。

ポリシーのページからもたどることができますが、こちらも本体はGitHub上にあるため、先ほどの例と同様にリポジトリをForkしてHCP Terraformに登録すること可能です。
が、変わり映えしないのでTerraform Registryからの直接参照を試してみます。

右上の Choose policies をクリックすると、このポリシーで使える制御項目が表示されます。
Choose policies

このチェックボックスから、適当に使いたいものをクリックしていくと、 USAGE INSTRUCTIONSにこのポリシーを使う時の sentinel.hcl が表示されます。
Usage Instructions

あとはこれをコピーして、先ほどのサンプルと同様にHCP TerraformでVersioned Policy Setsとして登録するだけです。
改めて、 + New run からRunを実行してみると、このポリシーもチェックされていることがわかります。
CIS Policy Passed

まとめ

HCP Terraformでポリシーを利用開始する方法について、簡単にご紹介いたしました。
自分で一からポリシーを書くのはそこそこ大変だなあと思っている方も、今回ご紹介したサンプルコードを使ったり、Terraform Registryにあるポリシーならすぐに使い始めていただけるのではないでしょうか?
ぜひIaCのメリットを最大限に生かすためにも、ポリシーを少しでも活用してマニュアルレビューを減らしていただければと思います!

参考

Discussion