如何使用AWS Lambda将S3对象备份到另一个帐户的存储桶中?
我正在尝试使用AWS Lambda将对象从Account-A
下的assets.myapp.com
S3存储桶备份到Account-B
下的backup-assets.myapp.com
S3存储桶,但是无论Bucket Policy
我使用的配置.
I'm attempting to use AWS Lambda to backup objects from an assets.myapp.com
S3 bucket under Account-A
to a backup-assets.myapp.com
S3 bucket under Account-B
, but I'm getting Access Denied
no matter the IAM
or Bucket Policy
configuration I use.
我有一个名为Backup-S3-Object
的Lambda函数,并由assets.myapp.com
存储桶上的s3:PutObject
事件触发器触发.
I've got a Lambda function called Backup-S3-Object
and it's fired by an s3:PutObject
event trigger on the assets.myapp.com
bucket.
期望的结果是Backup-S3-Object
函数将使用适用于Javascript的AWS-SDK执行s3.copyObject
至backup-assets.myapp.com
.
The desired result is that the Backup-S3-Object
function will the perform an s3.copyObject
to backup-assets.myapp.com
using the AWS-SDK for Javascript.
Lambda代码
var aws = require('aws-sdk');
var s3 = new aws.S3({ apiVersion: '2006-03-01' });
exports.backupObject = function(event, context, callback) {
var data = event.Records[0];
var sourceBucket = data.s3.bucket.name;
var targetBucket = 'backup-' + data.s3.bucket.name;
var key = data.s3.object.key;
console.log('BACKUP: ' + sourceBucket + '/' + key + ' to ' + targetBucket);
s3.copyObject({
Bucket : targetBucket,
CopySource : sourceBucket + '/' + key,
Key : key,
ACL : 'private',
ServerSideEncryption : 'AES256'
}, function(error, data) {
if (error) return context.done(error);
return context.done(null, 'Successful backup of ' + sourceBucket + '/' + key);
});
};
Lambda角色S3政策
对于Backup-S3-Lambda-Role
,我具有以下策略,该策略已分配给我的Lambda函数.这允许Lambda函数从源帐户Account-A
下的任何存储桶访问List
或Get
的任何对象.因此,此策略将允许Lambda函数从assets.myapp.com
(即源存储桶)中获取对象.
I've got the following policy for the Backup-S3-Lambda-Role
which is assigned to my Lambda function. This allows the Lambda function access to List
or Get
any object, from any bucket, under Account-A
, which is the source account. So this policy will allow the Lambda function to get the object from assets.myapp.com
, which is the source bucket.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:ListBucketVersions",
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": [
"arn:aws:s3:::*"
]
}
]
}
backup-assets.myapp.com
存储桶策略
The backup-assets.myapp.com
Bucket Policy
然后,在Account-B
下,我在backup-assets.myapp.com
上附加了以下存储桶策略,该策略旨在允许在Account-A
下运行的Lambda函数写入以下位置的backup-assets.myapp.com
存储桶Account-B
And then, under Account-B
, I've got the following bucket policy attached to the backup-assets.myapp.com
, which is intended to allow the Lambda function, running under Account-A
, to write to the backup-assets.myapp.com
bucket under Account-B
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "Allow PUT from Account-A Lambda function",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT-A-NUMBER-HERE:role/Backup-S3-Lambda-Role"
},
"Action": "s3:PutObject",
"Resource": [
"arn:aws:s3:::backup-assets.myapp.com",
"arn:aws:s3:::backup-assets.myapp.com/*"
]
}
]
}
发生了什么事?
assets.myapp.com
存储桶上的触发器会很好地触发.它会触发Backup-S3-Object
Lambda函数,并且该函数逻辑能够确定正确的存储桶名称和要复制的对象键,但始终会失败,并显示Access Denied
.
The trigger on the assets.myapp.com
bucket fires just fine. It triggers the Backup-S3-Object
Lambda function, and the function logic is able to determine the correct bucket names and object key to be copied, but it always fails with Access Denied
.
我已经使用相同的设置进行了测试,并将其转移到也在Account-A
下的另一个存储桶中,并且工作正常.因此,问题显然出在跨帐户权限上,但是我尝试过的任何方法都无法奏效.
I've done a test using the same setup and transferring to another bucket that's also under Account-A
and it works just fine. So the problem is obviously with the cross-account permissions, but nothing I've tried works.
我也曾尝试将Account-A
的CanonicalID
用作backup-assets.myapp.com
存储桶策略中的Principal
,但仍然会得到Access Denied
作为结果错误.
I've also attempted using the CanonicalID
of Account-A
as the Principal
in the backup-assets.myapp.com
bucket policy, but still get Access Denied
as the resulting error.
我尝试使用"AWS": "arn:aws:iam::ACCOUNT-A-NUMBER-HERE:root"
作为主体,同样的错误.
And I've attempted using "AWS": "arn:aws:iam::ACCOUNT-A-NUMBER-HERE:root"
as the principal, same error.
有帮助吗?
解决方案:如下面的Matt所述,该解决方案是您需要在Lambda角色策略中包含
s3:PutObject
权限 . 这对我来说有点奇怪,但是总体思路是 您在自己的存储桶策略中授予Lambda角色的权限 您还必须在Lambda策略中将目标存储分区复制到您的 源帐户.似乎完全采用了Lambda角色 当您在存储桶策略"中引用它时.为此,我添加了 我的Lambda角色的第二个内联策略,允许s3:PutObject
Account-B
下的backup-assets.myapp.com
存储桶.这不允许 Lambda函数可写入任何源存储桶,但 允许它写入备份存储桶.
A Solution: As outlined by Matt below, the solution is that you need to include
s3:PutObject
permission in the Lambda role policy. This is a little weird to me, but the general idea is that any permissions you grant the Lambda role in the Bucket Policy of your target bucket must also be replicated in the Lambda policy under your source account. It seems that the Lambda role is adopted entirely when you reference it in the Bucket Policy. To achieve this I've added a second inline policy to my Lambda role that allowss3:PutObject
to thebackup-assets.myapp.com
bucket underAccount-B
. This disallows the Lambda function to write to any of the source buckets, but does allow it to write to the backup bucket.
我看到两个可能的问题.
I see two possible problems.
- 您用于Lambda函数的IAM策略缺少写入到备份存储桶的权限.
- Your IAM policy for your Lambda function is missing permissions to write to your backup bucket.
尝试将s3:PutObject
添加到您的策略中,如下所示:
Try adding s3:PutObject
into your policy like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:ListBucketVersions",
"s3:GetObject",
"s3:GetObjectVersion",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::*"
]
}
]
}
或者,如果您想继续将Lambda函数限制为仅对源存储分区进行读取访问,则可以在Lambda角色中添加第二个策略,以使其s3:PutObject
在您的备份存储桶中,将您的备份存储桶命名为资源,如下所示:
Or, if you'd like to continue to restrict your Lambda function to read access only on your source bucket(s), you can add a second policy to your Lambda role allowing it to s3:PutObject
on your backup bucket, naming your backup bucket as the resource, like so:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::backup-assets.myapp.com",
"arn:aws:s3:::backup-assets.myapp.com/*"
]
}
]
}
- 有时,在您的IAM策略中使用IAM角色作为委托人并没有那么简单.我并不是说这是问题所在,但让我们放宽限制,直到您可以使用副本为止.然后,您可以收紧政策.
现在,只需让您的目标帐户访问源存储桶即可:
For now, just let your target account access to the source bucket:
{
"Version": "2008-10-17",
"Id": "Backup-Assets",
"Statement": [
{
"Sid": "Allow PUT from Account-A Lambda function",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT-A-NUMBER-HERE:root"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::backup-assets.myapp.com",
"arn:aws:s3:::backup-assets.myapp.com/*"
]
}
]
}
复制成功后,您可以尝试重新添加角色.
Once copying is working, you can try adding the role back.