Jwker is a Kubernetes operator that manages OAuth2 client registrations for applications that use the Tokendings authorization server as part of the TokenX system.
It does this through the Jwker custom resource definition (CRD):
apiVersion: nais.io/v1
kind: Jwker
metadata:
name: my-app
namespace: my-team
spec:
accessPolicy:
inbound:
rules:
- application: some-other-app
namespace: some-team
cluster: some-cluster
secretName: jwker-my-appFor the full CRD specification, see the spec in nais/liberator:
A Jwker resource contains:
- the access policies for the application
- the name of the Kubernetes secret that the application expects
The operator is responsible for managing the secret and reconciling the OAuth2 client with its policies and credentials with Tokendings.
The secret contains the following keys:
| Key | Description |
|---|---|
TOKEN_X_CLIENT_ID |
The application's client ID. |
TOKEN_X_PRIVATE_JWK |
The application's private JSON Web Key (JWK) for client authentication (RFC 7523, section 2.2) |
TOKEN_X_WELL_KNOWN_URL |
The URL pointing to the Tokendings' well-known metadata document. |
TOKEN_X_ISSUER |
The issuer property from the metadata document. |
TOKEN_X_JWKS_URI |
The jwks_uri property from the metadata document. |
TOKEN_X_TOKEN_ENDPOINT |
The token_endpoint property from the metadata document. |
sequenceDiagram
actor developer as Developer or<br/>Operator
box rgba(33,66,99,0.5) Kubernetes Cluster
participant crd as Jwker resource
participant secrets as Secrets
participant jwker as Jwker Controller
end
participant tokendings as Tokendings<br/>Authorization Server
loop forever
jwker ->> crd: watches
end
developer ->> crd: apply resource
jwker ->> crd: get resource
crd ->> secrets: owns
jwker ->> secrets: get all owned by resource
alt `spec.secretName` has changed
jwker ->> jwker: create new private key
else `spec.secretName` is unchanged
jwker ->> jwker: re-use private key from existing secret
end
jwker ->> jwker: create client assertion for<br/>authenticating with tokendings
jwker ->> tokendings: POST public keys (JWKS)<br/>and access policies to<br/>`/registration/client`
note over tokendings: JWKS contains all currently used public keys
jwker ->> secrets: create/update
loop for each owned secret
alt name equals `spec.secretName`
jwker ->> secrets: keep secret
else
jwker ->> secrets: delete if<br/>unreferenced
end
end
- When a
Jwkerresource is applied to the cluster (either by a developer or another operator), the Jwker controller will reconcile it. - The controller reads the
Jwkerresource and retrieves all existing secrets owned by the resource. - The controller then checks if the
spec.secretNamehas changed:- If the secret name has changed, it creates a new private key for the application.
- If the secret name is unchanged, it reuses the private key from the existing secret.
- The operator creates a client assertion for authenticating with Tokendings.
- The application's public keys (JWKS) and access policies are registered with Tokendings via the
/registration/clientendpoint.- The JWKS contains all currently used public keys to ensure key rotation works properly.
- Each application is registered with Tokendings using a unique identifier in the form of
clustername:namespace:application
- The operator creates or updates the Kubernetes secret with the specified
secretName. - Finally, any unreferenced secrets are deleted to clean up resources.
- Secrets are considered referenced if mounted as files or environment variables in a pod.
The pod must have a label
app=<name>where<name>is equal to.metadata.namein theJwkerresource.
- Secrets are considered referenced if mounted as files or environment variables in a pod.
The pod must have a label
helm install jwker ./chartsJwker can be configured using either command-line flags or equivalent environment variables:
| Flag | Environment Variable | Type | Description |
|---|---|---|---|
--cluster-name |
CLUSTER_NAME |
string | The cluster name where this Jwker is deployed to. |
--client-id |
JWKER_CLIENT_ID |
string | Client ID for Jwker for identifying itself with Tokendings. |
--client-jwk-json |
JWKER_PRIVATE_JWK |
string | JSON string containing the private key in JWK format. |
--tokendings-base-url |
TOKENDINGS_URL |
string | The base URL to Tokendings. |
--tokendings-instances |
TOKENDINGS_INSTANCES |
string | Comma separated list of base URLs to multiple Tokendings instances. |
--max-concurrent-reconciles |
int | Maximum number of concurrent reconciles for the controller. (default 20) |
|
--metrics-addr |
string | The address the metric endpoint binds to. (default :8181) |
|
--log-level |
string | Log level. (default info) |
Start a local Kubernetes cluster, e.g. using kind, minikube, or similar.
Install the CRD if you haven't already:
make install-crdStart up dependencies:
docker-compose up -dRun the operator:
make localDeploy a sample Jwker:
make sample