Identity Crisis
Moving Keystone from LDAP roles to SQL roles
Background
In early versions of OpenStack keystone did all its own user management. When it matured a bit, there was a cool new feature, you can point it at LDAP for authentication and authorization. This was a big step forward when running OpenStack as a part of a larger system.
Everything wasn't perfect though. OpenStack took all information form LDAP, including roles. This made it hard to run against "normal" LDAP setups, you had to have OpenStack specific data in LDAP. It's not usually not a Good Idea (tm) to have application specific data in centralized user management.
In Havana OpenStack came out with an option to have assignment in SQL and identities in LDAP. "Yay!" I thought. "Roles in SQL and identities from LDAP, this should be a simple fix". Silly me. I didn't find a good source how to do migration from completely LDAP based user info to SQL assignment, so here is my process and experience.
Why would I want to move? It is of course completely depends on the setup, and it has more to do with the development plans of the centralized user management than of the OpenStack installation. In our case it's mostly because we want to start connecting to a standard LDAP without any extra role crud.
Setup
First off, assignment isn't quite what I thought.I assumed it was user/role mapping. Apparently it maps users and groups to roles and projects (aka tenants). So projects don't come from LDAP any more? Apparently there's a new beast called "groups" which come from LDAP, and you can apparently map these groups to tenants. This is new in the keystone v3 API. So, a bigger update then.
Ok, so keystone grou<tab> nope. No group commands. Then I stumbled on this. To use keystone v3 api, you need the openstack cli tool, v3 won't be supported in the keystone cli tool.
After some trial and error, the easiest way seemed to be to install the openstack cli from git into an virtualenv.
So make a virtualenv, and check out openstack client, and install it. Use the git version, some older versions didn't have all required functionality.
You will need access to the keystone admin port (35357) from the machine you run the openstack client. Also, you need the admin token enabled in the keystone api, since we'll be without projects for a short while. Finally you'll need the keystone v3 api to be enabled, which is out of the scope of this post.
Checklist:
- A working openstack cli
- Access to the keystone admin api
- Keystone admin token in use
- Enabled keystone v3 api
Changes
Normal disclaimer. We're running Icehouse. Other versions might need tweaks to the process. Try this at your own risk.
So this is what we'll do
- Dump role data
- Change keystone config
- Create projects for all groups
- Assign groups roles within projects
- Assign the service group the admin roles
Dump role data
Since we need recreate the role mappings, we need to dump them somehow. In our case we just have all members, and a few admins , so not much dumping needed. Otherwise you'll probably have to do this from LDAP, since the keystone facilities for this are bad.
Change keystone config
We need to do two things, set the assignment driver and enable group config.
[assignment]
driver=keystone.assignment.backends.sql.Assignment
Since we'll be taking groups and not projects from LDAP, under the ldap section replace all tenant_* config params with group_ *, and restart keystone. Now OpenStack is down and we can't do anything, since we have no projects.
Check that groups, the keystone v3 api and the admin token work. First set up the environment (unset old OpenStack variables first).
export OS_IDENTITY_API_VERSION=3
export OS_TOKEN=<admintoken>
export OS_URL=<keystone_v3_api_endpoint>
Then test if this works
openstack group list
You should see a list of groups which matches your previous projects.
Create projects for all groups
Now we need to create the projects that we're missing. There is a small snag.
When you use LDAP, all OpenStack databases (nova, neutron e.g.) refer to your projects with their LDAP project id (for us the same as the project name). So when we create the projects, we need to make sure they have the same id as before. This is not possible with keystone, so we have to push them into the database manually. The following code assumes that the project name is the same as the project id.
echo "use keystone" >/tmp/keystonesql
groups=`openstack group list |grep -v "+---" |grep -v "| Name" |cut -f 2 -d "|"`
for group in $groups; do
echo "insert into project values(\"$group\", \"$group\", \"{}\", \"\", 1, \"default\");" >> /tmp/keystonesql
done
Then you run this into your database. Now
openstack project list
should show all your projects. They don't do much yet, since they're not mapped to groups. Let's do that. Here your previous role dumps come in, change the roles to what you have in your environment.
openstack role create admin
openstack role create member
for group in $groups; do
openstack role add --group $group --project $group member
done
Now this should show you how your groups are assigned to projects
openstack role assignment list
Then you still need to add admin rights to anyone who needs them, e.g. the service users. (Don't forget your admins too)
openstack role add --group service --project service admin
Test with a normal user account, and you should be back in business!
Remember, in the future when you add a new group to LDAP, you need to create the project, and make the mapping. Since it's a new project, you can create it with the keystone or openstack commands. It doesn't matter if the project id is an UUID, since it wouldn't match any existing resources anyway.
Conclusion and warning
First a warning. This way of changing backends is probably not supported. You will end up with non-UUID project ids in your keystone database. This isn't a problem now, but it is possible that the keystone SQL driver at some point for some reason expects them to be (although I don't see why).
There are other cool things in newer versions of keystone (Juno) which I haven't touched yet. Domain specific backends is one (don't store service users in LDAP, put them in SQL), a new policy.json to make admin roles more logical (per domain, not per tenant) among others. But that's for another time.
Geek. Product Owner @CSCfi