After I setup the keystone federation feature, it’s nice to go with the examples in official docs. However, I want to see more from it. :) First thing is that how do the rules to map federation protocol attributes to Identity API objects and how does SP manage the mapping users.
What’s Mapping
A mapping is a set of rules to map federation protocol attributes to Identity API objects. An Identity Provider can have a single mapping specified per protocol. A mapping is simply a list of rules.
As a simple example, if keystone is your IdP, you can map a few known remote users to the group you already created:
Value Setting in Mapping rules
A rule hierarchy looks as follows:
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.
Note: You can not set value arbitrary in remote rule. All the value must follow federation protocol attributes and the key should be type.
What’s Federation Protocol Attributes
Federation protocol attributes is the assertion sent by IdP. Normally You can see it in SP logs, and you can find openstack_user inside. It’s why we have to have “type”: “openstack_user” in the rule. Please refer to this if you want to have other values, such as SERVER_NAME, SERVER_PORT, etc.
How does keystone process mappings?
The main entry is from ‘keystone/federation/core.py’ and ‘keystone/federation/utils.py’ finishes the jobs. Take a look at the process function of RuleProcessor class, _verify_all_requirements function and _update_local_mapping function in utils.py.
why we have to use ‘type’? keystone will use ‘type’ as the key to get the value from assertion. If it’s None, it will cause a final failed in _transform function.
def_verify_all_requirements(self,requirements,assertion):"""Compare remote requirements of a rule against the assertion.
If a value of ``None`` is returned, the rule with this assertion
doesn't apply.
If an array of zero length is returned, then there are no direct
mappings to be performed, but the rule is valid.
Otherwise, then it will first attempt to filter the values according
to blacklist or whitelist rules and finally return the values in
order, to be directly mapped.
:param requirements: list of remote requirements from rules
:type requirements: list
Example requirements::
[
{
"type": "UserName"
},
{
"type": "orgPersonType",
"any_one_of": [
"Customer"
]
},
{
"type": "ADFS_GROUPS",
"whitelist": [
"g1", "g2", "g3", "g4"
]
}
]
:param assertion: dict of attributes from an IdP
:type assertion: dict
Example assertion::
{
'UserName': ['testacct'],
'LastName': ['Account'],
'orgPersonType': ['Tester'],
'Email': ['testacct@example.com'],
'FirstName': ['Test'],
'ADFS_GROUPS': ['g1', 'g2']
}
:returns: identity values used to update local
:rtype: keystone.federation.utils.DirectMaps or None
"""direct_maps=DirectMaps()forrequirementinrequirements:requirement_type=requirement['type']direct_map_values=assertion.get(requirement_type)regex=requirement.get('regex',False)ifnotdirect_map_values:returnNoneany_one_values=requirement.get(self._EvalType.ANY_ONE_OF)ifany_one_valuesisnotNone:ifself._evaluate_requirement(any_one_values,direct_map_values,self._EvalType.ANY_ONE_OF,regex):continueelse:returnNonenot_any_values=requirement.get(self._EvalType.NOT_ANY_OF)ifnot_any_valuesisnotNone:ifself._evaluate_requirement(not_any_values,direct_map_values,self._EvalType.NOT_ANY_OF,regex):continueelse:returnNone# If 'any_one_of' or 'not_any_of' are not found, then values are# within 'type'. Attempt to find that 'type' within the assertion,# and filter these values if 'whitelist' or 'blacklist' is set.blacklisted_values=requirement.get(self._EvalType.BLACKLIST)whitelisted_values=requirement.get(self._EvalType.WHITELIST)# If a blacklist or whitelist is used, we want to map to the# whole list instead of just its values separately.ifblacklisted_valuesisnotNone:direct_map_values=[vforvindirect_map_valuesifvnotinblacklisted_values]elifwhitelisted_valuesisnotNone:direct_map_values=[vforvindirect_map_valuesifvinwhitelisted_values]direct_maps.add(direct_map_values)LOG.debug('updating a direct mapping: %s',direct_map_values)returndirect_maps
In the previous post, I elaborated how to setup keystone to keystone federation with two devstacks. In this post, I’ll use the similar environment except change the token from fernet to uuid for simplicity.
Companies are on longer asking if they should move to the cloud. They’re asking how to migrate to hybrid cloud with OpenStack. A hybrid cloud can offer a company the best of both public and private cloud, meet the requirements such as Cloud bursting, Disaster Recovery, Lifecycle-based Deployment, etc. But not if you slip into one of these pitfalls.
Visibility: how to manage clouds with a single pane?
Access Control: how to handle different credentials with security manner?
Network Connectivity: how to manage network configurations and maintain connectivity across clouds?
Outage & DR: how to ensure hybrid applications stay up during one cloud outages?
Audit & Compliance: how to collect audit data and comply with regulations?
Some OpenStack projects/features like tacker, tricircle, freezer, federated identity, sso, etc have collaborated to address these problems. In this session, I’ll share1:
I setup the keystone to keystone federation with two devstacks. Please pay attention that this guide is based on devstack which assumes keystone is running under Apache already.
Use SAML2 as the federation protocol.
It only works in CLI. No horizon SSO enabled in this guide right now.
Software Versions
Software
Version
Description
OS
Ubuntu 14.04.3 LTS
libapache2-mod-shib2
2.5.2+dfsg-2
Federated web single sign-on system (Apache module)
liblog4shib1:amd64
1.0.8-1
log4j-style configurable logging library for C++ (runtime)
libshibsp6:amd64
2.5.2+dfsg-2
Federated web single sign-on system (runtime)
shibboleth-sp2-schemas
2.5.2+dfsg-2
Federated web single sign-on system (schemas)
xmlsec1
1.2.18-2ubuntu1
XML security command line processor
libxmlsec1
1.2.18-2ubuntu1
XML security library
libxmlsec1-openssl
1.2.18-2ubuntu1
Openssl engine for the XML security library
Keystone as a Service Provider (SP)
Finish the following configuration in SP:172.16.40.112.
After the configuration, the total changes in my /etc is shown below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ubuntu@shuquan-devstack-sp:/etc$ sudo git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)
modified: apache2/sites-available/keystone.conf
modified: keystone/keystone.conf
modified: shibboleth/attribute-map.xml
modified: shibboleth/shibboleth2.xml
Untracked files:
(use "git add <file>..." to include in what will be committed)
shibboleth/sp-cert.pem
shibboleth/sp-key.pem
no changes added to commit (use "git add" and/or "git commit -a")
Setup Shibboleth
Just follow the instruction of the official docs and nothing special. :) My changes are shown below.
/etc/shibboleth/shibboleth2.xml
/etc/shibboleth/attribute-map.xml
/etc/apache2/sites-available/keystone.conf
Configure Federation in Keystone
Please pay attention to idp_entity_id. It has to be identical in SP & IdP. You will use it when you config the Identity Provider in Keystone’s [saml]/idp_entity_id option in IdP.
idp_entity_id is the unique identifier for the Identity Provider in Keystone’s [saml]/idp_entity_id option in IdP. This value should be the same in SSO entityID in /etc/shibboleth/shibboleth2.xml and use this command
Add Identity Provider(s), Mapping(s), and Protocol(s)
Note: The name you give the protocol is not arbitrary. It must match the method name you gave in the [auth]/methods config option. When authenticating it will be referred to as the protocol_id.
Keystone as an Identity Provider (IdP)
Finish the following configuration in IdP:172.16.40.115.
After the configuration, the total changes in my /etc is shown below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ubuntu@shuquan-devstack-idp:/etc$ sudo git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)
modified: apache2/sites-available/default-ssl.conf
modified: apache2/sites-available/keystone.conf
modified: keystone/keystone.conf
Untracked files:
(use "git add <file>..." to include in what will be committed)
keystone/saml2_idp_metadata.xml
keystone/ssl/
no changes added to commit (use "git add" and/or "git commit -a")
Package Installation
The only package need to install is xmlsec1.
1
$ apt-get install xmlsec1
Configure Federation in Keystone
1.Enable IdP is easier because you don’t need to deal with Shibboleth. Before following the official documentation, you should generate a self-signed cert-key pair for signing in the future and configure it properly in keystone and apache configure file.
2.Generate Metadata.To create metadata for your keystone IdP, run the keystone-manage command and redirect the output to a file. For example:
3.Please pay attention to the SP creation. I made a mistake here and spent some time on debugging. The key is that you don’t need to use entityID of shibboleth2.xml in SP for –service-provider-url setting. http://172.16.40.112/Shibboleth.sso/SAML2/ECP is fine because IdP will send SAML assertion to this link and the entityID may not resolve to anything. Surely, you can set these two value identical.