OpenKeel: the sovereign French Cloud solution of the inherent group, with a European reach Discover inherent

Reverse-spec · Services

keystone — Async processing

Processing triggered outside the API — keystone — branch stable/2026.2

Branch stable/2026.2 @ e6dc5ae079e6 — repository https://opendev.org/openstack/keystone — analysed on 2026-10-28

Finding: no bus consumer, no periodic task

FamilyPresent?Check
Bus consumers (RPC, notification listeners)nooslo.messaging is only used through Notifier (keystone/notifications.py:487-506). The two "subscriptions" in the inventory are false positives: create_consumer creates an OAuth1 consumer (keystone/api/os_oauth1.py:132)
SQL polling, periodic tasksnono periodic_task, LoopingCall or timer outside tests
Cache pollingnothe caches expire (cache_time) or are invalidated by events (see interactions § 4)
In-process eventsyesnotifications.register_event_callback and the @notifications.listener decorator: callbacks run synchronously, inside the API request, when a manager emits a created, updated, deleted, disabled or internal event

So the "background" work of Keystone is of two kinds: cascades run inside the request that triggered them, and operator commands (keystone-manage) that must be scheduled outside (cron, Kubernetes jobs).

1. In-process callbacks (cascades)

notify_event_callbacks (keystone/notifications.py:466-485) calls every function registered for (event, resource type), in the request thread and in its transaction context. An exception in a callback propagates to the request [inferred: no try/except around the call].

EventRegistered reactionEffectDefined at
deleted userrevocationrevocation event user_id → every token of the user becomes invalidkeystone/revoke/core.py:76-90
disabled userrevocationsamekeystone/revoke/core.py:83
deleted / disabled userapplication credentialsdeletion of the user's application credentials and access ruleskeystone/application_credential/core.py:45-62
deleted usertrustsdeletion of the trusts where the user is trusteekeystone/trust/core.py:40-52
deleted / disabled user, domain; disabled project; deleted trusttoken and receipt cachesthe tokens and receipts regions are invalidatedkeystone/token/provider.py:96-130, keystone/receipt/provider.py:73-90
deleted projectrevocationrevocation event project_idkeystone/revoke/core.py:81
deleted projectidentitydefault_project_id is cleared for the users who had itkeystone/identity/core.py:613-617, keystone/identity/core.py:659
deleted project or endpointcatalogdeletion of the OS-EP-FILTER associationskeystone/catalog/core.py:58-90
deleted trust, OAuth1 consumerrevocationrevocation event trust_id / consumer_idkeystone/revoke/core.py:78-79
deleted domainassignmentsdeletion of every assignment in the domain, invalidation of computed assignmentskeystone/assignment/core.py:76-90
internal domain_deletedidentitydeletion of the domain's groups and users (SQL backend)keystone/identity/core.py:608-657
internal domain_deletedfederationdeletion of the identity providers tied to the domainkeystone/federation/core.py:48-60
internal persist_revocation_event_for_userrevocationrevocation event for the user (emitted by _persist_revocation_event_for_user, keystone/identity/core.py:1583-1594, called by update_user when the password or enabled changes, delete_group, remove_user_from_group and change_password: keystone/identity/core.py:1379, keystone/identity/core.py:1505, keystone/identity/core.py:1567, keystone/identity/core.py:1702)keystone/revoke/core.py:84-89
internal remove_application_credentials_for_userapplication credentialsdeletion of the application credentials that depend on a removed role assignment (emitted by keystone/assignment/core.py:111)keystone/application_credential/core.py:59-62
internal invalidate_token_cachetoken cacheinvalidation of tokens, emitted on role, assignment and membership changes (keystone/assignment/core.py:296, keystone/identity/core.py:1386)keystone/token/provider.py:110-112

Project deletion itself also cleans its assignments, credentials, trusts and limits, directly and without an event (keystone/resource/core.py:521-539).

