From 1baf3e65232183e8162eb46c28a4fa7708ff3509 Mon Sep 17 00:00:00 2001 From: Samriddhi Jain Date: Thu, 15 Jun 2017 10:53:10 +0530 Subject: [PATCH] Added configuration references to documentation Currently some of the config references docs are a part of general OpenStack-manuals. Migrating those docs to keystone documentation so that they can be reviewed effectively by keystone developers too. Following the specs, the files are added to admin/ and configuration/ directories. The files containing congiguration options are added in a subsequent patch using oslo.config plugin. Partial-Bug #1694460 Change-Id: I9a85f610e66a10dac54c50b2a54305e979888ee5 --- doc/source/admin/caching.rst | 35 ++ doc/source/admin/federated-identity.rst | 501 ++++++++++++++++++ .../admin/figures/keystone-federation.png | Bin 0 -> 21328 bytes .../admin/figures/keystone-federation.svg | 79 +++ doc/source/admin/identity-management.rst | 3 + doc/source/admin/token-provider.rst | 49 ++ doc/source/configuration/samples/index.rst | 13 + .../configuration/samples/keystone-conf.rst | 8 + .../samples/keystone-paste-ini.rst | 8 + .../configuration/samples/logging-conf.rst | 11 + .../configuration/samples/policy-json.rst | 8 + doc/source/index.rst | 8 + 12 files changed, 723 insertions(+) create mode 100644 doc/source/admin/caching.rst create mode 100644 doc/source/admin/federated-identity.rst create mode 100644 doc/source/admin/figures/keystone-federation.png create mode 100644 doc/source/admin/figures/keystone-federation.svg create mode 100644 doc/source/admin/token-provider.rst create mode 100644 doc/source/configuration/samples/index.rst create mode 100644 doc/source/configuration/samples/keystone-conf.rst create mode 100644 doc/source/configuration/samples/keystone-paste-ini.rst create mode 100644 doc/source/configuration/samples/logging-conf.rst create mode 100644 doc/source/configuration/samples/policy-json.rst diff --git a/doc/source/admin/caching.rst b/doc/source/admin/caching.rst new file mode 100644 index 0000000000..3fd6cca3b1 --- /dev/null +++ b/doc/source/admin/caching.rst @@ -0,0 +1,35 @@ +============= +Caching layer +============= + +Identity supports a caching layer that is above the configurable subsystems, +such as token or assignment. The majority of the caching configuration options +are set in the ``[cache]`` section. However, each section that has the +capability to be cached usually has a ``caching`` option that will toggle +caching for that specific section. By default, caching is globally disabled. + +Current functional back ends are: + +``dogpile.cache.memcached`` + Memcached back end using the standard ``python-memcached`` library. + +``dogpile.cache.pylibmc`` + Memcached back end using the ``pylibmc`` library. + +``dogpile.cache.bmemcached`` + Memcached using the ``python-binary-memcached`` library. + +``dogpile.cache.redis`` + Redis back end. + +``dogpile.cache.dbm`` + Local DBM file back end. + +``dogpile.cache.memory`` + In-memory cache, not suitable for use outside of testing as it does not + cleanup its internal cache on cache expiration and does not share cache + between processes. This means that caching and cache invalidation will not + be consistent or reliable. + +``dogpile.cache.mongo`` + MongoDB as caching back end. diff --git a/doc/source/admin/federated-identity.rst b/doc/source/admin/federated-identity.rst new file mode 100644 index 0000000000..173a92ace4 --- /dev/null +++ b/doc/source/admin/federated-identity.rst @@ -0,0 +1,501 @@ +================== +Federated Identity +================== + +You can use federation for the Identity service (keystone) in two ways: + +* Supporting keystone as a :abbr:`SP (Service Provider)`: consuming identity + assertions issued by an external Identity Provider, such as SAML + assertions or OpenID Connect claims. +* Supporting keystone as an :abbr:`IdP (Identity Provider)`: fulfilling + authentication requests on behalf of Service Providers. + + .. note:: + + It is also possible to have one keystone act as an SP that + consumes Identity from another keystone acting as an IdP. + +There is currently support for two major federation protocols: + +* `SAML `_ +* `OpenID Connect `_ + +.. figure:: figures/keystone-federation.png + :width: 100% + + Keystone federation + +To enable federation: + +#. Run keystone under Apache. See `Configure the Apache HTTP server + `_ + for more information. + + .. note:: + + Other application servers, such as `nginx `_, + have support for federation extensions that may work but are not tested + by the community. + +#. Configure Apache to use a federation capable module. + We recommend Shibboleth, see `the Shibboleth documentation `_ + for more information. + + .. note:: + + Another option is ``mod_auth_melon``, see `the mod's github repo `_ + for more information. + +#. Configure federation in keystone. + +.. note:: + + The external IdP is responsible for authenticating users and communicates + the result of authentication to keystone using authentication assertions. + Keystone maps these values to keystone user groups and assignments + created in keystone. + +Supporting keystone as a SP +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To have keystone as an SP, you will need to configure +keystone to accept assertions from external IdPs. Examples of external +IdPs are: + +* :abbr:`ADFS (Active Directory Federation Services)` +* FreeIPA +* Tivoli Access Manager +* Keystone + +Configuring federation in keystone +---------------------------------- + +#. Configure authentication drivers in ``keystone.conf`` by adding the + authentication methods to the ``[auth]`` section in ``keystone.conf``. + Ensure the names are the same as to the protocol names added via Identity + API v3. + + For example: + + .. code-block:: ini + + [auth] + methods = external,password,token,mapped,openid + + .. note:: + + ``mapped`` and ``openid`` are the federation specific drivers. + The other names in the example are not related to federation. + +#. Create local keystone groups and assign roles. + + .. important:: + + The keystone requires group-based role assignments to authorize + federated users. The federation mapping engine maps federated users into + local user groups, which are the actors in keystone's role assignments. + +#. Create an IdP object in keystone. The object must represent the + IdP you will use to authenticate end users: + + .. code:: ini + + PUT /OS-FEDERATION/identity_providers/{idp_id} + + More configuration information for IdPs can be found `Register an Identity Provider `_. + +#. Add mapping rules: + + .. code:: ini + + PUT /OS-FEDERATION/mappings/{mapping_id} + + More configuration information for mapping rules can be found `Create a mapping `_. + + .. note:: + + The only keystone API objects that support mapping are groups and users. + +#. Add a protocol object and specify the mapping ID you want to use with the + combination of the IdP and protocol: + + .. code:: ini + + PUT /OS-FEDERATION/identity_providers/{idp_id}/protocols/{protocol_id} + + More configuration information for protocols can be found `Add a protocol and attribute mapping to an identity provider `_. + +Performing federated authentication +----------------------------------- + +#. Authenticate externally and generate an unscoped token in keystone: + + .. note:: + + Unlike other authentication methods in keystone, the user does + not issue an HTTP POST request with authentication data in the request body. + To start federated authentication a user must access the dedicated URL with + IdP's and orotocol’s identifiers stored within a protected URL. + The URL has a format of: + ``/v3/OS-FEDERATION/identity_providers/{idp_id}/protocols/{protocol_id}/auth``. + + .. code:: ini + + GET/POST /OS-FEDERATION/identity_providers/{identity_provider}/protocols/{protocol}/auth + +#. Determine accessible resources. By using the previously returned token, the + user can issue requests to the list projects and domains that are + accessible. + + * List projects a federated user can access: GET /OS-FEDERATION/projects + * List domains a federated user can access: GET /OS-FEDERATION/domains + + .. code:: ini + + GET /OS-FEDERATION/projects + +#. Get a scoped token. A federated user can request a scoped token using + the unscoped token. A project or domain can be specified by either ID or + name. An ID is sufficient to uniquely identify a project or domain. + + .. code:: ini + + POST /auth/tokens + +Supporting keystone as an IdP +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When acting as an IdP, the primary role of keystone is +to issue assertions about users owned by keystone. This is done using PySAML2. + +Configuring federation in keystone +---------------------------------- + +There are certain settings in ``keystone.conf`` that must be set up, prior +to attempting to federate multiple keystone deployments. + +#. Within ``keystone.conf``, assign values to the ``[saml]`` + related fields, for example: + + .. code:: ini + + [saml] + certfile=/etc/keystone/ssl/certs/ca.pem + keyfile=/etc/keystone/ssl/private/cakey.pem + idp_entity_id=https://keystone.example.com/v3/OS-FEDERATION/saml2/idp + idp_sso_endpoint=https://keystone.example.com/v3/OS-FEDERATION/saml2/sso + idp_metadata_path=/etc/keystone/saml2_idp_metadata.xml + +#. We recommend the following `Organization` configuration options. + Ensure these values contain not special characters that may cause + problems as part of a URL: + + .. code:: ini + + idp_organization_name=example_company + idp_organization_display_name=Example Corp. + idp_organization_url=example.com + +#. As with the `Organization` options, the `Contact` options are not + necessary, but it is advisable to set these values: + + .. code:: ini + + idp_contact_company=example_company + idp_contact_name=John + idp_contact_surname=Smith + idp_contact_email=jsmith@example.com + idp_contact_telephone=555-55-5555 + idp_contact_type=technical + +Generate metadata +----------------- + +Metadata must be exchanged to create a trust between the IdP and the SP. + +#. Create metadata for your keystone IdP, run the ``keystone-manage`` command + and pipe the output to a file. For example: + + .. code:: console + + $ keystone-manage saml_idp_metadata > /etc/keystone/saml2_idp_metadata.xml + + .. note:: + + The file location must match the value of the ``idp_metadata_path`` + configuration option assigned previously. + +Create a SP +----------- + +To setup keystone-as-a-Service-Provider properly, you will need to +understand what protocols are supported by external IdPs. +For example, keystone as an SP can allow identities to federate in from a +ADFS IdP but it must be configured to understand the SAML v2.0 protocol. +ADFS issues assertions using SAML v2.0. Some examples +of federated protocols include: + +* SAML v2.0 +* OpenID Connect + +The following instructions are an example of how you can configure +keystone as an SP. + +#. Create a new SP with an ID of BETA. + +#. Create a ``sp_url`` of ``_. + +#. Create a ``auth_url`` of ``_. + + .. note:: + + Use the ``sp_url`` when creating a SAML assertion for BETA and signed by + the current keystone IdP. Use the ``auth_url`` when retrieving the token + for BETA once the SAML assertion is sent. + +#. Set the ``enabled`` field to ``true``. It is set to + ``false`` by default. + +#. Your output should reflect the following example: + + .. code:: console + + $ curl -s -X PUT \ + -H "X-Auth-Token: $OS_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"service_provider": {"auth_url": "http://beta.example.com:5000/v3/OS-FEDERATION/identity_providers/beta/protocols/saml2/auth", "sp_url": "https://example.com:5000/Shibboleth.sso/SAML2/ECP", "enabled": true}}' \ + http://localhost:5000/v3/OS-FEDERATION/service_providers/BETA | python -mjson.tool + +keystone-to-keystone +~~~~~~~~~~~~~~~~~~~~ + +Keystone acting as an IdP is known as :abbr:`k2k (keystone-2-keystone)` +or k2k federation, where a keystone somewhere is acting as the SP +and another keystone is acting as the IdP. All IdPs issue +assertions about the identities it owns using a `Protocol`. + +Mapping rules +~~~~~~~~~~~~~ + +Mapping adds a set of rules to map federation attributes to keystone users +or groups. An IdP has exactly one mapping specified per protocol. + +A mapping is a translation between assertions provided from an IdP and +the permission and roles applied by an SP. Given an assertion from an IdP, an +SP applies a mapping to translate attributes from the +IdP to known roles. A mapping is typically +owned by an SP. + +Mapping objects can be used multiple times by different combinations +of IdP and protocol. + +A rule hierarchy is as follows: + +.. code:: ini + + { + "rules": [ + { + "local": [ + { + " or " + } + ], + "remote": [ + { + "" + } + ] + } + ] + } + +* ``rules``: top-level list of rules. +* ``local``: a rule containing information on what local attributes + will be mapped. +* ``remote``: a rule containing information on what remote attributes will + be mapped. +* ``condition``: contains information on conditions that allow a rule, can + only be set in a remote rule. + +For more information on mapping rules, see `Mapping Rules +`_. + +Mapping creation +---------------- + +Mapping creation starts with the communication between the IdP and SP. +The IdP usually provides a set of assertions that their users +have in their assertion document. The SP will have to map +those assertions to known groups and roles. +For example: + +.. code:: ini + + Identity Provider 1: + name: jsmith + groups: hacker + other: + The Service Provider may have 3 groups: + Admin Group + Developer Group + User Group + + The mapping created by the Service Provider might look like: + Local: + Group: Developer Group + Remote: + Groups: hackers + +The ``Developer Group`` may have a role assignment on the +``Developer Project``. When `jsmith` authenticates against IdP 1, it +presents that assertion to the SP.The SP maps the `jsmith` user to the +``Developer Group`` because the assertion says `jsmith` is a member of +the ``hacker`` group. + +Mapping examples +---------------- + +A bare bones mapping is sufficient if you would like all federated users to +have the same authorization in the SP cloud. However, mapping is +quite powerful and flexible. You can map different remote +users into different user groups in keystone, limited only by the number of +assertions your IdP makes about each user. + +A mapping is composed of a list of rules, and each rule is further composed of +a list of remote attributes and a list of local attributes. If a rule is +matched, all of the local attributes are applied in the SP. For a +rule to match, all of the remote attributes it defines must match. + +In the base case, a federated user simply needs an assertion containing +an email address to be identified in the SP cloud. To achieve that, only +one rule is needed that requires the presence of one remote attribute: + +.. code:: javascript + + { + "rules": [ + { + "remote": [ + { + "type": "Email" + } + ], + "local": [ + { + "user": { + "name": "{0}" + } + } + ] + } + ] + } + +However, that is not particularly useful as the federated user would receive no +authorization. To rectify it, you can map all federated users with email +addresses into a ``federated-users`` group in the ``default`` domain. All +federated users will then be able to consume whatever role assignments that +user group has already received in keystone: + +.. note:: + + In this example, there is only one rule requiring one remote attribute. + +.. code:: javascript + + { + "rules": [ + { + "remote": [ + { + "type": "Email" + } + ], + "local": [ + { + "user": { + "name": "{0}" + } + }, + { + "group": { + "domain": { + "id": "0cd5e9" + }, + "name": "federated-users" + } + } + ] + } + ] + } + +This example can be expanded by adding a second rule that conveys +additional authorization to only a subset of federated users. Federated users +with a `title` attribute that matches either ``Manager`` or +``Supervisor`` are granted the hypothetical ``observer`` role, which would +allow them to perform any read-only API call in the cloud: + +.. code:: javascript + + { + "rules": [ + { + "remote": [ + { + "type": "Email" + }, + ], + "local": [ + { + "user": { + "name": "{0}" + } + }, + { + "group": { + "domain": { + "id": "default" + }, + "name": "federated-users" + } + } + ] + }, + { + "remote": [ + { + "type": "Title", + "any_one_of": [".*Manager$", "Supervisor"], + "regex": "true" + }, + ], + "local": [ + { + "group": { + "domain": { + "id": "default" + }, + "name": "observers" + } + } + ] + } + ] + } + +.. note:: + + ``any_one_of`` and ``regex`` in the rule above map federated users into + the ``observers`` group when a user's ``Title`` assertion matches any of + the regular expressions specified in the ``any_one_of`` attribute. + +Keystone also supports the following: + +* ``not_any_of``, matches any assertion that does not include one of + the specified values +* ``blacklist``, matches all assertions of the specified type except + those included in the specified value +* ``whitelist`` does not match any assertion except those listed in the + specified value. diff --git a/doc/source/admin/figures/keystone-federation.png b/doc/source/admin/figures/keystone-federation.png new file mode 100644 index 0000000000000000000000000000000000000000..b076e006d8d0bdb85329622772c776162807c5d8 GIT binary patch literal 21328 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 + + + + + + + + + + + + + +
+
+ Identity service +
(keystone)
+
+
+
+ [Not supported by viewer] +
+
+ + + + + + + +
+
+

