JWT Issuer in Rust

The jwt-issuer-rs project implements a simple JWT (JSON Web Token) Issuer in Rust. The project provides an example of how the JWT Issuer can be used as a JWT authenticator for Hashicorp Vault.

JWT Issuer

The jwt-issuer-rs project implements a JWT (JSON Web Token) Issuer in Rust using actix, jsonwebtoken and jsonwebkey.

Key generation

The first step in using the JWT issuer is to generate a key pair using openssl to sign the JWTs.

openssl ecparam -name prime256v1 -genkey -noout -out key.pem
openssl ec -in key.pem -pubout -out public.pem

The next step is to convert the private key into a JWK

cat key.pem | docker run -i danedmunds/pem-to-jwk:latest > key.json

Usage

Using your JWK stored in a file called key.json, run the JWT Issuer service as follows

cargo run

The above command starts a HTTP server which exposes two endpoints

  • auth/token: JWT token issuer
  • auth/jwks: The public JSON Web Keys

A JWT token for a user can be requested using the following curl command

curl -X POST http://localhost:8080/auth/token -d '{"name": "vishpat"}' -H 'Content-Type: application/json'

(In the real world this endpoint would have authentication and would be exposed via https. However, for simplicity, this is not the case)

The issued JWT can then be verified against the jwks endpoint as follows

# A simple python program to verify the JWT using the 
# JWKS endpoint. 
# Requires python packages pyjwt,requests,cryptography

import jwt
import requests

token = "TOKEN"
jwk_url = "http://localhost:8080/auth/jwks"

jwk = requests.get(jwk_url).json()
key = jwt.algorithms.ECAlgorithm.from_jwk(jwk["keys"][0])
data = jwt.decode(token, key=key, algorithms=['ES256'])
print(data)

Hashicorp Vault Integration

Vault Overview

Hashicorp Vault is an enterprise grade secret management system. Vault enables storing of secrets and accessing them using various authentication mechanisms.

We will be using Vault to store a username and password in it's kv secret store. The JWT Issuer will be used to setup JWT authentication to access the secrets stored in the Vault.

Vault Server

Start a local dev vault server

vault server -dev

Key Value Secret Engine

The above command will spit out the admin token that is required to manage the Vault instance. Use the admin token to enable the kv (version 1) secret engine for Vault as shown below.

export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN=<VAULT_ADMIN_TOKEN>
vault secrets enable -version=1 kv

Authentication Setup

The next step is to setup the JWT authentication for Vault. This can be done using terraform as follows.

provider "vault" {
}

resource "vault_jwt_auth_backend" "vishpat" {
    description         = "Enable JWT auth"
    path                = "jwt"
    default_role        = "jwt_vishpat"
    jwks_url            = "http://localhost:8080/auth/jwks"
}

resource "vault_jwt_auth_backend_role" "jwt_vishpat" {
  backend        = vault_jwt_auth_backend.vishpat.path
  role_name      = "jwt_vishpat"
  token_policies = ["vishpat_keys_policy"]

  bound_subject   = "vishpat"
  user_claim      = "sub"
  role_type       = "jwt"
}

Policy setup

Now setup a policy (using terraform) in Vault to allow the user vishpat to access the secrets stored under kv/vishpat/*

resource "vault_policy" "vishpat_keys_policy" {
  name   = "vishpat_keys_policy"
  policy = <<EOT

path "kv/vishpat/*" {
    capabilities = [ "create", "read", "update", "delete", "list" ]
}

                EOT
}

Terraform

Apply the terraform plan as shown below

terraform plan -out plan.out
terraform apply plan.out

JWT token

Now get the JWT token for the user vishpat as shown below.

curl -X POST -d '{"name": "vishpat"}'  -H 'Content-Type: application/json'   http://localhost:8080/auth/token

Vault authentication

Use the JWT token to authenticate against Vault inorder to get the Vault token to access the secrets.

vault write auth/jwt/login jwt=<JWT_TOKEN>

Key                  Value
---                  -----
token                hvs.CAESIDZZ-ol5ich3gnllpS6yhuaHDVnqEXwZUiRNlKqBslpIGh4KHGh2cy5pbURralBsZlhTdTRSdlBnMkRjVDJDQng
token_accessor       LY5IENUHKtxvugEiSAiLalH9
token_duration       768h
token_renewable      true
token_policies       ["default" "vishpat_keys_policy"]
identity_policies    []
policies             ["default" "vishpat_keys_policy"]
token_meta_role      jwt_vishpat

Access secrets

The secrets at kv/vishpat can now be accessed using the Vault user token.

export VAULT_TOKEN=hvs.CAESIDZZ-ol5ich3gnllpS6yhuaHDVnqEXwZUiRNlKqBslpIGh4KHGh2cy5pbURralBsZlhTdTRSdlBnMkRjVDJDQng

➜ vault kv put kv/vishpat/test username=X password=Y
Success! Data written to: kv/vishpat/test

➜ vault kv get kv/vishpat/test
=== Data ===
Key      Value
---      -----
password   Y
username   X