аутентификация и авторизация в микросервисных приложениях часть 2
Назад к микросервисам вместе с Istio. Часть 3
Прим. перев.: Первая часть этого цикла была посвящена знакомству с возможностями Istio и их демонстрации в действии, вторая — тонко настраиваемой маршрутизации и управлению сетевым трафиком. Теперь же речь пойдёт про безопасность: для демонстрации связанных с ней базовых функций автор использует identity-сервис Auth0, однако по аналогии с ним могут настраиваться и другие провайдеры.
Мы настроили Kubernetes-кластер, в котором развернули Istio и пример микросервисного приложения Sentiment Analysis, — так были продемонстрированы возможности Istio.
С помощью Istio нам удалось сохранить небольшой размер сервисов, поскольку они не нуждаются в реализации таких «слоёв», как повторные попытки подключения (Retries), таймауты (Timeouts), автоматический выключатели (Circuit Breakers), трассировка (Tracing), мониторинг (Monitoring). Кроме того, мы задействовали техники продвинутого тестирования и деплоя: A/B-тестирование, зеркалирование и канареечные выкаты.
В новом материале мы разберёмся с финальными слоями на пути к business value: аутентификацией и авторизацией — и в Istio это сплошное удовольствие!
Аутентификация и авторизация в Istio
Никогда бы не поверил, что вдохновлюсь аутентификацией и авторизацией. Что же такого с технологической точки зрения может предложить Istio для того, чтобы сделать эти темы увлекательными и даже более того — чтобы они вдохновили и вас?
Ответ прост: Istio переносит ответственность за эти возможности с ваших сервисов на прокси Envoy. Ко времени, когда запросы достигают сервисов, они уже аутентифицированы и авторизованы, так что вам остаётся просто писать полезный для бизнеса код.
Звучит неплохо? Заглянем же внутрь!
Аутентификация с Auth0
В качестве сервера для управления идентификацией и доступом будем использовать Auth0, у которого есть пробная версия, который интуитивно понятен в использовании и попросту нравится мне. Впрочем, те же самые принципы можно применить и по отношению к любой другой реализации OpenID Connect: KeyCloak, IdentityServer и многим другим.
Для начала зайдите на Auth0 Portal со своим аккаунтом, создайте tenant (tenant — «арендатор», логическая единица изоляции, подробнее см. в документации — прим. перев.) и зайдите в Applications > Default App, выбрав Domain, как показано на скриншоте ниже:
Укажите этот домен в файле resource-manifests/istio/security/auth-policy.yaml (исходник):
Вернитесь на страницу и сделайте запрос — увидите, что он закончится статусом 401 Unauthorized. Теперь перенаправим пользователей фронтенда на аутентификацию с Auth0.
Аутентификация запросов с Auth0
Чтобы аутентифицировать запросы конечного пользователя, необходимо создать API в Auth0, который будет представлять аутентифицированные сервисы (reviews, details и ratings). Для создания API перейдите в Auth0 Portal > APIs > Create API и заполните форму:
Важной информацией здесь является Identifier, который позже мы будем использовать в скрипте. Выпишем его себе так:
А для Allowed Logout URLs (разрешённые URL’ы для разлогинивания) добавим:
Перейдём к фронтенду.
Обновление фронтенда
Чтобы перевести фронтенд на использование данных tenant’а в Auth0, откройте sa-frontend/src/services/Auth.js и замените в нём значения, которые мы записали выше (Auth.js):
Приложение готово. Укажите свой Docker ID в командах ниже при сборке и деплое произведённых изменений:
Попробуйте приложение! Вас перенаправят на Auth0, где необходимо залогиниться (или зарегистрироваться), после чего вас отправят обратно на страницу, с которой будут производиться уже аутентифицированные запросы. Если же вы попробуете упомянутые в первых частях статьи команды с curl — получите код 401 Status Code, сигнализирующий о том, что запрос не авторизован.
Сделаем следующий шаг — авторизуем запросы.
Авторизация с Auth0
Аутентификация позволяет нам понять, кем является пользователь, но для того, чтобы узнать, к чему у него есть доступ, требуется авторизация. Istio предлагает инструменты и для этого.
В качестве примера создадим две группы пользователей (см. на схеме ниже):
Для создания этих групп воспользуемся расширением Auth0 Authorization и с помощью Istio предоставим им разные уровни доступа.
Установка и конфигурация Auth0 Authorization
На портале Auth0 перейдите к расширениям (Extensions) и установите Auth0 Authorization. После установки перейдите к Authorization Extension, а там — к конфигурации tenant’а по клику справа наверху и выбору соответствующей опции меню (Configuration). Активируйте группы (Groups) и нажмите на кнопку публикации правила (Publish rule).
Создание групп
В Authorization Extension перейдите в Groups и создайте группу Moderators. Поскольку мы будем рассматривать всех аутентифицированных пользователей как обычных, потребности в создании для них дополнительной группы нет.
Выберите группу Moderators, нажмите на Add Members, добавьте свой основной аккаунт. Оставьте некоторых пользователей без какой-либо группы, чтобы убедиться, что доступ для них запрещён. (Новых пользователей можно создать вручную через Auth0 Portal > Users > Create User.)
Добавьте Group Claim в Access Token
Пользователи добавлены в группы, однако эта информация должна быть отражена и в токенах для доступа. Чтобы соответствовать OpenID Connect и в то же время возвращать группы, которые нам нужны, токену потребуется добавлять свой custom claim. Реализуется через правила Auth0.
Для создания правила перейдите на Auth0 Portal к Rules, нажмите на Create Rule и выберите пустое правило из шаблонов.
Скопируйте код ниже и сохраните его как новое правило Add Group Claim (namespacedGroup.js):
Примечание: этот код берёт первую группу пользователя, определённую в Authorization Extension, и добавляет её в access-токен как custom claim (под своим пространством имён, как того требует Auth0).
Вернитесь к странице Rules и проверьте, что у вас есть два правила, записанные в следующем порядке:
Теперь необходимо настроить Envoy-прокси на проверку пользовательского доступа, для чего группа будет вытаскиваться из claim ( https://sa.io/group ) в возвращаемом access-токене. Это тема для следующего раздела статьи.
Конфигурация авторизации в Istio
Чтобы авторизация заработала, необходимо включить RBAC для Istio. Для этого воспользуемся следующей конфигурацией:
Применим конфигурацию такой командой:
Конфигурация доступа для обычных пользователей
Все пользователи должны иметь доступ к сервисам SA-Frontend и SA-WebApp. Реализуется с помощью следующих ресурсов Istio:
А через regular-user-binding применим ServiceRole ко всем посетителям страницы (regular-user-service-role-binding.yaml):
Означает ли «все пользователи», что и неаутентифицированные пользователи получат доступ к SA WebApp? Нет, политика проверит валидность JWT-токена.
Конфигурация доступа для модераторов
Для модераторов мы хотим включить доступ ко всем сервисам (mod-service-role.yaml):
Но мы хотим таких прав только для тех пользователей, в access-токене которых есть claim https://sa.io/group со значением Moderators (mod-service-role-binding.yaml):
Из-за кэширования в envoy’ях для вступления правил авторизации в силу может потребоваться пара минут. После этого вы сможете убедиться, что у пользователей и модераторов разные уровни доступа.
Заключение по этой части
Ну вот серьёзно: вы где-нибудь видели более простой, не требующий усилий, масштабируемый и безопасный подход к аутентификации и авторизации?
Всего лишь три ресурса Istio (RbacConfig, ServiceRole, and ServiceRoleBinding) потребовались для того, чтобы добиться тонкого контроля над аутентификацией и авторизацией доступа конечных пользователей к сервисам.
Вдобавок, мы вынесли заботу об этих проблемах из наших сервисов в envoy’и, добившись:
Вывод
Istio позволяет командам сфокусировать свои ресурсы на важных для бизнеса задачах, не добавляя накладные расходы сервисам, возвращая их к статусу «микро».
Статья (в трёх частях) предоставила базовые знания и готовую практическую инструкцию для начала работы с Istio в реальных проектах.
Идентификация, аутентификация и авторизация — в чем разница?
Объясняем на енотах, в чем разница между идентификацией и авторизацией, а также зачем нужна аутентификация, тем более двухфакторная.
Это происходит с каждым из нас, причем ежедневно: мы постоянно идентифицируемся, аутентифицируемся и авторизуемся в разнообразных системах. И все же многие путают значение этих слов и часто употребляют термин «идентификация» или «авторизация», когда на самом деле речь идет об аутентификации.
Ничего такого уж страшного в этом нет — пока идет бытовое общение и обе стороны диалога по контексту понимают, что в действительности имеется в виду. Но всегда лучше знать и понимать слова, которые употребляешь, а то рано или поздно нарвешься на зануду-специалиста, который вынет всю душу за «авторизацию» вместо «аутентификации», кофе среднего рода и такое душевное, но неуместное в серьезной беседе слово «ихний».
Идентификация, аутентификация и авторизация: серьезные определения
Итак, что же значат термины «идентификация», «аутентификация» и «авторизация» — и чем соответствующие процессы отличаются друг от друга? Для начала проконсультируемся с «Википедией»:
Объясняем идентификацию, аутентификацию и авторизацию на енотах
Выше было очень много умных слов, теперь давайте упростим до конкретных примеров. Скажем, пользователь хочет войти в свой аккаунт Google. Google подходит лучше всего, потому что там процедура входа явным образом разбита на несколько простейших этапов. Вот что при этом происходит:
Аутентификация без предварительной идентификации лишена смысла — пока система не поймет, подлинность чего же надо проверять, совершенно бессмысленно начинать проверку. Для начала надо представиться.
Идентификация без аутентификации — это просто глупо. Потому что мало ли кто ввел существующий в системе логин! Системе обязательно надо удостовериться, что этот кто-то знает еще и пароль. Но пароль могли подсмотреть или подобрать, поэтому лучше подстраховаться и спросить что-то дополнительное, что может быть известно только данному пользователю: например, одноразовый код для подтверждения входа.
А вот авторизация без идентификации и тем более аутентификации очень даже возможна. Например, в Google Документах можно публиковать документы так, чтобы они были доступны вообще кому угодно. В этом случае вы как владелец файла увидите сверху надпись, гласящую, что его читает неопознанный енот. Несмотря на то, что енот совершенно неопознанный, система его все же авторизовала — то есть выдала право прочитать этот документ.
А вот если бы вы открыли этот документ для чтения только определенным пользователям, то еноту в таком случае сперва пришлось бы идентифицироваться (ввести свой логин), потом аутентифицироваться (ввести пароль и одноразовый код) и только потом получить право на чтение документа — авторизоваться.
А уж если речь идет о содержимом вашего почтового ящика, то Google никогда и ни за что не авторизует неопознанного енота на чтение вашей переписки — если, конечно, он не идентифицируется с вашим логином и не аутентифицируется с вашим паролем. Но тогда это уже не будет неопознанный енот, поскольку Google однозначно определит этого енота как вас.
Теперь вы знаете, чем идентификация отличается от аутентификации и авторизации. Что еще важно понимать: аутентификация — пожалуй, самый важный из этих процессов с точки зрения безопасности вашего аккаунта. Если вы ленитесь и используете для аутентификации только слабенький пароль, то какой-нибудь енот может ваш аккаунт угнать. Поэтому:
Аутентификация и авторизация в микросервисных приложениях
Введение
Это вводная часть материала, основанного на докладе, прочитанном мной прошлым летом. Печатный материал предполагает больше информации, т.к. в одном докладе обычно не получается рассказать обо всех деталях.
Что такое аутентификация?
На процессах аутентификации и авторизации основано разделения прав доступа, без которого не обходится ни одно более или менее серьезное приложение. Поэтому понимать, как они происходили раньше и происходят теперь, очень важно, но, прежде чем углубиться в описание технологии, давайте разберемся с ключевыми терминами.
Идентификация — процесс определения, что за человек перед нами. Аутентификация — процесс подтверждения, что этот человек именно тот, за кого себя выдает. Авторизация — процесс принятия решения о том, что именно этой аутентифицированной персоне разрешается делать. То есть, это три разных, последовательных и взаимно не заменяемых понятия. Идентификацию часто подразумевают в составе аутентификации. Самое главное — четко различать аутентификацию и авторизацию.
В ходе аутентификации мы удостоверяемся, что человек, который к нам пришел, обладает доказательствами, подтверждающими личность. В этой статье речь в основном пойдет как раз об аутентификации.
Способы аутентификации
При использовании HTTP-протокола простейший способ аутентификации — Basic access authentication. В принципе этот протокол устарел и уже редко используется в интернете, особенно в незащищенных соединениях, но еще сохраняется во внутрикорпоративных системах, просто потому что некоторые из них созданы достаточно давно. Стоит разобраться, как он работает.
HTTP Basic Authentication
Первым, что при обращении к защищенному ресурсу сервер выдаст пользователю, не имеющему доступа, будет ошибка 401 Unauthorized. При этом ответ также содержит информацию о типе аутентификации (в нашем случае – Basic), который он может принимать, и контекст, в рамках которого эта аутентификация действует (Realm). Пользователь вводит логин и пароль, они упаковываются в Base64 и отправляются на сервер для проверки. Здесь существуют различные опасности. Самая распространенная — угроза man-in-the-middle attack, или атаки посредника, в ходе которой при использовании незащищенного соединения учетные данные могут перехватить злоумышленники в момент передачи от клиента к серверу или обратно.
HTTP Digest Authentication
Следующим этапом развития технологии стала чуть более сложная система HTTP digest authentication, которая исключает передачу учетных данных в открытом виде — здесь для проверки используется MD5-хеш с некоторыми примесями, что позволяет избежать подбора логина и пароля. Конечно, этот алгоритм выглядит более надежным, но и он подвержен целому ряду не самых сложных атак. Например, вот тут можно почитать об атаках более подробно.
Forms Authentication
Позднее появился процесс Forms authentication, при котором аутентификация происходит на более высоком уровне модели абстракции. HTTP-сервер при этом не сообщает об ошибке доступа, а просто перенаправляет неаутентифицированного пользователя на другую страницу. Обычно на этой странице отображаются поля для ввода логина и пароля, после заполнения которых формируется POST-запрос с данными и через защищенный канал направляется на сервер. Серверная сторона в свою очередь возвращает пользователю токен или идентификатор сессии, который сохраняется в Cookies и в дальнейшем используется для доступа к защищенному ресурсу.
Token Authentication
На схеме хорошо видно, как и в какой последовательности приложения обмениваются информацией при обращении к архитектуре c аутентификацией по токенам.
OAuth2 & Open ID Connect
Дальнейшее усовершенствование процесса понадобилось ввиду того, что токен-аутентификация требует присутствия пользователя в момент получения доступа к защищенному ресурсу. Потому что Identity provider при передаче ему управления будет с пользователем взаимодействовать, запрашивая, например, логин и пароль.
В случае сервиса, который от имени пользователя должен через определенные промежутки времени опрашивать некий третий ресурс, — допустим, получать доступ к списку контактов в социальной сети — токен-аутентификация работать уже не будет. Дело в том, что идентификаторы сессии обычно живут очень недолго, чтобы в случае их перехвата злоумышленники получили доступ к сервису лишь на ограниченное время. Но из-за короткого срока действия токена не хватает, например, на ночной процесс.
В 2006 году в ходе работы над реализацией протокола Open ID для Twitter обнаружилась потребность в новом открытом протоколе авторизации. В 2007 инженеры Google и AOL начали совместную работу над ним, а в 2009 Twitter предложил своим пользователям решение, делегировавшее сторонним сервисам доступ к аккаунтам и основанное на протоколе OAuth. Три года спустя была опубликована новая версия — OAuth 2, упростившая разработку клиентских приложений и получившая целый ряд новых возможностей, среди которых оказалось и обновление токена без участия пользователя. Многие сервисы начали использовать этот протокол еще до его официального утверждения.
Разбираемся детально ху из ху
В данный момент на слуху следующие протоколы:
Все три протокола позволяют пользователю не разглашать свои секретные логин и пароль недоверенным приложениям.
OpenID & OAuth разрабатывались параллельно вплоть до 2014 года и объединились в итоге в OpenID connect.
OpenID 1.0 (2006) & OpenID 2.0 (2007) позволяли приложению(арб) запрашивать у доверенного сервера (authority) проверку пользователя(user). Отличия между версиями для нас несущественны.
OpenID Attribute Exchange 1.0 (2007) расширяет OpenID 2.0 разрешая получать и хранить профиль пользователя.
OAuth 1.0 (2010) позволяет пользователю разрешать приложению получать ограниченный доступ на третьесторонних серверах(third-party server), доверяющих удостоверяющему центру.
OAuth 2.0 (2012) делает тоже самое, что и OAuth 1.0, но только протокол существенно поменялся и стал проще.
OpenID Connect (2014) объединяет возможности OpenID 2.0, OpenID Attribute Exchange 1.0, и OAuth 2.0 в один общий протокол. Он позволяет приложениям использовать удостоверяющий центр для:
Важно понимать, что OpenID Connect не дает доступ к внешним ресурсам. Он использует OAuth 2.0 для того, чтобы представить параметры профиля как будто это такие ресурсы.
Взгляд сверху
Обычно в системах встречаются разные компоненты: пользователи, работающие через браузер, пользователи, взаимодействующие с сервером через мобильные приложения, и просто серверные приложения, нуждающиеся в принадлежащих вам данных, хранящихся на других серверах, доступ к которым осуществляется через Web API.
Single sign-on — технология единого входа — позволяет пользователю переключаться между различными приложениями без повторной аутентификации. Используя SSO можно избежать множественных логинов, так что пользователь просто не будет замечать этих переключений. При этом ситуации, когда в рамках вашей инфраструктуры таких приложений будет больше одного, встречаются постоянно. Технология единого входа особенно удобна в больших энтерпрайз-системах, состоящих из десятков приложений, слабо связанных между собой. Вряд ли пользователи будут довольны, вводя логин и пароль при каждом обращении к системе учета рабочего времени, корпоративному форуму или внутренней базе документов.
В качестве реализации мы рассматриваем протокол OAuth2. В принципе, существуют и другие, например, Kerberos, успешно взаимодействующий с Windows, но в случае гетерогенной сети, в которой существуют компьютеры, использующие и Windows-, и Mac-, и UNIX-системы, использовать проприетарные протоколы зачастую неудобно. Тем более, это касается случаев, когда доступ к вашим сервисам осуществляется через веб — здесь OAuth2 оказывается лучшим кандидатом.
На рисунке выше показано, какие именно протоколы при каждом типе взаимодействия.
Как мы знаем из раздела «разбираемся детально ху из ху», OpenID Сonnect нужен, чтобы получить у пользователя его учетные данные и проверить их. OAuth 2.0 нужен, чтобы получать токены доступа и с ними обращаться к ресурсам.
Терминология OAuth2 & OpenID Connect
Сервис выдачи токенов
Open ID Connect Provider — важнейший объект всей конструкции централизованного сервиса аутентификации, он также может называться Security Token Service, Identity Provider authorization server и т. д. Различные источники называют его по-разному, но по смыслу это сервис, который выдает токены клиентам.
Клиент
Client — устройство или программа (браузер, приложение), которым требуется либо токен для аутентификации пользователя, либо токен для доступа к какому-то ресурсу (подразумевается, что данный ресурс «знаком» с тем конкретным «Security Token Service» у которого клиент запрашивает токен для доступа).
Пользователь
User — собственно конечный пользователь — человек.
Область (scope)
Scope — идентификатор ресурса, к которому клиент хочет получить доступ. Список scope посылается в адрес сервиса выдачи токенов в составе запроса на аутентификацию.
По умолчанию все клиенты имеют возможность запрашивать любые области, но это можно (и нужно) ограничивать в конфигурации сервиса выдачи токенов.
Scopes бывают двух видов:
Запрос на аутентификацию
Authentication/Token Request — процесс запроса аутентификации.
В зависимости от того какие области (scopes) запрошены, сервис выдачи токенов вернет:
Более подробно про процесс аутентификации можно прочесть в разделе «процесс aутентификации».
Токен личности
Identity Token — подтверждение аутентификации. Этот токен содержит минимальный набор информации о пользователе.
Токен доступа
Access Token — информация, что конкретному пользователю разрешается делать. Клиент запрашивает Access Token и затем использует его для доступа к ресурсам (Web APIs). Access Token содержит информацию о клиенте и пользователе, если она присутствует. Важно понимать, что есть такие типы авторизации, при которых пользователь в процессе непосредственно не участвует (подробнее в раздел «типы авторизации»)
Токен обновления
Refresh Token — токен, по которому STS вернет новый Access Token. В зависимости от режима, работа Refresh Token может быть многоразовым и одноразовым. В случае с одноразовым токеном, при запросе нового Access Token будет также сформирован готовый Refresh Token, который следует использовать при повторном обновлении. Очевидно, что одноразовые токены более безопасны.
Более подробно о составе токенов в разделе «структура токена».
Процесс аутентификации
При обращении пользователя к клиенту, тот перенаправляет пользователя на Open ID Connect Provider, который запрашивает у пользователя логин и пароль. В случае успешного прохождения проверки параметров аутентификации он возвращает назад identity token и access token, с которыми пользователь может обращаться к защищенному ресурсу.
Структура токена
Формат
В реализации OAuth2 используется так называемый jwt-токен, который состоит из трех частей. Допустим, при обращении к Identity provider вы отправляете логин/пароль и в ответ получаете токен. Он будет включать в себя: Header (заголовок), Payload (контент) и Signature (подпись). На сайте jwt.io его можно декодировать и посмотреть содержимое формате JSON. На этом сайте вы также найдете описание правил формирования jwt-токенов.
В том, что токены в процессе обмена передаются незашифрованными, ничего страшного нет. Мы изначально исходим из предположения, что коммуникация происходит по защищенному HTTPS-каналу, и повторное шифрование токена было бы избыточным. Единственное, в чем нам нужно убедиться – то, что токен не был подменен или сфальсифицирован на клиентской стороне, для этого достаточно иметь подпись и проверять ее на сервере. Кроме того, токен не содержит никакой критически важной информации.
Кроме identity tokens, есть еще и аccess tokens, которые содержат информацию о выданных пользователю клеймах. Срок действия access token достаточно короткий, потому что его хищение может обеспечить несанкционированный доступ к ресурсу. Т. е. злоумышленник, если ему удастся заполучить токен этого типа, доступ получит на очень непродолжительное время. Для получения нового access token используется refresh token, который обычно не фигурирует в незащищенных средах, в частности в режиме доступа из браузера он вообще не используется. Какие именно токены будут возвращены клиенту в процессе аутентификации, разбирается в разделе «типы авторизации».
Основные поля
Кратно остановимся на том, какие есть стандартные полях в токене и зачем они нужны:
Заключение первой части
В этой статье мы постарались дать теоретический и терминологический фундамент, который понадобится нам создании работающего решения в следующих статьях.
Спойлер второй части
Минимальная реализация интеграция Identity Server в ваше приложение выглядит так:
Минимальная реализация интеграции веб-клиента с Identity Server:
Минимальная реализация интеграции веб-API с Identity Server: