Проблема использования модуля aws_s3 в Ansible при работе с S3 от Yandex.Cloud
Вводные
У Ansible есть модуль amazon.aws.s3_object
с помощью которого можно работать с S3 бакетом. Но при попытке попытке загрузить объект в S3 Yandex .Cloud возникают ошибки.
Цель – сделать это с ролью storage.uploader
, поскольку этой роли должно быть достаточно.
Но, добавив в Playbook такую задачу
- name: Copy file to s3 bucket amazon.aws.s3_object: mode: put validate_certs: yes bucket: "s3_bucket" endpoint_url: "s3_endpoint" aws_access_key: "s3_aws_access_key" aws_secret_key: "s3_aws_secret_key" object: "example-content-5" content: "example-content-5"
мы не получаем ожидаемого результата. Давайте по-порядку попробуем разобраться с этим.
При отладке шаг за шагом, я получал ошибки.
Шаг 1
Первая наша ошибка: x_amz-_server-_side-_encryption": "only aws: kms value allowed"
Для отладки я запускал Playbook используя флаг -vvv
, а также для отладки используем content
вместо src
. Так вывод немного информативнее. Благодаря этому я получил текст ошибки, и, кажется, тут всё просто, добавляем параметр:
encryption_mode: "aws:kms"
Прочесть об этом параметре можно тут: encryption_mode: "aws:kms"
Шаг 2
Следующая ошибка не такая очевидная: Unable to set object ACL: An error occurred (AccessDenied) when calling the PutObjectAcl operation: Access Denied
Как я понял, после создания объекта в Bucket, этот модуль Ansible пыается выполнить какие-то оперции с ACL. Это конечно можно решить быстро, выдав что-то типа storage.admin
сервисному аккаунту. Но нас это не устраивает.
Шаг 3
Может можно добавить storage.editor
или storage.configurer
? Это работает пока не поменяем content
на src
. После этого снова получим AccessDenied.
Всё это кажется несправедливым, посколько storage.uploader
должно быть достаточно, чтобы загрузить файл в S3. Например при использовании aws-cli
c теми же кредами SA, операция выполняется успешно.
Эмпирическим методом выяснил, чтобы прав storage.uploader
на загрузку с помощью этого модуля может быть достаточно, давайте еще немного поправим конфиг:
- name: Copy file to s3 bucket amazon.aws.s3_object: mode: put encrypt: false encryption_mode: "aws:kms" permission: [] validate_certs: yes bucket: "s3_bucket" endpoint_url: "s3_endpoint" aws_access_key: "s3_aws_access_key" aws_secret_key: "s3_aws_secret_key" object: "example-object-5" src: "/path/to/file"
Мы отключили encrypt
и явным образом передаем пустой массив permission
. Так вроде всё работает.
Но что делать если мы желаем использовать encrypt: true
? Тогда используйте роль storage.configurer
.
Если честно, я не понял всё это заранее, читая документацию, поэтому обратился в техподдержку Yandex.Cloud. Вероятно для тех, кто досконально знает принцип работы S3, ответ не покажется чем-то новым.
Ответ техподдержки Yandex.Cloud
Изучили ситуацию. Да, кажется что, если вы хотите загрузить объект в бакет с шифрованием, достаточно ролейstorage.uploader
(для загрузки объекта) иkms.keys.encrypter
(для доступа к ключу). Это может привести к ситуации, когда пользователь перезапишет уже существующий зашифрованный объект новым, используя другой ключ шифрования. В итоге пользователи изначального объекта не смогут прочитать его.
Поэтому для более гранулярной настройки доступа в этом месте нужна рольstorage.configurer
. Так как использование шифрования фактически влияет на конфигурацию бакета. Поэтому это ожидаемое поведение со стороны Object Storage.
В документации мы упоминаем рольstorage.editor
при использовании шифрования на стороне Object Storage. Она сочетает в себе возможностиstorage.uploader
иstorage.configurer
. Да, согласны, стоит упомянуть, что ролиstorage.uploader
при загрузке объектов с использованием шифрования не достаточно. Мы передадим информацию коллегам.
Я добавлю от себя, что storage.editor
может не подойти для использования на каком-нибудь сервере, откуда вы хотите что-то бэкапировать. Поскольку storage.editor
также имеет возможность конфигурировать бакет.