1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
|
..
Copyright 2011-2013 OpenStack Foundation
All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
=======================
Middleware Architecture
=======================
Abstract
========
The Keystone middleware architecture supports a common authentication protocol
in use between the OpenStack projects. By using keystone as a common
authentication and authorization mechanism, the OpenStack project can plug in
to existing authentication and authorization systems in use by existing
environments.
In this document, we describe the architecture and responsibilities of the
authentication middleware which acts as the internal API mechanism for
OpenStack projects based on the WSGI standard.
This documentation describes the implementation in
:class:`keystonemiddleware.auth_token`
Specification Overview
======================
'Authentication' is the process of determining that users are who they say they
are. Typically, 'authentication protocols' such as HTTP Basic Auth, Digest
Access, public key, token, etc, are used to verify a user's identity. In this
document, we define an ''authentication component'' as a software module that
implements an authentication protocol for an OpenStack service. OpenStack is
using a token based mechanism to represent authentication and authorization.
At a high level, an authentication middleware component is a proxy that
intercepts HTTP calls from clients and populates HTTP headers in the request
context for other WSGI middleware or applications to use. The general flow
of the middleware processing is:
* clear any existing authorization headers to prevent forgery
* collect the token from the existing HTTP request headers
* validate the token
* if valid, populate additional headers representing the identity that has
been authenticated and authorized
* if invalid, or no token present, reject the request (HTTPUnauthorized)
or pass along a header indicating the request is unauthorized (configurable
in the middleware)
* if the keystone service is unavailable to validate the token, reject
the request with HTTPServiceUnavailable.
.. _authComponent:
Authentication Component
------------------------
Figure 1. Authentication Component
.. image:: images/graphs_authComp.svg
:width: 100%
:height: 180
:alt: An Authentication Component
The middleware may also be configured to operate in a 'delegated mode'.
In this mode, the decision to reject an unauthenticated client is delegated to
the OpenStack service, as illustrated in :ref:`authComponentDelegated`.
Here, requests are forwarded to the OpenStack service with an identity status
message that indicates whether the client's identity has been confirmed or is
indeterminate. It is the OpenStack service that decides whether or not a reject
message should be sent to the client.
.. _authComponentDelegated:
Authentication Component (Delegated Mode)
-----------------------------------------
Figure 2. Authentication Component (Delegated Mode)
.. image:: images/graphs_authCompDelegate.svg
:width: 100%
:height: 180
:alt: An Authentication Component (Delegated Mode)
.. _deployStrategies:
Deployment Strategy
===================
The middleware is intended to be used inline with OpenStack wsgi components,
based on the Oslo WSGI middleware class. It is typically deployed
as a configuration element in a paste configuration pipeline of other
middleware components, with the pipeline terminating in the service
application. The middleware conforms to the python WSGI standard [PEP-333]_.
In initializing the middleware, a configuration item (which acts like a python
dictionary) is passed to the middleware with relevant configuration options.
Configuration
-------------
The middleware is configured within the config file of the main application as
a WSGI component. Example for the auth_token middleware:
.. code-block:: ini
[app:myService]
paste.app_factory = myService:app_factory
[pipeline:main]
pipeline = authtoken myService
[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
# Prefix to prepend at the beginning of the path (string
# value)
#auth_admin_prefix=
# Host providing the admin Identity API endpoint (string
# value)
auth_host=127.0.0.1
# Port of the admin Identity API endpoint (integer value)
auth_port=35357
# Protocol of the admin Identity API endpoint(http or https)
# (string value)
auth_protocol=https
# Complete public Identity API endpoint (string value)
#auth_uri=<None>
# API version of the admin Identity API endpoint (string
# value)
#auth_version=<None>
# Do not handle authorization requests within the middleware,
# but delegate the authorization decision to downstream WSGI
# components (boolean value)
#delay_auth_decision=false
# Request timeout value for communicating with Identity API
# server. (boolean value)
#http_connect_timeout=<None>
# How many times are we trying to reconnect when communicating
# with Identity API Server. (integer value)
#http_request_max_retries=3
# Single shared secret with the Keystone configuration used
# for bootstrapping a Keystone installation, or otherwise
# bypassing the normal authentication process. (string value)
#admin_token=<None>
# Keystone account username (string value)
#admin_user=<None>
# Keystone account password (string value)
admin_password=SuperSekretPassword
# Keystone service account tenant name to validate user tokens
# (string value)
#admin_tenant_name=admin
# Env key for the swift cache (string value)
#cache=<None>
# Required if Keystone server requires client certificate
# (string value)
#certfile=<None>
# Required if Keystone server requires client certificate
# (string value)
#keyfile=<None>
# A PEM encoded Certificate Authority to use when verifying
# HTTPs connections. Defaults to system CAs. (string value)
#cafile=<None>
# Verify HTTPS connections. (boolean value)
#insecure=false
# Directory used to cache files related to PKI tokens (string
# value)
#signing_dir=<None>
# If defined, the memcached server(s) to use for caching (list
# value)
# Deprecated group/name - [DEFAULT]/memcache_servers
#memcached_servers=<None>
# In order to prevent excessive requests and validations, the
# middleware uses an in-memory cache for the tokens the
# Keystone API returns. This is only valid if memcache_servers
# is defined. Set to -1 to disable caching completely.
# (integer value)
#token_cache_time=300
# Value only used for unit testing (integer value)
#revocation_cache_time=1
# (optional) if defined, indicate whether token data should be
# authenticated or authenticated and encrypted. Acceptable
# values are MAC or ENCRYPT. If MAC, token data is
# authenticated (with HMAC) in the cache. If ENCRYPT, token
# data is encrypted and authenticated in the cache. If the
# value is not one of these options or empty, auth_token will
# raise an exception on initialization. (string value)
#memcache_security_strategy=<None>
# (optional, mandatory if memcache_security_strategy is
# defined) this string is used for key derivation. (string
# value)
#memcache_secret_key=<None>
# (optional) indicate whether to set the X-Service-Catalog
# header. If False, middleware will not ask for service
# catalog on token validation and will not set the X-Service-
# Catalog header. (boolean value)
#include_service_catalog=true
# Used to control the use and type of token binding. Can be
# set to: "disabled" to not check token binding. "permissive"
# (default) to validate binding information if the bind type
# is of a form known to the server and ignore it if not.
# "strict" like "permissive" but if the bind type is unknown
# the token will be rejected. "required" any form of token
# binding is needed to be allowed. Finally the name of a
# binding method that must be present in tokens. (string
# value)
#enforce_token_bind=permissive
For services which have a separate paste-deploy ini file, auth_token middleware
can be alternatively configured in [keystone_authtoken] section in the main
config file. For example in Nova, all middleware parameters can be removed
from ``api-paste.ini``:
.. code-block:: ini
[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
and set in ``nova.conf``:
.. code-block:: ini
[DEFAULT]
auth_strategy=keystone
[keystone_authtoken]
auth_host = 127.0.0.1
auth_port = 35357
auth_protocol = http
admin_user = admin
admin_password = SuperSekretPassword
admin_tenant_name = service
# Any of the options that could be set in api-paste.ini can be set here.
Note that middleware parameters in paste config take priority, they must be
removed to use values in [keystone_authtoken] section.
If the service doesn't use the global oslo.config object (CONF), then the
olso config project name can be set it in paste config and
keystonemiddleware will load the project configuration itself.
Optionally the location of the configuration file can be set if oslo.config
is not able to discover it.
.. code-block:: ini
[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
oslo_config_project = nova
# oslo_config_file = /not_discoverable_location/nova.conf
Configuration Options
---------------------
* ``auth_admin_prefix``: Prefix to prepend at the beginning of the path
* ``auth_host``: (required) the host providing the keystone service API endpoint
for validating and requesting tokens
* ``auth_port``: (optional, default `35357`) the port used to validate tokens
* ``auth_protocol``: (optional, default `https`)
* ``auth_uri``: (optional, defaults to
`auth_protocol`://`auth_host`:`auth_port`)
* ``auth_version``: API version of the admin Identity API endpoint
* ``delay_auth_decision``: (optional, default `0`) (off). If on, the middleware
will not reject invalid auth requests, but will delegate that decision to
downstream WSGI components.
* ``http_connect_timeout``: (optional) Request timeout value for communicating
with Identity API server.
* ``http_request_max_retries``: (default 3) How many times are we trying to
reconnect when communicating with Identity API Server.
* ``http_handler``: (optional) Allows to pass in the name of a fake
http_handler callback function used instead of `httplib.HTTPConnection` or
`httplib.HTTPSConnection`. Useful for unit testing where network is not
available.
* ``admin_token``: either this or the following three options are required. If
set, this is a single shared secret with the keystone configuration used to
validate tokens.
* ``admin_user``, ``admin_password``, ``admin_tenant_name``: if ``admin_token``
is not set, or invalid, then admin_user, admin_password, and
admin_tenant_name are defined as a service account which is expected to have
been previously configured in Keystone to validate user tokens.
* ``cache``: (optional) Env key for the swift cache
* ``certfile``: (required, if Keystone server requires client cert)
* ``keyfile``: (required, if Keystone server requires client cert) This can be
the same as the certfile if the certfile includes the private key.
* ``cafile``: (optional, defaults to use system CA bundle) the path to a PEM
encoded CA file/bundle that will be used to verify HTTPS connections.
* ``insecure``: (optional, default `False`) Don't verify HTTPS connections
(overrides `cafile`).
* ``signing_dir``: (optional) Directory used to cache files related to PKI
tokens
* ``memcached_servers``: (optional) If defined, the memcached server(s) to use
for caching
* ``token_cache_time``: (default 300) In order to prevent excessive requests
and validations, the middleware uses an in-memory cache for the tokens the
Keystone API returns. This is only valid if memcache_servers s defined. Set
to -1 to disable caching completely.
* ``memcache_security_strategy``: (optional) if defined, indicate whether token
data should be authenticated or authenticated and encrypted. Acceptable
values are MAC or ENCRYPT. If MAC, token data is authenticated (with HMAC)
in the cache. If ENCRYPT, token data is encrypted and authenticated in the
cache. If the value is not one of these options or empty, auth_token will
raise an exception on initialization.
* ``memcache_secret_key``: (mandatory if memcache_security_strategy is defined)
this string is used for key derivation.
* ``include_service_catalog``: (optional, default `True`) Indicate whether to
set the X-Service-Catalog header. If False, middleware will not ask for
service catalog on token validation and will not set the X-Service-Catalog
header.
* ``enforce_token_bind``: (default ``permissive``) Used to control the use and
type of token binding. Can be set to: "disabled" to not check token binding.
"permissive" (default) to validate binding information if the bind type is of
a form known to the server and ignore it if not. "strict" like "permissive"
but if the bind type is unknown the token will be rejected. "required" any
form of token binding is needed to be allowed. Finally the name of a binding
method that must be present in tokens.
Caching for improved response
-----------------------------
In order to prevent excessive requests and validations, the middleware uses an
in-memory cache for the tokens the keystone API returns. Keep in mind that
invalidated tokens may continue to work if they are still in the token cache,
so token_cache_time is configurable. For larger deployments, the middleware
also supports memcache based caching.
* ``memcached_servers``: (optonal) if defined, the memcached server(s) to use for
cacheing. It will be ignored if Swift MemcacheRing is used instead.
* ``token_cache_time``: (optional, default 300 seconds) Set to -1 to disable
caching completely.
When deploying auth_token middleware with Swift, user may elect
to use Swift MemcacheRing instead of the local Keystone memcache.
The Swift MemcacheRing object is passed in from the request environment
and it defaults to 'swift.cache'. However it could be
different, depending on deployment. To use Swift MemcacheRing, you must
provide the ``cache`` option.
* ``cache``: (optional) if defined, the environment key where the Swift
MemcacheRing object is stored.
Memcached dependencies
======================
In order to use `memcached`_ it is necessary to install the `python-memcached`_
library. If data stored in `memcached`_ will need to be encrypted it is also
necessary to install the `pycrypto`_ library. These libs are not listed in
the requirements.txt file.
.. _`memcached`: http://memcached.org/
.. _`python-memcached`: https://pypi.python.org/pypi/python-memcached
.. _`pycrypto`: https://pypi.python.org/pypi/pycrypto
Memcached and System Time
=========================
When using `memcached`_ with ``auth_token`` middleware, ensure that the system
time of memcached hosts is set to UTC. Memcached uses the host's system
time in determining whether a key has expired, whereas Keystone sets
key expiry in UTC. The timezone used by Keystone and memcached must
match if key expiry is to behave as expected.
Memcache Protection
===================
When using memcached, we are storing user tokens and token validation
information into the cache as raw data. Which means that anyone who
has access to the memcached servers can read and modify data stored
there. To mitigate this risk, ``auth_token`` middleware provides an
option to authenticate and optionally encrypt the token data stored in
the cache.
* ``memcache_security_strategy``: (optional) if defined, indicate
whether token data should be authenticated or authenticated and
encrypted. Acceptable values are ``MAC`` or ``ENCRYPT``. If ``MAC``,
token data is authenticated (with HMAC) in the cache. If
``ENCRYPT``, token data is encrypted and authenticated in the
cache. If the value is not one of these options or empty,
``auth_token`` will raise an exception on initialization.
* ``memcache_secret_key``: (optional, mandatory if
``memcache_security_strategy`` is defined) this string is used for
key derivation. If ``memcache_security_strategy`` is defined and
``memcache_secret_key`` is absent, ``auth_token`` will raise an
exception on initialization.
Exchanging User Information
===========================
The middleware expects to find a token representing the user with the header
``X-Auth-Token`` or ``X-Storage-Token``. `X-Storage-Token` is supported for
swift/cloud files and for legacy Rackspace use. If the token isn't present and
the middleware is configured to not delegate auth responsibility, it will
respond to the HTTP request with HTTPUnauthorized, returning the header
``WWW-Authenticate`` with the value `Keystone uri='...'` to indicate where to
request a token. The auth_uri returned is configured with the middleware.
The authentication middleware extends the HTTP request with the header
``X-Identity-Status``. If a request is successfully authenticated, the value
is set to `Confirmed`. If the middleware is delegating the auth decision to the
service, then the status is set to `Invalid` if the auth request was
unsuccessful.
An ``X-Service-Token`` header may also be included with a request. If present,
and the value of ``X-Auth-Token`` or ``X-Storage-Token`` has not caused the
request to be denied, then the middleware will attempt to validate the value of
``X-Service-Token``. If valid, the authentication middleware extends the HTTP
request with the header ``X-Service-Identity-Status`` having value `Confirmed`
and also extends the request with additional headers representing the identity
authenticated and authorised by the token.
If ``X-Service-Token`` is present and its value is invalid and the
``delay_auth_decision`` option is True then the value of
``X-Service-Identity-Status`` is set to `Invalid` and no further headers are
added. Otherwise if ``X-Service-Token`` is present and its value is invalid
then the middleware will respond to the HTTP request with HTTPUnauthorized,
regardless of the validity of the ``X-Auth-Token`` or ``X-Storage-Token``
values.
Extended the request with additional User Information
-----------------------------------------------------
:py:class:`keystonemiddleware.auth_token.AuthProtocol` extends the
request with additional information if the user has been authenticated. See the
"What we add to the request for use by the OpenStack service" section in
:py:mod:`keystonemiddleware.auth_token` for the list of fields set by
the auth_token middleware.
References
==========
.. [PEP-333] pep0333 Phillip J Eby. 'Python Web Server Gateway Interface
v1.0.'' http://www.python.org/dev/peps/pep-0333/.
|