Traefik plugin for verifying JSON Web Tokens (JWT). Supports public keys, certificates or JWKS endpoints. Supports RSA, ECDSA and symmetric keys. Supports Open Policy Agent (OPA) for additional authorization checks.
Features:
The plugin needs to be configured in the Traefik static configuration before it can be used.
Tested with official Traefik chart version 26.0.0.
The following snippet should be added to values.yaml
:
experimental:plugins:jwt:moduleName: github.com/traefik-plugins/traefik-jwt-pluginversion: v0.7.1
traefik \--experimental.plugins.jwt.moduleName=github.com/traefik-plugins/traefik-jwt-plugin \--experimental.plugins.jwt.version=v0.7.1
The plugin currently supports the following configuration settings: (all fields are optional)
Name | Description |
---|---|
OpaUrl | URL of OPA policy document requested for decision, e.g. http://opa:8181/v1/data/example. |
OpaAllowField | Field in the JSON result which contains a boolean, indicating whether the request is allowed or not. Default allow . |
OpaBody | Boolean indicating whether the request body should be added to the OPA input. |
OpaDebugMode | Set the opa response in the http response body when the request isn't allowed otherwise the response body is forbidden |
PayloadFields | The field-name in the JWT payload that are required (e.g. exp ). Multiple field names may be specified (string array) |
Required | Is Authorization header with JWT token required for every request. |
Keys | Used to validate JWT signature. Multiple keys are supported. Allowed values include certificates, public keys, symmetric keys. In case the value is a valid URL, the plugin will fetch keys from the JWK endpoint. |
ForceRefreshKeys | Force fetching keys from JWKS service when the key of current JWT token is not found. If set false, keys will only be refreshed every 15 minutes by default. |
Alg | Used to verify which PKI algorithm is used in the JWT. |
JwksHeaders | Map used to add headers to a JWKS request (e.g. credentials for a 3rd party JWKS service). |
JwtHeaders | Map used to inject JWT payload fields as HTTP request headers. |
OpaHeaders | Map used to inject OPA result fields as HTTP request headers. Populated if request is allowed by OPA. Only 1st level keys from OPA document are supported. |
OpaResponseHeaders | Map used to inject OPA result fields as HTTP response headers. Populated if OPA response has OpaAllowField present, regardless of value. Only 1st level keys from OPA document are supported. |
OpaHttpStatusField | Field in OPA JSON result, which contains int or string HTTP status code that will be returned in case of disallowed OPA response. Accepted range is >= 300 and < 600. Only 1st level keys from OPA document are supported. |
JwtCookieKey | (Deprecated, use JwtSources)Name of the cookie to extract JWT if not found in Authorization header. |
JwtQueryKey | (Deprecated, use JwtSources) Name of the query parameter to extract JWT if not found in Authorization header or in the specified cookie. |
JwtSources | Ordered List of sources [bearer, header, query, cookie] of the JWT. config format is a list of maps e.g. [{type: bearer, key: Authorization}, {type: query, key, jwt}] |
This example uses Kubernetes Custom Resource Descriptors (CRD) :
apiVersion: traefik.io/v1alpha1kind: Middlewaremetadata:name: jwtspec:plugin:jwt:OpaUrl: http://localhost:8181/v1/data/exampleOpaAllowField: allowOpaBody: truePayloadFields:- expRequired: trueKeys:- https://samples.auth0.com/.well-known/jwks.json- |-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHcaT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIytvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQAB-----END PUBLIC KEY-----OpaHeaders:X-Allowed: allowJwtHeaders:X-Subject: subOpaResponseHeaders:X-Allowed: allowOpaHttpStatusField: allow_status_codeJwtSources:- type: bearerkey: Authorization- type: cookiekey: jwt---apiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: test-serverlabels:app: test-serverannotations:kubernetes.io/ingress.class: traefiktraefik.ingress.kubernetes.io/router.middlewares: default-jwt@kubernetescrd
The following section describes how to use this plugin with Open Policy Agent (OPA)
The plugin will translate the HTTP request (including headers and parameters) and forwards the payload as JSON to OPA.
For example, the following URL: http://localhost/api/path?param1=foo¶m2=bar
will result in the following payload (headers are reduced for readability):
{"headers": {"Accept-Encoding": ["gzip, deflate, br"],"Authorization": ["Bearer XXX.XXX.XXX"],"X-Forwarded-Host": ["localhost"],"X-Forwarded-Port": ["80"],"X-Forwarded-Proto": ["http"],"X-Forwarded-Server": ["traefik-84c77c5547-sm2cb"],"X-Real-Ip": ["172.18.0.1"]},"host": "localhost","method": "POST","parameters": {"param1": ["foo"],"param2": ["bar"]},"body": {"foo": "bar"},"path": ["api","path"],"tokenHeader": {"alg": "RS512","kid": "abc123"},"tokenPayload": {"exp": 1652263686,}}
The policies you enforce can be as complex or simple as you prefer. For example, the policy could decode the JWT token and verify the token is valid and has not expired, and that the user has the required claims in the token.
The policy below shows an simplified example:
package exampleimport future.keywords.inimport future.keywords.ifdefault allow := falseallow if {input.method == "GET"input.path[0] == "public"}allow if {input.method == "GET"input.path[0] == "secure"input.path[1] in {"123", "456"}}
In the above example, requesting /public/anything
or /secure/123
or /secure/456
is allowed,
however requesting /secure/xxx
would be rejected and results in a 403 Forbidden.
This software is released under the Apache 2.0 License