【问题标题】:How to use AWS Lambda to backup an S3 object to a bucket on another account?如何使用 AWS Lambda 将 S3 对象备份到另一个账户的存储桶中?
【发布时间】:2016-10-22 02:26:05
【问题描述】:

我正在尝试使用 AWS Lambda 将对象从Account-A 下的assets.myapp.com S3 存储桶备份到Account-B 下的backup-assets.myapp.com S3 存储桶,但无论@987654326 是什么,我都会得到Access Denied @ 或 Bucket Policy 我使用的配置。

我有一个名为 Backup-S3-Object 的 Lambda 函数,它由 assets.myapp.com 存储桶上的 s3:PutObject 事件触发器触发。

期望的结果是 Backup-S3-Object 函数将使用适用于 Javascript 的 AWS-SDK 执行 s3.copyObjectbackup-assets.myapp.com

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 政策

我为分配给我的 Lambda 函数的 Backup-S3-Lambda-Role 制定了以下策略。这允许 Lambda 函数访问ListGet 来自任何存储桶的任何对象,位于Account-A 下,这是源账户。因此,此策略将允许 Lambda 函数从 assets.myapp.com 获取对象,即源存储桶。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:ListBucketVersions",
                "s3:GetObject",
                "s3:GetObjectVersion"
            ],
            "Resource": [
                "arn:aws:s3:::*"
            ]
        }
    ]
}

backup-assets.myapp.com 存储桶政策

然后,在Account-B 下,我将以下存储桶策略附加到backup-assets.myapp.com,其目的是允许在Account-A 下运行的Lambda 函数写入到backup-assets.myapp.com 下的存储桶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 失败。

我已经使用相同的设置完成了一项测试,并将其转移到另一个也在 Account-A 下的存储桶,它工作得很好。所以问题显然出在跨账户权限上,但我尝试过的都没有。

我还尝试在backup-assets.myapp.com 存储桶策略中使用Account-ACanonicalID 作为Principal,但仍然得到Access Denied 作为结果错误。

我尝试使用"AWS": "arn:aws:iam::ACCOUNT-A-NUMBER-HERE:root" 作为主体,同样的错误。

有什么帮助吗?

解决方案:如下面的 Matt 所述,解决方案是您需要在 Lambda 角色策略中包含s3:PutObject 权限。 这对我来说有点奇怪,但总体思路是,任何 您在您的存储桶策略中授予 Lambda 角色的权限 目标存储桶也必须在您的 Lambda 策略中复制 源账户。似乎 Lambda 角色已完全采用 当您在存储桶策略中引用它时。为了实现这一点,我添加了 我的 Lambda 角色的第二个内联策略,允许 s3:PutObject backup-assets.myapp.comAccount-B 下的存储桶。这不允许 Lambda 函数写入任何源存储桶,但确实 允许它写入备份存储桶。

【问题讨论】:

    标签: amazon-web-services amazon-s3 lambda


    【解决方案1】:

    我看到两个可能的问题。

    1. 您的 Lambda 函数的 IAM 策略缺少对备份存储桶写入的权限。

    尝试将s3:PutObject 添加到您的策略中,如下所示:

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "s3:ListBucket",
                    "s3:ListBucketVersions",
                    "s3:GetObject",
                    "s3:GetObjectVersion",
                    "s3:PutObject"
                ],
                "Resource": [
                    "arn:aws:s3:::*"
                ]
            }
        ]
    }
    

    或者,如果您想继续将您的 Lambda 函数限制为仅对您的源存储桶进行读取访问,您可以向您的 Lambda 角色添加第二个策略,使其能够@ 987654324@ 在您的备份桶上,将您的备份桶命名为资源,如下所示:

    {
        "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/*"
                ]
            }
        ]
    }
    
    1. 有时,在您的 IAM 策略中使用 IAM 角色作为委托人并不像您那样简单。我并不是说这是问题所在,但让我们放宽限制,直到您的副本正常工作。然后你可以收紧政策。

    现在,只需让您的目标帐户访问源存储桶:

    {
        "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/*"
                ]
            }
        ]
    }
    

    复制成功后,您可以尝试重新添加角色。

    【讨论】:

    • 感谢@Matt Houser 的回答,但我认为你把政策搞混了。 Backup-S3-Object Lambda 角色仅对源存储桶 (assets.myapp.com) 具有 ListGet 权限,因为它只需要从那里获取对象,不需要向该存储桶写入任何内容。然后我使用backup-assets.myapp.com 上的存储桶策略允许Lamba 角色写入Account-B 下的备份存储桶。我已经尝试过授予arn:aws:iam:ACCOUNT-A-NUMBER-HERE:root,但我会再试一次。但我认为 Lambda 函数在 root 下不会触发,不确定。
    • 是的,使用 root 主体时同样的问题。
    • 好吧,这搞砸了。当我将s3:PutObject 添加到 Lambda 角色策略时,它可以工作。但为什么?该策略应该规定 Lambda 函数对源存储桶 assets.myapp.com 的权限,只需要从中读取。为什么需要源存储桶上的PUT 凭据才能将对象复制到backup-assets.myapp.com 存储桶?
    • 当我将主体切换回Backup-S3-Object Lambda 角色时,这也有效。但是,我必须向我的源存储桶的 Lambda 函数授予 PutObject 权限,这让我很烦恼。它所要做的就是从它们那里读取,而不是写入,那为什么呢?
    • @AJB 这是因为您正在跨账户操作。外国帐户授予访问权限是不够的。您还需要本地帐户的许可才能访问外国帐户中的资源。 "As long as the user has permission from both the resource owner and the parent account, the user will be able to access the resource." 本地权限由角色授予,本例中。如果一切都在一个帐户中,那么这种明显的重复就没有必要了。
    猜你喜欢
    • 2019-01-15
    • 2019-06-28
    • 2019-10-25
    • 2017-07-21
    • 1970-01-01
    • 1970-01-01
    • 2020-07-05
    • 2020-01-03
    • 2020-09-15
    相关资源
    最近更新 更多