Much of the design is precipitated from the expectation that the auth backends for most deployments will actually be shims in front of existing user systems.
Keystone is organized as a group of internal services exposed on one or many endpoints. Many of these services are used in a combined fashion by the frontend, for example an authenticate call will validate user/tenant credentials with the Identity service and, upon success, create and return a token with the Token service.
The Identity service provides auth credential validation and data about Users, Tenants and Roles, as well as any associated metadata.
In the basic case all this data is managed by the service, allowing the service to manage all the CRUD associated with the data.
In other cases, this data is pulled, by varying degrees, from an authoritative backend service. An example of this would be when backending on LDAP. See LDAP Backend below for more details.
The Token service validates and manages Tokens used for authenticating requests once a user/tenant’s credentials have already been verified.
The Catalog service provides an endpoint registry used for endpoint discovery.
The Policy service provides a rule-based authorization engine and the associated rule management interface.
Keystone is an HTTP front-end to several services. Like other OpenStack applications, this is done using python WSGI interfaces and applications are configured together using Paste. The application’s HTTP endpoints are made up of pipelines of WSGI middleware, such as:
[pipeline:public_api] pipeline = token_auth admin_token_auth json_body debug ec2_extension public_service
These in turn use a subclass of keystone.common.wsgi.ComposingRouter to link URLs to Controllers (a subclass of keystone.common.wsgi.Application). Within each Controller, one or more Managers are loaded (for example, see keystone.catalog.core.Manager), which are thin wrapper classes which load the appropriate service driver based on the keystone configuration.
At this time, the policy service and associated manager is not exposed as a URL frontend, and has no associated Controller class.
Each of the services can configured to use a backend to allow Keystone to fit a variety of environments and needs. The backend for each service is defined in the keystone.conf file with the key driver under a group associated with each service.
A general class under each backend named Driver exists to provide an abstract base class for any implementations, identifying the expected service implementations. The drivers for the services are:
If you implement a backend driver for one of the keystone services, you’re expected to subclass from these classes. The default response for the defined apis in these Drivers is to raise a keystone.service.TokenController.
A simple backend interface meant to be further backended on anything that can support primary key lookups, the most trivial implementation being an in-memory dict.
Supports all features of the general data model.
A SQL based backend using SQLAlchemy to store data persistently. The keystone-manage command introspects the backends to identify SQL based backends when running “db_sync” to establish or upgrade schema. If the backend driver has a method db_sync(), it will be invoked to sync and/or migrate schema.
Extra simple backend that uses the current system’s PAM service to authenticate, providing a one-to-one relationship between Users and Tenants with the root User also having the ‘admin’ role.
Largely designed for a common use case around service catalogs in the Keystone project, a Catalog backend that simply expands pre-configured templates to provide catalog data.
Example paste.deploy config (uses $ instead of % to avoid ConfigParser’s interpolation):
[DEFAULT] catalog.RegionOne.identity.publicURL = http://localhost:$(public_port)s/v2.0 catalog.RegionOne.identity.adminURL = http://localhost:$(public_port)s/v2.0 catalog.RegionOne.identity.internalURL = http://localhost:$(public_port)s/v2.0 catalog.RegionOne.identity.name = 'Identity Service'
The LDAP backend stored Users and Tenents in separate Subtrees. Roles are recorded as entries under the Tenants.
Keystone was designed from the ground up to be amenable to multiple styles of backends and as such many of the methods and data types will happily accept more data than they know what to do with and pass them on to a backend.
There are a few main data types:
- User: has account credentials, is associated with one or more tenants
- Tenant: unit of ownership in openstack, contains one or more users
- Role: a first-class piece of metadata associated with many user-tenant pairs.
- Token: identifying credential associated with a user or user and tenant
- Extras: bucket of key-value metadata associated with a user-tenant pair.
- Rule: describes a set of requirements for performing an action.
While the general data model allows a many-to-many relationship between Users and Tenants and a many-to-one relationship between Extras and User-Tenant pairs, the actual backend implementations take varying levels of advantage of that functionality.
While it is expected that any “real” deployment at a large company will manage their users, tenants and other metadata in their existing user systems, a variety of CRUD operations are provided for the sake of development and testing.
CRUD is treated as an extension or additional feature to the core feature set in that it is not required that a backend support it. It is expected that backends for services that don’t support the CRUD operations will raise a keystone.exception.NotImplemented.