-
Notifications
You must be signed in to change notification settings - Fork 2.6k
JWT validation problem on 3.0.0-rc.1 (kid format mismatch) #4533
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
Comments
Can confirm the workaround of renaming the kid to the fingerprint of the JWK works. According to the spec, the structure of the kid value is unspecified (https://datatracker.ietf.org/doc/html/rfc7517#section-4.5), so for the real fix distribution should also calculate the fingerprint based on the modulo and exponent of the JWK instead of expecting the kid to be the fingerprint. When I find some free time I'll look into providing a PR. Following script can be used to generate the fingerprint programmatically: #!/bin/bash
# usage: cat jwks.json | jwks_fingerprint.sh
# curl -s https://<keycloakhost>/realms/<realm>/protocol/openid-connect/certs | jwks_fingerprint.sh
set -euo pipefail
decode_b64url() {
local input="${1//_//}"
input="${input//-/+}"
local mod4=$(( ${#input} % 4 ))
if [ "$mod4" -eq 2 ]; then input="$input=="
elif [ "$mod4" -eq 3 ]; then input="$input="
elif [ "$mod4" -eq 1 ]; then
echo "Invalid base64url input length" >&2
return 1
fi
echo "$input" | base64 -d
}
JWKS_JSON=$(cat)
N_B64=$(echo "$JWKS_JSON" | jq -r '.keys[] | select(.alg == "RS256") | .n' | head -n1)
E_B64=$(echo "$JWKS_JSON" | jq -r '.keys[] | select(.alg == "RS256") | .e' | head -n1)
if [[ "$N_B64" == "null" || -z "$N_B64" ]]; then
echo "No modulus n found in JWKS matching criteria"
exit 1
fi
if [[ "$E_B64" == "null" || -z "$E_B64" ]]; then
echo "No exponent e found in JWKS matching criteria"
exit 1
fi
N_HEX=$(decode_b64url "$N_B64" | xxd -p | tr -d '\n')
E_HEX=$(decode_b64url "$E_B64" | xxd -p | tr -d '\n')
FINGERPRINT=$( \
openssl asn1parse -genconf <(cat <<EOF
asn1=SEQUENCE:pubkey
[pubkey]
modulus=INTEGER:0x$N_HEX
publicExponent=INTEGER:0x$E_HEX
EOF
) -out /dev/stdout 2>/dev/null | \
openssl rsa -RSAPublicKey_in -inform DER -pubout -outform DER 2>/dev/null | \
sha256sum | \
awk '{print $1}' | \
xxd -r -p | \
base32 | \
fold -w4 | head -n12 | paste -sd:
)
echo "$FINGERPRINT"
|
Hi! We just ran into the same issue in the release 3.0.0 version, so we downgraded back to 2.X for now. /cc @fh1ch @ercanucan |
Description
Hi, I'm testing 3.0.0-rc.1 using keycloak 26.0.5 as the auth server.
I am downloading the jwks keys from keycloak's openid-connect/certs endpoint: https://sso.uds.dev/realms/uds/protocol/openid-connect/certs and configuring registry to use that file for the
REGISTRY_AUTH_TOKEN_JWKS
in my docker compose yaml below:With this configuration, I'm unable to perform
docker login
because there seems to be a problem resolving the token by kid.The following error is printed in the registry log when I authenticate
time="2024-12-12T18:40:32.10842518Z" level=info msg="failed to verify token: token signed by untrusted key with ID: \"24KL:52WX:HWNC:R2YW:I4TZ:T6UR:TKBS:TRGT:JCI6:NPHB:QTZW:7KCB\"
The JWT is actually signed by the correct key and is valid, but it registry can't look it up to validate it.
If I modify the jwks file so the format of the
kid
field matches the expected then it works. An example modification is below:Original certs file from keycloak:
Modified certs file to match the kid format that works with registry:
Another data point. On registry version 2.8.3, I don't need to pass
REGISTRY_AUTH_TOKEN_JWKS
-- Instead, it is able to validate my token using the key in theREGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE
pem file, which was created by exporting the contentsx5c[0]
field above and saving as a pem file. This works against the exact same installation as keycloak.Any suggestions on how to get the tokens to validate in registry v3 without having to modify the jwks file? It seems like this should work directly with the file exported from the keycloak realm
/certs
endpoint but with thekid
field mismatch I'm not sure if that's possible.This
REGISTRY_AUTH_TOKEN_JWKS
seems new in v3 so wanted to report this since I'm running onto it.Reproduce
docker-v2
protocol client calleddocker-registry
in the keycloak realmdocker compose up
Expected behavior
User is logged in to the registry
registry version
registry:3.0.0-rc.1
Additional Info
The same keycloak realm keys work fine on registry:2.8.3 but the mechanism is different. In that scenario, save the signing public key to a pem and pass that as the root bundle, and do not set REGISTRY_AUTH_TOKEN_JWKS
Looks related to #4470 though this situation is slightly different. However, if I was able to not specify REGISTRY_AUTH_TOKEN_JWKS and have it fall back to the behavior on 2.8.3 using the ROOTCERTBUNDLE that would be a workaround.
The text was updated successfully, but these errors were encountered: