A ForwardAuth service for Traefik with Casbin-based authorization.
This service provides a forward authentication endpoint for Traefik, allowing you to protect your services with fine-grained access control policies defined using Casbin. It acts as a gatekeeper, intercepting requests from Traefik, evaluating them against your Casbin policies, and then allowing or denying the request based on the outcome.
-
Flexible Access Control: Define authorization policies using the powerful Casbin model.
-
Multiple Policy Sources: Load policies from files or directly from Kubernetes ( using casbin-kube).
-
Dynamic Policy Reloading:
- For file-based policies, automatically reload policies at a configurable interval.
- For Kubernetes-based policies, rely on native Informer mechanisms to watch for changes - no separate Casbin watcher required.
-
Request-Based Authorization: Authorize requests based on headers, JWT claims, query parameters, and more.
-
JWT Authentication: Optionally validate JWT tokens to authenticate requests before applying authorization policies.
-
Declarative Configuration: Configure authorization rules and routes using a simple YAML file.
- Example Routing Configuration KEYMATCH Model
routes: - httpMethod: ANY relativePaths: - /*any params: - name: user source: basicAuthUser - name: resource source: urlPath - name: method source: httpMethod rules: - format: "%s" paramNames: [ user ] - format: "%s" paramNames: [ resource ] - format: "%s" paramNames: [ method ]
- Traefik Forward Authentication: Traefik is configured to use this service as a forward authentication provider.
- Request Interception: When a request comes to Traefik, it forwards the request to this service.
- Rule Evaluation: The service evaluates the incoming request against the configured authorization rules.
- Casbin Enforcement: The rules are then used to make a Casbin enforcement request.
- Authorization Response:
- If the request is authorized, the service returns a
200 OKresponse to Traefik, which then forwards the request to the upstream service. - If the request is denied, the service returns a
403 Forbiddenresponse, and Traefik denies access to the upstream service. - If JWT is enabled and validation fails, returns
401 Unauthorized.
- If the request is authorized, the service returns a
Demo showing request authorization with Casbin Traefik Forward Auth and the KEYMATCH policy model.
Before installing Casbin Traefik Forward Auth, ensure that the Casbin Kube CRD is deployed in your cluster. Casbin Kube Adapter manages Casbin policies and provides Kubernetes-native policy synchronization.
helm install casbin-kube oci://ghcr.io/grepplabs/helm/casbin-kube:0.0.1Install Casbin Traefik Forward Auth
Install the Casbin Traefik Forward Auth Helm chart:
helm install casbin-auth oci://ghcr.io/grepplabs/helm/casbin-forward-auth:<char version> -f your-values.yamlCreate a Traefik Middleware (ForwardAuth)
Example Traefik CRDs:
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: casbin-auth
namespace: traefik
spec:
forwardAuth:
address: http://casbin-auth.casbin-auth.svc.cluster.local/v1/auth
trustForwardHeader: true
authResponseHeaders:
- X-Casbin-Auth-JWT
- WWW-Authenticate
Attach the middleware to your route
You can apply the ForwardAuth middleware in several ways:
- Globally: configure Traefik to use the middleware on all entrypoints (
additionalArgumentsin Traefik Helm chart). - IngressRoute: reference the middleware in your IngressRoute.
- Ingress: use the annotation
traefik.ingress.kubernetes.io/router.middlewareson standard Kubernetes Ingress objects.
The service is configured using command-line flags or environment variables.
| Flag | Environment Variable | Description | Default |
|---|---|---|---|
server-addr |
SERVER_ADDR |
Server listen address. | :8080 |
server-admin-port |
SERVER_ADMIN_PORT |
Admin server port (0 to disable). | 0 |
server-tls-enable |
SERVER_TLS_ENABLE |
Enable server-side TLS. | false |
server-tls-refresh |
SERVER_TLS_REFRESH |
Interval for refreshing server TLS certificates. Set to 0 to disable auto-refresh. |
0 |
server-tls-key-password |
SERVER_TLS_KEY_PASSWORD |
Password to decrypt RSA private key. | |
server-tls-file-key |
SERVER_TLS_FILE_KEY |
Path to the server TLS private key file. | |
server-tls-file-cert |
SERVER_TLS_FILE_CERT |
Path to the server TLS certificate file. | |
server-tls-file-client-ca |
SERVER_TLS_FILE_CLIENT_CA |
Path to the server client CA file for client verification. | |
server-tls-file-client-crl |
SERVER_TLS_FILE_CLIENT_CRL |
Path to the TLS X509 CRL signed by the client CA. If unspecified, only the client CA is verified. | |
metrics-include-host |
METRICS_INCLUDE_HOST |
Include HTTP Host header as a Prometheus label (can increase cardinality). | false |
auth-route-config-path |
AUTH_ROUTE_CONFIG_PATH |
Path to the config YAML file containing route authorization rules. | |
casbin-model |
CASBIN_MODEL |
Path or reference to the Casbin model (e.g. file:///etc/casbin/model.conf or rbac_model.conf). |
rbac_model.conf |
casbin-adapter |
CASBIN_ADAPTER |
Casbin adapter. One of: file, kube. |
kube |
casbin-autoload-interval |
CASBIN_AUTOLOAD_INTERVAL |
Interval for automatically reloading Casbin policies (e.g. 30s, 1m). Set to 0 to disable. | 0 |
casbin-adapter-file-policy-path |
CASBIN_ADAPTER_FILE_POLICY_PATH |
Path to the policy file. | examples/rbac_policy.csv |
casbin-adapter-kube-disable-informer |
CASBIN_ADAPTER_KUBE_DISABLE_INFORMER |
Disable the Casbin Kubernetes informer. | false |
casbin-adapter-kube-config-context |
CASBIN_ADAPTER_KUBE_CONFIG_CONTEXT |
Name of the Kubernetes context to use from the kubeconfig file. | |
casbin-adapter-kube-config-namespace |
CASBIN_ADAPTER_KUBE_CONFIG_NAMESPACE |
Kubernetes namespace where Casbin policies are stored. | value of POD_NAMESPACE |
casbin-adapter-kube-config-path |
CASBIN_ADAPTER_KUBE_CONFIG_PATH |
Path to the kubeconfig file. | |
casbin-adapter-kube-config-labels |
CASBIN_ADAPTER_KUBE_CONFIG_LABELS |
Labels to filter policies. Example: key1=val1,key2=val2. |
|
jwt-enabled |
JWT_ENABLED |
Enable JWT verification for incoming requests. When enabled, jwt-jwks-url, jwt-issuer, and jwt-audience must be set. |
false |
jwt-jwks-url |
JWT_JWKS_URL |
URL or file path to the JWKS source (e.g. https://issuer.example.com/.well-known/jwks.json or file:///etc/jwks/keys.json). |
|
jwt-issuer |
JWT_ISSUER |
Expected JWT issuer (iss claim). |
|
jwt-audience |
JWT_AUDIENCE |
Expected JWT audience (aud claim). |
|
jwt-skew |
JWT_SKEW |
Clock skew tolerance for exp/nbf claims (e.g. 30s). |
0 |
jwt-init-timeout |
JWT_INIT_TIMEOUT |
Maximum time to wait for initial JWKS fetch during startup. | 15s |
jwt-refresh-timeout |
JWT_REFRESH_TIMEOUT |
Timeout for individual JWKS refresh requests. | 2s |
jwt-min-refresh-interval |
JWT_MIN_REFRESH_INTERVAL |
Minimum interval between JWKS refresh attempts. | 0 |
jwt-max-refresh-interval |
JWT_MAX_REFRESH_INTERVAL |
Maximum interval between JWKS refresh attempts. | 0 |
jwt-use-x509 |
JWT_USE_X509 |
Indicates that the JWKS source contains X.509-encoded keys (PEM certificates) instead of standard JWK JSON. | false |
jwt-tls-enable |
JWT_TLS_ENABLE |
Enable TLS configuration for the JWKS HTTPS client. | false |
jwt-tls-file-cert |
JWT_TLS_FILE_CERT |
Path to the client TLS certificate file (for mTLS). | |
jwt-tls-file-key |
JWT_TLS_FILE_KEY |
Path to the client TLS private key file (for mTLS). | |
jwt-tls-file-root-ca |
JWT_TLS_FILE_ROOT_CA |
Path to a custom root CA bundle for verifying the JWKS server. | |
jwt-tls-key-password |
JWT_TLS_KEY_PASSWORD |
Password to decrypt the RSA private key. | |
jwt-tls-insecure-skip-verify |
JWT_TLS_INSECURE_SKIP_VERIFY |
Skip server certificate verification (insecure; use only for testing). | false |
jwt-tls-refresh |
JWT_TLS_REFRESH |
Interval for reloading client TLS certificates. Set to 0 to disable auto-refresh. |
0 |
jwt-tls-use-system-pool |
JWT_TLS_USE_SYSTEM_POOL |
Use the system certificate pool for verifying server certificates. | true |
The routing configuration is defined in a YAML file specified by auth-route-config-path. It consists of a list of
routes, each defining how incoming requests should be authorized.
httpMethod(string): The HTTP method to match (e.g.,GET,POST,ANY).httpMethods(array of strings): A list of HTTP methods to match.relativePath(string): The URL path to match. Can include path parameters (e.g.,/user/:id).relativePaths(array of strings): A list of URL paths to match.params(array of objects): A list of parameters to extract from the incoming request.name(string): The name of the parameter.source(string): The source of the parameter. Possible values:path: Extracts the parameter from the URL path (e.g.,:idin/user/:id).query: Extracts the parameter from the URL query string (e.g.,?q=value).header: Extracts the parameter from an HTTP header.claim: Extracts the parameter from a JWT claim using. Requires a valid JWT in theAuthorization: Bearerheader.basicAuthUser: Extracts the username from theAuthorization: Basicheader.url: Extracts the full request URL.urlPath: Extracts the request URL path.httpMethod: Extracts the HTTP method of the request.
key(string, optional): The key to use whensourceisquery,header, orclaim. If omitted,nameis used.expr(string, optional): An expression to extract a value. Used withsource: claimfor GJSON paths (e.g.,sub,acme/project/project\.id) or withfunction: regexfor regular expressions.default(string, optional): A default value to use if the parameter is not found.function(string, optional): A function to apply to the extracted value. Supported functions:b64dec: Decodes a base64 encoded string.firstLabel: Extracts the first label from a dot-separated string (e.g.,foofromfoo.bar.com).regex: Extracts a substring from the value using a regular expression defined in theexprfield. Theexprfield must contain a valid regular expression with at least one capturing group.tolower: Converts the entire value to lowercase (e.g.,HeLLo→hello).toupper: Converts the entire value to uppercase (e.g.,HeLLo→HELLO).
rules(array of objects): A list of Casbin rules to enforce. Each rule can be a simple format string or a set of cases.format(string): A format string to construct the Casbin rule. Parameters are injected using%s.paramNames(array of strings): The names of the parameters to inject into theformatstring, in order.cases(array of objects, optional): A list of conditional rules. The firstwhenexpression that evaluates to true will have itsformatandparamNamesused.when(string): An expression that must evaluate to true for this case to be used. Uses the expr language. The following functions are available withinwhenexpressions:hasPrefix(s, prefix): Returnstrueif the stringsbegins withprefix.hasSuffix(s, suffix): Returnstrueif the stringsends withsuffix.contains(s, sub): Returnstrueif the stringscontainssub.equalsIgnoreCase(a, b): Returnstrueif stringsaandbare equal, ignoring case.equals(a, b): Returnstrueif stringsaandbare equal.match(s, re): Returnstrueif the stringsmatches the regular expressionre.
This example demonstrates how a Pub/Sub-style authorization flow can be expressed using Casbin rules and route-based parameter extraction.
routes:
- httpMethod: POST
relativePaths:
- /v1alpha/publish
params:
- name: topicId
source: header
expr: Host
function: firstLabel
- name: projectId
source: claim
expr: acme/project/project\.id
- name: sub
source: claim
expr: sub
rules:
- format: iam::%s:sa/%s
paramNames: [ projectId, sub ]
- format: pubsub:eu-central-1:%s:topics/%s
paramNames: [ projectId, topicId ]
- format: pubsub:publish---
apiVersion: casbin.grepplabs.com/v1alpha1
kind: Rule
metadata:
name: pubsub-publish
labels:
casbin.grepplabs.com/model: rbac
spec:
ptype: "p"
v0: "iam::p123:sa/user-42"
v1: "pubsub:eu-central-1:p123:topics/orders"
v2: "pubsub:publish"
POST /v1alpha/publish
Host: orders.example.com
Authorization: Bearer <token>
{
"acme/project/project.id": "p123",
"sub": "user-42"
}| Name | Value |
|---|---|
projectId |
p123 |
sub |
user-42 |
topicId |
orders |
| Attribute | Value |
|---|---|
| Subject | iam::p123:sa/user-42 |
| Resource | pubsub:eu-central-1:p123:topics/orders |
| Action | pubsub:publish |
The project provides a Helm chart for easy deployment to Kubernetes.
The following table lists the configurable parameters of the casbin-forward-auth chart and their default values.
| Key | Type | Default | Description |
|---|---|---|---|
replicaCount |
int | 1 |
Number of replicas for the deployment. |
image.repository |
string | ghcr.io/grepplabs/casbin-forward-auth |
Image repository. |
image.pullPolicy |
string | IfNotPresent |
Image pull policy. |
image.tag |
string | "" |
Overrides the image tag whose default is the chart appVersion. |
imagePullSecrets |
list | [] |
Secrets to use for pulling images. |
nameOverride |
string | "" |
Overrides the chart's name. |
fullnameOverride |
string | "" |
Overrides the chart's full name. |
serviceAccount.create |
bool | true |
Specifies whether a service account should be created. |
serviceAccount.automount |
bool | true |
Automatically mount a ServiceAccount's API credentials. |
serviceAccount.annotations |
object | {} |
Annotations for the service account. |
serviceAccount.name |
string | "" |
The name of the service account to use. If not set and serviceAccount.create is true, a name is generated. |
podAnnotations |
object | {} |
Annotations for the pod. |
podLabels |
object | {} |
Labels for the pod. |
podSecurityContext |
object | {} |
Pod security context. |
securityContext |
object | {} |
Container security context. |
service.type |
string | ClusterIP |
Service type. |
service.port |
int | 80 |
Service port. |
service.admin.type |
string | ClusterIP |
Service type for the admin endpoint. |
service.admin.port |
int | 8081 |
Service port for the admin endpoint. |
ingress.enabled |
bool | false |
Specifies whether an Ingress should be created. |
ingress.className |
string | "" |
Ingress class name. |
ingress.annotations |
object | {} |
Annotations for the Ingress. |
ingress.hosts |
list | [{"host":"chart-example.local","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}] |
Ingress hosts. |
ingress.tls |
list | [] |
Ingress TLS configuration. |
httpRoute.enabled |
bool | false |
Specifies whether an HTTPRoute should be created (requires Gateway API). |
httpRoute.annotations |
object | {} |
Annotations for the HTTPRoute. |
httpRoute.parentRefs |
list | [{"name":"gateway","sectionName":"http"}] |
Which Gateways this Route is attached to. |
httpRoute.hostnames |
list | ["chart-example.local"] |
Hostnames matching HTTP header. |
httpRoute.rules |
list | [{"matches":[{"path":{"type":"PathPrefix","value":"/headers"}}]}] |
List of rules and filters applied. |
resources |
object | {} |
Pod resource limits and requests. |
livenessProbe |
object | {"httpGet":{"path":"/healthz","port":"http"}} |
Liveness probe configuration. |
readinessProbe |
object | {"httpGet":{"path":"/readyz","port":"http"}} |
Readiness probe configuration. |
autoscaling.enabled |
bool | false |
Specifies whether autoscaling should be enabled. |
autoscaling.minReplicas |
int | 1 |
Minimum number of replicas for autoscaling. |
autoscaling.maxReplicas |
int | 100 |
Maximum number of replicas for autoscaling. |
autoscaling.targetCPUUtilizationPercentage |
int | 80 |
Target CPU utilization percentage for autoscaling. |
extraVolumes |
list | [] |
Additional volumes on the output Deployment definition. |
extraVolumeMounts |
list | [] |
Additional extraVolumeMounts on the output Deployment definition. |
extraEnvFrom |
list | [] |
Additional environment variables from secrets or configmaps. |
nodeSelector |
object | {} |
Node selector for pod scheduling. |
tolerations |
list | [] |
Tolerations for pod scheduling. |
affinity |
object | {} |
Affinity for pod scheduling. |
serviceMonitor.enabled |
bool | false |
If true, a ServiceMonitor resource will be created for Prometheus Operator scraping. |
serviceMonitor.interval |
string | "15s" |
Scrape interval used by Prometheus. |
serviceMonitor.scrapeTimeout |
string | "10s" |
Scrape timeout used by Prometheus. |
serviceMonitor.additionalLabels |
object | {} |
Extra labels to add to the ServiceMonitor metadata (for example release: prometheus). |
serviceMonitor.namespace |
string | "" |
If set, the ServiceMonitor will select this namespace via .spec.namespaceSelector.matchNames. If empty, Prometheus is expected to scrape in the same namespace. |
serviceMonitor.relabelings |
list | [] |
List of relabelings applied to samples before ingestion. |
serviceMonitor.metricRelabelings |
list | [] |
List of metricRelabelings applied to scraped metrics. |
application.env |
object | {} |
Environment variables for the application. |
application.authRouteConfig |
object | {} |
Route configuration for the application. |
application.server.port |
int | 8080 |
Port on which the main application server listens. |
application.server.adminPort |
int | 8081 |
Port on which the admin server listens. |
application.adapter.kube.namespace |
string | "" |
Kubernetes namespace where Casbin policies are stored. |
