2
Copyright 2011-2012 OpenStack, LLC
5
Licensed under the Apache License, Version 2.0 (the "License"); you may
6
not use this file except in compliance with the License. You may obtain
7
a copy of the License at
9
http://www.apache.org/licenses/LICENSE-2.0
11
Unless required by applicable law or agreed to in writing, software
12
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
License for the specific language governing permissions and limitations
20
Much of the design is precipitated from the expectation that the auth backends
21
for most deployments will actually be shims in front of existing user systems.
27
Keystone is organized as a group of internal services exposed on one or many
28
endpoints. Many of these services are used in a combined fashion by the
29
frontend, for example an authenticate call will validate user/tenant
30
credentials with the Identity service and, upon success, create and return a
31
token with the Token service.
37
The Identity service provides auth credential validation and data about Users,
38
Tenants and Roles, as well as any associated metadata.
40
In the basic case all this data is managed by the service, allowing the service
41
to manage all the CRUD associated with the data.
43
In other cases, this data is pulled, by varying degrees, from an authoritative
44
backend service. An example of this would be when backending on LDAP. See
45
`LDAP Backend` below for more details.
51
The Token service validates and manages Tokens used for authenticating requests
52
once a user/tenant's credentials have already been verified.
58
The Catalog service provides an endpoint registry used for endpoint discovery.
64
The Policy service provides a rule-based authorization engine and the
65
associated rule management interface.
67
------------------------
68
Application Construction
69
------------------------
71
Keystone is an HTTP front-end to several services. Like other OpenStack
72
applications, this is done using python WSGI interfaces and applications are
73
configured together using Paste_. The application's HTTP endpoints are made up
74
of pipelines of WSGI middleware, such as::
77
pipeline = token_auth admin_token_auth json_body debug ec2_extension public_service
79
These in turn use a subclass of :mod:`keystone.common.wsgi.ComposingRouter` to
80
link URLs to Controllers (a subclass of
81
:mod:`keystone.common.wsgi.Application`). Within each Controller, one or more
82
Managers are loaded (for example, see :mod:`keystone.catalog.core.Manager`),
83
which are thin wrapper classes which load the appropriate service driver based
84
on the keystone configuration.
87
* :mod:`keystone.identity.core.TenantController`
88
* :mod:`keystone.identity.core.UserController`
89
* :mod:`keystone.identity.core.RoleController`
92
* :mod:`keystone.catalog.core.ServiceController`
93
* :mod:`keystone.service.VersionController`
96
* :mod:`keystone.service.TokenController`
99
* :mod:`keystone.service.ExtensionsController`
101
At this time, the policy service and associated manager is not exposed as a URL
102
frontend, and has no associated Controller class.
105
.. _Paste: http://pythonpaste.org/
111
Each of the services can configured to use a backend to allow Keystone to fit a
112
variety of environments and needs. The backend for each service is defined in
113
the keystone.conf file with the key ``driver`` under a group associated with
116
A general class under each backend named ``Driver`` exists to provide an
117
abstract base class for any implementations, identifying the expected service
118
implementations. The drivers for the services are:
120
* :mod:`keystone.identity.core.Driver`
121
* :mod:`keystone.token.core.Driver`
123
If you implement a backend driver for one of the keystone services, you're
124
expected to subclass from these classes. The default response for the defined
125
apis in these Drivers is to raise a :mod:`keystone.service.TokenController`.
130
A simple backend interface meant to be further backended on anything that can
131
support primary key lookups, the most trivial implementation being an in-memory
134
Supports all features of the general data model.
140
A SQL based backend using SQLAlchemy to store data persistently. The
141
keystone-manage command introspects the backends to identify SQL based backends
142
when running "db_sync" to establish or upgrade schema. If the backend driver
143
has a method db_sync(), it will be invoked to sync and/or migrate schema.
149
Extra simple backend that uses the current system's PAM service to authenticate,
150
providing a one-to-one relationship between Users and Tenants with the `root`
151
User also having the 'admin' role.
157
Largely designed for a common use case around service catalogs in the Keystone
158
project, a Catalog backend that simply expands pre-configured templates to
159
provide catalog data.
161
Example paste.deploy config (uses $ instead of % to avoid ConfigParser's
165
catalog.RegionOne.identity.publicURL = http://localhost:$(public_port)s/v2.0
166
catalog.RegionOne.identity.adminURL = http://localhost:$(public_port)s/v2.0
167
catalog.RegionOne.identity.internalURL = http://localhost:$(public_port)s/v2.0
168
catalog.RegionOne.identity.name = 'Identity Service'
174
Keystone was designed from the ground up to be amenable to multiple styles of
175
backends and as such many of the methods and data types will happily accept
176
more data than they know what to do with and pass them on to a backend.
178
There are a few main data types:
180
* **User**: has account credentials, is associated with one or more tenants
181
* **Tenant**: unit of ownership in openstack, contains one or more users
182
* **Role**: a first-class piece of metadata associated with many user-tenant pairs.
183
* **Token**: identifying credential associated with a user or user and tenant
184
* **Extras**: bucket of key-value metadata associated with a user-tenant pair.
185
* **Rule**: describes a set of requirements for performing an action.
187
While the general data model allows a many-to-many relationship between Users
188
and Tenants and a many-to-one relationship between Extras and User-Tenant pairs,
189
the actual backend implementations take varying levels of advantage of that
197
While it is expected that any "real" deployment at a large company will manage
198
their users, tenants and other metadata in their existing user systems, a
199
variety of CRUD operations are provided for the sake of development and testing.
201
CRUD is treated as an extension or additional feature to the core feature set
202
in that it is not required that a backend support it. It is expected that
203
backends for services that don't support the CRUD operations will raise a
204
:mod:`NotImplementedError`.
207
----------------------------------
208
Approach to Authorization (Policy)
209
----------------------------------
211
Various components in the system require that different actions are allowed
212
based on whether the user is authorized to perform that action.
214
For the purposes of Keystone there are only a couple levels of authorization
217
* Require that the performing user is considered an admin.
218
* Require that the performing user matches the user being referenced.
220
Other systems wishing to use the policy engine will require additional styles
221
of checks and will possibly write completely custom backends. Backends included
234
Given a list of matches to check for, simply verify that the credentials
235
contain the matches. For example::
237
credentials = {'user_id': 'foo', 'is_admin': 1, 'roles': ['nova:netadmin']}
239
# An admin only call:
240
policy_api.can_haz(('is_admin:1',), credentials)
242
# An admin or owner call:
243
policy_api.can_haz(('is_admin:1', 'user_id:foo'),
247
policy_api.can_haz(('roles:nova:netadmin',),
251
Credentials are generally built from the user metadata in the 'extras' part
252
of the Identity API. So, adding a 'role' to the user just means adding the role
253
to the user metadata.
259
(Not yet implemented.)
261
Another approach to authorization can be action-based, with a mapping of roles
262
to which capabilities are allowed for that role. For example::
264
credentials = {'user_id': 'foo', 'is_admin': 1, 'roles': ['nova:netadmin']}
267
policy_api.add_policy('action:nova:add_network', ('roles:nova:netadmin',))
269
policy_api.can_haz(('action:nova:add_network',), credentials)
272
In the backend this would look up the policy for 'action:nova:add_network' and
273
then do what is effectively a 'Simple Match' style match against the creds.