Monday, February 15, 2016

Keystone and SSO: Keystone to Keystone configuration (ECP profile)

This post describes how to set up Single Sign-On system based on ECP profile of SAML standard.
Keystone can be Identity Provider as well as Service Provider. In production environment it means that user can have one Keystone for authentication and general authorization and other as for specific authorization.
We will have following configuration:


Keystone supports Single Sign-On by using Keystone feature "Federation".
Federated identity is a mechanism to establish trusts between Identity Providers and Service Providers (SP).
Keystone is no longer the only identity service for OpenStack services, but instead, there are be a wide range of identity services distributed around the Internet, called Identity Providers (IdPs).

SAML protocol

One of the ways to implement Single Sign-On is to use SAML protocol.
The SAML specification defines three roles: the Principal (typically a user), the Identity provider (IdP), and the Service provider (SP). In the use case addressed by SAML, the principal requests a service from the service provider. The service provider requests and obtains an identity assertion from the identity provider.

Keystone Federated Identity provides a way to securely use existing credentials to access cloud resources such as servers, volumes, and databases, across multiple endpoints provided in multiple authorized clouds using a single set of credentials, without having to provision additional identities or log in multiple times. The credential is maintained by the user’s Identity Provider.


One of SAML implementations is the Shibboleth.
Shibboleth is a standards based, open source software package for web single sign-on across or within organizational boundaries. It allows sites to make informed authorization decisions for individual access of protected online resources in a privacy-preserving manner. The Shibboleth software implements widely used federated identity standards, principally the Security Assertion Markup Language (SAML), to provide a federated single sign-on and attribute exchange framework. It is possible to configure Keystone to be Service Provider or/and Identity provider.

Many thanks to rodrigods. A lot of information was taken from


Keystone should be running under Apache:
  1. Copy httpd/wsgi-keystone.conf to /etc/apache2/sites-available/keystone.conf
  2. Enable keystone:
    sudo a2ensite keystone
  3. Restart Apache:
    sudo service apache2 restart
We will use 2 hosts:
keystone1 - Identity Provider Keystone
keystone2 - Service Provider Keystone

Keystone as a Service Provider (SP)

Service Provider (SP) - is a system entity that provides services to principals or other system entities, in this case, OpenStack Identity is the Service Provider.
This approach to federation supports keystone as a Service Provider, consuming identity properties issued by an external Identity Provider - SAML assertions.

Federated users are not mirrored in the keystone identity backend (for example, using the SQL driver). The external Identity Provider is responsible for authenticating users, and communicates the result of authentication to keystone using identity properties. Keystone maps these values to keystone user groups and assignments created in keystone.
  1. Enable saml2 authentication method. Make changes in /etc/keystone/keystone.conf:
    methods = external,password,token,oauth1,saml2
    saml2 = keystone.auth.plugins.mapped.Mapped
  2. Install Shibboleth:
    sudo apt-get install libapache2-mod-shib2
  3. Configure your Keystone virtual host and adjust the config to properly handle SAML2 workflow. Add WSGIScriptAlias directive to your vhost configuration:
    <VirtualHost *:5000> 
    WSGIScriptAliasMatch ^(/v3/OS-FEDERATION/identity_providers/.*?/protocols/.*?/auth)$ /var/www/keystone/main/$1
  4. Append the following lines to the end of the file:
    <Location /Shibboleth.sso> 
        SetHandler shib

    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth> 
        ShibRequestSetting requireSession 1
        AuthType shibboleth
        ShibExportAssertion Off
        Require valid-user
  5. Edit the /etc/shibboleth/attribute-map.xml file to add the attributes:
    <Attribute name="openstack_user" id="openstack_user"/> 
    <Attribute name="openstack_roles" id="openstack_roles"/> 
    <Attribute name="openstack_project" id="openstack_project"/>
  6. Edit the /etc/shibboleth/shibboleth2.xml file to add the Keystone IdP entityID and MetadataProvider:
    <SSO entityID="entityID="http://keystone1:5000/v3/OS-FEDERATION/saml2/idp"> 
        SAML2 SAML1

    <MetadataProvider type="XML" uri="http:/
  7. Generate Shibboleth's key-pair:
    sudo shib-keygen
  8. Restart Apache:
    sudo service apache2 restart
  9. Enable shibboleth module:
    sudo a2enmod shib2

Keystone as an Identity Provider (IP)

Identity Provider (IP) is a directory service, which allows users to login with a user name and password. It is a typical source of authentication tokens.
  1. This feature requires installation of the xmlsec1 and pysaml2:
    sudo apt-get install xmlsec1
    sudo pip install pysaml2
  2. Generate certificates:
    sudo keystone-manage pki_setup --keystone-user --keystone-group
  3. Add saml configuration to the /etc/keystone/keystone.conf file:
    certfile = /etc/keystone/ssl/certs/ca.pem
    keyfile = /etc/keystone/ssl/private/cakey.pem
    idp_entity_id = http://
    idp_sso_endpoint = http://
    idp_metadata_path = /etc/keystone/keystone_idp_metadata.xml
  4. In order to create a trust between the Identity Provider and the Service Provider, metadata must be exchanged. To create metadata for your Identity service, run the keystone-manage command and pipe the output to a file:
    sudo keystone-manage saml_idp_metadata > /etc/keystone/keystone_idp_metadata.xml
  5. Restart Keystone service:
    sudo service apache2 restart

