Skip to content

dimovnike/go-jwks-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Server for JSON Web Key sets (JWKS).

Action Marketplace Build Status

Designed to play nicely with kubernetes and other orchestration systems (like docker swarm).

Main features:

  • Serve JWKS from a directory with public PEM files. File names are used as key IDs.
  • Can watch the directory for changes and reload the keys (useful with kubernetes secrets).
  • Sets cache control headers according to the config.
  • Can be configured using command line flags and environment variables.
  • TLS support.
  • Configurable logging using zerolog.

Example usage:

Create the kubernetes pod (service, ingress, etc):

apiVersion: v1
kind: Pod
metadata:
  name: go-jwks-server
  labels:
    app: go-jwks-server
spec:
  containers:
    - name: go-jwks-server
      image: dimovnike/go-jwks-server:latest
      ports:
        - containerPort: 8080
      volumeMounts:
        - name: jwks-keys
          mountPath: /jwt-keys
      env:
        - name: GO_JWKS_SERVER_KEY_DIR
          value: /jwt-keys
        - name: GO_JWKS_SERVER_LOG_LEVEL
          value: debug
  volumes:
    - name: jwks-keys
      secret:
        secretName: jwks-public-keys
        optional: true

NOTE: the secret does not yet exist.

Now try accessing the service, it will produce empty keys as expected:

curl -s localhost:8080/keys | jq
{
  "keys": []
}

Create the secret with the public keys:

# generate a key pair
openssl ecparam -name prime256v1 -genkey -noout -out priv-key.pem
openssl ec -in priv-key.pem -pubout > pub-key.pem

# create and apply the secret
kubectl create secret generic jwks-public-keys --from-file=key1=pub-key.pem  --dry-run=client --save-config --dry-run=client -oyaml \
    | kubectl apply -f -

NOTE: you can run the last command multiple times to add more keys to the secret.

Wait for a while for the secret to propagate to the pod, you will see in the log:

{"level":"info","skipped":{"..2024_06_05_16_49_04.104114561":"directory","..data":"directory"},"loaded":{"key1":"key1"},"time":"2024-06-05T16:49:05Z","caller":"/build/internal/keyloader/keys.go:83","message":"loaded keys"}

and try accessing the service again:

curl -s localhost:8080/keys | jq
{
  "keys": [
    {
      "crv": "P-256",
      "kid": "key1",
      "kty": "EC",
      "x": "wYthzYx55RuKWa8Ru3Tp2_LcbBixW3TXjEkkt5ZrVsY",
      "y": "N2V-3e35eQrAxCyaXRnnV1IQVnhgVw2TgWZ6UZmj5n0"
    }
  ]
}

We can see the public key with the ID key1 is now present in the JWKS.

Install using helm

This service has a helm chart, you can install it using the following commands:

helm install go-jwks-server1 https://github.com/dimovnike/go-jwks-server-helm-chart/archive/refs/tags/v0.1.1.tar.gz

# or use https://github.com/dimovnike/go-jwks-server-helm-chart/archive/refs/heads/master.tar.gz for the latest version

For more information see the values.yaml of the chart.

Command line flags

Flags can be provided via environment variables by prefixing the flag name with GO_JWKS_SERVER_, replacing dashes with underscore and converting it to uppercase. Example: flag -dir-watch-interval can be provided via environment variable GO_JWKS_SERVER_DIR_WATCH_INTERVAL.

NOTE: It is not allowed to provide a flag both in the command line and in the environment variable.

The -key-dir directory must contain the public keys, one key in a file. The file name is the key ID, files my have an optional .pub extension.  Files that have .ignore extension are ignored.

Supported flags:

  -dir-watch-interval duration
        the interval to check the key directory for changes, set to 0 to disable watching (default 1s)
  -exit-on-error
        exit if loading keys fails
  -http-addr string
        the address to listen on (default ":8080")
  -http-cache-max-age duration
        set max-age in the cache-control header in seconds, set to 0 to disable caching (default 1h0m0s)
  -http-enable
        enable plain http server (default true)
  -http-idle-timeout duration
        the maximum amount of time to wait for the next request when keep-alives are enabled
  -http-keys-endpoint string
        the endpoint to serve the keys (default "/keys")
  -http-max-header-bytes int
        the maximum number of bytes the server will read parsing the request headers, including the request line (default 1048576)
  -http-read-header-timeout duration
        timeout for reading the request headers
  -http-read-timeout duration
        timeout for reading the entire request, including the body
  -http-shutdown-timeout duration
        timeout for graceful shutdown of the server (default 5s)
  -http-write-timeout duration
        timeout for writing the response
  -https-addr string
        the address to listen on (default ":8443")
  -https-cert-file string
        TLS cert file
  -https-enable
        enable https/TLS server
  -https-idle-timeout duration
        the maximum amount of time to wait for the next request when keep-alives are enabled
  -https-key-file string
        TLS key file
  -https-max-header-bytes int
        the maximum number of bytes the server will read parsing the request headers, including the request line (default 1048576)
  -https-read-header-timeout duration
        timeout for reading the request headers
  -https-read-timeout duration
        timeout for reading the entire request, including the body
  -https-shutdown-timeout duration
        timeout for graceful shutdown of the server (default 5s)
  -https-write-timeout duration
        timeout for writing the response
  -key-dir string
        the directory to load the keys from (default "./keys")
  -log-caller
        show caller file and line number (default true)
  -log-console
        human friendly logs on console
  -log-file string
        log file, stdout or stderr (default "stderr")
  -log-level string
        logging level (debug, info, warn, error, fatal, panic, no, disabled, trace) (default "error")
  -log-no-color
        do not show color on console
  -log-stack
        show stack info
  -log-timestamp
        show timestamp (default true)
  -print-config
        print the configuration and exit