Keystone: the HTTP identity layer OpenStack services actually ask
OpenStack Identity (Keystone). Mirror of code maintained at opendev.org.
At a glance
- What is it?
- OpenStack Keystone is the Python service that issues tokens, checks tokens and describes where other OpenStack services live, and it is commonly dropped in front of an existing LDAP directory. Here is what its plugin layout, packaging and release process really commit you to.
- Who is it for?
- Adopt Keystone if you are running more than one OpenStack service and want a single token authority in front of a directory you already have; do not adopt it as a general purpose login server for applications outside the OpenStack family.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Keystone exists to put one token authority in front of a directory
The problem Keystone solves is narrow and specific: an OpenStack cloud has many independent services, and each of them needs to know who is calling, what that caller is allowed to do, and where the other services are located. Keystone answers all three over HTTP. Its own description states that it provides authentication, authorization and service discovery mechanisms via HTTP primarily for use by projects in the OpenStack family, and that it is most commonly deployed as an HTTP interface to existing identity systems such as LDAP.
That last clause matters more than the headline. Keystone is usually not the source of truth for a person. LDAP, or whatever directory you already run, holds the credentials. Keystone's job is to translate that directory into a token protocol the rest of the cloud can consume without each service speaking LDAP or Kerberos directly. The audience is therefore infrastructure operators who have already decided where identities live and now need a uniform, HTTP-addressable way to ask about them.
The trade-off is that you now operate two things instead of one. The directory keeps its own schema, its own password policy and its own group model, and Keystone adds a second layer with its own database, its own policy files and its own token lifetimes on top. If you were hoping to replace an existing identity service with one Python package, that is not what this project does.
Credential types are chosen by stevedore entry points, not by a switch in one file
The clearest view of Keystone's design comes from the packaging metadata, where each authentication mechanism is registered under its own entry point group. A deployment loads the plugin set that the entry point registry resolves, which means the set of credential types a cloud accepts is partly a packaging question rather than a single switch in one configuration file.
The `keystone.auth.external` group is the clearest example. Three names are registered in it, and two of them point at the same class:
[project.entry-points."keystone.auth.external"]
default = "keystone.auth.plugins.external:DefaultDomain"
DefaultDomain = "keystone.auth.plugins.external:DefaultDomain"
Domain = "keystone.auth.plugins.external:Domain"So `default` and `DefaultDomain` resolve to the same implementation, while `Domain` resolves to a different one, and the `kerberos` group registers `keystone.auth.plugins.external:KerberosDomain` as its default. Other groups in the same listing cover `application_credential`, `ec2credential` and `oauth1`. The practical consequence for an operator is that renaming or removing a plugin changes which credential types the service will honour, and the set of names to load has to be decided deliberately rather than discovered at runtime.
This plugin-first shape is also why Keystone fits into a larger OpenStack deployment rather than standing alone: the token it issues is consumed by other services, and those services rely on the plugin conventions being consistent across the deployment.
Assignment data has a SQL backend, and the database choice is an entry point too
Keystone does not store everything in a directory. Assignments, which map an actor to a role on a project or domain, live in Keystone's own store, and that store is selected through another entry point:
[project.entry-points."keystone.assignment"]
sql = "keystone.assignment.backends.sql:Assignment"The dependency list backs that up: SQLAlchemy at a lower bound of 1.4.0, oslo.db at 6.0.0, oslo.messaging for the event notifications that accompany writes, and oslo.cache with dogpile.cache for caching. The presence of oslo.policy in the same list is what makes the authorization half of the story configurable, since policy enforcement is driven by rules rather than by code inside the plugin.
For a team evaluating this, the split is the thing to internalize. Users and credentials come from an external system, roles and assignments come from Keystone's database, and every service in the cloud reads the resulting token. That means a Keystone deployment needs a database with a migration story and a backup policy of its own, even though the user records themselves live elsewhere. It also means the assignment backend is the piece to look at first when assignments behave unexpectedly, since it is the piece whose data you actually own.
Installation is a packaging question, and the README sends you to the docs for the steps
There is no install command in the project README, and inventing one would be misleading. What the README does give is the set of documentation locations, the canonical client library, and the build metadata that describes what the package actually is. The build system is pbr, and the package metadata states the interpreter floor and the supported versions:
name = "keystone"
description = "OpenStack Identity"
requires-python = ">=3.11"
license = {text = "Apache-2.0"}The legacy entry point still exists and still pins the same backend, which tells you the project is mid-transition rather than newly written:
setuptools.setup(setup_requires=['pbr>=2.0.0'], pbr=True)For a first real use, the practical path is the one the README points to: the developer documentation lives in `doc/source/` and is published at docs.openstack.org/keystone/latest, the HTTP API reference is at docs.openstack.org/api-ref/identity, and administrator documentation is published from the openstack-manuals source. The canonical client is python-keystoneclient, and the dependency list requires python-keystoneclient at 3.8.0 or newer, so the client is expected to be part of your workflow from the first script. A `devstack/` directory sits at the top level of the tree, and the documentation for administrators is where a local trial deployment is described. What the reader should expect at the end of that exercise is a running HTTP endpoint that issues and validates tokens against whatever directory you configured, and an API reference to check the exact request shape rather than guessing it.
Dependency floors are declared as best effort and explicitly not tested
The dependency file carries a comment that most projects would be happy to leave unsaid. It states that the lower bounds listed are a best effort to keep them up to date, that the project does not test them, and that there is no guarantee they are all correct, with an invitation to report or propose a fix for incorrect bounds.
That single comment changes how you should read the whole file. Bounds like cryptography at 2.7, bcrypt at 3.1.3, PyJWT at 1.6.1, oauthlib at 0.6.2 and pysaml2 at 5.0.0 are not tested floors in the sense of a continuously exercised matrix; they are starting points. pysaml2 in particular is the SAML stack, and no version of it is pinned above a minimum, so an assembly that pulls in the current pysaml2 release may not match what a Keystone build was exercised against.
The same file also shows the dependency choices that shape behaviour. keystonemiddleware at 7.0.0 and oslo.middleware at 3.31.0 handle the request pipeline around the API, oslo.context carries request context, oslo.serialization carries the token payload format, and pycadf, osprofiler and msgpack cover audit trails, profiling and message serialization respectively. pycadf carries an explicit exclusion of version 2.0.0, and oslo.serialization excludes 2.19.1. Those exclusions exist because a specific release was known to be broken, which tells you the floor values are the result of incident response, not of a designed compatibility matrix.
There are no GitHub releases, so version tracking runs through Reno and Launchpad
The GitHub repository is a mirror. Its description says it mirrors code maintained at opendev.org, and the canonical homepage is opendev.org/openstack/keystone. The project is not archived, and the last push was on 2026-10-17, so the code is being moved, but the GitHub project itself publishes no releases at all.
That is a real difference in how you have to operate. There is no GitHub release page to point a colleague at, no tag list to skim, and no changelog rendered on the mirror. Instead the README directs you to three separate places: release notes published at docs.openstack.org/releasenotes/keystone, bug and feature tracking on Launchpad at bugs.launchpad.net/keystone, and future design work in the keystone-specs repository at specs.openstack.org/openstack/keystone-specs. The tree backs this up with a `releasenotes/` directory, a `reno.yaml` configuration, and a `doc/` directory.
For upgrade planning this means the version you care about is whatever Reno and the OpenStack release cycle defines, not a GitHub tag, and the Launchpad tracker is where a regression against your deployment belongs. The tree also carries `playbooks/`, `rally-jobs/`, `config-generator/`, `httpd/` and an `examples/pki/` directory, which is the shape of a project that ships deployment recipes and an example certificate tree alongside the service itself.
Where Keystone is the wrong tool
Keystone is the wrong choice in several fairly ordinary situations, and the source says so plainly enough even without a limitations section. If your application is not part of the OpenStack family, the README's own framing, 'primarily for use by projects in the OpenStack family', puts you outside the intended audience. Building an HTTP token service on top of a directory for a single internal web app means taking on a service discovery registry, a policy engine, an assignment database and a plugin system to solve a login problem that a library can solve.
A smaller alternative exists inside Keystone's own dependency list. oauthlib and PyJWT are both required, and both implement token issuance directly without a token service, a role model or a catalog. For a team that just needs signed bearer tokens, using those libraries directly is a smaller system with fewer moving parts, at the cost of having no service catalog and no cross-service role assignment. The difference in approach is exactly that: Keystone is a stateful, pluggable, multi-service identity service, while the libraries are stateless signing and verification utilities.
There is a second failure mode worth naming: the plugin surface is broad enough that a deployment can easily enable more credential types than it intends. With groups for application credentials, EC2 credentials, OAuth1, Kerberos and the external domain plugins, and with the enabled set selected by entry point names, it is entirely possible to ship a cloud that accepts credentials nobody expected it to accept. Verify which plugins your deployment loads before opening the endpoint to users, rather than after.
Editorial conclusion
Adopt Keystone if you are running more than one OpenStack service and want a single token authority in front of a directory you already have; do not adopt it as a general purpose login server for applications outside the OpenStack family. Before you commit, check the plugin entry points your deployment will load, confirm that the `keystone.assignment` backend points at the database you intend to use, and read the release notes at docs.openstack.org/releasenotes/keystone rather than assuming the GitHub mirror publishes tagged releases, because it does not.
Frequently asked questions
What is OpenStack Keystone used for?
Keystone provides authentication, authorization and service discovery over HTTP for OpenStack projects. It is most commonly deployed as an HTTP interface to existing identity systems such as LDAP.
What programming language and Python version does Keystone require?
Keystone is written in Python and its packaging metadata sets `requires-python = ">=3.11"`, with classifiers for Python 3.11, 3.12 and 3.13.
How is Keystone licensed and where do releases come from?
The license is Apache-2.0. The GitHub repository is a mirror of code maintained at opendev.org and publishes no GitHub releases; release notes are published at docs.openstack.org/releasenotes/keystone and bugs are tracked on Launchpad.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/openstack-keystone)Was this useful?