Terraformで構築したAWS LambdaがAWS KMSキーポリシーでエラーとなった話

AWS

2024.2.6

Topics

はじめに

本記事ではAurora S3エクスポートをLambda経由で実行するシステムを、Terraformで構築した時に詰まった話をご紹介します。

状況

構築したシステムの概要図は上記の通りです。
1. Auroraがスナップショット作成完了イベントを発砲する。
2. EventBridgeが1のイベントをキャッチし、Step Functionsを実行する。
3. Step Functionsの中のLambdaが実行される。
4. Lambda経由でAuroraスナップショットをS3にエクスポートする。

上記概要図のシステムをコンソールより構築した時は想定通りの動作結果を得られました。
しかし、Terraformにて同じものを再現し、実行したところ下記のエラーが発生しました。

{
  "errorMessage": "An error occurred (KMSKeyNotAccessibleFault) when calling the StartExportTask operation: The specified KMS key [arn:aws:kms:ap-northeast-1:*********:key/************] does not exist, is not enabled or you do not have permissions to access it.",
  "errorType": "KMSKeyNotAccessibleFault",
  "requestId": "fbaadd00-98b8-4fa9-9f16-a1515b603d02",
  "stackTrace": [.....

エラーの原因としてはAuroraのStartExportTaskを実行するIAMロールに対してKMSのキーポリシーの権限が足りていなかったことです。
コンソールからキーポリシーを設定した時と同様にキーポリシーを設定していたので、どこで不備があったのかわかりませんでした。
エラーを解決するために順に行ったことを説明します。

試したこと

①S3 Exportを実行するロールに対してKMSの権限を付与した

KMSKeyNotAccessibleFaultとあったためKMSを利用する権限がS3エクスポートを実行するロールに対して付与されていないことを推測しました。
LambdaはRDSのstart_export_taskをPassRoleによって実行する実装としていました。
KMSのキーポリシーにはLambdaを実行するロールに対しては権限を付与していたものの、PassRoleで引き受けるロールに対しては許可していませんでした。
そのため、PassRoleで引き受けるロールに対して同じキーポリシーを追加しました。
追加した権限は以下の5つです。

"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:Encrypt",
"kms:DescribeKey",
"kms:Decrypt"

こちらの対応を実施してもエラーは解消されませんでした。

Boto3 1.34.26 documentation – RDS / Client / start_export_task

②KMSのポリシーを確認した

次に既存で実行できている環境とKMSの差分を確認しました。
KMSのキーポリシーを確認したところ内容が異なっていることを確認しました。
上記で許可したKMSキーポリシーに加えて以下の3つの権限が追加されていました。

"kms:CreateGrant",
"kms:ListGrants",
"kms:RevokeGrant"

マネジメントコンソールでキーユーザーに設定した際には上記3つと①の権限を合わせて、8つの権限が割り当てられます。
今回Terraformに書き起こす際、AWS公式が提供しているkms moduleを使いましたが、そのオプションの中でkey_usersというものがあったため同様のものと想定して書いていました。
kms moduleのGitHubを確認したところ上記3つの権限は追加されず構築されてしまうことが確認できました。
kmsモジュールを使用したTerraformは以下の通り記載し実行していました。

module "kms" {
  source      = "terraform-aws-modules/kms/aws"
  description = "use for Aurora S3 export."
  key_usage   = "ENCRYPT_DECRYPT"

  # Policy
  key_users = [aws_iam_role.storage_transfer_role.arn, aws_iam_role.lambda_export_role.arn]

  # Aliases
  aliases = ["${var.project_name}-${var.env}-key"]
}

3つの権限を追加できるように以下のようにTerraformを修正しました。
修正後、実行を試したところ、無事にS3エクスポートが実行開始されました。
PassRoleで引き受ける際には元のIAMロールからCreateGrantでKMS権限を付与する必要がありますが、そのための権限がkms moduleを使って構築するとアタッチされないようでした。

resource "aws_kms_key" "s3export" {
  description = "use for Aurora S3 export."
  key_usage   = "ENCRYPT_DECRYPT"
}

resource "aws_kms_key_policy" "user" {
  key_id = aws_kms_key.s3export.id
  policy = data.aws_iam_policy_document.kms.json
}

data "aws_iam_policy_document" "kms" {
  statement {
    sid    = "Enable IAM User Permissions"
    effect = "Allow"
    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::${var.project_number}:root"]
    }
    actions   = ["kms:*"]
    resources = ["*"]
  }

  statement {
    sid    = "Allow use of the key"
    effect = "Allow"
    principals {
      type        = "AWS"
      identifiers = [aws_iam_role.storage_transfer_role.arn, aws_iam_role.lambda_export_role.arn]
    }
    actions = ["kms:Encrypt",
      "kms:Decrypt",
      "kms:ReEncrypt*",
      "kms:GenerateDataKey*",
    "kms:DescribeKey"]
    resources = ["*"]
  }

  statement {
    sid    = "Allow attachment of persistent resources"
    effect = "Allow"
    principals {
      type        = "AWS"
      identifiers = [aws_iam_role.storage_transfer_role.arn, aws_iam_role.lambda_export_role.arn]
    }
    actions = ["kms:CreateGrant",
      "kms:ListGrants",
    "kms:RevokeGrant"]
    resources = ["*"]
    condition {
      test     = "Bool"
      variable = "kms:GrantIsForAWSResource"
      values   = [true]
    }
  }
}

デフォルトのキーポリシー
kms module

まとめ

Terraformによって構築したKMSキーポリシーのトラブルシューティングについて紹介しました。
公式のモジュールでもコンソール経由の構築と異なるものを構築している場合があるので、構築後に正常に動作した環境との差分確認やGitHubのモジュールのコード確認などを行いましょう。

テックブログ新着情報のほか、AWSやGoogle Cloudに関するお役立ち情報を配信中!

reono

2022年4月、NHNテコラスに新卒入社。大学時代は山に登ったり、インドに行ったりしてました。

Recommends

こちらもおすすめ

Special Topics

注目記事はこちら