Перейти к содержанию

phantom-token: Модуль Phantom Token для NGINX

Установка на Debian/Ubuntu

Эти документы относятся к APT пакету nginx-module-phantom-token, предоставляемому репозиторием GetPageSpeed Extras.

  1. Настройте APT репозиторий, как описано в настройке APT репозитория.
  2. Установите модуль:
sudo apt-get update
sudo apt-get install nginx-module-phantom-token
Показать дистрибутивы и архитектуры
| Дистрибутив | Версия            | Компонент  | Архитектуры    |
|-------------|-------------------|------------|-----------------|
| debian      | bookworm          | main       | amd64, arm64    |
| debian      | bookworm-mainline | main       | amd64, arm64    |
| debian      | trixie            | main       | amd64, arm64    |
| debian      | trixie-mainline   | main       | amd64, arm64    |
| ubuntu      | focal             | main       | amd64, arm64    |
| ubuntu      | focal-mainline    | main       | amd64, arm64    |
| ubuntu      | jammy             | main       | amd64, arm64    |
| ubuntu      | jammy-mainline    | main       | amd64, arm64    |
| ubuntu      | noble             | main       | amd64, arm64    |
| ubuntu      | noble-mainline    | main       | amd64, arm64    |

Quality Availability

Модуль NGINX, который интроспектирует токены доступа в соответствии с RFC 7662, производя "призрачный токен", который можно пересылать на серверы API и веб-сервисы. Узнайте больше о подходе призрачного токена.

Этот модуль при включении фильтрует входящие запросы, отказывая в доступе тем, которые не имеют действительного токена доступа OAuth, представленного в заголовке Authorization. Из этого заголовка извлекается access_token и интерпретируется с использованием сконфигурированного конечного пункта. Curity Identity Server отвечает на этот запрос в соответствии со стандартом. Для активного токена доступа тело ответа Curity Identity Server содержит JWT, который заменяет токен доступа в заголовке запроса, пересылаемом NGINX на сервер. Если токен недействителен или отсутствует, запрос на сервер не выполняется, и вызывающему возвращается ошибка 401, неавторизован. Этот поток показан на следующей диаграмме:

Интеграция NGINX / Curity

Начальные вызовы приложением (веб или нативным) выполняются с использованием OpenID Connect (OIDC). Важно отметить, что токен, который выдается, является непрозрачным токеном доступа. Это GUID или UUID или несколько случайных байтов; в этом токене нет данных, связанных с личностью. Это призрак фактических данных пользователя, откуда и название -- призрачный токен. Приложение представляет токен шлюзу NGINX в соответствии с спецификацией Использование токенов Bearer (т.е. RFC 6750). Этот стандарт утверждает, что приложение должно отправить призрачный токен в заголовке запроса Authorization.

Как только сервер NGINX получает токен доступа, этот модуль активируется. Используя конфигурацию, подобную приведенной ниже, этот модуль будет опрашивать запрос, находить токен и выполнять побочный вызов к Curity Identity Server. Этот запрос веб-сервиса будет выполнен с использованием стандарта Интроспекция токена (RFC 7662) с типом Accept, установленным на application/jwt (как определено в RFC 7519). Это приведет к тому, что Curity Identity Server вернет не JSON, а просто JWT. Затем модуль пересылает JWT токен на серверные API и микросервисы.

Если модуль также настроен на кэширование результатов вызова к Curity Identity Server (что должно быть сделано для производственных случаев), призрачный токен будет использоваться в качестве ключа кэша для соответствующего JWT токена. Это устранит необходимость в последующих вызовах к Curity Identity Server до тех пор, пока он сообщает модулю NGINX, что может кэшировать JWT.

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

Директивы конфигурации модуля

Версия 2.0 внесла СУЩЕСТВЕННОЕ ИЗМЕНЕНИЕ в использование обновленных директив конфигурации.\ Смотрите предыдущие инструкции по конфигурации для настройки более старых релизов.

