Browse Source

Add introduction section to federation docs

Add an introduction to the federation documentation discussing
background information on identity federation and how it is implemented
in keystone.

This repurposes some of the content in this blog post[1] of which I am
the author.

[1] http://www.gazlene.net/demystifying-keystone-federation.html

Partial-bug: #1793374

Change-Id: I5f3a5e70c7b868762880930ea6277691f44c046a
tags/15.0.0.0rc1
Colleen Murphy 7 months ago
parent
commit
4a141fea51

+ 1
- 0
doc/requirements.txt View File

@@ -4,6 +4,7 @@
4 4
 openstackdocstheme>=1.18.1 # Apache-2.0
5 5
 sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD
6 6
 sphinxcontrib-apidoc>=0.2.0  # BSD
7
+sphinxcontrib-seqdiag>=0.8.4  # BSD
7 8
 reno>=2.5.0 # Apache-2.0
8 9
 os-api-ref>=1.4.0 # Apache-2.0
9 10
 python-ldap>=3.0.0  # PSF

+ 0
- 8
doc/source/admin/federation/configure_federation.rst View File

@@ -14,14 +14,6 @@
14 14
 Configuring Keystone for Federation
15 15
 ===================================
16 16
 
17
------------
18
-Definitions
19
------------
20
-* `Service Provider (SP)`: provides a service to an end-user.
21
-* `Identity Provider (IdP)`: service that stores information about users and
22
-  groups.
23
-* `SAML assertion`: contains information about a user as provided by an IdP.
24
-
25 17
 -----------------------------------
26 18
 Keystone as a Service Provider (SP)
27 19
 -----------------------------------

+ 1
- 0
doc/source/admin/federation/federated_identity.rst View File

@@ -4,6 +4,7 @@ Federated Identity
4 4
 
5 5
 Keystone's one-stop-shop for all federated identity documentation.
6 6
 
7
+.. include:: introduction.rst
7 8
 .. include:: configure_federation.rst
8 9
 .. include:: mapping_combinations.rst
9 10
 .. include:: openidc.rst

+ 424
- 0
doc/source/admin/federation/introduction.rst View File

