4

我正在使用 Amazon SES 接收电子邮件,然后通过规则集将其存储在 Amazon S3 中。这些消息然后由我用 Java 编写的程序检索。

整个过程目前正在像魅力一样工作。当我尝试加密电子邮件时,麻烦就来了……

以下是我的流程步骤:

  1. SES 接收电子邮件
  2. SES 使用 KMS 密钥加密电子邮件(感谢 SES 规则集)。
  3. SES 将电子邮件存储在 Amazon S3 上
  4. 我的 Java 应用程序从 S3 检索邮件。

但是,当我在 S3 上调用以检索电子邮件时,出现以下错误:

com.amazonaws.services.kms.model.AWSKMSException: The ciphertext refers to a customer master key that does not exist, does not exist in this region, or you are not allowed to access. (Service: AWSKMS; Status Code: 400; Error Code: AccessDeniedException; Request ID: 8de11099-1706-11e8-a931-c7b8c61f94bc)

如此错误中所述,我认为我用来检索 S3 对象的用户无权访问用于加密消息的密钥。但据我了解亚马逊的政策如何运作,我相信一切都是正确的(显然不是)。

有人知道我做错了什么或者我可以尝试做些什么吗?

下面是有关当前配置的信息,例如我的用户和 KMS 密钥的策略,以及我正在使用的 Java 代码。

地区

The S3 bucket is in EU_WEST_1 (Ireland)
The key has been created in the EU_WEST_1 (Ireland) region

用户政策(详见附图)

这里使用的用户名是delivery

AmazonS3FullAccess
AWSKeyManagementServicePowerUser

关键政策

{
  "Version": "2012-10-17",
  "Id": "key-consolepolicy-3",
  "Statement": [
    {
      "Sid": "Enable IAM User Permissions",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111222333444:root"
      },
      "Action": "kms:*",
      "Resource": "*"
    },
{
  "Sid": "Allow access for Key Administrators",
  "Effect": "Allow",
  "Principal": {
    "AWS": [
      "AIDAIEIV9CCM6CQJBN7HA",
      "arn:aws:iam::111222333444:user/delivery"
    ]
  },
  "Action": [
    "kms:Create*",
    "kms:Describe*",
    "kms:Enable*",
    "kms:List*",
    "kms:Put*",
    "kms:Update*",
    "kms:Revoke*",
    "kms:Disable*",
    "kms:Get*",
    "kms:Delete*",
    "kms:TagResource",
    "kms:UntagResource",
    "kms:ScheduleKeyDeletion",
    "kms:CancelKeyDeletion"
  ],
  "Resource": "*"
},
{
  "Sid": "Allow use of the key",
  "Effect": "Allow",
  "Principal": {
    "AWS": [
      "AIDAIEIV9CCM6CQJBN7HA",
      "arn:aws:iam::111222333444:user/delivery"
    ]
  },
  "Action": [
    "kms:Encrypt",
    "kms:Decrypt",
    "kms:ReEncrypt*",
    "kms:GenerateDataKey*",
    "kms:DescribeKey"
  ],
  "Resource": "*"
},
{
  "Sid": "Allow attachment of persistent resources",
  "Effect": "Allow",
  "Principal": {
    "AWS": [
      "AIDAIEIV9CCM6CQJBN7HA",
      "arn:aws:iam::111222333444:user/delivery"
    ]
  },
  "Action": [
    "kms:CreateGrant",
    "kms:ListGrants",
    "kms:RevokeGrant"
  ],
  "Resource": "*",
  "Condition": {
    "Bool": {
      "kms:GrantIsForAWSResource": "true"
    }
  }
},
{
  "Sid": "AllowSESToEncryptMessagesBelongingToThisAccount",
  "Effect": "Allow",
  "Principal": {
    "Service": "ses.amazonaws.com"
  },
  "Action": [
    "kms:Encrypt",
    "kms:GenerateDataKey*"
  ],
  "Resource": "*",
  "Condition": {
    "StringEquals": {
      "kms:EncryptionContext:aws:ses:source-account": "111222333444"
    },
    "Null": {
      "kms:EncryptionContext:aws:ses:rule-name": "false",
      "kms:EncryptionContext:aws:ses:message-id": "false"
    }
  }
}
]
}

