TerraformでのIAM role設定はこれで決定!
挨拶
畑田です。Terraformで環境構築中です。
AWSにTerraformで環境構築するのは初めての経験でした。それにあたり、既存のTerraformのソースを参照しながら勉強していたのですが、IAMの設定方法1つとっても書き方が複数あり、戸惑うことが多かったです。
その経験から、IAMの設定方法をまとめておこうと考えました。それに際して基本的な事項のおさらいも行っていこうと思います。
免責
この文章ではTerraformの実行方法や、HashiCorp Configuration Language (HCL)の文法は解説せず、既知のものとして扱います。
結論
まずはこのように書けば良いというsnippetを記載します。
前提としてRDS Proxyにアクセス権限を与える意図があるものとします。
data "aws_iam_policy_document" "rds_proxy_assume_role_policy_document" {
statement {
principals { # 誰が (RDSが)
type = "Service"
identifiers = ["rds.amazonaws.com"]
}
actions = ["sts:AssumeRole"] # 何をして (STSからIAM roleをassumeして)
effect = "Allow" # 良い
}
}
data "aws_iam_policy_document" "rds_proxy_policy_document" {
version = "2012-10-17"
statement {
resources = ["arn:aws:secretsmanager:*:*:*"] # 誰に (AWS Secrets Managerに対して)
actions = [ # 何をして (以下4つの操作をして)
"secretsmanager:GetResourcePolicy",
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:ListSecretVersionIds"
]
effect = "Allow" # 良い
}
}
resource "aws_iam_policy" "rds_proxy_policy" {
name = "rds-proxy-policy"
description = "Policy for RDS Proxy"
policy = data.aws_iam_policy_document.rds_proxy_policy_document.json
}
resource "aws_iam_role" "rds_proxy_role" {
name = "rds-proxy-role"
assume_role_policy = data.aws_iam_policy_document.rds_proxy_assume_role_policy_document.json
managed_policy_arns = [
aws_iam_policy.rds_proxy_policy.arn, # 作成したポリシーをアタッチ
"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore", # AWS managedなポリシーをアタッチ
]
}
IAMについて
AWSにおけるIAMとはAWS Identity and Access Managementの略称であり、AWS上のリソースに認証および認可を提供する仕組みです。今回の登場人物は以下です。
- STS (AWS Security Token Service)
- IAM policy
- IAM role
STS
いきなりIAMの接頭辞がついていないリソースからの説明になります。
公式ドキュメントによれば、ユーザーやAWSリソースが、一時的に他のAWSリソースへアクセスできるように、認証認可に関する秘匿情報を与える機能ということです。
詳細は公式ドキュメントに譲りますが、STSの仕組みによって、不用意に関係者やアプリケーションに認証情報を配布する必要がなくなったり、ある権限を与えるためにいちいち認証を作る必要がなくなったり、安全に認証認可を管理できたりする機能が提供されています。
STSの提供する機能の中でも今回注目するのはAssumeRole
APIです。AWS上の全てのリソースは、IAM role ARNを指定してAssumeRole
APIを呼び出すと、そのARNのroleに紐づいた権限のある一時的な認証秘匿情報を得ることができます。
IAM policy
IAM policyとはIAMの構成する単位のうち最も小さいものの一つです。
簡単のために不確かな表現をすると、「誰 (何)が」、「誰 (何)に」、「何を」、「して良いか、あるいはしてはならないか」というルールを示すドキュメントです。ここで「ドキュメント」と言ったのは、実際にAWSでは大半のIAM policyがJSON形式で管理されるからです。
consoleから操作する分にはそのJSONの形式を強く意識することはありません。しかし、TerraformやCDKなどで操作したり、consoleからでも複雑なルールを設定したりする場合は、簡単な文法や決まり事を知っておくと便利でしょう。
以下が公式ドキュメントから拝借したJSONのexampleです。
JSONのexample
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets",
"s3:GetBucketLocation"
],
"Resource": "arn:aws:s3:::*"
},
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::BUCKET-NAME",
"Condition": {"StringLike": {"s3:prefix": [
"",
"home/",
"home/${aws:username}/"
]}}
},
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::BUCKET-NAME/home/${aws:username}",
"arn:aws:s3:::BUCKET-NAME/home/${aws:username}/*"
]
}
]
}
こちらがIAM policyに指定できる内容を一覧したものです。個人的にはNotXxxx
はあまり使いません。また評価のロジックに関しては明示的に許可したもの以外否定が優先されます。
element | 役割 |
---|---|
Version | IAM policyをJSON形式で表す文法のversionを表す。IAM policyのversionではないことに注意されたい。 |
Id | IAM policyのidentifierであり、IAM policyのタイプや使用場面によって使用の可否が決まります。 |
Statement | IAM policyのコアとなる部分で、上述した「誰 (何)が」、「誰 (何)に」、「何を」、「して良いか、あるいはしてはならないか」というルールを書く場所です。このelementには配列形式で複数のルールを与えることができます。 |
Sid |
Statement のidentifierであり、原則としてoptionalですが、使用場面によってrequiredになる場合があります。Statement のelementの一つ。 |
Principal | AWS上のリソースを指定して「誰 (何)が」を表現するStatement のelementの一つ。 |
NotPrincipal |
Principal の否定に当たるStatement のelementの一つ。 |
Resource | AWS上のリソースを指定して「誰 (何)に」を表現するStatement のelementの一つ。 |
NotResource |
Resource の否定に当たるStatement のelementの一つ。 |
Action | 対象となるリソースへの操作を指定して「何を」表現するStatement のelementの一つ。 |
NotAction |
Action の否定に当たるStatement のelementの一つ。 |
Effect |
Allow またはDeny を指定して「して良い (してはいけない)」を表すStatement のelementの一つ。 |
Condition |
Statement のelementの一つ。そのStatement を適用する条件を記述するelementであり、StringEquals やStringLike などの条件演算子とともに用います。 |
IAM role
IAM roleは特定のアクセス許可権限をもつIAMの単位です。
IAM userにおいてもAWS上のリソースに対してアクセス許可権限を設定でき、IAM roleとよく似た機能を持っているため、これに対比して説明することで理解の助けとします。
IAM userに対してアクセス許可権限を付与したい場合、あるIAM userに特定の権限を付与するという形式になります。一方で、IAM roleは一度作成すれば、それを任意のリソースに引き受けさせることでアクセス権限の付与を実現できます。
例えば、2人の異なるIAM userがいて、同じ権限を2人に付与したいとき、それぞれに同じ権限を設定し直す必要があるのに対し、IAM roleは一度作成したら、そのIAM roleを引き受けさせるだけで簡単に権限を委任できます。
また、IAM userに対してアクセス許可権限を設定すると、そのIAM userは付与された権限を剥奪されない限り権限を行使し続けられます。これに対して、IAM roleではSTSによって提供される一時的なアクセス権限情報を用いるため、あるIAM roleを引き受けたリソースが一時的にその権限を行使することができるようになり、そのroleの有効性やroleの引き受けが終了すると元の権限に戻る仕組みになります。
これにより、IAM roleを用いることで、AWS上のリソースは場面に応じた権限を自在にかつセキュアに引き受け、その権限を行使できるようになっています。
TerraformにおけるIAM role設定のややこしさ
consoleから設定する分には特段難しくはないですが、それをTerraformで実現するとある程度正しい知識を要求されるので多少骨が折れます。以下にその内容を書き下します。
IAM policyの設定の仕方が5種類ある
この記事を書くにあたって先行記事を調べたところ、こちらがありましたので、詳細はこの記事を参照してください。
-
aws_iam_policy_document
を用いる方法 -
jsonencode
を用いる方法 - ヒアドキュメントを用いる方法
- IAM policyが書かれたJSONファイルを読み込む方法
- templateとなるJSONファイルを読み込む方法
AssumeRole
policyを明示的に設定する必要がある
上に示したAssumeRole
APIですが、consoleでroleを作成して、割り当てる際には意識することなく操作されます。
しかし、Terraformにおいてはaws_iam_role
のassume_role_policy
attributeに明示的にpolicyのJSONを渡してあげる必要があります。
IAM roleにIAM policyをアタッチする方法が2種類以上ある
-
managed_policy_arns
attributeを使用する方法- この方法を用いると、Terraformで管理しているIAM roleにconsoleから手動でIAM policyをアタッチしてもTerraformからの設定が優先され、次の
terraform apply
で手動設定のものはdetachされます。
- この方法を用いると、Terraformで管理しているIAM roleにconsoleから手動でIAM policyをアタッチしてもTerraformからの設定が優先され、次の
-
aws_iam_role_policy_attachment
resourceを使用する方法- 上の逆であり、手動設定のIAM policyがTerraformの預かり知らぬところで設定されてもTerraformは無視するため、その手動設定のものは残り続けます。Terraformで誤って削除されたくないリソースなどに使うのが向いていると考えられます。
意見
以上を踏まえて結論の項に書いた内容が自分なりのデファクトスタンダード的な書き方になりました。
- IAM policyで
aws_iam_policy_document
を用いる。- JSONのコメント機能の弱さなどJSON自体への使用感の悪さと、HCLのインフラリソース定義における秀出から、JSONよりHCLでの管理を好むから。
- HCLのmodule機能などの応用に耐える仕様で設定ファイルを記述できるから。
-
managed_policy_arns
attributeを使用してIAM roleにIAM policyをattachする。- 原則全てのリソースをIaCで管理することで、IaCから享受できる利益を最大化したいから。
- プロジェクトのIAM roleの記述方法は1, 2に統一する。
- 統一されていない記述方法が単純に読みにくいから。
- 記述方法が統一されている中で、異なる書き方がある場合、そうしている意図が必ずあるはずであり、それが伝わりやすくなるから。
あとがき
記載内容の間違いのご指摘や訂正案、より良い内容のご提案など、忌憚なきご意見を頂けますと幸いです。
今後、アプリの環境ごと再現性を高めながらデプロイメントの簡単化及び高頻度化を図ることで、質の高いアプリを量産していくため、積極的に社内のinfrastructureをIaCで管理していきたいと考えております。
Discussion