summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cinder/opts.py1
-rw-r--r--doc/source/configuration/block-storage/service-token.rst139
-rw-r--r--doc/source/configuration/index.rst1
-rw-r--r--tools/config/generate_cinder_opts.py5
4 files changed, 145 insertions, 1 deletions
diff --git a/cinder/opts.py b/cinder/opts.py
index a6872c4ba..3230ed06f 100644
--- a/cinder/opts.py
+++ b/cinder/opts.py
@@ -285,6 +285,7 @@ def list_opts():
('service_user',
itertools.chain(
cinder_serviceauth.service_user_opts,
+ loading.get_auth_plugin_conf_options('v3password'),
loading.get_session_conf_options(),
)),
('backend_defaults',
diff --git a/doc/source/configuration/block-storage/service-token.rst b/doc/source/configuration/block-storage/service-token.rst
new file mode 100644
index 000000000..108f4b0db
--- /dev/null
+++ b/doc/source/configuration/block-storage/service-token.rst
@@ -0,0 +1,139 @@
+=========================================================
+Using service tokens to prevent long-running job failures
+=========================================================
+
+When a user initiates a request whose processing involves multiple services
+(for example, a boot-from-volume request to the Compute Service will require
+processing by the Block Storage Service, and may require processing by the
+Image Service), the user's token is handed from service to service. This
+ensures that the requestor is tracked correctly for audit purposes and also
+guarantees that the requestor has the appropriate permissions to do what needs
+to be done by the other services. If the chain of operations takes a long
+time, however, the user's token may expire before the action is completed,
+leading to the failure of the user's original request.
+
+One way to deal with this is to set a long token life in Keystone, and this may
+be what you are currently doing. But this can be problematic for installations
+whose security policies prefer short user token lives. Beginning with the
+Queens release, an alternative solution is available. You have the ability to
+configure some services (particularly Nova and Cinder) to send a "service
+token" along with the user's token. When properly configured, the Identity
+Service will validate an expired user token *when it is accompanied by a valid
+service token*. Thus if the user's token expires somewhere during a long
+running chain of operations among various OpenStack services, the operations
+can continue.
+
+.. note::
+ There's nothing special about a service token. It's a regular token
+ that has been requested by a service user. And there's nothing special
+ about a service user, it's just a user that has been configured in the
+ Identity Service to have specific roles that identify that user as
+ a service.
+
+ The key point here is that the "service token" doesn't need to have
+ an extra long life -- it can have the same short life as all the
+ other tokens because it will be a **fresh** (and hence valid) token
+ accompanying the (possibly expired) user's token.
+
+.. _service-token-configuration:
+
+Configuration
+~~~~~~~~~~~~~
+
+To configure Cinder to send a "service token" along with the user's
+token when it makes a request to another service, you must do the
+following:
+
+1. Find the ``[service_user]`` section in the Cinder configuration
+ file (usually ``/etc/cinder/cinder.conf``, though it may be in a
+ different location in your installation).
+
+2. In that section, set ``send_service_user_token = true``.
+
+3. Also in that section, fill in the appropriate configuration for
+ your service user (``username``, ``project_name``, etc.)
+
+.. note::
+ There is no configuration required for a service to *receive*
+ service tokens. This is automatically handled by the keystone
+ middleware used by each service (beginning with the Pike release).
+
+ (The previous statement is true for the default configuration. It
+ is possible for someone to change some settings so that service
+ tokens will be ignored. See the :ref:`service-token-troubleshooting`
+ section below.)
+
+.. _service-token-troubleshooting:
+
+Troubleshooting
+~~~~~~~~~~~~~~~
+
+If you've configured this feature and are still having long-running
+job failures, there are basically three degrees of freedom to take into
+account: (1) each source service, (2) each receiving service, and (3) the
+Identity Service (Keystone).
+
+1. Each source service (basically, Nova and Cinder) must have the
+ ``[service_user]`` section in the **source service** configuration
+ file filled in as described in the :ref:`service-token-configuration`
+ section above.
+
+ .. note::
+ As of the Train release, Glance does not have the ability to pass
+ service tokens. It can receive them, though. The place where you may
+ still see a long running failure is when Glance is using a backend that
+ requires Keystone validation (for example, the Swift backend) and the
+ user token has expired.
+
+2. Each receiving service, by default, is set up to accept service tokens.
+ There are two options to be aware of, however, that can affect whether or
+ not a receiving service (for example, Glance) will actually accept service
+ tokens. These appear in the ``[keystone_authtoken]`` section of the
+ **receiving service** configuration file (for example,
+ ``/etc/glance/glance-api.conf``).
+
+ ``service_token_roles``
+ The value is a list of roles; the service user passing the service
+ token must have at least one of these roles or the token will be
+ rejected. (But see the next option.) The default value is
+ ``service``.
+
+ ``service_token_roles_required``
+ This is a boolean; the default value is ``false``. It governs whether
+ the keystone middleware used by the receiving service will pay any
+ attention to the ``service_token_roles`` setting. (Eventually the
+ default is supposed to become True, but it's still False as of Stein.)
+
+3. There are several things to pay attention to in Keystone:
+
+ * If you've decided to turn on ``service_token_roles_required`` for any of
+ the receiving services, then you must make sure that any service user who
+ will be contacting that receiving service (and for whom you want to
+ enable "service token" usage) has one of the roles specified in the
+ receiving services's ``service_token_roles`` setting. (This is a matter
+ of creating and assigning roles using the Identity Service API, it's
+ not a configuration file issue.)
+
+ * Even with a service token, an expired user token cannot be used
+ indefinitely. There's a Keystone configuration setting that controls
+ this: ``[token]/allow_expired_window`` in the **Keystone** configuration
+ file. The default setting is 2 days, so some security teams may want to
+ lower this just on general principles. You need to make sure it's not
+ set too low to be completely ineffective.
+
+ * If you are using Fernet tokens, you need to be careful with your Fernet
+ key rotation period. Whoever sets up the key rotation has to pay
+ attention to the ``[token]/allow_expired_window`` setting as well as the
+ obvious ``[token]/expiration`` setting. If keys get rotated faster than
+ ``expiration`` + ``allow_expired_window`` seconds, an expired user
+ token might not be decryptable, even though the request using it is
+ being made within ``allow_expired_window`` seconds.
+
+To summarize, you need to be aware of:
+
+* Keystone: must allow a decent sized ``allow_expired_window`` (default is 2
+ days)
+* Each source service: must be configured to be able to create and send
+ service tokens (default is OFF)
+* Each receiving service: has to be configured to accept service tokens
+ (default is ON)
diff --git a/doc/source/configuration/index.rst b/doc/source/configuration/index.rst
index 2666e3497..b6c5e08a7 100644
--- a/doc/source/configuration/index.rst
+++ b/doc/source/configuration/index.rst
@@ -15,6 +15,7 @@ Cinder Service Configuration
block-storage/fc-zoning.rst
block-storage/nested-quota.rst
block-storage/volume-encryption.rst
+ block-storage/service-token.rst
block-storage/config-options.rst
block-storage/samples/index.rst
diff --git a/tools/config/generate_cinder_opts.py b/tools/config/generate_cinder_opts.py
index d786f106e..931ced9f7 100644
--- a/tools/config/generate_cinder_opts.py
+++ b/tools/config/generate_cinder_opts.py
@@ -169,8 +169,11 @@ if __name__ == "__main__":
else:
opt_file.write(opt_line[0])
if opts.endswith('service_user_opts'):
+ su_dnt = " " * 16
+ su_plg = su_dnt + "loading.get_auth_plugin_conf_options"
opt_file.write(
- " loading.get_session_conf_options(),\n")
+ su_plg + "('v3password'),\n"
+ + su_dnt + "loading.get_session_conf_options(),\n")
def _retrieve_name(aline):
if REGISTER_OPT_STR in aline: