summaryrefslogtreecommitdiffstats
path: root/keystone-moon/doc/source/configure_tokenless_x509.rst
blob: 40b9fd20c93539e00dd49cc35268e1f5b7908089 (plain)
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
..
    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.

================================================
Configuring Keystone for Tokenless Authorization
================================================

.. NOTE::

    This feature is experimental and unsupported in Liberty.

-----------
Definitions
-----------

* `X.509 Tokenless Authorization`: Provides a means to authorize client
  operations within Keystone by using an X.509 SSL client certificate
  without having to issue a token. For details, please refer to the specs
  `Tokenless Authorization with X.509 Client SSL Certificate`_

.. _`Tokenless Authorization with X.509 Client SSL Certificate`: http://specs.openstack.org/openstack/keystone-specs/specs/liberty/keystone-tokenless-authz-with-x509-ssl-client-cert.html

Prerequisites
-------------

Keystone must be running in a web container with https enabled; tests have
been done with Apache/2.4.7 running on Ubuntu 14.04 . Please refer to
`running-keystone-in-httpd`_ and `apache-certificate-and-key-installation`_
as references for this setup.

.. _`running-keystone-in-httpd`: http://docs.openstack.org/developer/keystone/apache-httpd.html
.. _`apache-certificate-and-key-installation`: https://www.digitalocean.com/community/tutorials/how-to-create-a-ssl-certificate-on-apache-for-ubuntu-14-04

--------------------
Apache Configuration
--------------------

To enable X.509 tokenless authorization, SSL has to be enabled and configured
in the Apache virtual host file. The Client authentication attribute
``SSLVerifyClient`` should be set as ``optional`` to allow other token
authentication methods and attribute ``SSLOptions`` needs to set as
``+StdEnvVars`` to allow certificate attributes to be passed. The following
is the sample virtual host file used for the testing.

.. code-block:: ini

    <VirtualHost *:443>
        WSGIScriptAlias / /var/www/cgi-bin/keystone/main
        ErrorLog /var/log/apache2/keystone.log
        LogLevel debug
        CustomLog /var/log/apache2/access.log combined
        SSLEngine on
        SSLCertificateFile    /etc/apache2/ssl/apache.cer
        SSLCertificateKeyFile /etc/apache2/ssl/apache.key
        SSLCACertificatePath /etc/apache2/capath
        SSLOptions +StdEnvVars
        SSLVerifyClient optional
    </VirtualHost>

----------------------
Keystone Configuration
----------------------

The following options can be defined in `keystone.conf`:

* ``trusted_issuer`` - The multi-str list of trusted issuers to further
  filter the certificates that are allowed to participate in the X.509
  tokenless authorization. If the option is absent then no certificates
  will be allowed. The naming format for the attributes of a Distinguished
  Name(DN) must be separated by a comma and contain no spaces; however
  spaces are allowed for the value of an attribute, like 'L=San Jose' in
  the example below. This configuration option may be repeated for multiple
  values. Please look at the sample below.
* ``protocol`` - The protocol name for the X.509 tokenless authorization
  along with the option `issuer_attribute` below can look up its
  corresponding mapping. It defaults to ``x509``.
* ``issuer_attribute`` - The issuer attribute that is served as an IdP ID for
  the X.509 tokenless authorization along with the protocol to look up its
  corresponding mapping. It is the environment variable in the WSGI
  enviornment that references to the Issuer of the client certificate. It
  defaults to ``SSL_CLIENT_I_DN``.

This is a sample configuration for two `trusted_issuer` and a `protocol` set
to ``x509``.

.. code-block:: ini

    [tokenless_auth]
    trusted_issuer = emailAddress=mary@abc.com,CN=mary,OU=eng,O=abc,L=San Jose,ST=California,C=US
    trusted_issuer = emailAddress=john@openstack.com,CN=john,OU=keystone,O=openstack,L=Sunnyvale,ST=California,C=US
    protocol = x509

-------------
Setup Mapping
-------------

Like federation, X.509 tokenless authorization also utilizes the mapping
mechanism to formulate an identity. The identity provider must correspond
to the issuer of the X.509 SSL client certificate. The protocol for the
given identity is ``x509`` by default, but can be configurable.

Create an Identity Provider(IdP)
--------------------------------

In order to create an IdP, the issuer DN in the client certificate needs
to be provided. The following sample is what a generic issuer DN looks
like in a certificate.

.. code-block:: ini

    E=john@openstack.com
    CN=john
    OU=keystone
    O=openstack
    L=Sunnyvale
    S=California
    C=US

The issuer DN should be constructed as a string that contains no spaces
and have the right order seperated by commas like the example below.
Please be aware that ``emailAddress`` and ``ST`` should be used instead
of ``E`` and ``S`` that are shown in the above example. The following is
the sample Python code used to create the IdP ID.

.. code-block:: python

    import hashlib
    issuer_dn = 'emailAddress=john@openstack.com,CN=john,OU=keystone,
        O=openstack,L=Sunnyvale,ST=California,C=US'
    hashed_idp = hashlib.sha256(issuer_dn)
    idp_id = hashed_idp.hexdigest()
    print(idp_id)

The output of the above Python code will be the IdP ID and the following
sample curl command should be sent to keystone to create an IdP with the
newly generated IdP ID.

.. code-block:: bash

    curl -k -s -X PUT -H "X-Auth-Token: <TOKEN>" \
         -H "Content-Type: application/json" \
         -d '{"identity_provider": {"description": "Stores keystone IDP identities.","enabled": true}}' \
         https://<HOSTNAME>:<PORT>/v3/OS-FEDERATION/identity_providers/<IdP ID>