Configure Federation in Keystone

New users will not be added to the Identity backend, but the Identity Service requires group-based role assignments to authorize federated users. The federation mapping function will map the user into local Identity Service groups objects, and hence to local role assignments.
Thus, it is required to create the necessary Identity Service groups that correspond to the Identity Provider’s groups; additionally, these groups should be assigned roles on one or more projects or domains.
  1. Create domain “domainf”:
    curl -i -X POST \
    -H "X-Auth-Token: ADMIN" \
    -H "Content-Type: application/json" \
    -d '{"domain": {"enabled": true, "name": "domainf"}}' \
  2. Create group “groupf”:
    curl -i -X POST \
    -H "X-Auth-Token: ADMIN" \
    -H "Content-Type: application/json" \
    -d '{"group": {"description": "federated group","domain_id": "<domain_id>","name": "groupf"}}' \
  3. Create role “rolef”:
    curl -i -X POST \
    -H "X-Auth-Token: ADMIN" \
    -H "Content-Type: application/json" \
    -d '{"role": {"name": "rolef"}}' \
  4. Grant role “rolef”to “groupf” in “domainf”:
    curl -i -X PUT \
    -H "X-Auth-Token: ADMIN" \
  5. Create a mapping. A mapping is a list of rules. Mapping adds a set of rules to map federation attributes to Keystone users and/or groups. An Identity Provider has exactly one mapping specified per protocol. Mapping objects can be used multiple times by different combinations of Identity Provider and Protocol.
    curl -s -X PUT \
    -H "X-Auth-Token: ADMIN" \
    -H "Content-Type: application/json" \
    -d '{"mapping": {"rules": [{"local": [{"user": {"name": "federated_user"},"group": {"id": "<group_id>"}}],"remote": [{"type": "openstack_user","any_one_of": ["user1","admin"]}]}]}}' \
  6. Create an Identity Provider object in keystone, which represents the Identity Provider we will use to authenticate end users:
    curl -s -X PUT \
    -H "X-Auth-Token: ADMIN" \
    -H "Content-Type: application/json" \
    -d '{"identity_provider": {"description": "idp", "remote_ids": ["https://keystone1:5000/v3/OS-FEDERATION/saml2/idp"], "enabled": true}}' \
  7. Create a protocol. A protocol contains information that dictates which Mapping rules to use for an incoming request made by an IdP. An IdP may have multiple supported protocols.
    curl -s -X PUT \
    -H "X-Auth-Token: ADMIN" \
    -H "Content-Type: application/json" \
    -d '{"protocol": {"mapping_id": "keystone-idp-mapping"}}' \
  8. Create Service Provider object:
    curl -s -X PUT \
    -H "X-Auth-Token: ADMIN" \
    -H "Content-Type: application/json" \
    -d '{"service_provider": {"auth_url": "http://keystone2:5000/v3/OS-FEDERATION/identity_providers/keystone-idp/protocols/saml2/auth", "description": "Remote Service Provider", "enabled": true, "sp_url": "http://keystone2/Shibboleth.sso/SAML2/ECP"}}' \

Get unscoped token

To start Federated authentication an user must access the dedicated URL with Identity Provider’s and Protocol’s identifiers stored within a protected URL.
Enhanced Client or Proxy (ECP) profile is available in the keystoneclient in the Identity service API.
Current script standard SAML2 authentication procedure to get unscoped token:
  • authenticate
  • get saml2 assertation
  • post assertation data to the service provider
  • get unscoped token
In the returned unscoped token, a list of Identity service groups the user belongs to will be included.
import json 

from keystoneclient import session as keystone_session 
from keystoneclient.auth.identity import v3

def main():
    auth = v3.Password(auth_url='http://localhost:5000/v3',
    session = keystone_session.Session(auth=auth, verify=False)
    token = session.auth.get_token(session)

    data = json.dumps({

                          "auth": {
                              "identity": {
                                  "methods": ["token"],
                                  "token": {"id": token}
                              "scope": {
                                  "service_provider": {"id": "keystone-sp"}
    r ='http://localhost:5000/v3/auth/OS-FEDERATION/saml2/ecp',

    assertion = str(r.text)'http://localhost/Shibboleth.sso/SAML2/ECP',
                 headers={'Content-Type': 'application/vnd.paos+xml'},

    r = session.get(url='http://localhost:5000/v3/OS-FEDERATION/identity_providers/keystone-idp/protocols/saml2/auth', 

    fed_token_id = r.headers['X-Subject-Token']

    print fed_token_id

if __name__ == "__main__": 

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
A federated user may request a scoped token, by using the unscoped token. A project or domain may be specified by either ID or name. An ID is sufficient to uniquely identify a project or domain.

No comments:

Post a Comment