Sentinel Policies
Sentinel Policies
Sentinel Policiesとは
Sentinel Policiesは、HashiCorpのポリシーアズコード(Policy as Code)フレームワークであるSentinelを使用した、高度なポリシー制御機能です。通常のVaultポリシー(ACLポリシー)よりも柔軟で強力なルールを定義できます。
通常のポリシーとの違い
| 特徴 | ACLポリシー | Sentinel Policies |
|---|---|---|
| 言語 | HCL | Sentinel言語 |
| 制御 | パスベース | 条件ベース |
| 複雑な条件 | 限定的 | 高度な条件分岐 |
| 時間制御 | ❌ | ✅ |
| 外部データ | ❌ | ✅ |
| エンフォースメントレベル | なし | 3段階 |
Sentinelの基本概念
エンフォースメントレベル
Sentinel Policiesには3つのエンフォースメントレベルがあります。
1. advisory(助言)
- ポリシー違反時に警告を表示
- 操作は許可される
- 監査目的に使用
2. soft-mandatory(ソフト必須)
- ポリシー違反時に操作を拒否
- 上位権限者はオーバーライド可能
- 承認ワークフローと組み合わせて使用
3. hard-mandatory(ハード必須)
- ポリシー違反時に操作を拒否
- オーバーライド不可
- 最も厳格な制御
Sentinel言語の基本
Sentinel言語は、ポリシーを記述するための専用言語です。
# 基本的な構文
import "time"
import "strings"
# ルールの定義
main = rule {
time.now.weekday not in ["saturday", "sunday"]
}
Sentinel Policiesの作成
例1: 営業時間外のアクセス制限
営業時間外(平日18時以降、土日)のシークレットアクセスを制限します。
business-hours.sentinel:
import "time"
# 営業時間の定義
business_start = 9
business_end = 18
# 現在時刻の取得
hour = time.now.hour
weekday = time.now.weekday
# 営業時間内かチェック
is_business_hours = rule {
weekday not in ["saturday", "sunday"] and
hour >= business_start and
hour < business_end
}
# メインルール
main = rule {
is_business_hours
}
例2: 本番環境への書き込み制限
本番環境のシークレットへの書き込みを特定のユーザーのみに制限します。
prod-write-restriction.sentinel:
import "strings"
# リクエストパスの取得
request_path = request.path
# 本番環境のパスかチェック
is_prod_path = rule {
strings.has_prefix(request_path, "secret/data/prod/")
}
# 許可されたユーザー
allowed_users = [
"admin",
"prod-deployer",
]
# ユーザーチェック
is_allowed_user = rule {
request.entity.name in allowed_users
}
# メインルール: 本番環境の場合は許可ユーザーのみ
main = rule when is_prod_path {
is_allowed_user
}
例3: シークレットの有効期限制限
動的シークレットのTTLを制限します。
ttl-limit.sentinel:
import "strings"
# リクエストデータの取得
ttl = request.data.ttl else 0
# 最大TTL(秒)
max_ttl = 3600 # 1時間
# TTLチェック
main = rule {
ttl <= max_ttl
}
例4: MFA必須化
特定のパスへのアクセスにMFAを必須化します。
mfa-required.sentinel:
import "strings"
# リクエストパスの取得
request_path = request.path
# 機密パスの定義
sensitive_paths = [
"secret/data/prod/",
"secret/data/finance/",
]
# 機密パスかチェック
is_sensitive = rule {
any sensitive_paths as path {
strings.has_prefix(request_path, path)
}
}
# MFAが使用されているかチェック
has_mfa = rule {
length(request.mfa_credentials) > 0
}
# メインルール: 機密パスの場合はMFA必須
main = rule when is_sensitive {
has_mfa
}
Sentinel Policiesの適用
ポリシーのアップロード
# Sentinelポリシーの作成
vault write sys/policies/egp/business-hours \
policy=@business-hours.sentinel \
enforcement_level="soft-mandatory" \
paths="secret/data/*"
パラメータ
- policy: Sentinelポリシーの内容
- enforcement_level: エンフォースメントレベル(advisory/soft-mandatory/hard-mandatory)
- paths: ポリシーを適用するパス(ワイルドカード使用可能)
ポリシーの一覧表示
# EGP(Endpoint Governing Policies)の一覧
vault list sys/policies/egp
# 特定ポリシーの詳細
vault read sys/policies/egp/business-hours
ポリシーの更新
# ポリシーの更新
vault write sys/policies/egp/business-hours \
policy=@business-hours-updated.sentinel \
enforcement_level="hard-mandatory" \
paths="secret/data/*"
ポリシーの削除
# ポリシーの削除
vault delete sys/policies/egp/business-hours
高度な使用例
例5: 複数条件の組み合わせ
複数の条件を組み合わせた複雑なポリシーです。
advanced-policy.sentinel:
import "time"
import "strings"
# 現在時刻
hour = time.now.hour
weekday = time.now.weekday
# リクエスト情報
request_path = request.path
user_name = request.entity.name
operation = request.operation
# 営業時間
is_business_hours = rule {
weekday not in ["saturday", "sunday"] and
hour >= 9 and hour < 18
}
# 本番環境
is_prod = rule {
strings.has_prefix(request_path, "secret/data/prod/")
}
# 管理者
is_admin = rule {
user_name in ["admin", "security-admin"]
}
# 読み取り操作
is_read = rule {
operation == "read"
}
# ルール1: 本番環境への書き込みは営業時間内のみ
prod_write_rule = rule when is_prod and not is_read {
is_business_hours or is_admin
}
# ルール2: 本番環境の読み取りは常に許可
prod_read_rule = rule when is_prod and is_read {
true
}
# メインルール
main = rule {
prod_write_rule and prod_read_rule
}
例6: 外部データの使用
HTTPリクエストで外部APIからデータを取得します。
external-validation.sentinel:
import "http"
import "json"
# 外部APIでユーザーを検証
validate_user = func(username) {
resp = http.get("https://api.example.com/validate/" + username)
if resp.status_code == 200 {
data = json.unmarshal(resp.body)
return data.is_valid
}
return false
}
# ユーザー名の取得
username = request.entity.name
# メインルール
main = rule {
validate_user(username)
}
例7: カスタムメッセージ
ポリシー違反時にカスタムメッセージを表示します。
custom-message.sentinel:
import "time"
hour = time.now.hour
# 営業時間チェック
is_business_hours = rule {
hour >= 9 and hour < 18
}
# メインルール(カスタムメッセージ付き)
main = rule {
is_business_hours else "アクセスは営業時間内(9:00-18:00)のみ許可されています"
}
Sentinel関数とインポート
利用可能なインポート
| インポート | 説明 | 主な機能 |
|---|---|---|
time | 時間関連 | 現在時刻、日付操作 |
strings | 文字列操作 | 前方一致、後方一致、分割 |
http | HTTPリクエスト | GET、POST、認証 |
json | JSON操作 | パース、マーシャル |
decimal | 数値計算 | 高精度計算 |
よく使う関数
# 文字列操作
strings.has_prefix(str, prefix)
strings.has_suffix(str, suffix)
strings.contains(str, substr)
strings.split(str, sep)
# リスト操作
length(list)
any list as item { condition }
all list as item { condition }
# 時間操作
time.now.hour
time.now.weekday
time.now.unix
テストとデバッグ
ポリシーのテスト
# テスト用のリクエストを送信
vault write secret/data/prod/myapp \
data=@data.json
# ポリシー違反の場合のエラー例
Error writing data to secret/data/prod/myapp: Error making API request.
URL: PUT https://vault.example.com:8200/v1/secret/data/prod/myapp
Code: 403. Errors:
* 1 error occurred:
* business-hours: アクセスは営業時間内(9:00-18:00)のみ許可されています
デバッグ
Sentinelポリシーにprintステートメントを追加してデバッグできます。
import "time"
hour = time.now.hour
print("Current hour:", hour)
main = rule {
hour >= 9 and hour < 18
}
ベストプラクティス
1. 段階的な導入
最初はadvisoryレベルで導入し、影響を確認してからsoft-mandatory、hard-mandatoryに移行します。
# Phase 1: Advisory(警告のみ)
vault write sys/policies/egp/new-policy \
policy=@policy.sentinel \
enforcement_level="advisory" \
paths="secret/data/*"
# Phase 2: Soft-mandatory(オーバーライド可能)
vault write sys/policies/egp/new-policy \
enforcement_level="soft-mandatory"
# Phase 3: Hard-mandatory(オーバーライド不可)
vault write sys/policies/egp/new-policy \
enforcement_level="hard-mandatory"
2. 明確なエラーメッセージ
ユーザーが理解しやすいエラーメッセージを提供します。
main = rule {
condition else "具体的なエラーメッセージ: 何が問題で、どうすれば解決できるか"
}
3. パフォーマンスの考慮
外部APIへのリクエストは最小限に抑えます。
# 悪い例: 毎回APIリクエスト
main = rule {
http.get("https://api.example.com/check").status_code == 200
}
# 良い例: 条件付きでAPIリクエスト
main = rule {
not is_sensitive_operation or
http.get("https://api.example.com/check").status_code == 200
}
4. ドキュメント化
ポリシーの目的と動作を明確にドキュメント化します。
# ポリシー名: 本番環境書き込み制限
# 目的: 本番環境への意図しない変更を防止
# 適用範囲: secret/data/prod/*
# エンフォースメントレベル: hard-mandatory
# 作成日: 2024-01-15
# 作成者: Security Team
import "strings"
# ... ポリシーの内容 ...
次のステップ
Sentinel Policiesの基本を理解したら、次は以下を学びましょう:
- Control Groups - 承認ワークフローの実装
- 高度なSentinel使用例 - より複雑なユースケース