TerraformでAWS IAMポリシーとして設定するJSONはテキストで書くと構文チェックやエディタによる補完などができません。 そこでaws_iam_policy_documentデータソースを使うと便利です。 この記事ではaws_iam_policy_documentデータソースの使い方について説明します。

基本的な使い方

aws_iam_policy_documentデータソースを使用するには、aws_iam_policy_documentリソースを宣言する必要があります。次に、dataブロックを使用して、aws_iam_policy_documentデータソースを定義します。

以下は、S3バケットへの読み取りアクセスを許可するポリシーの例です。

data "aws_iam_policy_document" "s3_read_policy" {
  statement {
    sid       = "AllowRead"
    actions   = ["s3:GetObject"]
    effect    = "Allow"
    resources = ["arn:aws:s3:::my-bucket/*"]
  }
}

上記のコードでは、aws_iam_policy_documentデータソースをs3_read_policyという名前で宣言しています。statementブロックは、S3バケットへの読み取りアクセスを許可する1つのステートメントを定義しています。

aws_iam_policy_document データソースはIAMポリシーのJSONと対応しています。
aws_iam_policy_document.s3_read_policy.json で以下のように評価されます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowRead",
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::my-bucket/*"
      ]
    }
  ]
}

.jsonによってIAMポリシーのJSONが得られるので、IAMポリシーのJSON文字列が必要な箇所で利用できます。

resource "aws_iam_policy" "s3_read_policy" {
  name   = "s3_read_policy"
  policy = data.aws_iam_policy_document.s3_read_policy.json # データソースで定義したポリシーを使用
}

aws_iam_policy_documentのstatement以下の要素

sid

sidはステートメントの一意の識別子を表します。この値は外部から利用しないので必須ではありません。必要であれば人間に分かりやすい名前をつけておくと良いでしょう。

例えば以下のように記述します。

sid = "AllowRead"

JSONに変換すると以下のようになります。

"Sid": "AllowRead"

actions

actionsはステートメントで許可または拒否されるアクションを定義します。 アクションはAWSサービスが提供するAPI呼び出しを表します。 アクションはイルドカード(*)も使用できます。

以下は、S3バケットへの読み取りアクセスを許可するためのactionsの例です。

actions = [
  "s3:PutObject",
  "s3:GetObject"
]

この例では “s3:PutObject” と “s3:GetObject” を許可または拒否します。

JSONに変換すると以下のようになります。

"Action": [
  "s3:PutObject",
  "s3:GetObject"
],

effect

effectはステートメントで許可または拒否されるアクションの効果を定義します。許可のときはAllow拒否のときはDenyを指定します。

以下はS3バケットへの読み取りアクセスを許可するためのeffectの例です。

effect = "Allow"

actionsで指定したactionを許可します。

JSONに変換すると以下のようになります。

"Effect": "Allow"

principals

principalsはステートメントで許可または拒否されるプリンシパルを定義します。 プリンシパルはアクセス許可を要求するAWSアカウント、IAMユーザー、IAMロール、AWSサービス、AWSリソースなどを指します。

principalsAWSServiceFederatedCanonicalUserのいずれかの値を取ります。 例えばAWSアカウントIDを指定する場合はAWSを使用し、IAMロールを指定する場合はRoleを使用します。

以下は、S3バケットへの読み取りアクセスを許可するためのprincipalsの例です。

principals {
  type        = "AWS"
  identifiers = ["123456789012"]
}

上記コードではアカウントID 123456789012のAWSアカウントにアクセス許可を与えています。

JSONに変換すると以下のようになります。

"Principal" : { 
  "AWS": [ 
    "123456789012"
  ]
}

condition

conditionはステートメントの条件を定義します。actionを許可または拒否するための柔軟な条件を指定できます。

condition以下の要素は以下の通りです。

  • test: 条件の演算子
  • variable: 比較される変数
  • values: 比較する値

以下はS3のオブジェクトが指定されたプレフィクスとマッチするかどうかをチェックする例です。

condition {
  test     = "StringLike"
  variable = "s3:prefix"
  values   = ["prefix/*"]
}

上記はprefix/から始まるパスのオブジェクトのみにアクセスを許可もしくは拒否する例です。

JSONにすると以下になります。

"Condition": {
  "StringLike": {
    "s3:prefix": ["prefix/*"]
  }
}

さまざまな条件の演算子が利用できるようになっており、例えば接続元のIPアドレスでの比較も可能です。

以下はS3バケットへの読み取りアクセスをIPアドレスが192.0.2.0/24のユーザーに制限する条件の例です。

condition {
  test     = "IpAddress"
  variable = "aws:SourceIp"
  values   = ["192.0.2.0/24"]
}

上記のコードでは、aws:SourceIpという変数に192.0.2.0/24の値を設定し、testパラメーターにIpAddressを設定しています。これにより、IPアドレスが192.0.2.0/24の場合のみアクセスを許可します。

JSONに変換すると以下のようになります。

"Condition": {
  "IpAddress": {
    "aws:SourceIp": ["192.0.2.0/24"]
  }
}

Statementを複数書く方法

複数のステートメントを定義する場合は、statementブロックを複数回並べて書きます。

以下は、S3バケットへの読み取りアクセスと書き込みアクセスを許可するポリシーの例です。

data "aws_iam_policy_document" "s3_rw_policy" {
  statement {
    sid       = "AllowRead"
    actions   = ["s3:GetObject"]
    effect    = "Allow"
    resources = ["arn:aws:s3:::my-bucket/*"]
  }

  statement {
    sid       = "AllowWrite"
    actions   = ["s3:PutObject"]
    effect    = "Allow"
    resources = ["arn:aws:s3:::my-bucket/data/*"]
  }
}

上記のコードでは、2つのステートメントを定義しています。

  • 1つ目は my-bucket/ 以下に s3:GetObjectアクションに対して読み取りアクセスを許可
  • 2つ目は my-bucket/data/ 以下のみ s3:PutObjectアクションに対して書き込みアクセスを許可

これで my-bucket/直下への s3:PutObject 拒否しています。

JSONにすると以下になります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowRead",
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*"
    },
    {
      "Sid": "AllowWrite",
      "Effect": "Allow",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::my-bucket/data/*"
    },
  ]
}

Conditionを複数書く方法

複数の条件を定義する場合は、conditionブロックを複数回並べて書きます。

以下はS3バケットへの読み取りアクセスをIPアドレスが192.0.2.0/24のみに制限し、さらにHTTPSのみのアクセスに制限する例です。

data "aws_iam_policy_document" "s3_read_policy" {
  statement {
    sid       = "AllowRead"
    actions   = ["s3:GetObject"]
    effect    = "Allow"
    resources = ["arn:aws:s3:::my-bucket/*"]

    condition {
      test     = "IpAddress"
      variable = "aws:SourceIp"
      values   = ["192.0.2.0/24"]
    }

    condition {
      test     = "Bool"
      variable = "aws:SecureTransport"
      values   = ["true"]
    }
  }
}

上記のコードのようにconditionブロックをならべます。

JSONに変換するとCondition以下は以下のようになります。

"Condition": {
  "IpAddress": {
    "aws:SourceIp": [
      "192.0.2.0/24"
    ]
  },
  "Bool": {
    "aws:SecureTransport": [
      "true"
    ]
  }
}

“Principal”: “*” を書く方法

上記で説明したようにprincipalsブロックは以下の様に書きます。

principals {
  type        = "AWS"
  identifiers = ["123456789012"]
}

JSONは以下のようになります。

"Principal": {
  "type": "AWS",
  "identifiers": ["123456789012"]
}

上記はPrincipalの値がオブジェクトになっており、typeidentifiersは必須なので以下ようなすべてを許可するprincipalsは直接書けません。

"Principal": "*"

このPrincipalを書くにはtypeidentifiers*を指定します。

principals {
  type        = "*"
  identifiers = ["*"]
}

参考: 【Terraform】“Principal”: “*” を指定する方法

まとめ

この記事では、Terraformのaws_iam_policy_documentデータソースの使い方について紹介しました。

IAMポリシーはAWSリソースへのアクセスを管理するために重要なツールです。 aws_iam_policy_documentデータソースを使用するとポリシーを定義するためのコードを簡単に記述できます。 Terraformのコードでポリシーを定義することでバージョン管理や変更管理が簡単になりポリシーの適用に関する問題を回避できます。