Перейти к содержимому

11.03.2015

10

Прозрачная авторизация сервисов в гетерогенной среде на базе Nginx/LUA

Я давно уже полюбил связку Nginx и LUA. И сегодня хочу рассказать про один вариант использования этих инструментов.

Суть задачи/проблемы:
Представьте, что в вашей информационной системе есть набор различных сервисов, с которыми могут взаимодействовать клиентские приложения. Конечно же, доступ к системе и к сервисам, в частности, разрешается после авторизации.
Все сервисы общаются с клиентами по разным протоколам (HTTP REST API, SOAP, XML-RPC, WebSocket, WAMP, GET/POST запросы и так далее) и даже написаны на разных языках.

Вопрос: как минимальными усилиями сделать, чтобы доступ к любым сервисам был возможен только авторизованным пользователям?

Рассуждения и возможные способы решения:
Первое, что приходит в голову — это написать модуль авторизации для каждого сервиса и пусть сервис сам проверяет все входящие запросы. Минусы этого подхода достаточно очевидны:

  • Вам придется, как минимум, написать ровно столько реализаций модуля авторизации, сколько у вас различных языков, на которых написаны сервисы.
  • И в дальнейшем вам придется поддерживать все эти модули.
  • Так же, для начала придется четко описать и указать как должна быть устроена авторизация, иначе разработчики на разных языках напишут свои собственные велосипеды в соответствии со своим личным чувством прекрасного.

Другой вариант — это написать один сервис, который будет отвечать за авторизацию и проксировать все запросы уже на соответствующие сервисы. Отличный вариант! Но писать с нуля такой сервис, попутно решая задачи балансировки, масштабируемости, отказоустойчивости и прочие — совсем не хочется. У нас же есть Nginx и LUA!

Основная идея такого решения в следующем:
Поскольку REST/WebSocket/WAMP/SOAP/XML-RPC и прочее — это все подходы/протоколы, основанные на HTTP, Nginx будет являться входной точной всех запросов, далее, на этапе обработки запроса выполняется lua скрипт, который проверяет валидность сессии, например в базе данных, и если все ок, nginx проксирует запрос на соответствующий сервис. Так же мы запрещаем доступ к сервисам извне. В случае, если все сервисы живут в рамках одного сервера, переводим их на прослушивание только на localhost’е. Так же отмечу, что LUA модуль работает поверх NGINX cosockets & subrequests с неблокирующим I/O.

nginx lua architecture

Вот примерный конфиг nginx:

И вот каким может быть lua-обработчик запросов. В данном примере происходит подключение к локальному MySQL серверу, и выполняется запрос на проверку наличия в БД сессии пользователя с такого IP-адреса и с таким идентификатором сессии. В случае ошибки на любом шаге, возвращается статус «403: Forbidden». Пример упрощен, чтобы показать суть, и не стоит обращать внимание на тему SQL-инъекций и прочих штук.

Можно легко адаптировать данный lua-скрипт, чтобы он ходил в memcache, redis, postgres или даже просто сам обращался по сокету или вебсокету на какой-то внутренний сервис. На openresty.org можно посмотреть на большой список уже написанных модулей.
Так же можно (и даже нужно) сделать, чтобы все клиентские приложения общались с фронтом сервисов через https, а запросы на непосредственно сервисы nginx будет проксировать по http, тем самым снижая накладные расходы и избавляя сервисы от необходимости поддержки SSL/TLS.

Вот такое решение. Надеюсь, оно кому-то пригодится, или, как минимум, натолкнет на полезные мысли и решения.

Узнайте больше из Web-Разработка