Аутентификация и авторизация
Авторизация в TQE(MQ) работает на двух уровнях:
- Уровень gRPC — собственный механизм TQE: аутентификация клиента и проверка его прав на очереди.
- Уровень ядра (Tarantool) — штатные механизмы Tarantool: контроль прав сервисного аккаунта, под которым gRPC-сервер обращается к ядру по IPROTO.
Также см. пример конфигурации для работы на сервере с включенной авторизацией.
При каждом вызове gRPC API проверяются учетные данные клиента. Учетные данные хранятся в трех сущностях:
user— учетная запись клиента gRPC API.secret— данные о пароле пользователя, которые хранятся отдельно, в виде bcrypt-хэша.role— набор прав (tqe.produce,tqe.consume,tqe.admin).
Совокупность этих сущностей определяет прохождение базовой аутентификации и авторизацию (RBAC) клиента на сервере.
Клиент передает логин и пароль в gRPC-метаданных authorization: Basic base64(login:password) по обязательному
протоколу шифрования TLS.
Пароль передается внутри TLS-канала в Base64 кодировке, и никогда не хранится в открытом виде: в хранилище лежит только bcrypt-хэш. Успешная проверка пароля кэшируется на
короткое время, чтобы не повторять bcrypt при каждом запросе. После серии неудачных попыток секрет временно
блокируется (защита от подбора).
В TQE (MQ) привилегии выдаются на отдельные очереди сообщений и на шаблоны имен очередей (queue_patterns). Шаблон имени
очереди является частью имени очереди с маской с *, например billing.*. Операция с очередью разрешается,
если шаблон, на который назначена роль, совпадает с очередью, а роль содержит нужную привилегию.
Встроенные роли и их привилегии:
Роль | Привилегии | Назначение |
|---|---|---|
Admin | tqe.admin | Управление сущностями user, secret, и role (все методы Iam) |
Producer | tqe.produce | Публикация в очередь ( Produce, ProduceStream, Broadcast) |
Consumer | tqe.consume | Подписка и коммит курсора в пределах того же потока, чтение через consumer-group ( Subscribe, ConsumeGroup) |
Матрица прав по gRPC-методам:
RPC | Producer | Consumer |
|---|---|---|
Produce / ProduceStream / Broadcast | ✓ | — |
Subscribe / ConsumeGroup | — | ✓ |
Конфигурация аутентификации задается в разделе auth. Параметры раздела:
enabled- включает аутентификацию и авторизацию gRPC API. Значение по умолчанию:false. Приtrueтребуетсяgrpc_options.tls.enabled: true, иначе сервер не запускается.permission_cache_ttl- время жизни снимка прав поuser_id. Значение0разворачивает снимок на каждую проверку. Значение по умолчанию:1s.credentials_cache_ttl- время жизни кэша проверенных учетных данных. Позволяет не выполнятьbcryptна каждый запрос. Значение по умолчанию:30s.store_poll_interval- период фонового опроса хранилища данных аутентификации с указанием единиц измерения. Задает задержку отзыва прав и блокировок. Значение по умолчанию:10s.store_stale_ttl- период, в течение которого авторизационные данные считаются корректными, в случае недоступности их внешнего хранилища. Задается с указанием единиц измерения. Значение по умолчанию:5m. В случае его истечения, все вызовы возвращаютUnavailable. Должен превышатьstore_poll_interval.integrity- раздел проверки подписи сущностей (RSA-PSS).check- включает или выключает проверку подписи. Принимает значения:true- отклонять значение с несовпавшей подписью.false- возвращать значение. Используется по умолчанию.
private_key_file- путь к ключу подписи (RSA-2048, PKCS#1, PEM). Пустое значение - встроенный ключ по умолчанию (для разработки).
password_policy- раздел требований к паролям и блокировки после неудачных попыток.min_length- минимальная длина пароля. Сложность по классам символов не требуется. Значение по умолчанию:16.lockout_threshold- число неудачных попыток до временной блокировки секрета. Значение по умолчанию:10.lockout_duration- длительность временной блокировки, задается с указанием единиц измерения. Значение0выключает блокировку. Значение по умолчанию:1m.max_age- срок действия пароля. Значение0выключает принудительную смену; значение больше0включает смену по сроку.history_depth- количество прежних хэшей пароля, которые хранятся для запрета повторного использования. Значение по умолчанию:0. При таком значении история прошлых паролей не ведется и ничего не сверяется — задать можно любой пароль, включая действующий.
Пример настройки:
grpc_options:tls:enabled: true # Всегда true при auth.enabled: true.cert_file: /etc/tqe/grpc.crtkey_file: /etc/tqe/grpc.keyauth:enabled: truepermission_cache_ttl: 1scredentials_cache_ttl: 30sstore_poll_interval: 10sstore_stale_ttl: 5mintegrity:check: trueprivate_key_file: /etc/tqe/auth-sign.pempassword_policy:min_length: 16lockout_threshold: 10lockout_duration: 1mmax_age: 0history_depth: 0
При включенной аутентификации/авторизации ни один gRPC-вызов, включая методы сервиса tarantool.queue_ee.Iam не выполнится,
пока в хранилище нет хотя бы одного пользователя. Если в конфигурации указан блок auth.bootstrap, первый пользователь
(с привилегиями администратора) создается сервером при старте. Параметры раздела:
login- логин пользователя.password- пароль в открытом виде. Используется только для разработки.password_env- имя переменной окружения с паролем. Рекомендуемый вариант: пароль не хранится в конфигурации. Пустой пароль недопустим.
Опции password и password_env являются взаимоисключающими, и не могут использоваться одновременно.
auth:bootstrap:login: adminpassword_env: TQE_BOOTSTRAP_ADMIN_PASSWORD # или (не рекомендуется) password: "..."# queue_patterns: ["*"] # по умолчанию ["*"] — все очереди
Порядок начальной загрузки (при auth.enabled: true):
- При старте сервер загружает кэш из хранилища.
- Если в хранилище нет ни одного пользователя и задан блок
auth.bootstrap, сервер создает первого администратора: пользователя с именемauth.bootstrap.login, парольный секрет (bcrypt-хэш пароля изpasswordилиpassword_env) и назначение встроенной ролиAdminна шаблоныauth.bootstrap.queue_patterns. - Если пользователи в хранилище уже есть, начальная загрузка пропускается. Операция идемпотентна.
- Если хранилище пусто и блок
auth.bootstrapне задан, сервер запускается с предупреждением — все gRPC-вызовы будут возвращать ошибкуUnauthenticated: authentication failed.
Сущности учетных данных управляются сервисом tarantool.queue_ee.Iam (см.
описание Iam API). Для вызова его методов нужно право tqe.admin.
Пример настройки доступа через grpcurl. Логин и пароль администратора заданы в auth.bootstrap:
export TQE_ADDR=mq.example:8443export CACERT=/etc/tqe/ca.crtexport ADMIN_B64=$(printf '%s' "admin:${TQE_BOOTSTRAP_ADMIN_PASSWORD}" | base64 | tr -d '\n')export AUTH="authorization: Basic ${ADMIN_B64}"# Создать сервисного пользователя и задать ему пароль:grpcurl -cacert "$CACERT" -H "$AUTH" -d '{"name": "orders-svc", "description": "orders service producer/consumer"}' \"$TQE_ADDR" tarantool.queue_ee.Iam/CreateUsergrpcurl -cacert "$CACERT" -H "$AUTH" -d '{"name": "orders-svc", "password": "S3rv1ce-Pa55!"}' \"$TQE_ADDR" tarantool.queue_ee.Iam/SetPassword# Назначить роли на шаблоны очередей:grpcurl -cacert "$CACERT" -H "$AUTH" -d '{"name": "orders-svc", "role": "Producer", "queuePatterns": ["orders.*"]}' \"$TQE_ADDR" tarantool.queue_ee.Iam/GrantRolegrpcurl -cacert "$CACERT" -H "$AUTH" -d '{"name": "orders-svc", "role": "Consumer", "queuePatterns": ["orders.replies"]}' \"$TQE_ADDR" tarantool.queue_ee.Iam/GrantRole# Создать пользовательскую роль и назначить её:grpcurl -cacert "$CACERT" -H "$AUTH" -d '{"name": "billing-writer", "description": "publish to billing queues", "permissions": ["tqe.produce"]}' \"$TQE_ADDR" tarantool.queue_ee.Iam/CreateRolegrpcurl -cacert "$CACERT" -H "$AUTH" -d '{"name": "billing-svc", "role": "billing-writer", "queuePatterns": ["billing.*", "audit.invoices"]}' \"$TQE_ADDR" tarantool.queue_ee.Iam/GrantRole# Посмотреть и обновить пользователя:grpcurl -cacert "$CACERT" -H "$AUTH" -d '{"name": "orders-svc"}' \"$TQE_ADDR" tarantool.queue_ee.Iam/GetUsergrpcurl -cacert "$CACERT" -H "$AUTH" -d '{"name": "orders-svc", "description": "updated description"}' \"$TQE_ADDR" tarantool.queue_ee.Iam/UpdateUser# Сузить или снять роль:grpcurl -cacert "$CACERT" -H "$AUTH" -d '{"name": "billing-svc", "role": "billing-writer", "queuePatterns": ["audit.invoices"]}' \"$TQE_ADDR" tarantool.queue_ee.Iam/RevokeRolegrpcurl -cacert "$CACERT" -H "$AUTH" -d '{"name": "orders-svc", "role": "Consumer"}' \"$TQE_ADDR" tarantool.queue_ee.Iam/RevokeRole# Посмотреть роли (встроенные и пользовательские):grpcurl -cacert "$CACERT" -H "$AUTH" "$TQE_ADDR" tarantool.queue_ee.Iam/ListRolesgrpcurl -cacert "$CACERT" -H "$AUTH" -d '{"name": "billing-writer"}' \"$TQE_ADDR" tarantool.queue_ee.Iam/GetRole# Удалить пользовательскую роль и пользователя:grpcurl -cacert "$CACERT" -H "$AUTH" -d '{"name": "billing-writer"}' \"$TQE_ADDR" tarantool.queue_ee.Iam/DeleteRolegrpcurl -cacert "$CACERT" -H "$AUTH" -d '{"name": "orders-svc"}' \"$TQE_ADDR" tarantool.queue_ee.Iam/DeleteUser
Примеры отказов:
# Нет учетных данных:grpcurl -cacert "$CACERT" "$TQE_ADDR" tarantool.queue_ee.Iam/ListUsers# ERROR: Code: Unauthenticated# Действительный пользователь, но без tqe.admin:grpcurl -cacert "$CACERT" -H "authorization: Basic $(printf '%s' 'orders-svc:S3rv1ce-Pa55!' | base64 | tr -d '\n')" \"$TQE_ADDR" tarantool.queue_ee.Iam/ListUsers# ERROR: Code: PermissionDenied# Правка встроенной роли:grpcurl -cacert "$CACERT" -H "$AUTH" -d '{"name": "Admin", "permissions": []}' \"$TQE_ADDR" tarantool.queue_ee.Iam/UpdateRole# ERROR: Code: FailedPrecondition Message: builtin role is immutable
Каждый вызов записывается в журнал вместе с решением. В запись добавляются поля:
method— имя gRPC-метода.auth_method— способ аутентификации (basic).user— имя аутентифицированного пользователя (если известен).queue— имя очереди, к которой относится вызов (если метод привязан к очереди).perm— требуемое право.decision—allowлибоdeny:<причина>.
Разрешенный вызов записывается на уровне debug, отклоненный — на уровне warn. Причины отказа (deny:<причина>):
no_creds, auth_failed, no_grant, unknown_method, no_queue, store_unavailable, no_active_subscription.
На уровне ядра TQE(MQ) использует штатные механизмы Tarantool: пользователи, роли и привилегии объявляются в секции
credentials файла config.yml. Привилегии проверяет сам Tarantool.
Есть два вида учетных записей:
- Прикладные («Пользователи TQE») — публикатор и потребитель, через которых внешние приложения публикуют и читают сообщения.
- Служебные — внутренние пользователи Tarantool (
storage,replicator), обеспечивающие шардирование, репликацию и работу оркестратора. Доступа к данным очередей они не дают.
Привилегии выдаются на двух уровнях:
- Роли дают право вызывать функции (
executeнаlua_call). - Привилегии на спейсы очередей дают доступ к данным:
writeнаqueue_<name>— право публиковать,read— право читать. Публикация сdeduplication_keyтребует обоих прав (readиwrite).
Учетная запись | Роль | Привилегии на спейсы очередей |
|---|---|---|
публикатор | tqe_producer | read и write на каждый queue_<name> (публикация) |
потребитель | tqe_consumer | read на каждый queue_<name> (чтение) |
Одна учетная запись может совмещать публикацию и чтение — тогда ей выдаются обе роли (tqe_producer и tqe_consumer),
а на нужных очередях — обе привилегии read и write. Имена учетных записей произвольны (в примерах ниже —
tqe_producer_user и tqe_consumer_user).
storage— пользовательvshardдля маршрутизации между роутером и хранилищами. Использует встроенную рольshardingи указывается в блокеiproto.advertise.sharding. Нужен в любой шардированной конфигурации.replicator— пользователь для WAL-репликации между мастером и репликами; в конфигурации с оркестратором используется также для его внутренних (connpool) вызовов. Использует встроенную рольreplicationи указывается в блокеiproto.advertise.peer. Нужен при наличии реплик в наборе реплик или экземпляра с рольюroles.tqe-orchestrator.admin— встроенный пользователь со всеми административными привилегиями, доступен только через локальный UNIX-сокет экземпляра. Отдельной записью вcredentials.usersобъявляются пользователи для соединения по IPROTO для выполнения административных задач.
Роли tqe_producer и tqe_consumer дают право выполнять операции только своего типа — публикацию или чтение.
Привилегий на конкретные очереди в ролях нет: привязку к очередям задает администратор отдельно, на самой учетной
записи (credentials.users.<user>.privileges).
Служебные учетные записи получают следующие дополнительные привилегии execute (сверх встроенных ролей):
-
replicator(рольreplication):- vshard.router.buckets_info- router.is_vshard_bootstrapped- router.get_buckets- router.get_advertised_shards- storage.acquire_state- storage.delete_state
Пример конфигурации ядра с consumer-группами и минимальными привилегиями (боевой стенд):
security:disable_guest: truecredentials:roles:# Привилегии на функции выдаются явно через роли; привилегии на очереди — на учетках.tqe_producer:privileges:- permissions: [execute]lua_call:- router.is_vshard_bootstrapped- router.get_sharding_mode- router.get_buckets- router.get_shards- vshard.storage.buckets_discovery- storage.producetqe_consumer:privileges:- permissions: [execute]lua_call:- router.is_vshard_bootstrapped- router.get_sharding_mode- router.get_buckets- router.get_shards- vshard.storage.buckets_discovery- storage.create_poller- storage.poll_from- storage.delete_poller- storage.acquire_state- storage.commit_state- storage.release_state- storage.delete_state- storage.touch_state- orchestrator.partition_map- orchestrator.group_join- orchestrator.group_sync- orchestrator.group_exitusers:# admin — встроенная учетная запись Tarantool, отдельной записью не объявляется.# Служебная запись репликации и connpool-вызовов оркестратора.replicator:password: "<replicator-secret>"roles: [replication]privileges:- permissions: [execute]lua_call:- vshard.router.buckets_info- router.is_vshard_bootstrapped- router.get_buckets- router.get_advertised_shards- storage.acquire_state- storage.delete_state# Служебная запись vshard (роутер <-> хранилище).storage:password: "<storage-secret>"roles: [sharding]privileges:- permissions: [execute]lua_call:- storage.get_advertise_uri# Прикладные учетные записи; привилегии на конкретные очереди задаются здесь.# producer.tarantool.user / consumer.tarantool.user в config.service.yml.tqe_producer_user:password: "<producer-secret>"roles: [tqe_producer]privileges:# write — публикация; read добавляется при использовании deduplication_key.- permissions: [write]spaces: [queue_orders, queue_events]tqe_consumer_user:password: "<consumer-secret>"roles: [tqe_consumer]privileges:- permissions: [read]spaces: [queue_orders, queue_events]iproto:advertise:peer:login: replicatorpassword: "<replicator-secret>"sharding:login: storagepassword: "<storage-secret>"
- Выдавайте доступ к очередям по принципу минимальных привилегий: каждой прикладной учетной записи — только
write/readна те очереди, с которыми она действительно работает. - Для каждой новой очереди добавляйте отдельную привилегию.
- Не используйте роли
universeиsuperдля прикладных учетных записей в рабочих (production) окружениях. - Выставляйте
security.disable_guest: true. - Не храните пароли в открытом виде. Используйте
config.context(from: envилиfrom: file), а вcredentialsподставляйте ссылку вида{{ context.<имя> }}. - Осуществляйте доступ под
adminтолько через локальный UNIX-сокет экземпляра. - Не меняйте состав встроенных ролей служебных пользователей (для
replicatorдопустима только рольreplication, дляstorage— толькоsharding). - Регулярно меняйте пароли служебных записей.
- Проверяйте фактический набор привилегий на каждой реплике через
box.schema.user.info(<name>).
Если Tarantool отказывает в доступе, ядро возвращает ошибку с кодом box.error.ACCESS_DENIED (например,
Write access to space 'queue_orders' is denied for user '...'). gRPC-сервер возвращает статус PermissionDenied для
методов Produce, Broadcast, ProduceStream, Subscribe и ConsumeGroup.
В примере ниже представлена конфигурация модуля API с включенной аутентификацией и авторизацией gRPC:
## Модуль API с включенной аутентификацией и авторизацией gRPC.#### Три условия, без которых сервер не стартует:## 1. auth.enabled: true требует grpc_options.tls.enabled: true## (Basic-учетные данные не выпускаются в незашифрованный канал);## 2. auth.enabled: true требует источник конфигурации кластера —## config.etcd или config.storage: там лежат auth-данные;## 3. auth.bootstrap.password_env должна указывать на непустую переменную.app_name: MESSAGE_QUEUE_EE_APIapp_version: grpc-auth-examplecore_host: 0.0.0.0core_port: 18184grpc_listen:- uri: 'tcp://0.0.0.0:18182'grpc_options:## Рефлексия требует права tqe.admin: учетные записи с ролями Producer или## Consumer вызывают методы только с -proto / -protoset. Выключите рефлексию,## если клиенты и так работают по сгенерированным стабам.reflection_enabled: truetls:enabled: truecert_file: certs/grpc.crtkey_file: certs/grpc.key## ca_file здесь НЕ задан намеренно: он включает проверку клиентского## сертификата (mTLS), и тогда каждому клиенту нужны свои cert/key.## Пример с mTLS — examples/grpc-mtls.## Источник конфигурации кластера. Обязателен при auth.enabled: true:## пользователи, секреты и роли gRPC API хранятся здесь же.#### ВНИМАНИЕ: эта же секция включает автоматическое обнаружение топологии,## которое заполняет producer/consumer.tarantool.connections из etcd.## Поэтому connections ниже не задаются — заданные значения будут затерты.config:etcd:endpoints:- "http://127.0.0.1:2379"prefix: "/tqe/grpc-auth-example"timeout: 5sreconnect_after: 5smax_reconnect_attempts: 3## Для etcd с аутентификацией:# username: tqe# password: "{{ из окружения через шаблон вашего деплоя }}"## Для etcd по TLS:# ssl:# ca_file: certs/etcd-ca.crt# verify_peer: true# verify_host: true## Учетные записи Tarantool, под которыми модуль API ходит в ядро по IPROTO.## Это отдельный уровень доступа: с gRPC-пользователями он не связан.producer:enabled: truetarantool:user: tqe_producer_userpass: producer-secretconsumer:enabled: truepolling_timeout: 500mstarantool:user: tqe_consumer_userpass: consumer-secretauth:enabled: true## Время жизни снимка прав по пользователю. 0 — разворачивать на каждую проверку.permission_cache_ttl: 1s## Время жизни кэша проверенных учетных данных: позволяет не выполнять bcrypt## на каждый запрос. Учтите, что проверки блокировки и истечения срока секрета## внутри этого окна не выполняются — оно добавляется к задержке отзыва прав.credentials_cache_ttl: 30s## Период фонового опроса хранилища. Задает задержку, с которой до сервера## доходят отзыв прав, блокировка и удаление пользователя. Открытые стримы## Subscribe и ConsumeGroup при этом разрываются.store_poll_interval: 10s## Сколько сервер отвечает по копии auth-данных после того, как хранилище## перестало отвечать. По истечении все вызовы отклоняются с Unavailable,## а проба готовности /readyz по ключу auth-data гаснет.## Должно быть строго больше store_poll_interval.store_stale_ttl: 5mintegrity:## true — отклонять сущности с несовпавшей подписью.## Включайте вместе с собственным ключом: пустой private_key_file означает## встроенный ключ, общий для всех установок и пригодный только для разработки.check: false# private_key_file: certs/auth-sign.pempassword_policy:## Сложность по классам символов не требуется, длина — требуется.min_length: 16lockout_threshold: 10lockout_duration: 1m## 0 — принудительная смена по сроку выключена. Включать осознанно:## самостоятельной смены пароля нет, просроченный секрет чинит только## администратор через Iam/SetPassword.max_age: 0## 0 — история прошлых паролей не ведется, повтор действующего разрешен.history_depth: 0## Первый администратор, создаваемый на пустом хранилище при старте.## Без него ни один gRPC-вызов не пройдет, включая методы Iam.## Операция идемпотентна: на непустом хранилище пропускается.bootstrap:login: admin## Пароль берется из переменной окружения и не хранится в конфиге.## Должен удовлетворять password_policy.min_length.## Взаимоисключающе с полем password.password_env: TQE_BOOTSTRAP_ADMIN_PASSWORD## Шаблоны очередей для встроенной роли Admin. Право tqe.admin не## ограничивается очередями, поэтому сузить администратора этим полем нельзя.queue_patterns: ["*"]log:## debug дополнительно показывает аудит разрешенных вызовов;## отклоненные пишутся на уровне warn в любом случае.level: info