Terraformにはテンプレート機能がある。よく使われるのは、ポリシーの設定などで、ヒアドキュメントで記述されるようなものを、別ファイルに記述し変数を与えて埋めていく(IAMポリシーに限定するならばHCLで記述できるAWS_IAM_POLICY_DOCUMENTがあります)。
ポリシーを定義する
例えば、ユーザやグループにポリシーを設定するために、まずポリシーを定義する。
ここで、 bucket_name
は変数になっている。ポリシーの意味は ${bucket_name}
以下にあるオブジェクトに対しての操作を全て許可するというもの。リソースの最後に /*
をつけないとバケットの操作1になってしまうので注意。
これを、 s3_bucket_policy.tpl.json
というファイルに保存しておこう。拡張子を json
とかにしておいたほうがシンタックスハイライトの恩恵が受けられる(と個人的には思う)。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": [
"arn:aws:s3:::${bucket_name}/*",
]
}
]
}
IAM Policy リソースの定義
次に、リソースを定義しよう。
今までは policy
に <<EOF ... EOF
などを書いてポリシーを埋め込んでいたと思う。
ココも変数にする。
resource "aws_iam_policy" "developer" {
name = "developer_policy"
path = "/developer"
description = "Developer IAM policy"
policy = "${data.template_file.foo.rendered}"
}
Template データの定義
最後にテンプレートの定義をしていこう。data
でtemplate_file
を定義する。
template
には最初で作成したファイルを指定する。file
メソッドを使うとファイルを引っ張って来ることができ、引数にはパス、ファイル名を与えよう。最初に作成したファイル名はs3_bucket_policy.tpl.json
なので、それを指定する。
テンプレート内にbukcet_name
という変数があったが、それをここで埋める。
vars
のマップを記述すると、そのままテンプレートに渡され、埋められる。
data "template_file" "foo" {
template = "${file("s3_bucket_policy.tpl.json")}"
vars = {
bucket_name = "bar"
}
}
bukcet_name
をTerraformで作成したバケットにしたい場合は、vars
に変数を与えればいい。
resource "aws_s3_bucket" "bar" {
bucket = "dev-var-bucket"
acl = "private"
}
data "template_file" "foo" {
template = "${file("s3_bucket_policy.tpl.json")}"
vars = {
bucket_name = "${aws_s3_bucket.bar.bucket}"
}
}
Appendix
AWS_IAM_POLICY_DOCUMENT resource
AWS IAMポリシーの作成はHCLで記述できることを @mia_0032 さんから教えていただきました。 Terraform version 0.7.0 から aws_iam_policy_document
リソースが入っていた(CHANGELOG)。
New Data Source:
aws_iam_policy_document
(#6881)
これのメリットをちょっと考えてみると次のような感じだと思う。
- HCLのシンタックスハイライトを使ってポリシーを書ける
-
plan
実行時にある程度の構文チェックができる - 書くものが減りすこしスッキリする(テンプレートの方式だと、
json
ファイル、data
ソース、aws_iam_policy
リソースを用意しないといけない)
結構、多くのメリットがありそう。
ぼくがポリシーを書くときは、AWSコンソールで直接ポリシーを作成して、検証しながらJSONを組み立てていく。整ったところで、JSONをコピーし、変数になる部分の記述を変換してテンプレートを仕上げている。
JSONのポリシーをHCLに変換してくれる何かがほしい。
ちょっと調べてみた感じだとありそう(kvz/json2hcl)。