Amazon S3:加密来自 Amazon SES 的消息
Amazon S3: Encrypt messages coming from Amazon SES
我正在使用 Amazon SES 接收电子邮件,然后通过规则集将这些电子邮件存储在 Amazon S3 中。
然后我的程序检索这些消息,写在 Java.
整个过程目前非常顺利。
当我尝试加密电子邮件时,麻烦来了...
以下是我的流程步骤:
- SES 接收电子邮件
- SES 使用 KMS 密钥加密电子邮件(得益于 SES 规则集)。
- SES 将电子邮件存储在 Amazon S3 上
- 我的 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);
}
在此先感谢您的帮助!
可能是 Amazon SES 的加密类型有问题。
https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingEncryption.html
https://aws.amazon.com/articles/client-side-data-encryption-with-the-aws-sdk-for-java-and-amazon-s3/
SES 使用 S3 Client-side 加密,您必须使用 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
Your mail is encrypted by Amazon SES using the Amazon S3 encryption
client before the mail is submitted to Amazon S3 for storage. It is
not encrypted using Amazon S3 server-side encryption. This means that
you must use the Amazon S3 encryption client to decrypt the email
after retrieving it from Amazon S3, as the service has no access to
use your AWS KMS keys for decryption. This encryption client is
available in the AWS SDK for Java
感谢 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);
}
我正在使用 Amazon SES 接收电子邮件,然后通过规则集将这些电子邮件存储在 Amazon S3 中。 然后我的程序检索这些消息,写在 Java.
整个过程目前非常顺利。 当我尝试加密电子邮件时,麻烦来了...
以下是我的流程步骤:
- SES 接收电子邮件
- SES 使用 KMS 密钥加密电子邮件(得益于 SES 规则集)。
- SES 将电子邮件存储在 Amazon S3 上
- 我的 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);
}
在此先感谢您的帮助!
可能是 Amazon SES 的加密类型有问题。
https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingEncryption.html
https://aws.amazon.com/articles/client-side-data-encryption-with-the-aws-sdk-for-java-and-amazon-s3/
SES 使用 S3 Client-side 加密,您必须使用 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
Your mail is encrypted by Amazon SES using the Amazon S3 encryption client before the mail is submitted to Amazon S3 for storage. It is not encrypted using Amazon S3 server-side encryption. This means that you must use the Amazon S3 encryption client to decrypt the email after retrieving it from Amazon S3, as the service has no access to use your AWS KMS keys for decryption. This encryption client is available in the AWS SDK for Java
感谢 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);
}