Federation protocols in keystone are very confusing due to the way they have evolved since the original service provider implementation where the auth plugin was defined in saml2.py. We renamed saml2.py to mapped.py[1] and now we can effectively support any federation protocol as long as there is some kind of Apache module that can understand it and pass certain IdP and user attributes through to keystone. So we started recommending not using the 'saml2' auth plugin and instead using the 'mapped' plugin, eventually removing the the notice when we removed the plugin[2]. Since the name of the federation protocol resource created in keystone must match one of the [auth]/methods, we also changed the documentation to start creating the 'mapped' protocol and use 'mapped' in the Apache settings[3]. This was really the wrong course. 'mapped' is not a protocol. Using only 'mapped' prevents us from defining multiple remote_id_attributes for different protocols. This patch changes references to the 'mapped' protocol and 'mapped' plugin back to 'saml2' (we never changed the openid ones). While the saml2 plugin does not itself exist, it is defined as an entrypoint to the mapped plugin, so it all works out. This doesn't solve the problem for if we want to define different remote_id_attributes for different SAML2.0 implementations, but there is a workaround for that[4]. Using 'saml2' as the protocol name is just much more intuitive than 'mapped'. [1] https://git.openstack.org/cgit/openstack/keystone-specs/tree/specs/keystone/juno/generic-mapping-federation.rst [2] https://review.openstack.org/#/c/397456/ [3] https://review.openstack.org/#/c/371210/ [4] https://bugs.launchpad.net/keystone/+bug/1724645/comments/1 Change-Id: I23fc3f1f651c12c4e3c1987dc71008e6e97b4ed8 Related-bug: #1724645
16 KiB
Federated Identity
You can use federation for the Identity service (keystone) in two ways:
Supporting keystone as a
SP (Service Provider)
: consuming identity assertions issued by an external Identity Provider, such as SAML assertions or OpenID Connect claims.Supporting keystone as an
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:
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<../advanced-topics/federation/shibboleth>
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:
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 inkeystone.conf
. Ensure the names are the same as to the protocol names added via Identity API v3.For example:
[auth] methods = external,password,token,saml2,openid
Note
saml2
andopenid
are instances of themapped
plugin. These must match the name of the of the federation protocol created via the Identity API. 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:
PUT /OS-FEDERATION/identity_providers/{idp_id}
More configuration information for IdPs can be found Register an Identity Provider.
Add mapping rules:
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:
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 protocol's identifiers stored within a protected URL. The URL has a format of:
/v3/OS-FEDERATION/identity_providers/{idp_id}/protocols/{protocol_id}/auth
.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
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.
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:[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:
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:
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:$ 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 http://beta.example.com/Shibboleth.sso/SAML2/ECP.Create a
auth_url
of http://beta.example.com:5000/v3/OS-FEDERATION/identity_providers/beta/protocols/saml2/auth.Note
Use the
sp_url
when creating a SAML assertion for BETA and signed by the current keystone IdP. Use theauth_url
when retrieving the token for BETA once the SAML assertion is sent.Set the
enabled
field totrue
. It is set tofalse
by default.Your output should reflect the following example:
$ 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 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:
{
"rules": [
{
"local": [
{
"<user> or <group>"
}
],
"remote": [
{
"<condition>"
}
]
}
]
}
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:
Identity Provider 1:
name: jsmith
groups: hacker
other: <assertion information>
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:
{"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.
{"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:
{"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 valuesblacklist
, matches all assertions of the specified type except those included in the specified valuewhitelist
does not match any assertion except those listed in the specified value.