Наша система переходит от монолитной к микросервисной архитектуре.Архитектура микросервиса сопряжена с техническими проблемами, которые нам необходимо решить, и одна из них - AuthN / AuthZ.
Наш подход заключается в создании службы аутентификации, которая аутентифицирует пользователей и генерирует токены доступа / обновления (JWT).Затем токены доступа будут передаваться в заголовке запроса через цепочку микросервисов, так что каждому микросервису просто нужно проверить токен, чтобы определить, что пользователь был успешно аутентифицирован.Для части AuthZ принудительное выполнение разрешений выполняется в самом микросервисе.Мои вопросы связаны с AuthZ.
Чтобы проиллюстрировать разговор, давайте рассмотрим конкретный пример администратора, который хочет зарегистрировать нового участника в своей программе верности, например, из веб-приложения.Для поддержки этого варианта использования предположим, что в системе есть 2 микросервиса, ReceptionService и MemberService.ReceptionService предлагает один API REST для запуска процесса регистрации участника.Требуется разрешение пользователя «регистрация», чтобы разрешить выполнение.MemberService предлагает один API REST для создания нового ресурса участника, который защищен разрешениями CRUD.Поток запросов будет выглядеть следующим образом:
- Веб-приложение, в которое ранее входил пользователь, отправляет запрос регистрации участника в API ReceptionService, включая маркер доступа пользователя в заголовке.
- ReceptionService проверяет токен пользователя, гарантирует, что пользователю предоставлено разрешение «регистрация», выполняет любую бизнес-логику, в которой он нуждается, и, наконец, отправляет запрос на создание члена API-интерфейсу MemberService, включая токен доступа пользователя в заголовке.*
- MemberService проверяет токен пользователя, гарантирует, что пользователю предоставлено разрешение «member.create», и, наконец, создает участника.
Чтобы разработать решение для такого случая, моя команда работала надследующие предположения / предварительные условия:
- Микросервис всегда должен обеспечивать разрешение (по крайней мере, для значительных операций API, таких как создание члена).Таким образом, разрешения CRUD для MemberService в приведенном выше примере, даже если Менеджерам продуктов может потребоваться только разрешение «регистрации» верхнего уровня.
- Пользователь, который может запустить вариант использования, поскольку у него есть «top-уровень »разрешение должно быть в состоянии завершить его.Значение. Он не должен получать ошибки, потому что ему не хватает другого разрешения где-то в цепочке вызовов базовых сервисов.
- Пользователи-администраторы не должны понимать цепочку разрешений, которая требуется для выполнения сценария использования.В нашем примере администраторы должны иметь возможность предоставлять пользователям только разрешение «регистрация».
Чтобы завершить приведенный выше пример, пользователю необходимо назначить 2 разных разрешения, которыеломает некоторые из наших предположений / предпосылок.Чтобы преодолеть это, один из моих коллег предложил рассмотреть возможность объявления микросервисов в качестве идентификаторов / пользователей в нашей системе AuthN, чтобы им могли быть назначены соответствующие разрешения.Первоначально предоставленный пользовательский токен будет заменен участвующим сервисным токеном в цепочке вызовов.Чтобы вернуться к примеру, новый поток запросов будет выглядеть следующим образом:
Веб-приложение, в которое ранее входил пользователь, отправляет запрос регистрации участника в API ReceptionService, включаятокен доступа пользователя в заголовке.
ReceptionService проверяет токен пользователя, гарантирует, что пользователю предоставлено разрешение «регистрация», выполняет любую бизнес-логику, которую ему необходимо сделать, и, наконец, отправляет участниказапрос на создание API-интерфейса MemberService, включающий в заголовок собственный токен службы (и, таким образом, заменяющий исходный токен пользователя).
MemberService проверяет токен службы, гарантирует, что служба предоставляется с разрешения «member.create »и, наконец, создает участника.
При таком решении идентификаторы службы в системе AuthN будут помечаться таким образом, что они будут отфильтрованы от пользователя-администратора, управляющего назначениями разрешений.Назначения разрешений для идентификаторов служб будут заранее определены, и пользователь не сможет их настроить.Несмотря на то, что он соответствует нашим предположениям / предварительным условиям, у меня мало вопросов об этом подходе:
- Когда речь идет о том, «кто что сделал» (аудит), идентификация пользователя и идентификация службы, предоставленные в токенах,быть в списке равнодушным.В нашем примере RegistrationService будет проверять фактического пользователя, который инициировал операцию, но MemberService будет проверять, что операция была выполнена «RegistrationService».В сценариях отчетности это означает, что мне нужно будет согласовать аудит из обеих систем, чтобы определить, «кто на самом деле создал участника», используя каким-либо образом идентификатор корреляции.
- Хотя я понимаю необходимость создания идентификатора для системного компонентав сценариях, в которых не задействован реальный пользователь (автоматический пакетный / сторонний доступ ...), мне неудобно заменять пользовательский токен сервисным токеном в тех случаях, когда пользователь фактически инициировал сценарий использования.Это стандартный шаблон проектирования?
Может быть, некоторые наши предположения / предпосылки ошибочны?
- Например, действительно ли это дыра в безопасности, что некоторые микросервисыне применять разрешения, даже если к ним обращаются только другие
контролируемые микросервисы в безопасной среде?Если предположить, что ответ
на последний вопрос «нет, это не будет дырой в безопасности», то что, если завтра мне нужно сделать API-интерфейс MemberService также доступным
вне безопасной среды (например, потому что я
сделать доступным для третьей стороны).Скорее всего, мне нужно было бы добавить разрешение
, что нарушило бы мой процесс регистрации. - Неправильно ли говорить, что мы хотим, чтобы пользователи с правами администратора знали, какой набор разрешений
необходим длясценарий использования и что нам лучше
построить систему, чтобы она корректно обрабатывала сбои из-за отсутствия одного разрешения в цепочке вызовов (возможно, с использованием процедур Sagas и компенсации
)?
Любой комментарий или ссылки на ресурсы будут с благодарностью.Спасибо!