Create a Map
------------

A mapping needs to be created to map the ``Subject DN`` in the client
certificate as a user to yield a valid local user if the user's ``type``
defined as ``local`` in the mapping. For example, the client certificate
has ``Subject DN`` as ``CN=alex,OU=eng,O=nice-network,L=Sunnyvale,
ST=California,C=US``, in the following examples, ``user_name`` will be
mapped to``alex`` and ``domain_name`` will be mapped to ``nice-network``.
And it has user's ``type`` set to ``local``. If user's ``type`` is not
defined, it defaults to ``ephemeral``.

Please refer to `mod_ssl`_ for the detailed mapping attributes.

.. _`mod_ssl`: http://httpd.apache.org/docs/current/mod/mod_ssl.html

.. code-block:: javascript

    {
         "mapping": {
             "rules": [
                 {
                     "local": [
                         {
                            "user": {
                                "name": "{0}",
                                "domain": {
                                    "name": "{1}"
                                },
                                "type": "local"
                            }
                         }
                    ],
                    "remote": [
                        {
                            "type": "SSL_CLIENT_S_DN_CN"
                        },
                        {
                            "type": "SSL_CLIENT_S_DN_O"
                        }
                    ]
                }
            ]
        }
    }

When user's ``type`` is not defined or set to ``ephemeral``, the mapped user
does not have to be a valid local user but the mapping must yield at least
one valid local group. For example:

.. code-block:: javascript

    {
         "mapping": {
             "rules": [
                 {
                     "local": [
                         {
                            "user": {
                                "name": "{0}",
                                "type": "ephemeral"
                            }
                         },
                         {
                            "group": {
                                "id": "12345678"
                            }
                         }
                    ],
                    "remote": [
                        {
                            "type": "SSL_CLIENT_S_DN_CN"
                        }
                    ]
                }
            ]
        }
    }

The following sample curl command should be sent to keystone to create a
mapping with the provided mapping ID. The mapping ID is user designed and
it can be any string as opposed to IdP ID.

.. code-block:: bash

    curl -k -s -H "X-Auth-Token: <TOKEN>" \
         -H "Content-Type: application/json" \
         -d '{"mapping": {"rules": [{"local": [{"user": {"name": "{0}","type": "ephemeral"}},{"group": {"id": "<GROUPID>"}}],"remote": [{"type": "SSL_CLIENT_S_DN_CN"}]}]}}' \
         -X PUT https://<HOSTNAME>:<PORT>/v3/OS-FEDERATION/mappings/<MAPPING ID>


Create a Protocol
-----------------

The name of the protocol will be the one defined in `keystone.conf` as
``protocol`` which defaults to ``x509``. The protocol name is user designed
and it can be any name as opposed to IdP ID.

A protocol name and an IdP ID will uniquely identify a mapping.

The following sample curl command should be sent to keystone to create a
protocol with the provided protocol name that is defined in `keystone.conf`.

.. code-block:: bash

    curl -k -s -H "X-Auth-Token: <TOKEN>" \
         -H "Content-Type: application/json" \
         -d '{"protocol": {"mapping_id": "<MAPPING ID>"}}' \
         -X PUT https://<HOSTNAME>:<PORT>/v3/OS-FEDERATION/identity_providers/<IdP ID>/protocols/<PROTOCOL NAME>

-------------------------------
Setup ``auth_token`` middleware
-------------------------------

In order to use ``auth_token`` middleware as the service client for X.509
tokenless authorization, both configurable options and scope information
will need to be setup.

Configurable Options
--------------------

The following configurable options in ``auth_token`` middleware
should set to the correct values:

* ``auth_protocol`` - Set to ``https``.
* ``certfile`` - Set to the full path of the certificate file.
* ``keyfile`` - Set to the full path of the private key file.
* ``cafile`` - Set to the full path of the trusted CA certificate file.

Scope Information
-----------------

The scope information will be passed from the headers with the following
header attributes to:

* ``X-Project-Id`` - If specified, its the project scope.
* ``X-Project-Name`` - If specified, its the project scope.
* ``X-Project-Domain-Id`` - If specified, its the domain of project scope.
* ``X-Project-Domain-Name`` - If specified, its the domain of project scope.
* ``X-Domain-Id`` - If specified, its the domain scope.
* ``X-Domain-Name`` - If specified, its the domain scope.

---------------------
Test It Out with cURL
---------------------

Once the above configurations have been setup, the following curl command can
be used for token validation.

.. code-block:: bash

    curl -v -k -s -X GET --cert /<PATH>/x509client.crt \
         --key /<PATH>/x509client.key \
         --cacert /<PATH>/ca.crt \
         -H "X-Project-Name: <PROJECT-NAME>" \
         -H "X-Project-Domain-Id: <PROJECT-DOMAIN-ID>" \
         -H "X-Subject-Token: <TOKEN>" \
         https://<HOST>:<PORT>/v3/auth/tokens | python -mjson.tool

Details of the Options
----------------------

* ``--cert`` - The client certificate that will be presented to Keystone.
  The ``Issuer`` in the certificate along with the defined ``protocol``
  in `keystone.conf` will uniquely identify the mapping. The ``Subject``
  in the certificate will be mapped to the valid local user from the
  identified mapping.
* ``--key`` - The corresponding client private key.
* ``--cacert`` - It can be the Apache server certificate or its issuer
  (signer) certificate.
* ``X-Project-Name`` - The project scope needs to be passed in the header.
* ``X-Project-Domain-Id`` - Its the domain of project scope.
* ``X-Subject-Token`` - The token to be validated.