Reverse-specification of Keystone — branch stable/2026.2
Branch
stable/2026.2@e6dc5ae079e6(30.0.0-5-ge6dc5ae07) — repository https://opendev.org/openstack/keystone — analysed on 2026-10-28
- Scope: all non-test code (351 files, about 67,000 lines): the Flask API and its middlewares, authentication and tokens, identity (SQL and LDAP), resource, assignment, catalog, credentials, trusts, federation, OAuth1/2, limits, revocation, notifications and cache, the
keystone-manageCLI, and the branch history. - References are
file:linerelative to the repository root. [inferred] marks a statement that was not followed to the end in the code.
Files of this specification
| File | Content |
|---|---|
| 01-rest-api_stable-2026.2.md | conventions, functional description by area, the 259 operations extracted from the Flask application with handler and policy rule |
| 02-errors_stable-2026.2.md | central translation, message masking, statuses and situations, catalogue of 109 exceptions |
| 03-interactions_stable-2026.2.md | HTTP, token format (Fernet payloads, keys), 47 tables, cache and distributed invalidation, CADF notifications, LDAP, xmlsec1 |
| 04-scenarios_stable-2026.2.md | 5 scenarios: authentication and validation, user disabling, OIDC federation, application credential, key rotation |
| 05-async-processing_stable-2026.2.md | no consumer or periodic task; in-process cascade callbacks; keystone-manage commands |
| 06-change-history_stable-2026.2.md | the 4 commits of the branch (1 security, 1 fix) and the carry-over plan |
| 07-rewrite-pack_stable-2026.2.md | rewrite pack (OpenKeel): contracts in _rewrite/ (routes, OpenAPI, request and response schemas, migrated schema and its differences, policies, configuration), Fernet token format with 227 vectors, mapping engine with 705 cases, client expectations, strategies, conformance |
Overview
Keystone is OpenStack's identity and authorisation service:
- it authenticates users, services and federated identities;
- it issues tokens that are not stored (Fernet), which the other services have validated by keystonemiddleware;
- it holds the projects, domains, roles and assignments that the policies of every service use;
- it publishes the service catalog.
It is a synchronous service:
- no RPC, and no outbound REST call;
- its effects outside its database are the CADF notifications it publishes, and the key files shared between nodes.
flowchart LR
subgraph clients[Clients]
U[Users / CLI / Horizon]
S[OpenStack services<br/>keystonemiddleware]
end
subgraph ks[keystone-api WSGI — Flask]
MW[middlewares<br/>CORS, size limit, request-id,<br/>URL normalisation, auth context]
API[27 API modules<br/>keystone/api/*]
MGR[managers + drivers<br/>identity, resource, assignment,<br/>catalog, token, revoke…]
end
U -->|HTTP /v3| MW --> API --> MGR
S -->|GET /v3/auth/tokens| MW
MGR -->|SQL| DB[(47 tables)]
MGR -->|LDAP, read-only| LDAP[(directory)]
MGR -->|memcache| C[(oslo.cache)]
MGR -->|AMQP notify| MQ[(RabbitMQ)]
MGR -->|reads| K[[fernet-keys / credential-keys]]
CLI[keystone-manage] -->|db_sync, bootstrap, *_rotate, trust_flush| DB
CLI --> KProcesses
| Process | Entry point | Role |
|---|---|---|
| keystone-api | WSGI keystone.wsgi.api:application (keystone/wsgi/api.py), built by initialize_application (keystone/server/flask/core.py:145-186) | the whole REST API (port 5000 by convention [inferred]) |
| keystone-manage | keystone.cmd.manage:main (pyproject.toml) | migrations, bootstrap, key rotation, purges, federation tools (keystone/cmd/cli.py) |
| keystone-status | keystone.cmd.status:main | pre-upgrade checks |
External dependencies
| System | Protocol | Configuration | Usage |
|---|---|---|---|
| SQL database | SQL (oslo.db) | [database]/connection | all persistent state; tokens excepted |
| Key files | file system | [fernet_tokens], [credential], [fernet_receipts], [jwt_tokens] | token and receipt encryption, credential encryption |
| Cache | memcache, redis… | [cache] | validated tokens, effective roles, catalog… |
| RabbitMQ | AMQP (notifier) | [oslo_messaging_notifications], [DEFAULT]/notification_format | CADF audit and resource events |
| LDAP | LDAP v3 | [ldap], per-domain configuration | read-only users and groups |
| xmlsec1 | process | [saml] | SAML assertion signing (Keystone as IdP) |
Key figures
259 HTTP operations on 125 paths, 204 default policy rules, 109 exception classes and 689 raise sites, 47 tables, 11 Fernet payload versions, 7 cache regions plus 6 memoised groups, 0 periodic tasks, about 15 types of cascade callbacks.
Points of attention
- Token format = an inter-version and inter-node contract: Fernet keys shared by every node; the authentication methods encoded as **bits in the order of
[auth]/methods** (changing that order breaks existing tokens); payloads versioned 0 to 10 (see 03 § 2). - Revocation: every validation queries
revocation_eventunless cached. The table is only purged when a new revocation is written; there is no periodic task. - Synchronous cascades: deleting a domain or a project, or disabling a user, does all its cleanup inside the request (05 § 1).
- Cache and invalidation: correct only with a shared cache (memcached); with a per-process cache, invalidations stay local.
- 401 vs 404: an invalid token being validated is a 404
TokenNotFound; auth messages are masked unlessinsecure_debugis set. - Collection methods that answer 400 instead of 405 (
DELETE /v3/policies…), because of the shared Flask resources. - Security: the EC2/S3 fix on this branch (bug 2165281) must be carried over to any fork (06).
Blind spots / [inferred]
- The behaviour of keystonemiddleware (caches,
delay_auth_decision) is described from what Keystone expects of it, not read. - Federation: the mapping engine (
keystone/federation/utils.py, about 1,100 lines) is described by its role, not rule by rule. SAML/ECP and Keystone-to-Keystone were not followed down to the XML. - LDAP: the attribute mappings and filters (
keystone/identity/backends/ldap/common.py, about 2,000 lines) were not detailed. - JWS provider: described from its configuration, its claims not detailed.
- Policies: the 204 rules are in the extraction (
_rewrite/); their effective behaviour by persona (system reader, domain manager…) is not tabulated rule by rule. - The inventory found no RPC or periodic task, and reading the code confirms it.
Source: reverse-spec-keystone/00-summary_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.