Доброго времени суток, codeby.
Сегодня хочу рассказать об обеспечение безопасности микросервисного приложения. Тема довольно интересная и поистине творческая: существует довольно большое множество способов, которые меняются от системы к системе. В рамках двух статей я постараюсь дать хорошие теоретические знания вопроса и практическую реализацию одного из рецептов. Я решил разделить материал, так первая статья будет про теорию а вторая будет чисто практической. Статьи сосредоточены на механизме авторизации и аутентификации, поэтому читателю предлагается самостоятельное погружение в тему микросервисов и их архитектуры. Однако небольшие отступления, дабы читатель видел картину целиком, всё таки будут присутствовать.
В качестве приложения для примера - выбраны микросервисы, из моей статьи о docker. Читателю также предлагается ознакомиться с ними самостоятельно. Стоит сказать, что приложение было модифицировано. Фронтенд вынесен в контейнер с ngnix, о чём я также расскажу во второй части, apigetway мы перепишем в рамках второй части.
Как говорилось ранее - читателю предлагается самостоятельно ознакомится в различии микросервисной и монолитной архитектур. В контексте безопасности стоит сказать, что в монолитной системе за безопасность отвечает сам монолит. В противовес, в системе состоящей из микросервисов, чтоб удовлетворить запрос пользователя приходится вовлекать несколько микросервисов, исходя из этого напрашивается вопросы:
Кейсы аутентификации и авторизации встречается во всех системах. Различие между монолитом и микросервисами (в контексте данных проблем) в том, что в микросервисной системе всегда присутствует вопрос о том, какие из микросервисов должны отвечать за авторизацию и аутентификацию.
Словарь
Рассуждая теоретически, очень важно говорить на одном языке, поэтому давайте для начала определимся с некоторыми моментами.
Задача аутентификации - убедиться, что пользователь - тот за кого себя выдаёт.
Задача авторизации - убедиться, что пользователь имеет право делать то или иное действие в системе.
Данные бывают передаваемыми и хранимыми. Передаваемые данные - это данные которые “гуляют” от микросервиса до микросервиса. Хранимые - это данные которые хранятся в базах данных микросервисов.
Область действия - идентификатор для группы ресурсов, которые необходимо защитить. Например, все конечные точки способные изменить местоположение Пети, должны входить в группу location_information_write. Этакие наименования прав.
Маркер доступа - подписанный объект, используемый для предоставления доступа к микросервисам. Микросервис может запросить маркер доступа к любой области действий, если доступ разрешен - микросервис начинает взаимодействовать с разрешенной зоной.
OAuth и OpenId Connect - мы будем использовать эти протоколы для аутентификации и авторизации, реализацию возьмём из IdentityServer.
Аутентификация
Разобравшись с понятиями давайте приступим к размышлениям. Напомни, что раньше мы использовали архитектуру frontend for backend, где в качестве бэкэнда мы использовали микросервисы. Тогда каждый фрагмент фронтенда либо прорисовывался, либо нет - в зависимости от того был ли запущен сервис. Сейчас же давайте изменим архитектуру на нечто такое:
Что произошло: я вынес фронтенд часть на волю ngnix, действительно, нет особой необходимости иметь целый .net core проект, который существует лишь для того, чтобы рендерить заглавную страницу сайта, ngnix легковесней, дешевле и быстрее, этого вполне достаточно чтобы сделать выбор в его пользу. Появилось бизнесс-требование, которое гласит: “Необходимо дать пользователю возможность предустанавливать свою страну и город, для корректного вывода погоды и курса валют”. Вот у нас и появился функционал, который должен быть разграничен пользовательским контекстом. Так для Пети из Москвы погода и курс рубля к доллару будет отличаться от Тараса из Харькова (курс валюты для Тараса будет представлен как гривна к доллару).
Появился микросервис Login, в рамках которого и строится дальнейшее проектирование, предполагается что микросервис логин будет аутентифицировать пользователей, так как только Петя может менять свои настройки, ну суть ясна я думаю.
Взглянем ещё раз на новую архитектуру. Микросервис Login отвечает за вход Тараса и Пети в систему, однако за запросы Пети и Тараса всё ещё отвечает API Gateway (вернее он вообще отвечает за то что запросы могут выполнять только вошедшие в систему пользователи). Следовательно микросервис API Gateway должен знать аутентифицирован ли пользователь отправивший запрос или нет.
Тут нам на помощь придёт промежуточное ПО, которое перенаправляет пользователей, которые не вошли в систему, в микросервис Login. Сам же микросервис Login решает как именно пользователь будет входить в систему и проводит его через процесс входа. В рамках статьи, Петя и Тарас смогут попасть в систему двумя способами:
Хочу обратить ваше внимание, что аутентификация пользователя происходит на периферии системы, т.е. она проводится микросервисом, получившем запрос непосредственно от пользователя (через промежуточное ПО перенаправления). Это хорошо зарекомендовавший себя принцип разработки систем безопасности для микросервисов: аутентификация пользователя происходит на периферии системы.
Авторизация пользователей
После аутентификации пользователя - мы знаем кто он такой, однако в нормальных системах присутствует система прав, а значит знания, что пользователь является тем за кого себя выдаёт не гарантирует того что у пользователя есть разрешение на совершение того или иного действия. Ну банальный пример: уборщице Таси не нужно давать разрешения на визирование документов отправленных Тарасом для Петра. Также понятно, что система должна отклонять запрос на изменение местоположения Тараса направленного от имени Петра.
Так как мы имеем дело с микросервисной архитектурой, нам нужно понять какой сервис должен отвечать за авторизацию запросов. И вот ответ: поскольку один микросервис это всегда одна бизнес-возможность, мы вполне можем оставить авторизацию в конкретном сервисе. То есть, если Тарас имеет право на визирования документов для Петра, проверку этого визирования можно и нужно оставить в микросервисе документов. Так мы приходим к тому, что авторизация - это тоже часть бизнес возможности, если конкретней то это бизнес-правило.
Теперь поразмышляем о том как это реализовать. Несомненно проясняется факт, что мы должны передавать идентифицированную информацию пользоватяля от микросервиса к микросервису. Так сказать прокидывать её. Эту ответственность мы делегируем нашему Api Gateway так как именно он первым принимает запросы от пользователя, он должен каким то образом модифицировать пользовательский запрос.
Доверие микросервисов друг к другу
Поговорим о моменте, который нередко (разумеется во вред) упускается из вида. Смоделируем ситуацию атаки, допустим злоумышленник смог завладеть микросервисом валют и собирается отправить от его имени запрос на изменение логина и пароля Тараса на микросервис Login. В сценарии, где микросервисы доверяют друг другу и ничем не ограничены - мы, как blue team, потерпели сокрушительное фиаско. Однако, если голова нам дана “не чтоб шапку носить” и мы ограничили доступ к микросервису Login (разумно, чтоб его мог вызывать только Api Gateway, так как он находится на периферии) то всё будет хорошо.
Так насколько же микросервис должен доверять другому микросервису? Ответ на это вопрос, к сожалению, когда как. Это очень сильно зависит от проектируемых систем, от орг. структур, от требований соблюдений нормативных стандартов и т.д.
Чтобы обеспечить ограничение по взаимодействию - мы создадим в микросервисе Login области действий (см словарь). При необходимости вызова другого микросервиса, вызывающий микросервис должен будет запросить доступ у микросервиса Login в виде маркера доступа к конкретной области действия. К тому же мы должны передавать эти данные в зашифрованном виде, а не обычным текстом.
Google OAuth
Напоследок хочу сказать пару слов о том, как работает гугл аутентификация.
Давайте взглянем на картинку:
Процесс описан сверху вниз. В данном случае Client - это фронтенд часть приложения которое мы обсуждаем. Server - это его серверная часть, которая представлена у нас микросервисом Login. Google API Server - апи гугла, с которым мы будем взаимодействовать, а OAuth Dialog - это тот самый диалог, которые предоставляет гугл для аутентификации юзеров. Для использование google oauth нам нужен api-ключ: не имеет смысла расписывать пошагово как его получить, поэтому вот:
Ну а в следующей части я расскажу и покажу как всё это реализовать.
Сегодня хочу рассказать об обеспечение безопасности микросервисного приложения. Тема довольно интересная и поистине творческая: существует довольно большое множество способов, которые меняются от системы к системе. В рамках двух статей я постараюсь дать хорошие теоретические знания вопроса и практическую реализацию одного из рецептов. Я решил разделить материал, так первая статья будет про теорию а вторая будет чисто практической. Статьи сосредоточены на механизме авторизации и аутентификации, поэтому читателю предлагается самостоятельное погружение в тему микросервисов и их архитектуры. Однако небольшие отступления, дабы читатель видел картину целиком, всё таки будут присутствовать.
В качестве приложения для примера - выбраны микросервисы, из моей статьи о docker. Читателю также предлагается ознакомиться с ними самостоятельно. Стоит сказать, что приложение было модифицировано. Фронтенд вынесен в контейнер с ngnix, о чём я также расскажу во второй части, apigetway мы перепишем в рамках второй части.
Как говорилось ранее - читателю предлагается самостоятельно ознакомится в различии микросервисной и монолитной архитектур. В контексте безопасности стоит сказать, что в монолитной системе за безопасность отвечает сам монолит. В противовес, в системе состоящей из микросервисов, чтоб удовлетворить запрос пользователя приходится вовлекать несколько микросервисов, исходя из этого напрашивается вопросы:
- какие из микросервисов должны отвечать за авторизацию, а какие за аутентификацию
- предположим, что одни из сервисов аутентифицировал пользователя, значит ли это что этому пользователю должны доверять другие микросервисы
- должны ли микросервисы доверять другу
- должны ли все микросервисы иметь доступ ко всем микросервисам, т.е. имеют ли право все микросервисы обращаться друг к другу
Кейсы аутентификации и авторизации встречается во всех системах. Различие между монолитом и микросервисами (в контексте данных проблем) в том, что в микросервисной системе всегда присутствует вопрос о том, какие из микросервисов должны отвечать за авторизацию и аутентификацию.
Словарь
Рассуждая теоретически, очень важно говорить на одном языке, поэтому давайте для начала определимся с некоторыми моментами.
Задача аутентификации - убедиться, что пользователь - тот за кого себя выдаёт.
Задача авторизации - убедиться, что пользователь имеет право делать то или иное действие в системе.
Данные бывают передаваемыми и хранимыми. Передаваемые данные - это данные которые “гуляют” от микросервиса до микросервиса. Хранимые - это данные которые хранятся в базах данных микросервисов.
Область действия - идентификатор для группы ресурсов, которые необходимо защитить. Например, все конечные точки способные изменить местоположение Пети, должны входить в группу location_information_write. Этакие наименования прав.
Маркер доступа - подписанный объект, используемый для предоставления доступа к микросервисам. Микросервис может запросить маркер доступа к любой области действий, если доступ разрешен - микросервис начинает взаимодействовать с разрешенной зоной.
OAuth и OpenId Connect - мы будем использовать эти протоколы для аутентификации и авторизации, реализацию возьмём из IdentityServer.
Аутентификация
Разобравшись с понятиями давайте приступим к размышлениям. Напомни, что раньше мы использовали архитектуру frontend for backend, где в качестве бэкэнда мы использовали микросервисы. Тогда каждый фрагмент фронтенда либо прорисовывался, либо нет - в зависимости от того был ли запущен сервис. Сейчас же давайте изменим архитектуру на нечто такое:
Что произошло: я вынес фронтенд часть на волю ngnix, действительно, нет особой необходимости иметь целый .net core проект, который существует лишь для того, чтобы рендерить заглавную страницу сайта, ngnix легковесней, дешевле и быстрее, этого вполне достаточно чтобы сделать выбор в его пользу. Появилось бизнесс-требование, которое гласит: “Необходимо дать пользователю возможность предустанавливать свою страну и город, для корректного вывода погоды и курса валют”. Вот у нас и появился функционал, который должен быть разграничен пользовательским контекстом. Так для Пети из Москвы погода и курс рубля к доллару будет отличаться от Тараса из Харькова (курс валюты для Тараса будет представлен как гривна к доллару).
Появился микросервис Login, в рамках которого и строится дальнейшее проектирование, предполагается что микросервис логин будет аутентифицировать пользователей, так как только Петя может менять свои настройки, ну суть ясна я думаю.
Взглянем ещё раз на новую архитектуру. Микросервис Login отвечает за вход Тараса и Пети в систему, однако за запросы Пети и Тараса всё ещё отвечает API Gateway (вернее он вообще отвечает за то что запросы могут выполнять только вошедшие в систему пользователи). Следовательно микросервис API Gateway должен знать аутентифицирован ли пользователь отправивший запрос или нет.
Тут нам на помощь придёт промежуточное ПО, которое перенаправляет пользователей, которые не вошли в систему, в микросервис Login. Сам же микросервис Login решает как именно пользователь будет входить в систему и проводит его через процесс входа. В рамках статьи, Петя и Тарас смогут попасть в систему двумя способами:
- логин и пароль
- google auth
Хочу обратить ваше внимание, что аутентификация пользователя происходит на периферии системы, т.е. она проводится микросервисом, получившем запрос непосредственно от пользователя (через промежуточное ПО перенаправления). Это хорошо зарекомендовавший себя принцип разработки систем безопасности для микросервисов: аутентификация пользователя происходит на периферии системы.
Авторизация пользователей
После аутентификации пользователя - мы знаем кто он такой, однако в нормальных системах присутствует система прав, а значит знания, что пользователь является тем за кого себя выдаёт не гарантирует того что у пользователя есть разрешение на совершение того или иного действия. Ну банальный пример: уборщице Таси не нужно давать разрешения на визирование документов отправленных Тарасом для Петра. Также понятно, что система должна отклонять запрос на изменение местоположения Тараса направленного от имени Петра.
Так как мы имеем дело с микросервисной архитектурой, нам нужно понять какой сервис должен отвечать за авторизацию запросов. И вот ответ: поскольку один микросервис это всегда одна бизнес-возможность, мы вполне можем оставить авторизацию в конкретном сервисе. То есть, если Тарас имеет право на визирования документов для Петра, проверку этого визирования можно и нужно оставить в микросервисе документов. Так мы приходим к тому, что авторизация - это тоже часть бизнес возможности, если конкретней то это бизнес-правило.
Теперь поразмышляем о том как это реализовать. Несомненно проясняется факт, что мы должны передавать идентифицированную информацию пользоватяля от микросервиса к микросервису. Так сказать прокидывать её. Эту ответственность мы делегируем нашему Api Gateway так как именно он первым принимает запросы от пользователя, он должен каким то образом модифицировать пользовательский запрос.
Доверие микросервисов друг к другу
Поговорим о моменте, который нередко (разумеется во вред) упускается из вида. Смоделируем ситуацию атаки, допустим злоумышленник смог завладеть микросервисом валют и собирается отправить от его имени запрос на изменение логина и пароля Тараса на микросервис Login. В сценарии, где микросервисы доверяют друг другу и ничем не ограничены - мы, как blue team, потерпели сокрушительное фиаско. Однако, если голова нам дана “не чтоб шапку носить” и мы ограничили доступ к микросервису Login (разумно, чтоб его мог вызывать только Api Gateway, так как он находится на периферии) то всё будет хорошо.
Так насколько же микросервис должен доверять другому микросервису? Ответ на это вопрос, к сожалению, когда как. Это очень сильно зависит от проектируемых систем, от орг. структур, от требований соблюдений нормативных стандартов и т.д.
Чтобы обеспечить ограничение по взаимодействию - мы создадим в микросервисе Login области действий (см словарь). При необходимости вызова другого микросервиса, вызывающий микросервис должен будет запросить доступ у микросервиса Login в виде маркера доступа к конкретной области действия. К тому же мы должны передавать эти данные в зашифрованном виде, а не обычным текстом.
Google OAuth
Напоследок хочу сказать пару слов о том, как работает гугл аутентификация.
Давайте взглянем на картинку:
Процесс описан сверху вниз. В данном случае Client - это фронтенд часть приложения которое мы обсуждаем. Server - это его серверная часть, которая представлена у нас микросервисом Login. Google API Server - апи гугла, с которым мы будем взаимодействовать, а OAuth Dialog - это тот самый диалог, которые предоставляет гугл для аутентификации юзеров. Для использование google oauth нам нужен api-ключ: не имеет смысла расписывать пошагово как его получить, поэтому вот:
Ссылка скрыта от гостей
Ну а в следующей части я расскажу и покажу как всё это реализовать.