Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature jwt auth #938

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open

Conversation

spunkedy
Copy link

@spunkedy spunkedy commented Mar 8, 2024

With a client id / secret, to be secure you will have to go through a rotation. If you do a JWT signer, it's a little bit more complex, but you can still get the client going.

here is an example with grabbing the jwt from a signed aws kms so that you aren't responsible for getting the details.

#!/bin/bash

# Variables
KMS_KEY_ARN="arn_here"
ALGORITHM="RSASSA_PKCS1_V1_5_SHA_256"
CLIENT_ID="test"
AUTH_SERVER_TOKEN_ENDPOINT_URL="http://localhost:8080/realms/master/protocol/openid-connect/token"

# Helper functions
base64url_encode() {
    openssl enc -base64 -A | tr '+/' '-_' | tr -d '='
}

generate_jti() {
    # Generates a random string for jti using /dev/urandom
    head -c 16 /dev/urandom | base64 | tr -d '/+=' | cut -c -22
}


# JWT Claims
ISSUER="$CLIENT_ID" # Issuer
SUBJECT="$CLIENT_ID" # Subject
AUDIENCE="$AUTH_SERVER_TOKEN_ENDPOINT_URL" # Audience
JTI=$(generate_jti) # JWT ID
CURRENT_TIME=$(date +%s)
EXPIRATION_TIME=$(($CURRENT_TIME + 3600)) # 1 hour from now

# Create JWT Header
HEADER=$(jq -n --arg alg "RS256" --arg typ "JWT" '{alg: $alg, typ: $typ}')
HEADER_BASE64=$(echo -n "$HEADER" | base64url_encode)

# Create JWT Payload
PAYLOAD=$(jq -n \
    --arg iss "$ISSUER" \
    --arg sub "$SUBJECT" \
    --arg aud "$AUDIENCE" \
    --arg jti "$JTI" \
    --argjson iat $CURRENT_TIME \
    --argjson exp $EXPIRATION_TIME \
    '{iss: $iss, sub: $sub, aud: $aud, jti: $jti, iat: $iat, exp: $exp}')
PAYLOAD_BASE64=$(echo -n "$PAYLOAD" | base64url_encode)

# Prepare the message to be signed
MESSAGE="$HEADER_BASE64.$PAYLOAD_BASE64"

# Use AWS KMS to sign the message
SIGNATURE_JSON=$(echo -n "$MESSAGE" | aws kms sign \
    --key-id "$KMS_KEY_ARN" \
    --message-type RAW \
    --signing-algorithm "$ALGORITHM" \
    --message fileb:///dev/stdin \
    --output json)
SIGNATURE=$(echo $SIGNATURE_JSON | jq -r '.Signature' | base64 -d | base64url_encode)

# Construct the JWT
JWT="$HEADER_BASE64.$PAYLOAD_BASE64.$SIGNATURE"

echo "jwt = \"$JWT\"" > terraform.tfvars

you can then use it like:

variable "jwt" {
  type        = string
  description = "JWT for client authorization"
}

provider "keycloak" {
  client_assertion = var.jwt
  url = "http://localhost:8080"
}

@spunkedy
Copy link
Author

spunkedy commented Mar 8, 2024

Just updated the logic since the JTI of the token isn't allowed to be reused and the existing logic retried.

Looking for feedback and I can update this, if it's better to do it a different way let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant