Валідація 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