Обязательные директивы конфигурации

Директивы в этом подразделе обязательны; если какая-либо из них опущена, модуль будет отключен.

phantom_token

Синтаксис: phantom_token on | off

По умолчанию: off

Контекст: location

phantom_token_introspection_endpoint

Синтаксис: phantom_token_introspection_endpoint string

По умолчанию:

Контекст: location

Дополнительные директивы конфигурации

Следующие директивы являются необязательными и не требуют настройки.

phantom_token_realm

Синтаксис: phantom_token_realm string

По умолчанию: api

Контекст: location

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

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

location / {
   ...
   phantom_token_realm "myGoodRealm";
}   

phantom_token_scopes

Синтаксис: phantom_token_scopes string

По умолчанию:

Контекст: location

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

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

location / {
   ...
   phantom_token_scopes "scope_a scope_b scope_c";
}

phantom_token_scope

Синтаксис: phantom_token_scope string

По умолчанию:

Контекст: location

Массив областей, о которых сервер должен сообщить клиенту, что они необходимы, когда он не предоставляет токен доступа. Если phantom_token_scopes также настроен, это значение будет иметь приоритет.

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

location / {
   ...
   phantom_token_scope "scope_a";
   phantom_token_scope "scope_b";
   phantom_token_scope "scope_c";
}

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

Загрузка модуля

Если модуль загружен из GitHub или скомпилирован как общая библиотека (по умолчанию) и не был явно скомпилирован в NGINX, его нужно будет загрузить с помощью директивы load_module. Это нужно сделать в главной части конфигурации NGINX:

load_module modules/ngx_curity_http_phantom_token_module.so;

Файл может иметь абсолютный или относительный путь. Если он не абсолютный, он должен быть относительно корневого каталога NGINX.

Параметры NGINX для конечной точки интерпретации

Вы также должны настроить следующие параметры NGINX для подс запроса интерпретации:

location curity {
    internal;
    proxy_pass_request_headers off;
    proxy_set_header Accept "application/jwt";
    proxy_set_header Content-Type "application/x-www-form-urlencoded";
    proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";
    proxy_pass "https://curity.example.com/oauth/v2/oauth-introspect";
}
Параметр интроспекции Описание
internal Предотвращает внешнюю доступность конечной точки интроспекции.
proxy_pass_request_headers Установите в off, чтобы избежать использования заголовков основного запроса в подс запросе на интроспекцию.
Accept header Настроить фиксированное значение application/jwt.
Content-Type header Настроить фиксированное значение application/x-www-form-urlencoded.
Authorization header Настроить базовую учетную запись с идентификатором клиента и секретом клиента для интроспекции.

Чтобы получить базовую учетную запись, объедините идентификатор клиента, двоеточие и секрет клиента, а затем закодируйте их в base64. Следующая команда дает примеры.

echo -n "my_client_id:my_client_secret" | base64

Простая конфигурация

Следующая конфигурация может быть использована в демонстрационных или рабочих средах, где обратный прокси NGINX находится на одном хосте с Curity Identity Server:

server {
    location /api {
        phantom_token on;
        phantom_token_introspection_endpoint curity;
        proxy_pass https://example.com/api;
    }

    location curity {
        internal;
        proxy_pass_request_headers off;
        proxy_set_header Accept "application/jwt";
        proxy_set_header Content-Type "application/x-www-form-urlencoded";
        proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";
        proxy_pass "https://curity.example.com/oauth/v2/oauth-introspect";
    }
}

Сложная конфигурация

Следующая конфигурация более сложная, где обратный прокси NGINX находится на отдельном хосте от Curity Identity Server:

