Как использовать AWS Lambda для резервного копирования объекта S3 в корзину в другой учетной записи?

#amazon-web-services #amazon-s3 #lambda

#amazon-веб-сервисы #amazon-s3 #лямбда

Вопрос:

Я пытаюсь использовать AWS Lambda для резервного копирования объектов из assets.myapp.com корзины S3 под Account-A в backup-assets.myapp.com корзину S3 под Account-B , но я получаю, Access Denied независимо от того, IAM или Bucket Policy какую конфигурацию я использую.

У меня есть вызванная лямбда-функция Backup-S3-Object , и она запускается s3:PutObject триггером события в assets.myapp.com корзине.

Желаемый результат заключается в том, что Backup-S3-Object функция выполнит s3.copyObject to backup-assets.myapp.com с использованием AWS-SDK для Javascript.

Лямбда-код

 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 получить доступ к List или Get любому объекту из любой корзины в Account-A разделе, который является исходной учетной записью. Таким образом, эта политика позволит лямбда-функции получать объект из 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 , которая предназначена для того, чтобы разрешить функции Lambda, запущенной в Account-A разделе, выполнять запись в 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 , и она работает просто отлично. Итак, проблема, очевидно, в разрешениях для разных учетных записей, но ничего из того, что я пробовал, не работает.

Я также пытался использовать CanonicalID of Account-A в качестве Principal в backup-assets.myapp.com политике корзины, но все равно получаю Access Denied результирующую ошибку.

И я попытался использовать "AWS": "arn:aws:iam::ACCOUNT-A-NUMBER-HERE:root" в качестве основного ту же ошибку.

Есть помощь?

Решение: Как описано Мэттом ниже, решение заключается в том, что вам необходимо включить s3:PutObject разрешение в политику роли Lambda. Для меня это немного странно, но общая идея заключается в том, что любые разрешения, которые вы предоставляете роли Lambda в политике корзины вашего целевого корзины, также должны быть реплицированы в политике Lambda под вашей исходной учетной записью. Похоже, что роль Lambda принимается полностью, когда вы ссылаетесь на нее в Политике корзины. Чтобы достичь этого, я добавил вторую встроенную политику к моей роли Lambda, которая позволяет s3:PutObject использовать backup-assets.myapp.com корзину под Account-B . Это запрещает лямбда-функции выполнять запись в любой из исходных сегментов, но позволяет ей выполнять запись в резервный сегмент.

Ответ №1:

Я вижу две возможные проблемы.

  1. В вашей политике IAM для вашей функции Lambda отсутствуют разрешения на запись в вашу корзину резервного копирования.

Попробуйте добавить 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, позволяющую ей s3:PutObject работать в вашей корзине резервного копирования, называя вашу корзину резервного копирования ресурсом, например, так:

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

Как только копирование сработает, вы можете попробовать добавить роль обратно.

Комментарии:

1. Спасибо за ответ @Matt Houser, но я думаю, что вы перепутали политику. Backup-S3-Object Лямбда-роль имеет только разрешения List и Get на исходную корзину ( assets.myapp.com ), потому что ей просто нужно извлечь объект оттуда, не нужно ничего записывать в эту корзину. Затем я использую политику корзины на backup-assets.myapp.com , чтобы разрешить роли Lamba выполнять запись в корзину резервного копирования под Account-B . Я уже пробовал предоставить arn:aws:iam:ACCOUNT-A-NUMBER-HERE:root , но попробую еще раз. Но я думаю, что лямбда-функция не запускается под root , не уверен.

2. Да, та же проблема с root участником.

3. Ладно, это ошибка. Когда я добавляю s3:PutObject в политику роли Lambda, это работает. Но почему? Предполагается, что эта политика определяет разрешения, которые лямбда-функция имеет для исходной корзины, assets.myapp.com из которой требуется только чтение . Почему для копирования объекта в PUT корзину требуются backup-assets.myapp.com учетные данные в исходной корзине?

4. Это также работает, когда я переключаю участника обратно на Backup-S3-Object роль Lambda. Но меня действительно беспокоит, что я должен давать PutObject разрешение функции Lambda для моих исходных корзин. Все, что ему нужно сделать, это прочитать из них, а не записать, так почему?

5. @AJB это потому, что вы работаете с разными учетными записями. Для предоставления доступа внешней учетной записи недостаточно. Для доступа к ресурсу из внешней учетной записи также требуется разрешение от вашей локальной учетной записи. «Пока у пользователя есть разрешение как от владельца ресурса, так и от родительской учетной записи, пользователь сможет получить доступ к ресурсу». В данном случае локальное разрешение предоставляется ролью. Если все находится в одной учетной записи, это очевидное дублирование необязательно.