Federation

+
+
+
+ [Not supported by viewer] +
+
+ + + +
+
+

Service Provider (SP)

+
+
    +
  • SAML v2
  • +
  • OpenID Connect
  • +
+
+
+
+
+ [Not supported by viewer] +
+
+ + + +
+
+

Identity Provider (IdP)

+
+
    +
  • Keystone 2 KeyStore
  • +
  • PySAML 2
  • +
  • SAML
  • +
+
+
+
+
+ [Not supported by viewer] +
+
+
+
\ No newline at end of file diff --git a/doc/source/admin/identity-management.rst b/doc/source/admin/identity-management.rst index 3c740b7ca1..0537627318 100644 --- a/doc/source/admin/identity-management.rst +++ b/doc/source/admin/identity-management.rst @@ -29,3 +29,6 @@ command-line client. identity-auth-token-middleware.rst identity-service-api-protection.rst identity-troubleshoot.rst + token-provider.rst + federated-identity.rst + caching.rst diff --git a/doc/source/admin/token-provider.rst b/doc/source/admin/token-provider.rst new file mode 100644 index 0000000000..8de2f09245 --- /dev/null +++ b/doc/source/admin/token-provider.rst @@ -0,0 +1,49 @@ +============== +Token provider +============== + +OpenStack Identity supports customizable token providers. This is specified +in the ``[token]`` section of the configuration file. The token provider +controls the token construction, validation, and revocation operations. + +You can register your own token provider by configuring the following property: + +.. note:: + + More commonly, you can use this option to change the token provider to one + of the ones built in. Alternatively, you can use it to configure your own + token provider. + +* ``provider`` - token provider driver. + Defaults to ``uuid``. + Implemented by :class:`keystone.token.providers.uuid.Provider`. This is the + entry point for the token provider in the ``keystone.token.provider`` + namespace. + +Each token format uses different technologies to achieve various performance, +scaling, and architectural requirements. The Identity service includes +``fernet``, ``pkiz``, ``pki``, and ``uuid`` token providers. + +Below is the detailed list of the token formats: + +UUID + ``uuid`` tokens must be persisted (using the back end specified in the + ``[token] driver`` option), but do not require any extra configuration + or setup. + +PKI and PKIZ + ``pki`` and ``pkiz`` tokens can be validated offline, without making HTTP + calls to keystone. However, this format requires that certificates be + installed and distributed to facilitate signing tokens and later validating + those signatures. + +Fernet + ``fernet`` tokens do not need to be persisted at all, but require that you run + ``keystone-manage fernet_setup`` (also see the + ``keystone-manage fernet_rotate`` command). + +.. warning:: + + UUID, PKI, PKIZ, and Fernet tokens are all bearer tokens. They + must be protected from unnecessary disclosure to prevent unauthorized + access. diff --git a/doc/source/configuration/samples/index.rst b/doc/source/configuration/samples/index.rst new file mode 100644 index 0000000000..1d9e65d9ef --- /dev/null +++ b/doc/source/configuration/samples/index.rst @@ -0,0 +1,13 @@ +========================== +Sample configuration files +========================== + +You can find the files described in this section in the +``/etc/keystone`` directory. + +.. toctree:: + + keystone-conf.rst + keystone-paste-ini.rst + logging-conf.rst + policy-json.rst diff --git a/doc/source/configuration/samples/keystone-conf.rst b/doc/source/configuration/samples/keystone-conf.rst new file mode 100644 index 0000000000..683216eb17 --- /dev/null +++ b/doc/source/configuration/samples/keystone-conf.rst @@ -0,0 +1,8 @@ +============= +keystone.conf +============= + +Use the ``keystone.conf`` file to configure most Identity service +options: + +.. literalinclude:: ../../_static/keystone.conf.sample diff --git a/doc/source/configuration/samples/keystone-paste-ini.rst b/doc/source/configuration/samples/keystone-paste-ini.rst new file mode 100644 index 0000000000..e3c844b15b --- /dev/null +++ b/doc/source/configuration/samples/keystone-paste-ini.rst @@ -0,0 +1,8 @@ +================== +keystone-paste.ini +================== + +Use the ``keystone-paste.ini`` file to configure the Web Service Gateway +Interface (WSGI) middleware pipeline for the Identity service: + +.. literalinclude:: ../../../../etc/keystone-paste.ini diff --git a/doc/source/configuration/samples/logging-conf.rst b/doc/source/configuration/samples/logging-conf.rst new file mode 100644 index 0000000000..4d4232b617 --- /dev/null +++ b/doc/source/configuration/samples/logging-conf.rst @@ -0,0 +1,11 @@ +============ +logging.conf +============ + +You can specify a special logging configuration file in the ``keystone.conf`` +configuration file. For example, ``/etc/keystone/logging.conf``. + +For details, see the `Python logging module documentation +`__. + +.. literalinclude:: ../../../../etc/logging.conf.sample diff --git a/doc/source/configuration/samples/policy-json.rst b/doc/source/configuration/samples/policy-json.rst new file mode 100644 index 0000000000..02b7bb371b --- /dev/null +++ b/doc/source/configuration/samples/policy-json.rst @@ -0,0 +1,8 @@ +=========== +policy.json +=========== + +Use the ``policy.json`` file to define additional access controls that apply to +the Identity service: + +.. literalinclude:: ../../_static/keystone.policy.yaml.sample diff --git a/doc/source/index.rst b/doc/source/index.rst index a2547adc65..a67bf8eab0 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -96,6 +96,14 @@ Administrator Guides admin/identity-management.rst +Configuration Options +~~~~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 2 + + configuration/samples/index.rst + API Documentation ~~~~~~~~~~~~~~~~~