server {
    server_name server1.example.com;n
    location /api {
        phantom_token on;
        phantom_token_introspection_endpoint curity;
        phantom_token_realm "myGoodAPI";
        phantom_token_scopes "scope_a scope_b scope_c";
        proxy_pass https://example.com/api;
    }

    location curity {
        internal;
        proxy_pass_request_headers off;
        proxy_set_header Accept "application/jwt";
        proxy_set_header Content-Type "application/x-www-form-urlencoded";
        proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";
        proxy_pass "https://server2.example.com:8443/oauth/v2/oauth-introspect";
    }
}

server {
    listen 8443;
    server_name server2.example.com;
    location / {
        proxy_pass "https://curity.example.com";
    }
}

Более сложная конфигурация с отдельными серверами и кэшированием

Этот модуль использует встроенную директиву NGINX proxy_cache. Чтобы иметь возможность кэшировать запросы, сделанные к конечной точке интерпретации, кроме указания proxy_cache_path в контексте http и proxy_cache в контексте location, вам нужно будет добавить следующие 3 директивы в контекст location конечной точки интерпретации.

  • proxy_cache_methods POST; Запросы POST не кэшируются по умолчанию.
  • proxy_cache_key $request_body; Ключ кэша связан с access_token, отправленным в исходном запросе. Разные запросы с одним и тем же access_token достигают одного и того же кэша.
  • proxy_ignore_headers Set-Cookie; NGINX не будет кэшировать ответ, если заголовок Set-Cookie не игнорируется.
http {
    proxy_cache_path /path/to/cache/cache levels=1:2 keys_zone=my_cache:10m max_size=10g
                     inactive=60m use_temp_path=off;
    server {
        server_name server1.example.com;
        location /api {
            phantom_token on;
            phantom_token_introspection_endpoint curity;
            phantom_token_scopes "scope_a scope_b scope_c";
            phantom_token_realm "myGoodAPI";
            proxy_pass https://example.com/api;
        }

        location curity {
            internal;            
            proxy_pass_request_headers off;
            proxy_set_header Accept "application/jwt";
            proxy_set_header Content-Type "application/x-www-form-urlencoded";
            proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";

            proxy_cache_methods POST;
            proxy_cache my_cache;
            proxy_cache_key $request_body;
            proxy_ignore_headers Set-Cookie;

            proxy_pass "https://server2.example.com:8443/oauth/v2/oauth-introspect";
        }
    }

    server {
        listen 8443;
        server_name server2.example.com;
        location / {
            proxy_pass "https://curity.example.com";
        }
    }
}   

Конфигурация без кэширования

Рекомендуется кэшировать результаты вызова к Curity Identity Server, чтобы избежать триггеров запроса introspection для каждого API запроса. Ако вы хотите отключить кэширование, вам следует увеличить значение по умолчанию для proxy_buffer_size, чтобы гарантировать, что модуль может читать большие JWT. Сделайте это, обновляя конфигурацию запроса интроспекции, как в следующем примере.

http {
    server {
        server_name server1.example.com;
        location /api {
            phantom_token on;
            phantom_token_introspection_endpoint curity;
            phantom_token_scopes "scope_a scope_b scope_c";
            phantom_token_realm "myGoodAPI";
            proxy_pass https://example.com/api;
        }

        location curity {
            internal;
            proxy_pass_request_headers off;
            proxy_set_header Accept "application/jwt";
            proxy_set_header Content-Type "application/x-www-form-urlencoded";
            proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";

            proxy_ignore_headers Set-Cookie;
            proxy_buffer_size 16k;
            proxy_buffers 4 16k;

            proxy_pass "https://server2.example.com:8443/oauth/v2/oauth-introspect";
        }
    }

    server {
        listen 8443;
        server_name server2.example.com;
        location / {
            proxy_pass "https://curity.example.com";
        }
    }
}   

Дополнительная информация

Для получения дополнительной информации о Curity Identity Server, его возможностях и о том, как использовать его для выдачи призрачных токенов для микросервисов, посетите curity.io. Для получения основополагающей информации о том, как использовать Curity Identity Server для защиты доступа к API, смотрите наши ресурсы по безопасности API.