AWS: настройка S3 Cross-Region Replication и удаление файлов при репликации

Автор: | 17/07/2019

В данный момент мы настраиваем CDN для проекта.

В роли CDN-провайдера будут CloudFront и CloudFlare, для которых требуется создать две AWS S3 корзины с разными именами (cdn.cfr.example.com => CloudFront и cdn.cfl.example.com => CloudFlare).

Что бы не копировать данные в обе корзины дважды – можно настроить репликацию данных между двумя корзинами – это и будет AWS Simple Sorage Service Cross Region Replication, или AWS S3 CRR.

Документация – Cross-Region Replication.

Для работы CRR требуется:

  1. обе корзины должны иметь включенное версинирование (см. Using Versioning)
  2. корзины должны располагаться в разных регионах
  3. корзины должны иметь права на репликацию объектов между этими корзинами

Ограничения CRR:

  1. существующие файлы в исходной корзине не будут реплицированы, если они были добавлены до настройки репликации (т.е. только новые файлы будут скопированы в корзину-приёмник)
  2. нельзя использовать цепочку репликаций, т.е. из корзины А в корзину Б, а затем в корзину В

Настройка AWS S3 Cross-Region Replication

Создаём две корзины:

Для обеих корзин включаем версинирование:

В исходной корзине bttrm-crr-source переходим во вкладку Management > Replication, кликаем Add rule:

Указываем репликацию всего содержимого исходной корзины:

Жмём Next, и указываем имя корзины-получателя:

Далее – доступ.

Выбираем Create new IAM role, указываем её имя:

Сохраняем:

Проверка репликации

Загружаем тестовый файл в корзину bttrm-crr-source:

[simterm]

$ touch testfile.txt
$ aws --profile bm-backend --region us-east-2 s3 cp testfile.txt s3://bttrm-crr-source
upload: ./testfile.txt to s3://bttrm-crr-source/testfile.txt

[/simterm]

Проверяем его:

[simterm]

$ aws --profile bm-backend --region us-east-2 s3 ls s3://bttrm-crr-source
2019-07-15 15:36:38          0 testfile.txt

[/simterm]

И проверяем вторую корзину:

[simterm]

$ aws --profile bm-backend --region us-west-1 s3 ls s3://bttrm-crr-dest
2019-07-15 15:36:38          0 testfile.txt

[/simterm]

Файл на месте, всё работает.

Удаление файлов из S3 при Cross-Region Replication и DeleteMarkers

Если просто удалить файл из исходной корзины – он удалится в ней, но останется во второй корзине.

Удаляем в исходной корзине:

[simterm]

$ aws --profile bm-backend --region us-east-2 s3 rm s3://bttrm-crr-source/testfile.txt
delete: s3://bttrm-crr-source/testfile.txt

[/simterm]

Проверяем корзину-приёмник в Европе:

[simterm]

$ aws --profile bm-backend --region us-west-1 s3 ls s3://bttrm-crr-dest
2019-07-15 15:36:38          0 testfile.txt

[/simterm]

Файл на месте.

Для удаления файлов при использовании S3 Versioning – AWS добавляет специальную метку к файлу, т.н. DeleteMarker (см. Working with Delete Markers):

[simterm]

$ aws --profile bm-backend --region us-west-1 s3api list-object-versions --bucket bttrm-crr-source
{
    "Versions": [
        {
            "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
            "Size": 0,
            "StorageClass": "STANDARD",
            "Key": "testfile.txt",
            "VersionId": "Qc5.Z2XumG6uilJ99XcHJ1vIfzMFcx6C",
            "IsLatest": false,
            "LastModified": "2019-07-15T12:36:38.000Z",
            "Owner": {
                "DisplayName": "example.aws",
                "ID": "9365528c1a92cd01abba171eb7b95c352a330a40ceb28b420c9462fac5891bd2"
            }
        }
    ],
    "DeleteMarkers": [
        {
            "Owner": {
                "DisplayName": "example.aws",
                "ID": "9365528c1a92cd01abba171eb7b95c352a330a40ceb28b420c9462fac5891bd2"
            },
            "Key": "testfile.txt",
            "VersionId": "PIr6ZOPcdi9oFP8y0rMXkRhrFuKpDQ4P",
            "IsLatest": true,
            "LastModified": "2019-07-15T12:39:24.000Z"
        }
    ]
}

[/simterm]

При этом сама метка не реплицируется на вторую корзину, см. What Does Amazon S3 Replicate:

  • если вы выполняете DELETE запрос без указания ID версии объекта – AWS S3 добавляет т.н. “Delete Marker“:
    • при использовании последней версии конфигурации репликации, т.е. в ней задаётся елемент Filter – S3 не выполнит репликацию Delete Marker
    • если элемент Filter не задан – S3 будет считать, что используется версия 1, в которой маркеры удаления обрататываются иначе, см. Backward Compatibility
  • если вы выполняете DELETE запрос с указанием ID версии – S3 удалит его в исходной корзине, но не выполнит репликацию удаления во вторую корзину

Проверяем файл во второй корзине:

[simterm]

$ aws --profile bm-backend --region us-west-1 s3api list-object-versions --bucket bttrm-crr-dest
{
    "Versions": [
        {
            "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
            ...
            "Key": "testfile.txt",
            "VersionId": "Qc5.Z2XumG6uilJ99XcHJ1vIfzMFcx6C",
            ...
        }
    ]
}

[/simterm]

DeleteMarkers нет.

Проверяем статус репликации:

[simterm]

$ aws --profile bm-backend --region us-west-1 s3api get-bucket-replication --bucket bttrm-crr-source  --query 'ReplicationConfiguration.Rules[*].DeleteMarkerReplication' --output text
Disabled

[/simterm]

DeleteMarkerReplication"Status": "Disabled", окей.

IAM s3:ReplicateDelete

Сначала проверим IAM роль – есть ли разрешение на передачу маркеров (см. Setting Up Permissions for Cross-Region Replication).

Находим IAM роль корзины:

Саму роль:

Проверяем её – должно присутствовать правило "s3:ReplicateDelete" в Actions:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:Get*",
                "s3:ListBucket"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::bttrm-crr-source",
                "arn:aws:s3:::bttrm-crr-source/*"
            ]
        },
        {
            "Action": [
                "s3:ReplicateObject",
                "s3:ReplicateDelete",
                "s3:ReplicateTags",
                "s3:GetObjectVersionTagging"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:s3:::bttrm-crr-dest/*"
        }
    ]
}

Хорошо, дальше.

S3 Bucket Policy

Экспортируем имеющуюся политику корзины:

[simterm]

$ aws --profile bm-backend --region us-west-1 s3api get-bucket-replication --bucket bttrm-crr-source > bttrm-crr-source-origin.json

[/simterm]

Проверяем её:

{
    "ReplicationConfiguration": {
        "Role": "arn:aws:iam::534***385:role/service-role/s3crr_role_for_bttrm-crr-source_to_bttrm-crr-dest",
        "Rules": [
            {
                "ID": "bttrm-s3-crr-replica",
                "Priority": 1,
                "Filter": {},
                "Status": "Enabled",
                "Destination": {
                    "Bucket": "arn:aws:s3:::bttrm-crr-dest"
                },
                "DeleteMarkerReplication": {
                    "Status": "Disabled"
                }
            }
        ]
    }
}

Теперь удаляем ReplicationConfiguration, "Filter": {}, "Priority": 1,  DeleteMarkerReplication и добавляем "Prefix": "", по сути – приводим её к виду версии 1:

{
        "Role": "arn:aws:iam::534***385:role/service-role/s3crr_role_for_bttrm-crr-source_to_bttrm-crr-dest",
        "Rules": [
            {
                "ID": "bttrm-s3-crr-replica",
                "Prefix": "",
                "Status": "Enabled",
                "Destination": {
                    "Bucket": "arn:aws:s3:::bttrm-crr-dest"
                }
            }
        ]
}

Конфиг версии 2 на момент написание не умеет репликацию DeleteMarkers вообще, ответ от тех. поддержки AWS:

The internal team is working on bringing feature of Delete replication in V2 as well but it may take some time for that to happen. It is possible that the way V2 has been implemented in back-end is little different from V1 and using this feature directly may have been causing issues. Unfortunately, I don’t have any ETA on when this would finish. Till then, I’m sure your blog would be able to help AWS Users 🙂

Применяем новую политику к корзине:

[simterm]

$ aws --profile bm-backend --region us-west-1 s3api put-bucket-replication --bucket bttrm-crr-source --replication-configuration file://bttrm-crr-source.json

[/simterm]

Загружаем ещё один файл в корзину-исходник:

[simterm]

$ aws --profile bm-backend --region us-east-2 s3 cp test.file s3://bttrm-crr-source

[/simterm]

Удаляем его:

[simterm]

$ aws --profile bm-backend --region us-east-2 s3 rm s3://bttrm-crr-source/test.file

[/simterm]

Проверяем файлы в исходной корзине теперь:

[simterm]

$ aws --profile bm-backend --region us-west-1 s3api list-object-versions --bucket bttrm-crr-source
{
    "Versions": [
        {
            "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
            ...
            "Key": "test.file",
            "VersionId": "0mkfsrIRdkGCgL.zKgMyMXjo_UydigIt",
            ...
        },
        {
            "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
            ...
            "Key": "testfile.txt",
            "VersionId": "Qc5.Z2XumG6uilJ99XcHJ1vIfzMFcx6C",
            ...
        }
    ],
    "DeleteMarkers": [
        {
            ...
            "Key": "test.file",
            "VersionId": "1kpKJlgOM7xpFnH4qsEp0EzqhCE1HFMX",
            ...
        },
        {
            ...
            "Key": "testfile.txt",
            "VersionId": "PIr6ZOPcdi9oFP8y0rMXkRhrFuKpDQ4P",
            ...
        }
    ]
}

[/simterm]

Отлично – оба файла есть, у обоих есть DeleteMarkers – тут всё хорошо.

Проверяем вторую корзину:

[simterm]

$ aws --profile bm-backend --region us-west-1 s3api list-object-versions --bucket bttrm-crr-dest
{
    "Versions": [
        {
            "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
            ...
            "Key": "test.file",
            "VersionId": "0mkfsrIRdkGCgL.zKgMyMXjo_UydigIt",
            ...
        },
        {
            "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
            ...
            "Key": "testfile.txt",
            "VersionId": "Qc5.Z2XumG6uilJ99XcHJ1vIfzMFcx6C",
            ...
        }
    ],
    "DeleteMarkers": [
        {
            ...
            "Key": "test.file",
            "VersionId": "1kpKJlgOM7xpFnH4qsEp0EzqhCE1HFMX",
            ...
        }
    ]
}

[/simterm]

В ней для первого файла testfile.txt DeleteMarker так и не появился – всё правильно, т.к. мы его удалили до внесения изменений.

А вот для второго, test.fileDeleteMarker есть, и он теперь тоже “удалён”:

[simterm]

$ aws --paws --profile bm-backend --region us-west-1 s3 ls s3://bttrm-crr-dest
2019-07-15 15:36:38          0 testfile.txt

[/simterm]

Файла test.file нет.

Готово.