Плагины аутентификации: Key Auth, JWT, OAuth2, OIDC, LDAP
Kong предоставляет множество плагинов для аутентификации (кто пользователь?) и авторизации (что ему разрешено?).
Проблема: Нужна простая аутентификация по API-ключу без сложных протоколов.
Решение: Плагин key-auth проверяет наличие API-ключа и связывает запрос с Consumer.
# Включение плагина глобально
curl -X POST http://localhost:8001/plugins \
--data "name=key-auth"
# Или на конкретный Route
curl -X POST http://localhost:8001/routes/api-route/plugins \
--data "name=key-auth"# Создание Consumer
curl -X POST http://localhost:8001/consumers \
--data "username=mobile-app"
# Создание API-ключа для Consumer
curl -X POST http://localhost:8001/consumers/mobile-app/key-auth \
--data "key=secret-key-123"Проблема: Клиент должен передать API-ключ в запросе.
Решение: Ключ передаётся в заголовке, query-параметре или теле запроса.
# В заголовке (по умолчанию)
curl http://localhost:8000/api/users \
-H "apikey: secret-key-123"
# В query-параметре
curl http://localhost:8000/api/users?apikey=secret-key-123
# В теле запроса (POST/PUT)
curl -X POST http://localhost:8000/api/users \
-d "apikey=secret-key-123" \
-d "name=John"Ответы Kong:
401 Unauthorized: No API key found in request401 Unauthorized: Invalid API keyПроблема: Нужно изменить имя параметра или место поиска ключа.
Решение: Конфигурация плагина.
curl -X POST http://localhost:8001/routes/api-route/plugins \
--data "name=key-auth" \
--data "config.key_names[]=X-API-Key" \
--data "config.key_in_header=true" \
--data "config.key_in_query=false" \
--data "config.key_in_body=false" \
--data "config.hide_credentials=true"Параметры:
key_names — имена параметров/заголовков для поиска ключаkey_in_header — искать в заголовках (по умолчанию true)key_in_query — искать в query-параметрах (по умолчанию true)key_in_body — искать в теле запроса (по умолчанию true)hide_credentials — удалять ключ из запроса перед проксированием (по умолчанию false)Проблема: Нужна Stateless аутентификация с токенами, которые можно верифицировать без обращения к базе данных.
Решение: Плагин jwt проверяет подпись JWT-токена и извлекает claims.
# Включение плагина
curl -X POST http://localhost:8001/plugins \
--data "name=jwt"Проблема: Consumer нужен JWT credentials для генерации токенов.
Решение: Создание credentials с алгоритмом подписи.
# Создание Consumer
curl -X POST http://localhost:8001/consumers \
--data "username=mobile-app"
# Создание JWT credentials с HS256
curl -X POST http://localhost:8001/consumers/mobile-app/jwt \
--data "algorithm=HS256" \
--data "key=mobile-app-key" \
--data "secret=my-super-secret-key"Важно: key — это iss (issuer) или kid (key id) в токене. secret — секретный ключ для подписи.
# Генерация ключей
openssl genrsa -out jwt_private.key 2048
openssl rsa -in jwt_private.key -pubout -out jwt_public.key
# Создание JWT credentials с RS256
curl -X POST http://localhost:8001/consumers/mobile-app/jwt \
--data "algorithm=RS256" \
--data "key=mobile-app-key" \
--data "rsa_public_key=$(cat jwt_public.key)"Важно: Приватный ключ хранится у авторизационного сервера (генерирует токены), публичный — в Kong (верифицирует токены).
Проблема: Клиенту нужен валидный JWT токен.
Решение: Генерация токена с правильной структурой.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJtb2JpbGUtYXBwLWtleSIsImV4cCI6MTcwMDAwMDAwMH0.signature
↓ ↓ ↓
Header (алгоритм) Payload (claims) Signature
import jwt
import time
secret = "my-super-secret-key"
payload = {
"iss": "mobile-app-key", # Должен совпадать с 'key' в credentials
"iat": int(time.time()),
"exp": int(time.time()) + 3600, # 1 час
"sub": "user-123", # Идентификатор пользователя
"name": "John Doe"
}
token = jwt.encode(payload, secret, algorithm="HS256")
print(token)# Для RS256
HEADER='{"alg":"RS256","typ":"JWT"}'
PAYLOAD='{"iss":"mobile-app-key","exp":1700000000,"sub":"user-123"}'
HEADER_B64=$(echo -n $HEADER | openssl base64 -e -A)
PAYLOAD_B64=$(echo -n $PAYLOAD | openssl base64 -e -A)
SIGNATURE=$(echo -n "$HEADER_B64.$PAYLOAD_B64" | \
openssl dgst -sha256 -sign jwt_private.key | \
openssl base64 -e -A | tr '+/' '-_' | tr -d '=')
TOKEN="$HEADER_B64.$PAYLOAD_B64.$SIGNATURE"
echo $TOKEN# В заголовке Authorization (рекомендуется)
curl http://localhost:8000/api/users \
-H "Authorization: Bearer <jwt-token>"
# В query-параметре
curl http://localhost:8000/api/users?jwt=<jwt-token>Проблема: Нужно проверять дополнительные claims (например, expiration).
Решение: Конфигурация плагина jwt.
curl -X POST http://localhost:8001/plugins \
--data "name=jwt" \
--data "config.key_claim_name=iss" \
--data "config.claims_to_verify=exp" \
--data "config.secret_is_base64=false" \
--data "config.run_on_preflight=true"Параметры:
key_claim_name — claim, который содержит identifier (по умолчанию iss)claims_to_verify — список claims для проверки (exp — expiration)secret_is_base64 — если secret в base64run_on_preflight — проверять JWT для OPTIONS запросовПроблема: Нужно связать JWT токен с Consumer в Kong.
Решение: Kong автоматически извлекает Consumer по claim iss (или key_claim_name).
# Если токен содержит {"iss": "mobile-app-key"}
# Kong найдёт JWT credentials с key="mobile-app-key"
# и свяжет запрос с Consumer "mobile-app"Для кастомной логики используйте claim sub:
# Токен содержит {"sub": "user-123"}
# Можно использовать в кастомном плагине:
local credential = kong.client.get_credential()
local user_id = credential.sub -- "user-123"Проблема: Нужна поддержка OAuth2 flow для сторонних приложений.
Решение: Плагин oauth2 предоставляет OAuth 2.0 сервер авторизации.
curl -X POST http://localhost:8001/plugins \
--data "name=oauth2" \
--data "config.scopes[]=read" \
--data "config.scopes[]=write" \
--data "config.enable_authorization_code=true" \
--data "config.enable_client_credentials=true" \
--data "config.enable_password_grant=true" \
--data "config.enable_implicit_grant=false" \
--data "config.token_expiration=7200" \
--data "config.mandatory_scope=true"Grant types:
authorization_code — для веб-приложений (redirect на callback URL)client_credentials — для machine-to-machine (нет пользователя)password — для trusted clients (пользователь вводит credentials)implicit — устарел, не рекомендуется (токен в URL)# Создание Consumer
curl -X POST http://localhost:8001/consumers \
--data "username=web-app"
# Создание OAuth2 credentials
curl -X POST http://localhost:8001/consumers/web-app/oauth2 \
--data "name=My Web App" \
--data "client_id=web-app-client-id" \
--data "client_secret=web-app-secret" \
--data "redirect_uris[]=https://app.example.com/callback"Проблема: Веб-приложение должно получить токен через redirect.
Решение: OAuth2 authorization code flow.
GET /oauth2/authorize?
client_id=web-app-client-id&
response_type=code&
scope=read write&
redirect_uri=https://app.example.com/callback
Ответ: Kong перенаправляет на redirect_uri с кодом:
https://app.example.com/callback?code=AUTH_CODE
curl -X POST http://localhost:8000/oauth2/token \
-d "grant_type=authorization_code" \
-d "code=AUTH_CODE" \
-d "client_id=web-app-client-id" \
-d "client_secret=web-app-secret" \
-d "redirect_uri=https://app.example.com/callback"Ответ:
{
"access_token": "ACCESS_TOKEN",
"token_type": "bearer",
"expires_in": 7200,
"refresh_token": "REFRESH_TOKEN",
"scope": "read write"
}curl http://localhost:8000/api/users \
-H "Authorization: Bearer ACCESS_TOKEN"Проблема: Machine-to-machine аутентификация без пользователя.
Решение: OAuth2 client credentials grant.
curl -X POST http://localhost:8000/oauth2/token \
-d "grant_type=client_credentials" \
-d "client_id=web-app-client-id" \
-d "client_secret=web-app-secret" \
-d "scope=read"Ответ:
{
"access_token": "ACCESS_TOKEN",
"token_type": "bearer",
"expires_in": 7200
}Проблема: Нужна аутентификация через внешний провайдер (Google, Auth0, Okta).
Решение: Плагин openid-connect для интеграции с OIDC провайдерами.
Проблема: Нужно подключить Kong к внешнему OIDC провайдеру.
Решение: Конфигурация плагина с issuer и credentials.
curl -X POST http://localhost:8001/plugins \
--data "name=openid-connect" \
--data "config.issuer=https://accounts.google.com" \
--data "config.client_id=your-google-client-id" \
--data "config.client_secret=your-google-client-secret" \
--data "config.redirect_uri=https://api.example.com/callback" \
--data "config.scopes=openid profile email" \
--data "config.response_type=code" \
--data "config.token_endpoint_auth_method=client_secret_post" \
--data "config.logout_query_arg_name=logout" \
--data "config.logout_redirect_uri=https://app.example.com/logged-out"Проблема: Бэкенд должен знать, кто пользователь.
Решение: Kong добавляет заголовки с claims из ID token.
# Заголовки, которые добавляет Kong:
X-Consumer-Username: <sub из ID token>
X-Consumer-Id: <consumer id в Kong>
Authorization: Bearer <access token>Для кастомных заголовков:
curl -X POST http://localhost:8001/plugins \
--data "name=openid-connect" \
--data "config.authenticated_user_claim=email" \
--data "config.set_access_token_header=true" \
--data "config.set_id_token_header=true" \
--data "config.set_refresh_token_header=false"Проблема: Нужна аутентификация через корпоративный LDAP/Active Directory.
Решение: Плагин ldap-auth.
curl -X POST http://localhost:8001/plugins \
--data "name=ldap-auth" \
--data "config.ldap_host=ldap.example.com" \
--data "config.ldap_port=389" \
--data "config.base_dn=dc=example,dc=com" \
--data "config.attribute=uid" \
--data "config.start_tls=false" \
--data "config.verify_ldap_host=true" \
--data "config.header_type=Basic"# Basic Auth с LDAP credentials
curl http://localhost:8000/api/users \
-H "Authorization: Basic $(echo -n 'username:password' | base64)"Kong проверяет credentials против LDAP сервера.
Проблема: Нужно ограничить доступ к API для определённых групп пользователей.
Решение: Плагин acl работает в паре с плагином аутентификации.
# Включение плагина acl
curl -X POST http://localhost:8001/routes/admin-route/plugins \
--data "name=acl" \
--data "config.allow[]=admin" \
--data "config.allow[]=manager" \
--data "config.hide_groups=true"# Создание Consumer
curl -X POST http://localhost:8001/consumers \
--data "username=john"
# Добавление в группу admin
curl -X POST http://localhost:8001/consumers/john/acl \
--data "group=admin"
# Добавление в группу manager
curl -X POST http://localhost:8001/consumers/jane/acl \
--data "group=manager"1. Пользователь аутентифицируется (key-auth/jwt/oauth2)
↓
2. Kong извлекает Consumer
↓
3. Плагин acl проверяет, состоит ли Consumer в разрешённых группах
↓
4. Если да → запрос проксируется
Если нет → 403 Forbidden
Проблема: Нужна поддержка нескольких методов аутентификации.
Решение: Применение нескольких плагинов к одному Route.
# Key-auth для внутренних сервисов
curl -X POST http://localhost:8001/routes/internal/plugins \
--data "name=key-auth"
# JWT для мобильных приложений
curl -X POST http://localhost:8001/routes/mobile/plugins \
--data "name=jwt"
# OAuth2 для партнёров
curl -X POST http://localhost:8001/routes/partners/plugins \
--data "name=oauth2"
# Глобальный ACL для админских endpoints
curl -X POST http://localhost:8001/routes/admin/plugins \
--data "name=acl" \
--data "config.allow[]=admin"claims_to_verify=exp — проверка expiration# Проверка количества выданных токенов
curl http://localhost:8001/oauth2/tokens
# Отзыв токена
curl -X DELETE http://localhost:8001/oauth2/tokens/{token-id}Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.