@@ -0,0 +1,424 @@
1
+..
2
+      Copyright 2018 SUSE Linux GmbH
3
+      All Rights Reserved.
4
+
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
8
+
9
+          http://www.apache.org/licenses/LICENSE-2.0
10
+
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
15
+      under the License.
16
+
17
+Introduction to Keystone Federation
18
+===================================
19
+
20
+----------------------------
21
+What is keystone federation?
22
+----------------------------
23
+
24
+Identity federation is the ability to share identity information across multiple
25
+identity management systems. In keystone, this is implemented as an
26
+authentication method that allows users to authenticate directly with another
27
+identity source and then provides keystone with a set of user attributes. This
28
+is useful if your organization already has a primary identity source since it
29
+means users don't need a separate set of credentials for the cloud. It is also
30
+useful for connecting multiple clouds together, as we can use a keystone in
31
+another cloud as an identity source. Using `LDAP as an identity backend`_ is
32
+another way for keystone to obtain identity information from an external source,
33
+but it requires keystone to handle passwords directly rather than offloading
34
+authentication to the external source.
35
+
36
+Keystone supports two configuration models for federated identity. The most
37
+common configuration is with `keystone as a Service Provider (SP)`_, using an
38
+external Identity Provider, such as a Keycloak or Google, as the identity source
39
+and authentication method. The second type of configuration is "`Keystone to
40
+Keystone`_", where two keystones are linked with one acting as the identity
41
+source.
42
+
43
+This document discusses identity federation involving a secondary identity
44
+management that acts as the source of truth concerning the users it contains,
45
+specifically covering the SAML2.0 and OpenID Connect protocols, although
46
+keystone can work with other protocols. A similar concept is `external
47
+authentication`_ whereby keystone is still the source of truth about its users
48
+but authentication is handled externally. Yet another closely related topic is
49
+`tokenless authentication`_ which uses some of the same constructs as described
50
+here but allows services to validate users without using keystone tokens.
51
+
52
+.. _LDAP as an identity backend: ../../admin/identity-integrate-with-ldap.html
53
+.. _keystone as a Service Provider (SP): configure_federation.html#keystone-as-a-service-provider-sp
54
+.. _Keystone to Keystone: configure_federation.html#keystone-as-an-identity-provider-idp
55
+.. _external authentication: ../external-authentication.html
56
+.. _tokenless authentication: ../configure_tokenless_x509.html
57
+
58
+--------
59
+Glossary
60
+--------
61
+
62
+**Service Provider (SP)**
63
+  A Service Provider is the service providing the resource an end-user is
64
+  requesting. In our case, this is keystone, which provides keystone tokens that
65
+  we use on other OpenStack services. We do NOT call the other OpenStack
66
+  services "service providers". The specific service we care about in this
67
+  context is the token service, so that is our Service Provider.
68
+
69
+**Identity Provider (IdP)**
70
+  An Identity Provider is the service that accepts credentials, validates
71
+  them, and generates a yay/nay response. It returns this response along with
72
+  some other attributes about the user, such as their username, their display
73
+  name, and whatever other details it stores and you've configured your Service
74
+  Provider to accept.
75
+
76
+**Entity ID or Remote ID**
77
+  An Entity ID or a Remote ID are both names for a unique identifier string for
78
+  either a Service Provider or an Identity Provider. It usually takes the form
79
+  of a URN, but the URN does not need to be a resolvable URL. The only
80
+  requirement is that it uniquely identifies the IdP to the SP, or the SP to the
81
+  IdP.
82
+
83
+**SAML2.0**
84
+  `SAML2.0`_ is an XML-based federation protocol. It is commonly used in
85
+  internal-facing organizations, such as a university or business in which IT
86
+  services are provided to members of the organization.
87
+
88
+**OpenID Connect (OpenIDC)**
89
+  `OpenID Connect`_ is a JSON-based federation protocol built on OAuth 2.0. It's
90
+  used more often by public-facing services like Google.
91
+
92
+**Assertion**
93
+  An assertion is a formatted statement from the Identity Provider that asserts
94
+  that a user is authenticated and provides some attributes about the user. The
95
+  Identity Provider always signs the assertion and typically encrypts it as
96
+  well.
97
+
98
+**Single Sign-On (SSO)**
99
+  `Single Sign-On`_ is a mechanism related to identity federation whereby a user
100
+  may log in to their identity management system and be granted a token or
101
+  ticket that allows them access to multiple Service Providers.
102
+
103
+.. _SAML2.0: http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html
104
+.. _OpenID Connect: https://openid.net/connect/
105
+.. _Single Sign-On: https://en.wikipedia.org/wiki/Single_sign-on
106
+
107
+--------------------
108
+Authentication Flows
109
+--------------------
110
+
111
+Understanding the flow of information as a user moves through the authentication
112
+process is key to being able to debug later on.
113
+
114
+Normal keystone
115
+---------------
116
+
117
+.. seqdiag::
118
+   :name: normal-keystone
119
+   :alt: Diagram of keystone's normal auth flow, in which a user agent
120
+         authenticates and authorizes themself with keystone and obtains a
121
+         scoped token to pass to an OpenStack service.
122
+
123
+   seqdiag {
124
+     default_fontsize = 13;
125
+     useragent [label = "User Agent"]; keystone [label = "Keystone"]; openstack [label = "OpenStack"];
126
+     useragent -> keystone [label = "GET /v3/auth/tokens"];
127
+     keystone -> keystone [label = "Authenticate"];
128
+     keystone -> keystone [label = "Authorize"];
129
+     useragent <- keystone [label = "Scoped token"];
130
+     useragent -> openstack [label = "GET /v2.1/servers"];
131
+   }
132
+
133
+In a normal keystone flow, the user requests a scoped token directly from
134
+keystone. Keystone accepts their credentials and checks them against its local
135
+storage or against its LDAP backend. Then it checks the scope that the user is
136
+requesting, ensuring they have the correct role assignments, and produces a
137
+scoped token. The user can use the scoped token to do something else in
138
+OpenStack, like request servers, but everything that happens after the token is
139
+produced is irrelevant to this discussion.
140
+
141
+SAML2.0
142
+-------
143
+
144
+SAML2.0 WebSSO
145
+~~~~~~~~~~~~~~
146
+
147
+.. seqdiag::
148
+   :name: saml2-websso
149
+   :alt: Diagram of a standard WebSSO authentication flow.
150
+
151
+   seqdiag {
152
+     edge_length = 325;
153
+     default_fontsize = 13;
154
+     useragent [label = "User Agent"]; sp [label = "Service Provider"]; idp [label = "Identity Provider"];
155
+     useragent -> sp [label = "GET /secure"];
156
+     useragent <- sp [label = "HTTP 302
157
+                               Location: https://idp/auth?
158
+                                         SAMLRequest=req"];
159
+     useragent -> idp [label = "GET /auth?SAMLRequest=req"];
160
+     idp -> idp [label = "Authenticate"];
161
+     useragent <- idp [label = "HTTP 200
162
+                                SAMLResponse in HTML form"];
163
+     useragent -> sp [label = "POST /assertionconsumerservice"];
164
+     sp -> sp [label = "Validate"];
165
+     useragent <- sp [label = "HTTP 302; Location: /secure"];
166
+     useragent -> sp [label = "GET /secure"];
167
+   }
168
+
169
+This diagram shows a standard `WebSSO`_ authentication flow, not one involving
170
+keystone. WebSSO is one of a few `SAML2.0 profiles`_. It is based on the idea that a
171
+web browser will be acting as an intermediary and so the flow involves concepts
172
+that a browser can understand and act on, like HTTP redirects and HTML forms.
173
+
174
+First, the user uses their web browser to request some secure resource from the
175
+Service Provider. The Service Provider detects that the user isn't authenticated
176
+yet, so it generates a SAML Request which it base64 encodes, and then issues an
177
+HTTP redirect to the Identity Provider.
178
+
179
+The browser follows the redirect and presents the SAML Request to the Identity
180
+Provider. The user is prompted to authenticate, probably by filling out a
181
+username and password in a login page. The Identity Provider responds with an
182
+HTTP success and generates a SAML Response with an HTML form.
183
+
184
+The browser automatically POSTs the form back to the Service Provider, which
185
+validates the SAML Response. The Service Provider finally issues another
186
+redirect back to the original resource the user had requested.
187
+
188
+.. _WebSSO: http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0-cd-02.html#5.1.Web%20Browser%20SSO%20Profile|outline
189
+.. _SAML2.0 profiles: http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0-cd-02.html#5.Major%20Profiles%20and%20Federation%20Use%20Cases|outline
190
+
191
+SAML2.0 ECP
192
+~~~~~~~~~~~
193
+
194
+.. seqdiag::
195
+   :name: saml2-ecp
196
+   :alt: Diagram of a standard ECP authentication flow.
197
+
198
+   seqdiag {
199
+     default_fontsize = 13;
200
+     useragent [label = "User Agent"]; sp [label = "Service Provider"]; idp [label = "Identity Provider"];
201
+     useragent -> sp [label = "GET /secure"];
202
+     useragent <- sp [label = "HTTP 200
203
+                               SAML Request"];
204
+     useragent -> idp [label = "POST /auth
205
+                                SAML Request"];
206
+     idp -> idp [label = "Authenticate"];
207
+     useragent <- idp [label = "HTTP 200
208
+                                SAMLResponse in SOAP"];
209
+     useragent -> sp [label = "POST /responseconsumer"];
210
+     sp -> sp [label = "Validate"];
211
+     useragent <- sp [label = "HTTP 200 /secure"];
212
+   }
213
+
214
+`ECP`_ is another SAML profile. Generally the flow is similar to the WebSSO
215
+flow, but it is designed for a client that natively understands SAML, for
216
+example the `keystoneauth`_ library (and therefore also the
217
+`python-openstackclient
218
+<https://docs.openstack.org/python-openstackclient/latest/>`__ CLI tool). ECP is
219
+slightly different from the browser-based flow and is not supported by all
220
+SAML2.0 IdPs, and so getting WebSSO working does not necessarily mean ECP is
221
+working correctly, or vice versa. ECP support must often be turned on explicitly
222
+in the Identity Provider.
223
+
224
+.. _ECP: http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0-cd-02.html#5.2.ECP%20Profile|outline
225
+.. _keystoneauth: https://docs.openstack.org/keystoneauth/latest/
226
+
227
+WebSSO with keystone and horizon
228
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
229
+
230
+
231
+.. seqdiag::
232
+   :name: saml2-keystone-horizon
233
+   :alt: Diagram of the SAML2.0 WebSSO auth flow specific to horizon, keystone, and the
234
+         HTTPD module acting as service provider.
235
+
236
+   seqdiag {
237
+     default_fontsize = 13;
238
+     useragent [label = "User Agent"]; horizon [label = "Horizon"]; httpd [label = "HTTPD", color = "lightgrey"]; keystone [label = "Keystone", color = "lightgrey"]; idp [label = "Identity Provider"];
239
+     useragent -> horizon [label = "POST /auth/login"];
240
+     useragent <- horizon [label = "HTTP 302
241
+                                    Location:
242
+                                    /v3/auth/OS-FEDERATION
243
+                                    /websso/saml2"];
244
+     useragent -> httpd [label = "GET /v3/auth/OS-FEDERATION/websso/saml2"];
245
+     useragent <- httpd [label = "HTTP 302
246
+                                   Location: https://idp/auth?SAMLRequest=req"];
247
+     useragent -> idp [label = "GET /auth"];
248
+     idp -> idp [label = "Authenticate"];
249
+     useragent <- idp [label = "HTTP 200
250
+                                SAMLResponse in HTML form"];
251
+     useragent -> httpd [label = "POST /assertionconsumerservice"];
252
+     httpd -> httpd [label = "Validate"];
253
+     useragent <- httpd [label = "HTTP 302
254
+                                   Location: /v3/auth/OS-FEDERATION/websso/saml2"];
255
+     useragent -> keystone [label = "GET /v3/auth/OS-FEDERATION/websso/saml2"];
256
+     keystone -> keystone [label = "Issue token"];
257
+     useragent <- keystone [label = "HTTP 200
258
+                                     HTML form containing unscoped token"];
259
+     useragent -> horizon [label = "POST /auth/websso"];
260
+     useragent <- horizon [label = "successful login"];
261
+   }
262
+
263
+Keystone is not a web front-end, which means horizon needs to handle some parts
264
+of being a Service Provider to implement WebSSO.
265
+
266
+In the diagram above, horizon is added, and keystone and HTTPD are split out
267
+from each other to distinguish which parts each are responsible for, though
268
+typically both together are referred to as the Service Provider.
269
+
270
+In this model, the user requests to log in to horizon by selecting a federated
271
+authentication method from a dropdown menu. Horizon automatically generates a
272
+keystone URL based on the Identity Provider and protocol selected and redirects
273
+the browser to keystone. That location is equivalent to the /secure resource in
274
+the `SAML2.0 WebSSO`_ diagram. The browser follows the redirect, and the HTTPD
275
+module detects that the user isn't logged in yet and issues another redirect to
276
+the Identity Provider with a SAML Request. At this point, the flow is the same
277
+as in the normal WebSSO model. The user logs into the Identity Provider, a SAML
278
+Response is POSTed back to the Service Provider, where the HTTPD module
279
+validates the response and issues a redirect back to the location that horizon
280
+had originally requested, which is a special federation auth endpoint. At this
281
+point keystone is able to grant an unscoped token, which it hands off as another
282
+HTML form. The browser will POST that back to horizon, which triggers the normal
283
+login process, picking a project to scope to and getting a scoped token from
284
+keystone.
285
+
286
+Note that horizon is acting as a middleman, since it knows the endpoint of the
287
+secure resource it requests from keystone.
288
+
289
+Keystone to Keystone
290
+~~~~~~~~~~~~~~~~~~~~
291
+
292
+.. seqdiag::
293
+   :name: keystone-to-keystone
294
+   :alt: Diagram of the IdP-initiated auth flow in a keystone-to-keystone model.
295
+
296
+   seqdiag {
297
+     edge_length = 240;
298
+     default_fontsize = 13;
299
+     useragent [label = "User Agent"]; sp [label = "Service Provider"]; idp [label = "Identity Provider"];
300
+     useragent -> idp [label = "POST /v3/auth/tokens"];
301
+     idp -> idp [label = "Authenticate"];
302
+     useragent <- idp [label = "HTTP 201
303
+                                X-Subject-Token: token"];
304
+     useragent -> idp [label = "POST /v3/auth/OS-FEDERATION/saml2/ecp"];
305
+     useragent <- idp [label = "HTTP 201
306
+                                SAMLResponse in SOAP envelope"];
307
+     useragent -> sp [label = "POST /PAOS-url"];
308
+     sp -> sp [label = "Validate"];
309
+     useragent <- sp [label = "HTTP 201
310
+                               X-Subject-Token: unscoped token"];
311
+     useragent -> sp [label = "POST /v3/auth/tokens
312
+                               (request scoped token)"];
313
+   }
314
+
315
+When keystone is used as an Identity Provider in a Keystone to Keystone
316
+configuration, the auth flow is nonstandard. It is similar to an `IdP-initiated
317
+auth flow`_. In this case, the user goes directly to the Identity Provider first
318
+before requesting any resource from the Service Provider. The user will get a
319
+token from keystone, then use that to request a SAML Response via ECP. When it
320
+gets that response back, it POSTs that to the Service Provider, which will grant
321
+a token for it.
322
+
323
+Notice that the Service Provider has to accept data from the Identity Provider
324
+and therefore needs to have a way of trusting it. The Identity Provider, on the
325
+other hand, never has to accept data from the Service Provider. There is no back
326
+and forth, the user simply completes the auth process on one side and presents
327
+the result to the other side.
328
+
329
+.. _IdP-initiated auth flow: http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0-cd-02.html#5.1.4.IdP-Initiated%20SSO:%20%20POST%20Binding|outline
330
+
331
+OpenID Connect
332
+--------------
333
+
334
+OpenID Connect Authentication Flow
335
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
336
+
337
+.. seqdiag::
338
+   :name: openidc
339
+   :alt: Diagram of a standard OpenID Connect authentication flow
340
+   :align: left
341
+
342
+   seqdiag {
343
+     edge_length = 330;
344
+     default_fontsize = 13;
345
+     useragent [label = "User Agent"]; sp [label = "Service Provider"]; idp [label = "Identity Provider"];
346
+     useragent -> sp [label = "GET /secure"];
347
+     useragent <- sp [label = "HTTP 302
348
+                               Location: https://idp/auth?
349
+                               client_id=XXX&redirect_uri=https://sp/secure"];
350
+     useragent -> idp [label = "GET /auth?client_id=XXX&redirect_uri=https://sp/secure"];
351
+     idp -> idp [label = "Authenticate"];
352
+     useragent <- idp [label = "HTTP 302
353
+                                Location: https://sp/auth?code=XXX"];
354
+     useragent -> sp [label = "GET /auth?code=XXX"];
355
+     sp -> idp [label = "POST https://idp/token
356
+                         code=XXX&redirect_uri=https://sp/secure"];
357
+     sp <- idp [label = "HTTP 200
358
+                         {\"access_code\": \"XXX\",
359
+                          \"id_token\": \"XXX\"}"];
360
+     useragent <- sp [label = "HTTP 302; Location: /secure"];
361
+     useragent -> sp [label = "GET /secure"];
362
+   }
363
+
364
+OpenID Connect is different from any SAML2.0 flow because the negotiation is not
365
+handled entirely through the client. The Service Provider must make a request
366
+directly to the Identity Provider, which means this flow would not be
367
+appropriate if the Service Provider and Identity Provider are in segregated
368
+networks.
369
+
370
+When the user requests a secure resource from the Service Provider, they are
371
+redirected to the Identity Provider to log in. The Identity Provider then
372
+redirects the user back to the Service Provider using a known redirect URI and
373
+providing an authorization code. The Service Provider must then make a
374
+back-channel request directly to the Identity Provider using the provided code,
375
+and exchange it for an ID token.
376
+
377
+OpenID Connect with keystone and horizon
378
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
379
+
380
+.. seqdiag::
381
+   :name: oidc-keystone-horizon
382
+   :alt: Diagram of the OpenID Connect WebSSO auth flow specific to horizon,
383
+         keystone, and the HTTPD module acting as service provider.
384
+
385
+   seqdiag {
386
+     edge_length = 200
387
+     default_fontsize = 13;
388
+     useragent [label = "User Agent"]; horizon [label = "Horizon"]; httpd [label = "HTTPD", color = "lightgrey"]; keystone [label = "Keystone", color = "lightgrey"]; idp [label = "Identity Provider"];
389
+     useragent -> horizon [label = "POST /auth/login"];
390
+     useragent <- horizon [label = "HTTP 302
391
+                                    Location:
392
+                                    /v3/auth/OS-FEDERATION
393
+                                    /websso/saml2"];
394
+     useragent -> httpd [label = "GET /v3/auth/OS-FEDERATION/websso/saml2"];
395
+     useragent <- httpd [label = "HTTP 302
396
+                                   Location:
397
+                                   https://idp/auth?
398
+                                   client_id=XXX&
399
+                                   redirect_uri=https://sp/v3/auth/OS-FEDERATION/websso"];
400
+     useragent -> idp [label = "GET /auth?client_id=XXX&
401
+                                    redirect_uri=https://sp/v3/auth/OS-FEDERATION/websso"];
402
+     idp -> idp [label = "Authenticate"];
403
+     useragent <- idp [label = "HTTP 302
404
+                                Location: https://sp/v3/auth/OS-FEDERATION/websso"];
405
+     useragent -> httpd [label = "GET /v3/auth/OS-FEDERATION/websso"];
406
+     httpd -> idp [label = "POST https://idp/token
407
+                                 code=XXX&
408
+                                 redirect_uri=https://sp/v3/auth/OS-FEDERATION/websso"];
409
+     httpd <- idp [label = "HTTP 200
410
+                           {\"access_code\": \"XXX\",
411
+                            \"id_token\": \"XXX\"}"];
412
+     useragent <- httpd [label = "HTTP 302
413
+                                  Location: /v3/auth/OS-FEDERATION/websso/mapped"];
414
+     useragent -> keystone [label = "GET /v3/auth/OS-FEDERATION/websso/mapped"];
415
+     keystone -> keystone [label = "Issue token"];
416
+     useragent <- keystone [label = "HTTP 200
417
+                                     HTML form containing unscoped token"];
418
+     useragent -> horizon [label = "POST /auth/websso"];
419
+     useragent <- horizon [label = "successful login"];
420
+   }
421
+
422
+From horizon and keystone's point of view, the authentication flow is the same
423
+for OpenID Connect as it is for SAML2.0. It is only the HTTPD OpenIDC module
424
+that must handle the flow in accordance with the spec.

+ 5
- 0
doc/source/conf.py View File

@@ -54,6 +54,7 @@ extensions = ['sphinx.ext.coverage',
54 54
               'oslo_policy.sphinxext',
55 55
               'ext.support_matrix',
56 56
               'sphinxcontrib.apidoc',
57
+              'sphinxcontrib.seqdiag',
57 58
               ]
58 59
 
59 60
 # sphinxcontrib.apidoc options
@@ -65,6 +66,10 @@ apidoc_excluded_paths = [
65 66
     'test']
66 67
 apidoc_separate_modules = True
67 68
 
69
+# sphinxcontrib.seqdiag options
70
+seqdiag_antialias = True
71
+seqdiag_html_image_format = 'SVG'
72
+
68 73
 config_generator_config_file = '../../config-generator/keystone.conf'
69 74
 sample_config_basename = '_static/keystone'
70 75
 

Loading…
Cancel
Save