В современной быстро меняющейся цифровой среде обеспечение надежной безопасности на каждом этапе взаимодействия с пользователем имеет первостепенное значение. Хотя существует множество инструментов для защиты наших приложений, найти идеальное сочетание между ними может быть непросто. На помощь приходит динамичный дуэт: Nginx и Keycloak. В паре эти инструменты обеспечивают мощное решение по обеспечению безопасности вашего приложения. Nginx, известный своей высокой производительностью и масштабируемостью, в сочетании с надежными механизмами аутентификации и авторизации Keycloak строит крепость, защищающую ваши приложения от несанкционированного доступа. В этой статье мы рассмотрим все тонкости этой привлекательной комбинации и покажем, как можно использовать их общие преимущества для создания надежного и удобного шлюза для ваших приложений.

Прежде чем погрузиться в рассмотрение Nginx и Keycloak, давайте вернемся к некоторым основополагающим концепциям безопасности.

Понимание разницы: Аутентификация vs Авторизация

В сфере безопасности часто встречаются термины "аутентификация" и "авторизация". Хотя они могут звучать похоже и иногда используются как взаимозаменяемые, все же имеют разные значения и функции. Давайте разберемся в каждом из этих терминов, чтобы понять их разницу и важность.

1. Аутентификация

Определение: Аутентификация - это процесс проверки подлинности личности пользователя, системы или приложения. Она отвечает на вопрос: «Вы тот, за кого себя выдаете?»

Как это работает: Наиболее распространенной формой аутентификации является комбинация имени пользователя и пароля. Когда пользователь вводит эти учетные данные, система сравнивает их с сохраненными данными, чтобы подтвердить его личность. Другие методы включают биометрию (например, распознавание отпечатков пальцев или лица), OTP (одноразовые пароли) и аппаратные токены.

Примеры:

Ввод пароля для входа в учетную запись электронной почты.

Использование отпечатка пальца для разблокировки смартфона.

Получение SMS-кода для подтверждения личности на сайте банка.

2. Авторизация

Определение: После того как аутентификация установлена, авторизация определяет, что разрешено делать пользователю, системе или приложению. Она отвечает на вопрос: "Есть ли у вас разрешение на выполнение этого действия?".

Как это работает: Авторизация обычно управляется путем установки разрешений или ролей. Например, пользователю может быть предоставлен доступ к базе данных только для чтения, в то время как администратор имеет право как читать, так и изменять ее.

Примеры:

Обычный сотрудник может получить доступ к порталу компании, но не может вносить изменения в определенные важные документы. Администратор, напротив, может изменять, удалять и даже делиться этими документами.

В приложении для обмена файлами можно предоставить одним пользователям возможность просматривать файл, а другим - редактировать его.

Хотя и аутентификация, и авторизация играют важную роль в безопасности, они служат разным целям:

Аутентификация гарантирует, что вы общаетесь с нужным субъектом, подтверждая его личность.

Авторизация гарантирует, что у субъекта есть разрешения на выполнение определенных действий.

Что такое шлюз (Gateway)?

Также известный как API-шлюз (API Gateway) - это инструмент, который выступает в качестве посредника для запросов от клиентов, ищущих ресурсы на других серверах или сервисах. Многие организации используют шлюзы API в микросервисных архитектурах для управления и обеспечения безопасности сложных взаимодействий между микросервисами. Популярные API-шлюзы: Amazon API Gateway, Kong, Apigee и WSO2.

Если вы хотите узнать больше об API Gateway и его использовании, есть отличная статья:

https://medium.com/buildpiper/how-do-api-gateways-work-3b989fdcd751

Как защитить приложение?

Представим, что мы разрабатываем веб-приложение, состоящее из трех компонентов:

  • Одностраничное приложение (SPA), созданное с помощью таких фреймворков, как React или Angular.

  • Data Service обрабатывает все CRUD-операции, связанные с нашими доменами, и управляет подключением к базе данных.

  • Report Service получает данные из Data Service и инкапсулирует логику для генерации пользовательских отчетов.

Пример архитектуры приложения
Пример архитектуры приложения

Когда речь заходит о защите бэкенда, следует рассмотреть три основные стратегии:

1. Каждый микросервис выполняет собственную аутентификацию и авторизацию.

2. Шлюз занимается аутентификацией, а отдельные сервисы отвечают за авторизацию.

3. Шлюз обеспечивает как аутентификацию, так и авторизацию.

Каждый подход имеет свои сильные и слабые стороны. Для краткости в этой статье не будем вдаваться в подробности того, какая стратегия лучше. По правде говоря, определение наилучшего варианта требует всестороннего понимания системы, о которой идет речь.

В следующих разделах мы подробно рассмотрим вторую и третью стратегии, сосредоточившись на том, как NGINX и Keycloak могут эффективно использоваться для этих целей.

Что такое Keycloak?