S3 存储桶策略

{
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "AllowSESPuts-111222333444",
        "Effect": "Allow",
        "Principal": {
            "Service": "ses.amazonaws.com"
        },
        "Action": "s3:PutObject",
        "Resource": "arn:aws:s3:::received-emails.my-company-name/*",
        "Condition": {
            "StringEquals": {
                "aws:Referer": "111222333444"
            }
        }
    }
]
}

Java 代码

private static void getS3Object() {
    // Use credentials to login.
    BasicAWSCredentials awsCred = new BasicAWSCredentials("user access key", "user secret");
    AWSCredentialsProvider credentialProvider = new AWSStaticCredentialsProvider(awsCred);

    KMSEncryptionMaterialsProvider materialsProvider = new KMSEncryptionMaterialsProvider("id of the key");
    AmazonS3Encryption s3Client = AmazonS3EncryptionClientBuilder
            .standard()
            .withCryptoConfiguration(new CryptoConfiguration(CryptoMode.EncryptionOnly))
            .withEncryptionMaterials(materialsProvider)
            .withCredentials(credentialProvider)
            .withRegion(Regions.EU_WEST_1).build();

    // Get the object from S3
    GetObjectRequest request = new GetObjectRequest(new S3ObjectId("Bucket name", "Object key"));
    S3Object object = s3Client.getObject(request);
}

在此先感谢您的帮助!

4

3 回答 3

4

感谢 Sudharsan,这是我问题的答案;

看来,即使我使用了正确的客户端(用于客户端加密),我也不知何故忘记了一些参数(很可能是witAwshKmsRegion()参数)。

这是有效的代码:

private static void getS3Object() {
  // Use credentials to login.
  BasicAWSCredentials awsCred = new BasicAWSCredentials("user access key", "user secret");
  AWSCredentialsProvider credentialProvider = new AWSStaticCredentialsProvider(awsCred);

  KMSEncryptionMaterialsProvider materialsProvider = new KMSEncryptionMaterialsProvider("id of the key");
  AmazonS3Encryption s3Client = AmazonS3EncryptionClientBuilder
        .withCryptoConfiguration(new CryptoConfiguration().withAwsKmsRegion(com.amazonaws.regions.Region.getRegion(Regions.EU_WEST_1)))
        .withEncryptionMaterials(materialsProvider)
        .withCredentials(credentialProvider)
        .withRegion(Regions.EU_WEST_1).build();

  // Get the object from S3
  GetObjectRequest request = new GetObjectRequest(new S3ObjectId("Bucket name", "Object key"));
  S3Object object = s3Client.getObject(request);
}
于 2018-02-26T10:51:32.653 回答
1

SES 使用 S3 客户端加密,您必须在从 Amazon S3 检索电子邮件后使用 Amazon S3 加密客户端解密电子邮件,这是来自 AWS 文档的代码示例和参考。

https://docs.aws.amazon.com/AmazonS3/latest/dev/client-side-using-kms-java.html

https://docs.aws.amazon.com/ses/latest/DeveloperGuide/receiving-email-action-s3.html

在将邮件提交到 Amazon S3 进行存储之前,Amazon SES 使用 Amazon S3 加密客户端对您的邮件进行加密。它未使用 Amazon S3 服务器端加密进行加密。这意味着您必须在从 Amazon S3 检索电子邮件后使用 Amazon S3 加密客户端对其进行解密,因为该服务无权使用您的 AWS KMS 密钥进行解密。此加密客户端在适用于 Java 的 AWS 开发工具包中可用

于 2018-02-23T15:59:25.690 回答