Валідація JWT-токенів за допомогою Istio Envoy
JWT-токен (англ. JSON Web Token) — формат безпечного обміну даними, який використовується найчастіше для передачі чутливої інформації або авторизації HTTP-запитів користувачів. JWT-токен може бути підписаний секретом (за допомогою HMAC алгоритму) або пар відкритий/приватний ключ використовуючи алгоритми RSA або ECDSA. Стандартизований у RFC 7519. |
Вступ
JWT-токен зазвичай відправляється як Bearer токен у заголовку користувацького HTTP запиту. Перед тим як запит досягне мікросервісу, Istio Envoy може:
-
Перевірити JWT-токен всередині заголовку HTTP запиту на коректність та відповідність встановленим правилам
-
Пропускати трафік з коректним JWT-токеном у мікросервіс
-
Не пропускати трафік з не коректним JWT-токеном.
1. Конфігурація правил для валідації токенів
Загалом, конфігурація Envoy проксі правил складається зі створення наступних API обʼєктів у OpenShift кластері для кожного сервісу, який виконує авторизацію користувачів:
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: request-auth-digital-signature-ops
spec:
jwtRules:
- forwardOriginalToken: true
fromHeaders:
- name: X-Access-Token
issuer: >-
https://platform-keycloak.apps.cicd2.mdtu-ddm.projects.epam.com/auth/realms/mdtu-ddm-edp-cicd-platform-sit-officer-portal
jwksUri: >-
https://platform-keycloak.apps.cicd2.mdtu-ddm.projects.epam.com/auth/realms/mdtu-ddm-edp-cicd-platform-sit-officer-portal/protocol/openid-connect/certs
selector:
matchLabels:
app: digital-signature-ops
Конфігурація складається з декількох полів:
-
forwardOriginalToken
— токен з початкового запиту буде переданий далі; -
fromHeaders
— імʼя заголовока з токеном; -
issuer
— постачальник який сгенерував токен; -
jwksUri
— URL-адреса відкритого ключа постачальника, встановленого для перевірки підпису JWT-токена; -
selector
— селектор визначає до якого мікросервісу треба застосувати конфігурацію.
Щоб відхилити запити без коректних JWT-токенів, треба додати політику авторизації з правилом, що вказує дію DENY
для запитів без RequestPrincipal
, що відображаються як notRequestPrincipals: ["*"]
у наступному прикладі.
apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
name: digital-signature-ops
spec:
selector:
matchLabels:
app: digital-signature-ops
action: DENY
rules:
- from:
- source:
notRequestPrincipals: ["*"]
Таким чином, правило AuthorizationPolicy
відхиляє запити без коректних JWT-токенів.
Далі Istio Envoy проксі отримує конфігурацію з istiod у наступному порядку:
-
При старті нової поди, за допомогою механізму
MutationWebhooks
, у неї додається додатковий контейнер Envoy проксі, який відповідає за перехоплення усього трафіку перед основним контейнером мікросервісу. -
При ініціалізації Envoy-проксі отримує необхідну конфігурацію від
istiod
, яка містить у собі наступну інформацію, яку було задано на минулому кроці при створенніRequestAuthentication
обʼєкту:
...
{
"name": "envoy.filters.http.jwt_authn",
"typed_config": {
"@type": "type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication",
"providers": {
"origins-0": {
"issuer": "https://platform-keycloak.apps.cicd2.mdtu-ddm.projects.epam.com/auth/realms/mdtu-ddm-edp-cicd-sk-test-qa-admin",
"local_jwks": {
"inline_string": "<JWKS який буде отримано від issuer>"
},
"forward": true,
"from_headers": [{
"name": "X-Access-Token"
}],
"payload_in_metadata": "https://platform-keycloak.apps.cicd2.mdtu-ddm.projects.epam.com/auth/realms/mdtu-ddm-edp-cicd-sk-test-qa-admin"
}
...
-
На наступному кроці Envoy проксі використовуючи URL з поля
issuer
отримує JWKS з відкритим ключем від мікросервісу генерації JWT-токенів (Keycloak) та записує його уlocal_jwks
поле. За замовчуванням, тривалість, після якої термін дії кешованого відкритого ключа закінчиться дорівнює 2 хвилинам. -
Далі виконується інша додаткова конфігурація та невдовзі Envoy проксі готовий обробляти запити.
2. Валідація токенів на стороні Envoy проксі
Кожний запит який надходить на мікросервіс перехоплюється Envoy проксі та перевіряється на відповідність вказану у RequestAuthentication
, а саме:
-
Перевірка чи присутній JWT-токен взагалі
-
Отримання JWT-токена з заголовку
-
Перевірка JWT-токена за допомогою відкритого ключа отриманого раніше з URL.
Далі наведений приклад Envoy логів:
2021-12-24T12:48:45.867291Z debug envoy http [C8][S790218861205563098] request end stream 2021-12-24T12:48:45.867334Z debug envoy jwt Called Filter : setDecoderFilterCallbacks 2021-12-24T12:48:45.867376Z debug envoy jwt Called Filter : decodeHeaders 2021-12-24T12:48:45.867393Z debug envoy jwt Prefix requirement '/' matched. 2021-12-24T12:48:45.867400Z debug envoy jwt extract x-access-token 2021-12-24T12:48:45.867447Z debug envoy jwt Jwt authentication completed with: OK 2021-12-24T12:48:45.867497Z debug envoy filter AuthenticationFilter::decodeHeaders with config policy { peers { mtls { mode: PERMISSIVE } } origins { jwt { issuer: "https://platform-keycloak.apps.cicd2.mdtu-ddm.projects.epam.com/auth/realms/mdtu-ddm-edp-cicd-sk-test-qa-admin" } } origins { jwt { issuer: "https://platform-keycloak.apps.cicd2.mdtu-ddm.projects.epam.com/auth/realms/mdtu-ddm-edp-cicd-sk-test-qa-citizen-portal" } } origins { jwt { issuer: "https://platform-keycloak.apps.cicd2.mdtu-ddm.projects.epam.com/auth/realms/mdtu-ddm-edp-cicd-sk-test-qa-external-system" } } origins { jwt { issuer: "https://platform-keycloak.apps.cicd2.mdtu-ddm.projects.epam.com/auth/realms/mdtu-ddm-edp-cicd-sk-test-qa-officer-portal" } } origin_is_optional: true principal_binding: USE_ORIGIN } skip_validate_trust_domain: true 2021-12-24T12:48:45.867507Z debug envoy filter [C8] validateX509 mode PERMISSIVE: ssl=false, has_user=false 2021-12-24T12:48:45.867616Z debug envoy rbac checking request: requestedServerName: , sourceIP: 10.128.32.10:55660, directRemoteIP: 10.128.32.10:55660, remoteIP: 10.128.32.10:55660,localAddress: 10.130.18.67:8080, ssl: none, headers: ':authority', '10.130.18.67:8080' 2021-12-24T12:48:45.867628Z debug envoy rbac enforced allowed, matched policy none