VMware Integrated Openstack, or VIO, is our answer to a more easily managed private cloud offering while still leveraging the openness of what Openstack traditionally grants. Long story short, VIO simplifies the deployment and scaling of Openstack while optimizing the mechanics for integration with a vSphere environment.
One of the common questions I’ve gotten from customers is surrounding user management and the RBAC model within Openstack, or lack thereof. Out of the box, both VIO and Openstack have the ability to tie into LDAP or local users relatively simply. But what happens when you have an entire forest of users who need access to various projects while keeping them logically separated from one another AND keeping the management at a minimum? Time to federate!
Key differences between the federation process of Openstack and VIO are to be noted as VIO ‘simplifies’ the process leveraging a custom application flag of viocli to automate much of the configuration. While Openstack requires manual manipulation of Shibboleth and Keystone to configure federation, VIO walks you through a short prompt questionnaire and then pushes the changes via Ansible playbooks.
Several of our customers have wanted to leverage vIDM (VMware Identity Manager) but I do not see that as a viable solution for VIO. Two reasons for this, the first being that it requires a standalone vIDM and not the built-in vRA vIDM, the second being vIDM effectively disables VIO’s API/cli. Why even bother with Openstack if you aren’t going to hammer it via API? So that leaves us with SAML2 integration and in most cases, SAML2 for ADFS.
The following will leave you with a federated VIO that will automatically create projects based upon a user’s AD security group, grant them access to it, and block all access to other projects.
The remainder of this post is going to assume you already have ADFS setup, VIO deployed, and all certificates trusted between the two if you want full SSL between VIO and AD.
In ADFS:
- Select Action > Add Relying Party Trust….
- Click Start.
- Select Enter data about the relying party manually and click Next.
- Enter OpenStack for the display name and click Next.
- Select AD FS profile and click Next.
- Click Next.
- Select Enable support for the SAML 2.0 WebSSO protocol.
- Enter https://{VIO-API-IP-OR-FQDN}:5000/saml for the relying party URL and click Next.
- Enter https://{VIO-API-IP-OR-FQDN}:5000/saml for the relying party trust identifier, click Add, and click Next.
- Select I do not want to configure multi-factor authentication and click Next.
- Select Permit all users to access this relying party and click Next.
- Click Next, select Edit Claim Rules, and click Close.
- Click Add Rule…
- Select Pass Through or Filter an Incoming Claim and click Next.
- Enter UPN passthrough for the rule name and select UPN for the incoming claim type.
- Select Pass through all claim values and click Finish
- Click Add Rule…
- Select Send Group Membership as a Claim and click Next.
- Enter a name for the Claim Rule (AD Group is what I use)
- Click Browse and select the AD Group you wish to grant access to
- Select Group for Outgoing Claim Type
- Enter a unique Outgoing Claim Value for this AD Group and click Finish
- Repeat steps for all AD Groups you wish to grant access to
By the end, it should resemble this:
Mapping.json:
I will first give the entire mapping.json file for those who just want the goods without the explanation but below the json, I will outline what each portion of the file means so you can easily adjust it and tinker to your liking for your environment.
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 |
[{ "local": [{ "user": { "name": "{0}" }, "group": { "domain": { "name": "adfs-users" }, "name": "Project1 Users" }, "projects": [{ "name": "VIO-Project1", "roles": [{ "name": "_member_" }] }] }], "remote": [{ "type": "upn" }, { "type": "group", "any_one_of": ["VIO-Project1"] } ] }, { "local": [{ "user": { "name": "{0}" }, "group": { "domain": { "name": "adfs-users" }, "name": "Project2 Users" }, "projects": [{ "name": "VIO-Project2", "roles": [{ "name": "_member_" }] }] }], "remote": [{ "type": "upn" }, { "type": "group", "any_one_of": ["VIO-Project2"] } ] } ] |
1 2 3 4 5 |
[{ "local": [{ "user": { "name": "{0}" }, |
First portion of the file deals with the VIO side of user creation. The {0} is a wildcard which is filled in automatically by the first portion of the “remote” section, in our case it will be the upn of the user.
1 2 3 4 5 6 |
"group": { "domain": { "name": "adfs-users" }, "name": "Project1 Users" }, |
This is VIO’s group management call-out. The domain (adfs-users) and group (Project1 Users) names can be unique or already existing in the environment. You can only have a single ADFS federated domain within a VIO deployment so choose wisely. These names are also what you will need to pipe into the viocli command later in the setup.
1 2 3 4 5 6 7 |
"projects": [{ "name": "VIO-Project1", "roles": [{ "name": "_member_" }] }] }], |
VIO’s Project management call-out. This is the name of the project to be created for the user and the role is what permissions it will have in said project. Ensure the project name is unique.
1 2 3 |
"remote": [{ "type": "upn" }, |
This remote section handles the ADFS side of things. It links to the first section of local’s wildcard. It basically says that within ADFS, look for the Outgoing Claim called ‘upn’ and give VIO its value. As a whole, I recommend leaving the first part of the local section and this portion of remote unchanged for ease of use purposes.
1 2 3 4 5 6 |
{ "type": "group", "any_one_of": ["VIO-Project1"] } ] }, |
Similar to the first remote section, this calls back to ADFS and is looking for an Outgoing Claim called ‘VIO-Project1’ of type Group. The VIO-Project1 value is what you made the Outgoing Claim Value within the ADFS Manager’s Claim Rule, not the Claim Rule’s name itself as you can see in the below screenshot.
That is the overall explanation of the mapping file. Local sections deal with VIO, remote sections deal with ADFS. As you can see, you can just copy and paste sections to add more groups/projects to VIO adjusting as you need.
Note: Users of multiple AD groups within VIO will get access to all associated projects, but not without adjusting a python file within VIO itself which is detailed in this guide as well.
Attribute.json
The attribute file is relatively self-explanatory so I won’t go into much detail here.
1 2 3 4 5 6 7 8 9 10 |
[ { "name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn", "id": "upn" }, { "name": "http://schemas.xmlsoap.org/claims/Group", "id": "group" } ] |
These are just the pointers to the Claim Descriptors for ADFS. If you choose to use different Claims, you will have to adjust the name and id fields as necessary.
Configuring ADFS via VIO OMS Server
- SSH into your VIO OMS server.
- Create and/or copy the contents of the mapping.json and attribute.json sections of this guide to 2 separate files.
- sudo viocli federation identity-provider add –type saml2
- Answer the prompted questions:
- Identity provider name []:
- This has to match the sub URL you entered in the ADFS Manager for VIO’s Relying Party Trust. You only need what’s after the :5000/
- Identity provider display name (for Horizon) []: Active Directory Federation Services
- Display of what user’s will see on the main VIO login page
- Description []: ADFS deployment
- Superfluous description that only is visible when viewing federation via cli on the OMS
- Do you wish to use URL or local file for IdP metadata? (url, file) [url]: url
- Always use URL, it’s more accurate and less error prone
- IdP metadata URL []: https://adfs.example.com/federationmetadata/2007-06/federationmetadata.xml
- Enter the FQDN of your ADFS server followed by /federationmetadata/2007-06/federationmetadata.xml
- Do not verify certificates when establishing TLS/SSL connections [False]: false
- False = Use SSL, True = Ignore SSL
- Do you wish to use a static file or template file for mapping rules? (static, template) [static]: static
- Choose static since we have created the files already
- Enter the local path of mapping rules file: mapping.json
- Relative or full path works
- Enter the name of the domain that federated users associate with [Default]: adfs-users
- This has to match the domain name entered within mapping.json else will fail
- Enter the name to the groups that federated users associate with (separated by commas “,”) []: Federated Users
- This has to match the group names within mapping.json else will fail. If using multiple groups, simply separate them with a comma, no need for quotes around strings either
- Do you wish to use a static file or template file for attribute mapping? (static, template) [static]: static
- Choose static since we have created the files already
- Enter the local path of attribute mapping file: attribute.json
- Relative or full path works
- Identity provider name []:
- sudo viocli identity configure –verbose
- If you have to modify this federation, for instance, if you need to make updates to the mapping.json file, be sure to run sudo viocli federation identity-provider edit –id 1
Depending on if you are using a compact or HA deployment of VIO, this can take anywhere between 10-20 minutes to complete so take a walk or check email.
Multi-group Membership Users (Shoutout to Katherine Skilling of www.kskilling.com for figuring this part out)
If you have users that belong to multiple AD security groups that are a part of your VIO deployment and subsequent project hierarchy, you will have to modify a single python script within VIO to ensure they recursively get all VIO memberships properly.
1. SSH into OMS server
2. If compact deployment: ssh loadbalancer01
3. If HA deployment: ssh controller01
4. sudo mv /usr/lib/python2.7/dist-packages/keystone/federation/utils.py /usr/lib/python2.7/dist-packages/keystone/federation/utils.py.orig
5. sudo cp /usr/lib/python2.7/dist-packages/keystone/federation/utils.py.orig /usr/lib/python2.7/dist-packages/keystone/federation/utils.py
6. Open utils.py in your editor and modify line 663 to be: projects.extend(identity_value[‘projects’])
7. Save and exit utils.py
8. If HA deployment, repeat this on all other controllers or SCP the file over.
9. Reboot the controllers (sudo reboot)
Troubleshooting
If this fails, it will tell you to look into /var/log/oms/oms.log. Ignore that. Instead, you’ll want to go into /var/log/column/ansible.log.
Remember before when I said that VIO streamlined federation by using a series of Ansible playbooks? That is exactly what is happening here. The OMS.log will only tell you that backend.yaml failed but beyond that, is of absolutely no help.
Ansible.log is the true source of failure and troubleshooting when it comes to federation. You can setup a tail -f on the log while the re-configure occurs to watch all the playbooks run and also the failure.
Most of the time the failures have to do with a typo, or something misconfigured in the mapping.json file. The other half of the time, the failure has to do with your SSL trusts being incorrect.
Also, make sure to use a JSON Linter to ensure your formatting is proper as well as all the options are accurate across the board.
And that’s it. This took many hours of poking and prodding of VIO to finally understand how it liked its information formatted in the mapping files, but part of the secret also lies within utils.py.
Lines 54-231 give a hint in what each class type can accept as a value and how to pass it down to the remote section as well.
‘user’ can take properties of:
- id (optional)
- name (optional)
- email (optional)
- domain (optional)
‘projects’ can take properties of:
- name (required)
- roles (required)
‘group’ can take properties of:
- groupid (required)
- group (required)