Operational consequences:

  • Deleting a domain or a large project is one long request that does all the cleanup. There is no queue: a timeout on the HTTP proxy side can interrupt the response while the work goes on, or leave it half done if the WSGI worker is killed [inferred].
  • Revocation events are written in the request, so a token is invalid on every node as soon as the commit is done, within the token cache: each node keeps its tokens cache, unless the cache is shared and invalidated by region (see 03 § 4).

2. Notifications sent (to the outside)

Every create, update, delete or disable operation, every role assignment and every authentication (success excluded by default) publishes an identity.* event (see interactions § 5). It is fire-and-forget: a bus failure is logged and does not fail the request (keystone/notifications.py:582-636). Consumers outside Keystone include Ceilometer, Designate and the audit middleware [inferred: outside this repository].

3. Work at API process startup

StepPurposeDefined at
keystone.server.configureread the configuration (OS_KEYSTONE_CONFIG_*), set up loggingkeystone/server/flask/core.py:145-170
setup_backendsload the drivers through stevedore (keystone.identity, keystone.token.provider…, see pyproject.toml), configure the caches, register the callbacks abovekeystone/server/backends.py
application_factorybuild Flask, register the exception handlers and the 27 API modules, mount /healthcheckkeystone/server/flask/application.py:186-238
middlewarestack the pipeline (CORS, size limit, proxy, profiler, request ID, URL normalisation, auth context)keystone/server/flask/core.py:93-142

Unlike Placement, Keystone writes nothing to the database at startup: no standard data is copied. Default roles, the admin user and the catalog come from keystone-manage bootstrap.

4. Operator commands (keystone-manage, keystone/cmd/cli.py)

CommandPurposeFrequencyDefined at
db_sync [--expand|--migrate|--contract|--check]Alembic migrations, in rolling-upgrade phaseseach upgradekeystone/cmd/cli.py:361-494
bootstrapcreate (idempotently) the admin, member, reader and service roles and their implications, the admin domain, project and user, the system assignment, and the region and Keystone endpointsinstall, then each upgradekeystone/cmd/cli.py:64-262, keystone/cmd/bootstrap.py
fernet_setup / fernet_rotate (and token_setup/token_rotate)create and rotate the token keysregular (cron), with the repository synchronised on every nodekeystone/cmd/cli.py:613-780
create_jws_keypairES256 keys for the JWS provideroncekeystone/cmd/cli.py:688
receipt_setup / receipt_rotateMFA receipt keysregularkeystone/cmd/cli.py:781-826
credential_setup / credential_rotate / credential_migratecredential encryption keys; migrate re-encrypts every credential row with the primary key before old keys are droppedat each credential key rotationkeystone/cmd/cli.py:828-970
trust_flush [--project-id] [--trustor-user-id] [--trustee-user-id] [--date]purge expired or deleted trusts (keystone never deletes them by itself)regularkeystone/cmd/cli.py:972-1050
mapping_purge / mapping_populateclean or pre-fill id_mapping (LDAP)as neededkeystone/cmd/cli.py:1051, keystone/cmd/cli.py:1594
domain_config_uploadload domain configuration files into the databaseas neededkeystone/cmd/cli.py:1358
saml_idp_metadatagenerate the SAML IdP metadataoncekeystone/cmd/cli.py:1393
mapping_enginetest a federation mapping against an assertion, offlineas neededkeystone/cmd/cli.py:1404
doctorconfiguration checksas neededkeystone/cmd/cli.py:345
reset_last_activereset last_active_at (account inactivity)as neededkeystone/cmd/cli.py:505
keystone-status upgrade checkpre-upgrade checksbefore an upgradekeystone/cmd/status.py

What nobody purges automatically:

  • expired trusts: trust_flush is needed;
  • users inactive beyond [security_compliance]/disable_user_account_days_inactive: no task disables them. The enabled property is computed on read from last_active_at, or created_at if never active (keystone/identity/backends/sql_model.py:217-238), so such a user simply reads as disabled. Accounts with the ignore_user_inactivity option are exempt;
  • revocation events: purged at each new revocation (see 03 § 3).

Source: reverse-spec-keystone/05-async-processing_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.