Sentinel Policy CLI入門
想定読者
- "Sentinel"と聞いて、「HashiCorpのPolicy as Codeのことか!」とは ならない 方。
- ちょっと
sentinel
触ってみたい方。 - HCP Terraformをご利用中、またはご利用予定の方。
はじめに
みなさん、"sentinel"ってご存知でしょうか?
そもそも知らないか、「あーM社のセキュリティのあれね」となる方がほとんどだと思います(所感)。
ここでは、TerraformなどのHashiCorp製品でPolicy as Codeを実現するためのSentinelというフレームワークをご紹介します。
Sentinelとは?
すでに若干ネタバレしてしまっていますが、Sentinelとは、主にTerraform含むHashiCorpのプロダクトに対してPolicy as Codeを実現するためのフレームワークになります。
PolicyをCodeで管理することには、以下のようなメリットがあります。
- ポリシーの再利用性
- ポリシーをコードでUIや手動で制御するのではなく、コードによって実現することで、モジュール等の作成が可能になり、再利用性が高まります。
- ポリシーのバージョン管理
- IaC (Infrastructure as Code)と同様に、ポリシーもコードとして管理することで、バージョン管理が可能になります。誰が、いつ、なぜ、そのポリシーを設定したのか、変更したのか、などの情報も含めた管理ができるようになります。
- ポリシーのテスト
- マニュアルの制御からコードによる制御になると、新しいポリシーがうまく機能しているかどうかなどのテストも容易になります。
- ポリシーの自動化
- ポリシーをCI/CDパイプラインに組み込み、自動的にポリシーをチェックするような運用も可能になります。
- などなど
TerraformのみならずVaultやNomadなど、HashiCorpのその他プロダクトとも組み合わせて使っていただけるもので、CLIも提供されています。
また、HCP TerraformやTerraform Enterpriseなどをお使いの場合には、Terraformが実行(plan
/apply
)されるタイミングで自動的にPolicyチェックを行い、その結果によってはapplyの手前で実行を止めるようなことも可能です。
PRが上がるたびに目grepするのはやめて、自動化できるところは自動化していきましょう!
とりあえず動かしてみる
何はともあれ動かしてみます。
ツール準備
-
sentinel
コマンド。きっとあなたのPCに入っていることはないと思うので、ダウンロードしてください。- macOSやLinuxでHomebrewを導入している場合、
brew tap hashicorp/tap
からのbrew install sentinel
で多分インストールできるはずです。 - できなかった、もしくはHomebrew入れてない、という場合は こちらからダウンロードしてください。PATH通しもお忘れなく。
- macOSやLinuxでHomebrewを導入している場合、
一応バージョンを確認しておきます。
➜ sentinel -version
Sentinel v0.28.0
これでツールの準備は完了です。
コードの準備
次に、お試し用のSentinelポリシーと、それに対するテストコードを用意します。
それぞれ、以下のように配置してください。
(作業ディレクトリ)
├ 📄 test_sentinel.sentinel
└ 📁 test/
└ 📁 test_sentinel/
├ 📄 pass.hcl
└ 📄 fail.hcl
param weather
param day
is_sunny = rule {
weather == "sunny"
}
is_wednesday = rule {
day == "wednesday"
}
main = rule {
is_sunny and is_wednesday
}
param "weather" {
value = "sunny"
}
param "day" {
value = "wednesday"
}
param "weather" {
value = "sunny"
}
param "day" {
value = "tuesday"
}
動かしてみる
準備が整ったので、sentinel
を動かしてみます。
# 作業ディレクトリにいない場合は作業ディレクトリに移動してからコマンドを実行してください。
➜ sentinel test
FAIL - test_sentinel.sentinel
FAIL - test/test_sentinel/fail.hcl
trace:
test_sentinel.sentinel:12:1 - Rule "main"
Value:
false
test_sentinel.sentinel:4:1 - Rule "is_sunny"
Value:
true
test_sentinel.sentinel:8:1 - Rule "is_wednesday"
Value:
false
PASS - test/test_sentinel/pass.hcl
1 tests completed in 6.946375ms
同じような結果が出れば成功です!
簡単な解説
概ね見て想像できる結果かなと思いますが、簡単にポイントを説明します。
- Sentinelのポリシーコードは、
.sentinel
拡張子で記述します。- 今回の例では、
test_sentinel.sentinel
が本体ファイルです。
- 今回の例では、
- ポリシーをテストするためのコードは、
.hcl
拡張子で記述し、(作業ディレクトリ)/test/(ポリシー名)
に配置します。- 今回の例では、
pass.hcl
とfail.hcl
がテストコードです。 - これらの中に、ポリシーそのものをテストするためのもろもろを記述します。
- 今回の例では、
- sentinelポリシーの中には一つの
main
が存在し、これがtrueになると成功となります。 - 可読性向上のために、
rule
を使ってロジックを分割することができます。 - sentinelのtestなどのコマンドは、
terraform
と同様に、トップディレクトリで実行します。
基本的な文法
個人の主観に基づき一部の文法を抜粋して紹介します。
網羅的に見たい方は公式ドキュメントもご参照ください。
変数
Sentinelでは変数を扱うことができます。main
も変数の一つです。
a = 1 // a == 1
b = 2 // b == 2
c = a + b // c == 3
型変換もできます。
d = 1.1
a = int(d) // a == 1
e = string(a) // e == "1"
その他いくつか種類がありますが、例えばparam
を使うことで、外部からの入力を受け取ることができます。
param weather
param day
param宣言した上で、ポリシー設定時に値を渡すことで、ポリシーの再利用が可能です。
(この辺りはHCP Terraformとの組み合わせパートで多分触れます。)
policy "test" {
source = "foo.sentinel"
enforcement_level = "hard-mandatory"
params = {
"weather" = "sunny"
}
}
Rule
sentinel
では、ruleを使ってポリシー判定を行います。
is_sunny = rule {
weather == "sunny"
}
is_wednesday = rule {
day == "wednesday"
}
main = rule {
is_sunny and is_wednesday
}
こちらの例のように、複数のruleを組み合わせてmain
で判定することもできるので、見やすいようにある程度分割しておくと良いでしょう。
条件分岐/ループ
if/elseやforなどの制御構文を扱うこともできます。
if condition {
// ...
} else {
// ...
}
if condition {
// ...
} else if other_condition {
// ...
} else {
// ...
}
list = []
for { "a": 1, "b": 2 } as name {
append(list, name)
}
print(list) // ["a" "b"]
Collection Operations
filterやmapを使うこともできます。resource全体のうち、特定の条件に合致するものがないかを探す時など、filterはよく使う気がします。
list = [1, 1, 2, 3, 5, 8]
evens = filter l as v { v % 2 is 0 } // [2, 8]
list = [1, 2, 3]
res = map list as l { l * 2 } // [2, 4, 6]
関数
関数を定義することも可能です。
func add_one(x) {
return x + 1
}
result = add_one(1) // 2
匿名関数も作れます。
Imports
Sentinelには標準ライブラリ(Standard Imports)が用意されており、import
して使うことができます。
import "time"
date_now = time.now() // {"day": 11, "hour": 14, "minute": 59, "month": 10, "month_name": "October", ...
HCP Terraformで使う場合には、このimport
を使って、stateやplanの結果などの情報を取得し、ポリシー判定に使うことができます。
さいごに
いかがでしたでしょうか?
少しでもSentinelについての興味を持っていただけたら幸いです。
ここでは触れませんでしたが、SentinelにはSentilel Playgroundというものがあり、ブラウザ上でSentinelのコードを書いて実行することができます。ぜひ、そちらもお試しください!
Discussion