Validating JWT with Istio Envoy
🌐 This document is available in both English and Ukrainian. Use the language toggle in the top right corner to switch between versions. |
JWT-token (eng. JSON Web Token) — a secure data exchange format that is most commonly used to transfer sensitive information or authorize user HTTP requests. The JWT token can be signed with a secret (using the HMAC algorithm) or a public/private key pair using the RSA or ECDSA algorithms. Standardized in RFC 7519. |
1. Introduction
JWT token is usually sent as a Bearer token in the header of a custom HTTP request. Before the request reaches the microservice, Istio Envoy can:
-
Check the JWT token inside the HTTP header of the request for correctness and compliance with the established rules
-
Pass traffic with the correct JWT token to the microservice
-
Do not allow traffic with an incorrect JWT token.
2. Configuring rules for token validation
In general, the configuration of Envoy proxy rules consists of creating the following API objects in the OpenShift cluster for each service that performs user authorization:
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
The configuration consists of several fields:
-
forwardOriginalToken
— the token from the initial request will be forwarded; -
fromHeaders
— header name with token; -
`issuer' — the provider that generated the token;
-
jwksUri
— URL of the public key of the provider set to verify the signature of the JWT token; -
selector
— the selector determines to which microservice the configuration should be applied.
To reject requests without valid JWT tokens, you need to add an authorization policy with a rule specifying the DENY' action for requests without a `RequestPrincipal', shown as `notRequestPrincipals: ["*"]
in the following example.
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: ["*"]
Thus, the AuthorizationPolicy
rule rejects requests without valid JWT tokens.
Next, the Istio Envoy proxy receives the configuration from istiod in the following order:
-
When starting a new pod, using the ``MutationWebhooks'' mechanism, an additional Envoy proxy container is added to it, which is responsible for intercepting all traffic in front of the main microservice container.
-
During initialization, the Envoy-proxy receives the necessary configuration from
istiod
, which contains the following information, which was specified in the previous step when creating theRequestAuthentication
object:
...
{
"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 which will be received from the 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"
}
...
-
In the next step, the Envoy proxy, using the URL from the
issuer
field, receives JWKS with a public key from the JWT token generation microservice (Keycloak) and writes it in thelocal_jwks
field. By default, the duration after which the cached public key will expire is for 2 minutes. -
Next, another additional configuration is performed and soon the Envoy proxy is ready to process requests.
3. Token validation on the Envoy proxy side
Every request that comes to the microservice is intercepted by the Envoy proxy and checked for compliance specified in RequestAuthentication
, namely:
-
Checking if the JWT token is present at all
-
Getting the JWT token from the header
-
Validating the JWT token using the public key obtained earlier from the URL.
The following is an example of Envoy logs:
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