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

OIDC identity tokens can have a TTL longer than their signing key will be visible #11441

Closed
ianferguson opened this issue Apr 22, 2021 · 3 comments

Comments

@ianferguson
Copy link
Contributor

Describe the bug
JWTs issued by the Identity backend can be issued with a TTL that is longer than the signing key used to create them will be visible to clients on the identity/oidc/.well-known/keys endpoint, causing services to verifying those JWTs to reject the JWTs as invalid prior to exp claim included in the JWT.

Signing keys remain visible on the identity/oidc/.well-known/keys endpoint for the length of time configured by the identity keys' verification_ttl configuration.

An Identity backend token role can be configured to issue JWTs with any TTL value using the ttl configuration. This ttl determines how the exp claim in the JWT is populated.

When a service receives a request authenticated with a JWT from Vault and needs to verify it, it will validate the that the iss claim is a known/trusted value and then (periodically) retrieve the JSON Web Key Set from $issuer_url/.well-known/keys. The service will then validate that the kid claim in the JWT header matches a kid returned by the .well-known/keys endpoint for that issuer.

If a Vault OIDC Identity signing key is configured with a verification_ttl of 1 hour and an Identity token role is configured with a ttl value of 24h, a token created immediately prior to a key rotation will have a 24h ttl, but the key used to sign it will be removed from .well-known/keys after an hour, leaving up to 23 hours where the JWT is nominally valid but will fail authentication/validation by servers as they refresh the JWKS keyset for that issuer

To Reproduce

  1. run a vault dev server: vault server -dev -dev-root-token-id=dev-root-token -log-level=debug
  2. in another terminal pane or tab:
VAULT_ADDR=http://127.0.0.1:8200
VAULT_TOKEN=dev-root-token

# create identity role/keyset
vault write identity/oidc/key/a-key rotation_period=1m verification_ttl=1m allowed_client_ids="*"
vault write identity/oidc/role/a-role key=a-key ttl=60m

# configure and use identity based user -- root tokens can't get identity tokens
policy=identity
cat <<- EOF >> ${policy}
path "identity/oidc/*" {
  capabilities = ["read"]
}
EOF
vault write $policy $policy
vault auth enable userpass
vault write auth/userpass/users/dave.matthews password=underthetableanddreaming token_policies=$policy

# switch to configured identity based user 
unset VAULT_TOKEN
vault login -method=userpass username=dave.matthews password=underthetableanddreaming

# Retrieve an identity token, print key id of the signing key, as well as human readable form of `exp` claim
JWT=$(vault read identity/oidc/token/a-role -format=json | jq '.data.token' -r)    

HEADERS=$(echo $JWT |  awk 'BEGIN{FS="."}{print $1}' | base64 -d)
KID=$(echo $HEADERS | jq -r '.kid')
echo "JWT was signed with key $KID"

CLAIMS=$(echo $JWT | awk 'BEGIN{FS="."}{print $2}' | base64 -d)
EXPIRE=$(echo $CLAIMS | jq -r '.exp')
echo "Expires at $(date -d @$EXPIRE)" # this will be 1 hour in the future

# Print currently vended signing key Key IDs -- it will include the same value set to $KID above:
curl --silent $VAULT_ADDR/v1/identity/oidc/.well-known/keys | jq -r '.keys[].kid'

# sleep 10 minutes, or wait until anytime between now + 5 minutes and the expiration time printed above (`date -d @$EXPIRE`)
sleep 600

# Print currently vended signing key Key IDs -- $KID will no longer be present, and servers verifying this JWT will treat it as invalid, even though we have not reached the expected expiration time based on the `exp` claim returned by Vault
curl --silent $VAULT_ADDR/v1/identity/oidc/.well-known/keys | jq -r '.keys[].kid'

Expected behavior
Vault should either not allow identity token roles to have a TTL that is greater than the verification_ttl time of the signing key they use, or should dynamically truncate the identity token role TTL to never be greater than remaining time until rotation + verification_ttl at the time a token is issued.

This would avoid clients believing their token should be valid until exp being surprised by servers rejecting the JWT prior to the time encoded in the exp claim

Environment:

  • Vault Server Version (retrieve with vault status): v1.6.2
  • Vault CLI Version (retrieve with vault version): v1.6.2
  • Server Operating System/Architecture: OS X

Vault server configuration file(s):

None, works with vault server -dev and no config

Additional context
None

@kalafut
Copy link
Contributor

kalafut commented Apr 22, 2021

@ianferguson Thanks for the report, and you're absolutely right. We do some checking between verification_ttl and rotation_ttl, but not between token_ttl and verification_ttl. Adding such a check is a good idea.

@calvn
Copy link
Member

calvn commented Aug 10, 2021

@ianferguson Closing this since it should now be addressed on Vault 1.8.1. Feel free to re-open if you encounter any further issues on this.

@calvn calvn closed this as completed Aug 10, 2021
@ianferguson
Copy link
Contributor Author

@calvn thanks!

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

No branches or pull requests

4 participants