Current Series Release Notes

29.0.0-36

New Features

  • The JWS token signing algorithm is now configurable via two new options in [jwt_tokens]:

    • jws_algorithm selects the algorithm used when signing new tokens (default ES256, preserving backward compatibility). Supported values are ES256, ES384, ES512, and EdDSA.

    • jws_accepted_algorithms lists the algorithms accepted during token validation. This allows operators to accept tokens signed with a previous algorithm during a migration window.

    Changing the signing algorithm requires regenerating the JWS key pair via keystone-manage create_jws_keypair, since each algorithm uses a different key type.

Upgrade Notes

  • [bug 2148398] The identity:create_trust policy rule now uses %(target.trust.trustor_user_id)s instead of %(trust.trustor_user_id)s. The trust data from the request body is now passed explicitly via target_attr rather than relying on the JSON body merge. This aligns create_trust with all other trust policy rules which already use the target.trust.* prefix. Deployments that override the identity:create_trust policy and reference %(trust.trustor_user_id)s must update to %(target.trust.trustor_user_id)s.

  • [bug 2150089] Two new [security_compliance] options control opt-in insecure behaviour for operators with workflows that break after this upgrade:

    allow_insecure_admin_trust_cross_project_credentials_access (default False): set to True if admin-role trusts or application credentials need to access credentials across multiple projects (e.g. Mistral cron triggers syncing EC2 credentials system-wide).

    allow_insecure_application_credential_trust_escalation (default False): set to True if application credentials must create or manage trusts (e.g. Heat stacks authenticated via application credentials). Use OIDC federation flows (v3oidcclientcredentials, v3oidcdeviceauthz) as the proper long-term alternative.

    Both options are intentionally named to signal that enabling them is insecure. Migrate affected workflows away from these options.

  • Two new configuration options have been added to the [jwt_tokens] section: jws_algorithm and jws_accepted_algorithms. The defaults (ES256 and ['ES256']) preserve the previous behavior, so no action is required for existing deployments.

    To migrate to a new algorithm, operators should:

    1. Add the new algorithm to jws_accepted_algorithms alongside the current one.

    2. Generate a new key pair with keystone-manage create_jws_keypair.

    3. Set jws_algorithm to the new algorithm.

    4. After all tokens signed with the old algorithm have expired, remove the old algorithm from jws_accepted_algorithms.

Critical Issues

  • [bug 2148398] The RBAC enforcer unconditionally merged the raw JSON request body into the policy enforcement dictionary after trusted target data had been set from the database. An attacker could include a target key in the JSON body to overwrite database-sourced RBAC target attributes, causing all %(target.*)s policy substitutions to evaluate against attacker-controlled values. This affected 88 endpoint/method combinations across all Keystone API resource areas. Any authenticated user could exploit this to read every credential secret in the deployment, create EC2 credentials for arbitrary users, or revoke other users’ tokens. A domain administrator could escalate to full cloud admin by creating inherited role grants on other domains. The vulnerability has been present since the Rocky release (14.0.0).

Security Issues

  • [bug 2148398] The RBAC policy enforcer now namespaces JSON request body data under a request_body key in the policy dictionary instead of merging it at the top level. This prevents user-controlled input from overwriting security-critical keys such as target (populated from the database by build_target or target_attr) and URL path parameters like user_id. All upstream policy rules are unaffected by this change. Deployments with custom policy rules that reference JSON body fields directly via %(field_name)s substitutions (not under target.) will need to update those references to %(request_body.field_name)s.

  • [bug 2150089] Delegated tokens (trusts, application credentials, OAuth1 access tokens) are now restricted to credentials whose project_id matches the token’s project scope. This closes a cross-project lateral movement vector where a delegated token could read, modify, or delete credentials belonging to a different project, including EC2 keys and TOTP/MFA seed bindings.

    Application credential tokens are now blocked from all trust operations (create, delete, list, get). Allowing an application credential to bootstrap a trust creates a new delegation context whose token can access authentication material outside the delegation chain, breaking the audit trail. The unrestricted flag governs credential management, not trust management.

  • [bug 2152932] Fixed a database connection leak that could affect deployments using a MySQL backend for federation service provider or identity mapping data. Under sustained token validation or federation-related API activity, keystone workers could retain database connections longer than intended and eventually exhaust their local connection pools. Operators may have observed intermittent API failures, request timeouts, or MySQL connection exhaustion until affected worker processes were restarted.

Bug Fixes

  • [bug 2134925] Fixed a crash (HTTP 500) when listing sub-resource endpoints with a limit query parameter (e.g. GET /v3/users/{user_id}/projects?limit=1). The wrap_collection method now includes URL path parameters from flask.request.view_args when building the next pagination link, so that flask.url_for() can correctly resolve sub-resource routes.

  • Fixed token validation to correctly handle mixed key types in the public key repository. Previously, jwt.decode() could raise InvalidKeyError or InvalidAlgorithmError when encountering public keys of a different type than expected, causing token validation to fail instead of trying the next available key. These exceptions are now handled gracefully during the key iteration loop.

  • Fixed jwt.decode() call in _decode_token_from_id to pass algorithms as a list instead of a string. While PyJWT accepted the string form, it was inconsistent with the documented API.