[小ネタ] Kinesis Data FirehoseのIAMポリシーに含まれるプレースホルダーについて

2022.01.21

しばたです。

検証用にAmazon Kinesis Data Firehose(以後Kinesis Firehose)を手作業で作成した際に気が付いた点について、ネット上に意外と情報が無かったのでブログにしてみました。

配信ストリーム作成時に生成されるIAMロール

マネジメントコンソールからKinesis Firehose配信ストリームを新規作成する場合、配信ストリームと同時にIAMロールを新規作成することが可能です。

例として下図の様にシンプルなS3への配信ストリーム(PUT-S3-Test1)を作る場合、

Advanced settingsの「Permissions」欄でIAMロールを新規作成するかどうかを指定できます。

ここでIAMロールを新規作成した場合以下の様なポリシーを持つロールとなり、ところどころに%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%という値が紛れ込んでいるのが見て取れます。

自動生成されたIAMロールに紐づくポリシー(例)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "glue:GetTable",
                "glue:GetTableVersion",
                "glue:GetTableVersions"
            ],
            "Resource": [
                "arn:aws:glue:ap-northeast-1:123456789012:catalog",
                "arn:aws:glue:ap-northeast-1:123456789012:database/%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%",
                "arn:aws:glue:ap-northeast-1:123456789012:table/%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%/%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "s3:AbortMultipartUpload",
                "s3:GetBucketLocation",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::your-test-bucket",
                "arn:aws:s3:::your-test-bucket/*"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeFunction",
                "lambda:GetFunctionConfiguration"
            ],
            "Resource": "arn:aws:lambda:ap-northeast-1:123456789012:function:%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%"
        },
        {
            "Effect": "Allow",
            "Action": [
                "kms:GenerateDataKey",
                "kms:Decrypt"
            ],
            "Resource": [
                "arn:aws:kms:ap-northeast-1:123456789012:key/%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%"
            ],
            "Condition": {
                "StringEquals": {
                    "kms:ViaService": "s3.ap-northeast-1.amazonaws.com"
                },
                "StringLike": {
                    "kms:EncryptionContext:aws:s3:arn": [
                        "arn:aws:s3:::%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%/*",
                        "arn:aws:s3:::%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%"
                    ]
                }
            }
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/kinesisfirehose/PUT-S3-Test1:log-stream:*",
                "arn:aws:logs:ap-northeast-1:123456789012:log-group:%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%:log-stream:*"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "kinesis:DescribeStream",
                "kinesis:GetShardIterator",
                "kinesis:GetRecords",
                "kinesis:ListShards"
            ],
            "Resource": "arn:aws:kinesis:ap-northeast-1:123456789012:stream/%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%"
        },
        {
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": [
                "arn:aws:kms:ap-northeast-1:123456789012:key/%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%"
            ],
            "Condition": {
                "StringEquals": {
                    "kms:ViaService": "kinesis.ap-northeast-1.amazonaws.com"
                },
                "StringLike": {
                    "kms:EncryptionContext:aws:kinesis:arn": "arn:aws:kinesis:ap-northeast-1:123456789012:stream/%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%"
                }
            }
        }
    ]
}

FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER プレースホルダー is 何?

で、この%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%は何なのか疑問に思ったのが本記事の趣旨となります。

名前からしてプレースホルダーだというのはわかるのですが、公開された情報が全然無く、マネジメントコンソールのヘルプや開発者ガイドの中で

コンソールはプレースホルダーを使ってロールを作成する可能性があります。

と軽く触れられている程度です。

そこで配信ストリームを作成する条件をいろいろ変えて挙動を確認してみたところ、

  • マネジメントコンソールから自動生成されるIAMロールのポリシーは最大公約数となる単一のテンプレートから生成されている様に見受けられる
  • 配信ストリーム作成時に実際に使用するサービスだけ%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%の部分が実際のリソースのものに置換される
  • 使用しないサービスについてはプレースホルダー(%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%)が置換されずそのまま残る

という動作をすることがわかり、結果、IAMロール生成処理の実装が素朴であるというシンプルな話であることがわかりました。

実際IAMポリシーの定義において特別なプレースホルダーが使えるわけでは無いので、この%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%が残っていても意味のない記述となるだけで実害はありません。
とはいえ使われない定義を残しておくのは行儀が良くないので不要な部分についてはIAMロール生成後に適宜修正することをお勧めします。

実際開発者ガイドでは使用するサービス毎で個別にアクセス権の指定方法が記載されおり、こちらに倣い必要な分だけ記述すると良いでしょう。

最後に

簡単ですが以上となります。

慣れている方にとってはなんてことのない話でしょうが、そうでない方もいると思いますので本記事で共有しておきます。
IAMポリシーは常に必要最低限・最小権限の記述にする様にしましょう。