You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Cognito自定义邮件发送Lambda中正确使用KMS解密的方法

问题描述

我已按如下方式配置AWS Cognito用户池及自定义邮件发送Lambda:

resource "aws_kms_key" "cognito-send-mails" {
  description             = "This key is used to decrypt Cognito codes for CustomEmailSender lambda"
  deletion_window_in_days = 10
  enable_key_rotation     = true
}

resource "aws_cognito_user_pool" "users" {
  # ...
  lambda_config {
    kms_key_id          = aws_kms_key.cognito-send-mails.arn

    custom_email_sender {
      lambda_arn     = aws_lambda_function.cognito-send-emails.arn
      lambda_version = "V1_0"
    }
  }
}

resource "aws_lambda_function" "cognito-send-emails" {
  # ...
  environment {
    variables = {
      KEY_ID               = aws_kms_key.cognito-send-mails.arn
    }
  }
}

resource "aws_lambda_permission" "cognito-send-mails" {
  statement_id   = "AllowExecutionFromCognitoUserPool"
  action         = "lambda:InvokeFunction"
  function_name  = aws_lambda_function.cognito-send-emails.function_name
  principal      = "cognito-idp.amazonaws.com"
  source_account = data.aws_caller_identity.current.account_id
}

resource "aws_iam_role_policy" "cognito-send-mails-kms" {
  name = "cognito-${local.deployment-name}-send-emails-lambda-kms"
  role = aws_iam_role.lambda_exec_role.id

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
        "Effect": "Allow",
        "Action": [
            "kms:Decrypt"
        ],
        "Resource": "${aws_kms_key.cognito-send-mails.arn}"
    }
  ]
}
EOF
}

Lambda已成功触发,收到的请求如下:

{
  "callerContext": {
    "awsSdkVersion": "aws-sdk-unknown-unknown",
    "clientId": "..."
  },
  "region": "...",
  "request": {
    "clientMetadata": null,
    "code": "AYADe1...ANY=",
    "type": "customEmailSenderRequestV1",
    "userAttributes": {
      "cognito:email_alias": "...",
      "cognito:user_status": "UNCONFIRMED",
      "email": "...",
      "email_verified": "false",
      "name": "...",
      "sub": "..."
    }
  },
  "triggerSource": "CustomEmailSender_SignUp",
  "userName": "...",
  "userPoolId": "...",
  "version": "1"
}

我的目标是解密code字段以构建邮件内容。由于只能使用基于API生成的库(我用的是Haskell的amazonka),必须直接调用AWS KMS API。我调用KMS API的参数如下:

Decrypt {
  encryptionAlgorithm = null,
  encryptionContext = null,
  grantTokens = null,
  keyId = "arn:aws:kms:***:***:key/***",
  ciphertextBlob = "AYADe1...ANY="
}

但遇到了如下错误:

ServiceError {
  abbrev = "KMS",
  status = Status {statusCode = 400, statusMessage = "Bad Request"},
  headers = [
    ("x-amzn-RequestId","***"),
    ("Cache-Control","no-cache, no-store, must-revalidate, private"),
    ("Expires","0"),
    ("Pragma","no-cache"),
    ("Date","***"),
    ("Content-Type","application/x-amz-json-1.1"),
    ("Content-Length","39")
  ],
  code = "InvalidCiphertext",
  message = null,
  requestId = "***"
}

我尝试过对code进行base64解码后再重新编码,但仍得到相同的错误码。请问仅使用KMS API的正确解密流程是什么?


解决方案

按照以下步骤调整KMS API调用参数,即可正确解密Cognito传递的code字段:

  • 正确处理密文格式
    Cognito传递的code是base64编码的完整KMS密文块,KMS的Decrypt API要求ciphertextBlob参数是原始二进制数据,而非base64字符串。你需要直接对code执行base64解码,得到二进制字节流后传入API,不要解码后重新编码。

  • 必须指定匹配的加密上下文
    Cognito加密验证码时会自动添加固定的加密上下文,解密时必须完全匹配才能成功。加密上下文的键值对为:

    • aws:cognito:userPoolId: Lambda请求中的userPoolId字段值
    • aws:cognito:tokenUsage: 根据触发类型选择:注册场景填REGISTER,忘记密码场景填FORGOT_PASSWORD(对应triggerSource字段的后缀)
  • 显式指定加密算法
    Cognito默认使用RSAES_OAEP_SHA_256算法加密验证码,调用Decrypt时必须显式指定该算法,不能留空。

调整后的Haskell调用示例:

Decrypt {
  encryptionAlgorithm = Just RSAES_OAEP_SHA_256,
  encryptionContext = Just (fromList [
      ("aws:cognito:userPoolId", "<你的userPoolId>"),
      ("aws:cognito:tokenUsage", "REGISTER") -- 按实际触发场景调整
    ]),
  grantTokens = Nothing,
  keyId = Just "arn:aws:kms:***:***:key/***",
  ciphertextBlob = "<base64解码后的二进制字节流>"
}

另外,确认Lambda角色的KMS权限配置正确(你的现有配置已包含kms:Decrypt权限),且使用的KMS密钥ARN与Cognito用户池配置的完全一致。


内容的提问来源于stack exchange,提问作者GlinesMome

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 11:05:15