Политики трафика
Обзор
Функция позволяет описать правила и действия обработки трафика для входящих запросов и более гибко настроить взаимодействие с вашим приложением.
Функция находится на стадии отрытого BETA тестирования. Критические изменения могут произойти в любое время без предварительного уведомления, включая изменения в структуре документов политики, поведении политик и ценообразовании этой функции.
Доступно только по подписке в тарифе Команда.
Чтобы понять, зачем нужны политики и как они работают, разберём пример включения базовой авторизации только для префикса /admin
:
---
rules:
- name: Authorization for admin panel
expressions:
- req.URL.Path contains "/admin"
actions:
- name: Enable basic auth
type: basic_auth
config:
userList:
admin: password
Тут описано 1 правило(rules), в нём есть выражение(expressions), оно содержит условие в котором мы проверяем, что запрос предназначается для префикса /admin
, если условие истинно, наступает действие(actions), в примере мы применяем базовую авторизацию, задаём список из пар username
, password
. Если пользователь проходит авторизацию, то далее трафик направляется к вашему сервису. Это правило позволит вам открыть доступ к разрабатываемому сайту для всех, например для заказчиков или коллег, но при этом вы можете запретить доступ к приватным частям сайта. Это лишь один пример, нижу вы найдёте полное описание и больше живых примеров.
Чтобы вам было проще написать нужное правило мы добавили отладчик прямо в личном кабинете, там вы можете проверить корректно ли работает правило, а так же приведено несколько примеров:

Правила (rules)
Правила состоят из действий - actions
(обязательно), которые должны вступить в силу и выражений - expressions
(не обязательно), фильтрующ их трафик, к которому они применяются. Правила оцениваются и выполняются последовательно в порядке их описания, без прерывания их выполнения. Т.е. если запрос подпадает сразу под несколько правил, то все действия также будет применены к данному запросу. Также можно указать имя name
. Описание правил хранится в файле .tuna.yml
в текущем каталоге, в YAML формате. Путь к файлу можно переопределить с помощью флага --policy-file
или переменной окружения TUNA_POLICY_FILE
.
Например существует 2 правила. В первом мы включаем базовую авторизацию для всех запросов к префиксу /admin
.
Во втором проверяем есть ли заголовок Accept-Language
и присутствует ли в нём русский язык ru-RU
. Клиент сначала должен будет ввести username и password, а далее сработает запрет по заголовку Accept-Language
если в значении заголовка есть ru-RU
.
---
rules:
- expressions:
- req.URL.Path contains "/admin"
actions:
- type: basic_auth
config:
userList:
admin: admin
- expressions:
- any(req.Headers["Accept-Language"], {# matches "ru-RU"})
actions:
- type: deny
Выражения (expressions)
Сайт с описанием синтаксиса expr-lang
Выражения основаны на синтаксисе expr-lang. Это богатый язык с множеством функций, операциями сравнения, вхождения, работы с строками и многим другим. Перечисление выражений в списке воспринимается как логическое И (and
).
Пример блокировки POST
запросов от ботов:
---
rules:
- expressions:
- lower(req.UserAgent) matches "(chatgpt-user|gptbot)"
- req.Method in ["POST"]
actions:
- type: deny
Переменные с данными из запроса
Чтобы работать с входящим запросом есть несколько переменные для получения информации или метаданных:
Название | Описание |
---|---|
req.Proto | Содержит версию протокола HTTP, которая была использована при отправке запроса (например HTTP/1.1 или HTTP/2.0 ) |
req.Host | Содержит хост URL, включая порт, если он указан (алиас для req.URL.Host) |
req.Method | Содержит метод запроса GET / POST и другие |
req.URL | Полный URL запроса (имеет свои методы, которые описаны в таблице ниже) |
req.UserAgent | Содержимое заголовка User-Agent |
req.RemoteAddr | IP адрес клиента с которого пришёл запрос |
req.ContentLength | Возвращает длину тела запроса в байтах, если она известна, берётся из заголовка Content-Length . |
req.Headers | Список всех заголовков |
Переменные внутри req.URL позволяют получить отдельные части URL:
Название | Описание |
---|---|
req.URL.Scheme | Содержит схему URL, которая определяет протокол (например, http, https, ftp и т.д.). |
req.URL.Opaque | Содержит непрозрачные (закодированные) данные URL, которые не могут быть напрямую разобраны на части, такие как схема, хост и путь. |
req.URL.User | Содержит информацию о пользователе, содержащую имя пользователя и, возможно, пароль в URL. |
req.URL.Host | Содержит хост URL, включая порт, если он указан (например, example.com:8080 ). |
req.URL.Path | Содержит путь URL, который указывает на конкретный ресурс (например, /articles/2024/ ). |
req.URL.RawPath | Содержит закодированную версию пути (если она отличается), может быть полезен для случаев, когда путь содержит специальные символы. |
req.URL.RawQuery | Содержит закодированные параметры запроса без символа ? (например, name=John&age=30 ). |
req.URL.Fragment | Содержит фрагмент URL, который указывает на определенную часть документа, без символа # (например, section2 ). |
req.URL.RawFragment | Содержит закодированную версию фрагмента, если он содержит специальные символы (например, пробелы или символы Unicode). |
Метаданные запроса:
Название | Описание |
---|---|
meta.Time | Точное время в которое пришёл запрос, +- текущее время |
meta.RequestID | Индивидуальный идентификатор запроса |
Встроенные функции
Помимо достаточно богатого синтаксиса expr-lang, доступны также и встроенные функции для быстрой работы с данными.
Название | Описание | Пример |
---|---|---|
IpInRange | Проверяет входит ли IP в подсеть | IpInRange(req.RemoteAddr, "127.0.0.0/8") |
IsIPV6 | Проверяет является ли строка IPv6 адресом | IsIPV6(req.RemoteAddr) |
IsIPV4 | Проверяет является ли строка IPv6 адресом | IsIPV4(req.RemoteAddr) |
IsIP | Проверяет является ли строка IP адресом | IsIP(req.RemoteAddr) |
RandInt | Генерация случайного целого числа | RandInt(0, 10) |
RandDouble | Генерация случайного дробного числа в диапазоне от 0 до 1 | RandDouble() |
Примеры expressions
Проверяем, что запрос пришёл по https
:
- expressions:
- req.URL.Scheme == "https"
Запрос содержит префикс /admin
:
- expressions:
- req.URL.Path contains "/admin"
Запрос не из подсети 10.0.0.0/8
:
- expressions:
- not IpInRange(req.RemoteAddr, "10.0.0.0/8")
Действия (actions)
Выполнение действий зависит от того истинно ли условие в выражениях (expressions
), если выражение отсутствует, то действие выполняется всегда.
Действие должно содержать тип type
и конфигурацию config
(не всегда о бязательно). Также можно указать имя name
.
Типы действий (type)
Доступно несколько типов действий, одни модифицируют запрос, другие отвечают за самостоятельную обработку. Можно указывать несколько типов, они будут обработаны по порядку.
add_headers
Добавить заголовки.
Можно добавлять заголовки как при передаче их к вышестоящему приложению context: request
, так и при ответе клиенту context: response
.
Ключевое слово headers
определяет карту ключ=значение, где ключ - название заголовка, а значение - содержимое заголовка.
---
rules:
- actions:
- type: add_headers
config:
context: request
headers:
foo: bar
qwe: rty
- actions:
- type: add_headers
config:
context: response
headers:
foo: bar
qwe: rty
remove_headers
Удалить заголовки.
Можно удалять заголовки как при передаче их к вышестоящему приложению context: request
, так и при ответе клиенту context: response
.
Ключевое слово headers
определяет список заголовков.
---
rules:
- actions:
- type: remove_headers
config:
context: request
headers:
- foo
- qwe
- actions:
- type: remove_headers
config:
context: response
headers: ["foo", "qwe"]
basic_auth
Включить базовую авторизацию.
Ключевое слово userList
определяет карту ключ=значение, где ключ - username
, а значение - password
.
---
rules:
- actions:
- type: basic_auth
config:
userList:
admin: admin
foma: kiniaev
ащьф: лштшфум
url_rewrite
Перезаписать URI.
Ключевое слово from
определяет path с которого нужно перезаписать запрос к вышестоящему серверу, а to
определяет path который будет передан к к вышестоящему серверу. Также работают регулярные выражения.
---
rules:
- actions:
- type: url_rewrite
config:
from: /foo
to: /bar
redirect
Перенаправление URL.
Ключевое слово to
определяет Location на который перенаправлять, также можно переопределить statusCode
(по умолчанию 307).
Ключевое слово headers
определяет карту ключ=значение, где ключ - название заголовка, а значение - содержимое заголовка.
---
rules:
- actions:
- type: redirect
config:
to: /foobar
statusCode: 304
headers:
foo: bar
deny
Запретить обращение к вышестоящему приложению.
Можно переопределить statusCode
(по умолчанию 403).
---
rules:
- actions:
- type: deny
config:
statusCode: 451
restrict_ips
Ограничить обращения по подсетям.
Ключевое слово allow
определяет список подсетей с которых разрешены обращения.
Ключевое слово deny
определяет список подсетей с которых запрещены обращения.
---
rules:
- actions:
- type: restrict_ips
config:
allow:
- 127.0.0.1/32
deny:
- 10.0.0.10/32
rate_limit
Ограничить обращения по количеству запро сов.
Ключевое слово rate
определяет промежуток времени, а capacity
количество запросов которые можно совершить. При превышении этого порога, клиент начнёт получать 429 Too Many Requests
.
---
rules:
- actions:
- type: rate_limit
config:
rate: "60s"
capacity: 2
custom_response
Пользовательский ответ.
Обязательный параметр statusCode
определяет HTTP статус. Можно также передать тело, содержимое задаётся в параметре content
.
И заголовки, headers
определяет карту ключ=значение, где ключ - название заголовка, а значение - содержимое заголовка.
---
rules:
- actions:
- type: custom_response
config:
statusCode: 200
content: |
User-agent: *
Disallow: /
headers:
content-type: "text/plain"