Кэширование объектов S3-хранилищ
Услуга - CDN для бакетов
CDN для бакетов решает следующие проблемы:
- снижение стоимости пользования услугами S3-провайдера, за счет уменьшения количества обращений к оригинальным объектам в хранилище
- увеличение скорости загрузки объектов
Подключение
Для включения CDN для объектов бакета потребуются данные S3-провайдера:
- тип провайдера (AWS, Google, и т.д.)
- базовый url S3-провайдера, например
https://s3.eu-central-1.amazonaws.com/ - имя бакета, например
bucket-1
Перед подключением ознакомьтесь с настройками Вашего провайдера.
Пример 1. Оригинальный бакет размещен по адресу https://example-bucket1.s3.us-west-2.amazonaws.com/:
- домен провайдера (
provider_host):s3.us-west-2.amazonaws.com - протокол провайдера:
https - порт провайдера:
443 - имя бакета:
example-bucket1
Пример 2. Оригинальный бакет размещен по адресу http://storage.googleapis.com/example-bucket2/:
- домен провайдера (
provider_host):storage.googleapis.com - протокол провайдера:
http - порт провайдера:
80 - имя бакета:
example-bucket2
S3 провайдеры
Arviol поддерживает кэширование объектов ряда основных S3 провайдеров (s3_provider):
- aws (https://aws.amazon.com/ru/s3/)
- google (https://cloud.google.com/storage/)
- cloudflare (https://developers.cloudflare.com/r2/)
- yandex (https://yandex.cloud/ru/services/storage)
- прочие (полный список доступен при обращении к специальному методу API)
При необходимости добавления нового провайдера обратитесь в службу поддержки.
S3 ресурсы
Базовым объектом для подключения CDN для объектов S3-хранилищ является s3_resource.
S3 ресурс является основой для бакетов, добавляемых клиентом далее. Он необходим для настройки взаимодействия между оригинальными бакетами клиента и бакетами, создаваемыми в системе.
S3 бакеты
После создания ресурса появляется возможность создавать бакеты, указывая конкретный ресурс. На каждый ресурс можно добавить не более 20 бакетов.
Каждому бакету можно добавить до 20 HTTP-заголовков, управляющих поведением CDN.
headers — заголовки ответа, которые CDN возвращает конечному пользователю при выдаче объектов бакета. С их помощью можно задать политику кэширования (Cache-Control), включить дополнительные меры безопасности (Strict-Transport-Security, X-Content-Type-Options) или передать диагностические метки.
request_headers — заголовки, которые CDN проксирует на origin при запросе оригинального объекта. Они помогают передавать дополнительные признаки маршрутизации, идентификаторы A/B-тестов или другие служебные данные, необходимые backend-системам клиента.
CORS заголовки (cors_headers) настраиваются отдельно. Имена и количество CORS-заголовков предопределены. Подробнее про CORS.
Управление кэшем
Для каждого бакета доступны методы очистки кэша. Данные методы используются при фактической замене существующих объектов хранилища без изменения пути к ним. При очистке кэша объекты удаляются с кэширующих серверов и наполняются при последующих первых запросах от пользователей бакета. Возможна частичная очистка кеша только для объектов, ключи которых соответствуют указанным паттернам. Очистку кэша допускается вызывать не чаще, чем один раз в 30 минут.
Ограничение доступа
Для S3 бакетов и ресурсов доступна функция ограничения доступа из определенных стран.
Подписанные ссылки
Подписанные ссылки — это временные уникальные ссылки, позволяющие получить доступ к объектам в S3 бакете без прямого публичного доступа. Они защищают контент и позволяют выдавать ограниченный по времени доступ к скачиванию или загрузке объектов.
Для генерации подписанной ссылки используется секретный ключ, который должен храниться как в системе Arviol, так и у клиента в защищённом месте. Клиент генерирует подписанные ссылки самостоятельно. Ниже приведен код функции для генерации подписанных ссылок на Python 3.
import binascii
import hashlib
import hmac
import time
from urllib.parse import urlparse
def sign_url(url: str,
secret_key: str,
acl: str = "*",
lifetime: int = 31_536_000,
) -> str:
"""
Generate a signed URL with an expiration token for access control
Args:
url (str): URL to be signed
secret_key (str): Secret key for signing (UTF-8 string)
acl (str): Access control list, defaults to "*" (all paths)
lifetime (int): Token lifetime in seconds, defaults to 1 year
Returns:
str: Signed URL with token appended as query parameter
Example usage:
>>> sign_url(
... url="https://example.com/private/example.jpg",
... secret_key="secret",
... acl="/private/*",
... lifetime=60 * 60 * 7,
... )
'https://example.com/private/example.jpg?token=exp=1759879396~acl=/private/*~hmac=4fdb5e8bd60bbdeca1ddbeb93677de595a02d424e8211a3c0fb17e3735950db4'
"""
exp = int(time.time() + lifetime)
token_params = f"exp={exp}~acl={acl}"
key_hex = secret_key.encode("utf-8").hex()
token_hmac = hmac.new(
key=binascii.a2b_hex(key_hex.encode()),
msg=token_params.encode(),
digestmod=hashlib.sha256,
)
token_digest = token_hmac.hexdigest()
token = f"{token_params}~hmac={token_digest}"
if urlparse(url).query:
return f"{url}&token={token}"
return f"{url}?token={token}"
Параметр lifetime - срок действия ссылки в секундах. Параметр acl - шаблон пути к ресурсам, на которые распространяется действие ссылки, относительно базового URL сайта. Примеры acl:
*- все файлы (используется по умолчанию)/media/private_*- все файлы в папкеmediaс префиксомprivate_/media/*- только файлы в папкеmediaи вложенных папках/media/example.mp4- только файлexample.mp4в папкеmedia
acl для S3 бакета должен содержать имя бакета. Например, для ограничения доступа к бакету https://s403.s3-clients.cdn.itglobal.com/my-bucket значение acl будет /my-bucket/*
Если клиент подозревает, что ключ скомпрометирован, он может сменить ключ. В этом случае все ранее выданные подписанные ссылки перестанут работать, обеспечивая безопасность доступа.
Иерархия объектов
Итоговая иерархия объектов управления кэшированием статики веб-сайтов:
{
"s3_resource": {
"provider": "aws",
"buckets": [
{
"headers": [
{
"key": "value"
}
],
"request_headers": [
{
"key": "X-Origin-Feature",
"value": "image-optimizer"
}
],
"cors_headers": {
"access_control_allow_origin": [
"*"
],
"access_control_expose_headers": [
"*"
],
"access_control_max_age": 600,
"access_control_allow_credentials": true,
"access_control_allow_methods": [
"DELETE"
],
"access_control_allow_headers": [
"*"
]
}
}
],
"other_params": []
}
}