Keycloak - это инструмент управления идентификацией и доступом (IAM) с открытым исходным кодом, разработанный компанией Red Hat. Он предоставляет расширенные функции, такие как SSO (технология единого входа в систему), Identity Brokering (посредничество в установлении личности) и Social Login (вход в систему через социальные сети), не требуя глубоких знаний в области безопасности.

Сочетание гибкости, широкого функционала и активной поддержки сообщества укрепило репутацию Keycloak в области управления идентификацией и доступом. Поскольку компании продолжают искать эффективные способы управления идентификационными данными без ущерба для безопасности, такие инструменты, как Keycloak, остаются незаменимыми.

Что такое Nginx?

Nginx был создан Игорем Сысоевым в 2002 году, а первый публичный релиз состоялся в 2004 году. Изначально разработанный для решения проблемы C10K (обработка 10 000 одновременных соединений), Nginx создавался с нуля для высокоэффективности и масштабируемости.

По своей сути Nginx - это веб-сервер. Но за прошедшие годы он превратился в нечто большее. Сегодня Nginx также может работать как обратный прокси-сервер, балансировщик нагрузки, прокси-сервер почты и даже HTTP-кэш.

Недостатки Nginx Plus

Nginx предлагает бесплатную версию своего программного обеспечения, но есть и платная версия премиум-класса, известная как Nginx Plus. В то время как Nginx Plus поддерживает единый вход с Keycloak, бесплатная версия, к сожалению, этого не делает. Это немного разочаровывает, учитывая популярность как Nginx, так и Keycloak. В TargPatrol мы используем оба инструмента, поэтому нам пришлось разработать метод, позволяющий им эффективно взаимодействовать друг с другом.

Модернизированная архитектура

Давайте внесем некоторые изменения в нашу архитектуру. Обновленная версия изображена на рисунке ниже.

Модернизированная архитектура приложения
Модернизированная архитектура приложения

Как показано на рисунке, служба Nginx теперь работает как API-шлюз. Его основная роль заключается в обеспечении аутентификации и авторизации. Тем временем служба Keycloak действует как наш сервер единого входа (SSO). DataService и ReportService обрабатывают запросы, поступающие от Nginx, но они больше не управляют аутентификацией и авторизацией для этих запросов.

Я не буду углубляться в интеграцию SPA с Keycloak в этой статье, поскольку существует множество исчерпывающих ресурсов по этой теме. Например, вы можете обратиться к этому руководству.

Как мы должны работать с аутентификацией в этом сценарии? Мы можем использовать nginx прокси аутентификации.

Пример nginx конфигурации:

http {

 ...

 location /auth {
    proxy_ssl_server_name on;
    proxy_pass  https://targpatrol-keycloak.local/realms/targpatrol-dev/protocol/openid-connect/userinfo;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Original-URI $request_uri;
 }

 location /data {
    auth_request /auth;
    auth_request_set $auth_status $upstream_status;
    error_page 401 = @handle_unauthorized;

    proxy_pass http://data-service.local;
    include /etc/nginx/common/ssl-headers.conf;

    js_content authService.authorize;
 }

 location /report {
    auth_request /auth;
    auth_request_set $auth_status $upstream_status;
    error_page 401 = @handle_unauthorized;

    proxy_pass http://report-service.local;
    include /etc/nginx/common/ssl-headers.conf;

    js_content authService.authorize;
 }
}

Что здесь происходит? Сначала мы определили /auth route, который проверяет наш запрос с помощью Keycloak. Мы просто отправляем запрос с Authorization header в Keycloak, запрашивая информацию о пользователе. Если в заголовке будет указан действительный токен, Keycloak ответит 200 OK, вернув текущие данные пользователя.

Маршруты для сервисов Data и Report содержат инструкцию 'auth_request'. Каждый раз, когда мы пытаемся получить к ним доступ, сначала будет отправлен запрос в Keycloak.

Хорошо, с процессом аутентификации мы разобрались, а как насчет авторизации? Для этого мы можем использовать функциональность nginx под названием ngx_http_js_module. Этот модуль позволяет выполнять JavaScript-код при запросе. Давайте разберемся, что такое 'js_content':

function extractPayload (token) {
  const tokenParts = token.split('.');
  const encodedPayload = tokenParts[1];
  const decodedPayload = Buffer.from(encodedPayload, 'base64').toString('utf-8');

  return JSON.parse(decodedPayload);
}


function authorize(request) {
  const token = request.headersIn.Authorization;

  if (!token || !(token.slice(0, 7) === 'Bearer ')) {
      return false;
  }

  const payload = extractPayload(token);
  const roles = payload['roles'];

  # request url
  const url = request.uri;


  # here we can compare url and roles
  # to allow or deny access 

  return false;
}

Этот файл называется authService.js. Он должен содержать функцию с именем authorize, поскольку в инструкции js_content мы ссылаемся на нее как на authService.authorize (в соответствии с форматом fileName.functionName). Здесь можно использовать обычный JavaScript. Сначала мы разбираем заголовок Authorization, чтобы извлечь токен Bearer, который был сгенерирован Keycloak, в объектную форму. Затем мы можем сопоставить роли с URL-адресом запроса, чтобы либо удовлетворить, либо отклонить запрос. Все довольно просто!

Одна из проблем этого подхода заключается в том, что каждый запрос направляется в Keycloak. Возможное решение - перейти от js_content в nginx к сервису Node.js (или другому подходящему языку). Этот сервис будет иметь интеграцию с Keycloak на стороне сервера. Отметим, что эту функцию поддерживает только Nginx Plus, а не бесплатная версия. Для получения более подробной информации вы можете обратиться к: Документация Keycloak. (Keycloak’s documentation)

Заключение

Подводя итог, можно сказать, что сочетание Nginx и Keycloak представляет собой убедительное решение для обеспечения безопасности шлюза. В то время как Nginx эффективно управляет и маршрутизирует веб-трафик, Keycloak обеспечивает надежную аутентификацию и авторизацию. Их совместные возможности создают укрепленный уровень защиты, повышая удобство работы пользователей и безопасность системы. Благодаря бесшовной интеграции этих инструментов компании могут не только повысить уровень защиты, но и оптимизировать работу. Поскольку цифровой ландшафт продолжает развиваться, такие инструменты, как Nginx и Keycloak, становятся незаменимыми для тех, кто ищет сбалансированное сочетание производительности, гибкости и безопасности.

Комментарии (10)


  1. shai_hulud
    08.12.2023 09:28

    А у вас в примере специально не проверяется заголовок и подпись JWT токена или это ошибка?


    1. BeQuick Автор
      08.12.2023 09:28

      Добрый день, если вы про js, то в этом нет необходимости, так как это проверяет Keycloak при auth_request /auth


      1. shai_hulud
        08.12.2023 09:28

        он каждый запрос к /data делает допольнительный запрос к keycloak? не кажется это расточительным, когда JWT используют именно для того что бы этого не делать.

        Я понимаю, что это перевод. Но вопросики всегда могут быть к тому кто перевел, ведь он выбирает качество материала.


        1. ndrwK
          08.12.2023 09:28

          Это, например, для проверки, что токен не отозван на keycloak.


        1. BeQuick Автор
          08.12.2023 09:28

          В статье это упоминается, что nginx free не поддерживает интеграцию с keycloak.

          На самом деле ручная проверка токена в коде ( signature, exp, iss & etc ) даст мнимое улучшение производительности по сравнению с отправкой в keycloak, который сделает это сам. Плюс возможен кейс, когда токен пользователя отозван ( например, закрыли доступ, поменяли атрибуты или еще что-то). Тогда без проверки на уровне кейклока это не решить.

          Либо же выпускать короткоживущие токены, например, на 1 мин, и забить на лаг в 1 мин в таких моментах. Но с точки зрения производительности - это самая большая нагрузка на auth service, так как именно генерация токена самая сложная операция.


          1. shai_hulud
            08.12.2023 09:28

            На самом деле ручная проверка токена в коде ( signature, exp, iss & etc ) даст мнимое улучшение производительности по сравнению с отправкой в keycloak, который сделает это сам.

            Это очень смело утверждать что посчитать SHA-1/SHA-256 хеш либо RSA подпись == по перфомансу с открытием соединения, отправкой данных, подсчетом того-же SHA хеша и парсингом ответа.

            Я бы сказал что разница в порядок, а может и в порядки.

            Отзыв JWT токенов скорее это неправильный дизайн чем кейс.

            Генерация токена настолько дорогая, насколько и проверка - посчитать хеш и чуток JSON сериализации. Я реализовывал всё из списка, там ничего "тяжелого" по перформансу нет.


  1. BcTpe4HbIu
    08.12.2023 09:28
    +1

    Очень сомневаюсь что KeyCloak переживет сколько нибудь существенную нагрузку в таком решении.
    Для чего вообще руками ходить в KC и руками же парсить токен, если уже давно придумали решения вроде oauth2-proxy? Он и токен проверит без похода в KC и в заголовки положит содержимое из токена (имя, роли, почту) и пользователя отправит на страницу аутентификации если токен не верный. Плюс сам может сессию продлить через refresh токен.


  1. keylase
    08.12.2023 09:28

    В целом можно без nginx обойтись

    https://github.com/oneconcern/keycloak-gatekeeper


    1. BeQuick Автор
      08.12.2023 09:28
      +1

      Последний релиз в 2021 году. Похоже, что больше не поддерживается.


      1. heejew
        08.12.2023 09:28

        https://gogatekeeper.github.io/ (https://github.com/gogatekeeper/gatekeeper) стоит смотреть, он поддерживается.