Full support for Keystone LDAP integration

Adding full support for integrating Keystone via LDAP. Enables
support for managing all LDAP related Keystone options.

 - Add two examples of LDAP configuration, although LDAP environments
   are highly variable, these will help get everyone started
 - Modify the keystone::ldap class to support all LDAP related options
 - Check sane defaults in the keystone::ldap class to hopefully reduce mistakes
 - Add a dependency on the python-ldap package
 - Modify the LDAP test to match the new class
 - Make the default-tenant optional since some LDAP backends do not
   support this

Change-Id: Ie6879eb4816fd2b906f72cac8deb3b62bd4b2430
This commit is contained in:
Matt Fischer
2014-03-25 10:07:45 -06:00
parent 4b57bbd8a3
commit 6fd675a2fe
6 changed files with 282 additions and 29 deletions

66
examples/ldap_full.pp Normal file
View File

@@ -0,0 +1,66 @@
# A full example from a real deployment that allows Keystone to modify
# everything except users, uses enabled_emulation, and ldaps
# Ensure this matches what is in LDAP or keystone will try to recreate
# the admin user
class { 'keystone::roles::admin':
email => 'test@example.com',
password => 'ChangeMe',
}
# You can test this connection with ldapsearch first to ensure it works.
# LDAP configurations are *highly* dependent on your setup and this file
# will need to be tweaked. This sample talks to ldap.example.com, here is
# an example of ldapsearch that will search users on this box:
# ldapsearch -v -x -H 'ldap://69.134.70.154:389' -D \
# "uid=bind,cn=users,cn=accounts,dc=example,dc=com" -w SecretPass \
# -b cn=users,cn=accounts,dc=example,dc=com
class { 'keystone:ldap':
url => 'ldap://ldap.example.com:389',
user => 'uid=bind,cn=users,cn=accounts,dc=example,dc=com',
password => 'SecretPass',
suffix => 'dc=example,dc=com',
query_scope => 'sub',
user_tree_dn => 'cn=users,cn=accounts,dc=example,dc=com',
user_id_attribute => 'uid',
user_name_attribute => 'uid',
user_mail_attribute => 'mail',
user_allow_create => 'False',
user_allow_update => 'False',
user_allow_delete => 'False',
user_enabled_emulation => 'True',
user_enabled_emulation_dn => 'cn=openstack-enabled,cn=groups,cn=accounts,dc=example,dc=com',
group_tree_dn => 'ou=groups,ou=openstack,dc=example,dc=com',
group_objectclass => 'organizationalRole',
group_id_attribute => 'cn',
group_name_attribute => 'cn',
group_member_attribute => 'RoleOccupant',
group_desc_attribute => 'description',
group_allow_create => 'True',
group_allow_update => 'True',
group_allow_delete => 'True',
tenant_tree_dn => 'ou=projects,ou=openstack,dc=example,dc=com',
tenant_objectclass => 'organizationalUnit',
tenant_id_attribute => 'ou',
tenant_member_attribute => 'member',
tenant_name_attribute => 'ou',
tenant_desc_attribute => 'description',
tenant_allow_create => 'True',
tenant_allow_update => 'True',
tenant_allow_delete => 'True',
tenant_enabled_emulation => 'True',
tenant_enabled_emulation_dn => 'cn=enabled,ou=openstack,dc=example,dc=com',
role_tree_dn => 'ou=roles,ou=openstack,dc=example,dc=com',
role_objectclass => 'organizationalRole',
role_id_attribute => 'cn',
role_name_attribute => 'cn',
role_member_attribute => 'roleOccupant',
role_allow_create => 'True',
role_allow_update => 'True',
role_allow_delete => 'True',
identity_driver => 'keystone.identity.backends.ldap.Identity',
assignment_driver => 'keystone.assignment.backends.ldap.Assignment',
use_tls => 'True',
tls_cacertfile => '/etc/ssl/certs/ca-certificates.crt',
tls_req_cert => 'demand',
}

28
examples/ldap_identity.pp Normal file
View File

@@ -0,0 +1,28 @@
# Example using LDAP to manage user identity only.
# This setup will not allow changes to users.
# Ensure this matches what is in LDAP or keystone will try to recreate
# the admin user
class { 'keystone::roles::admin':
email => 'test@example.com',
password => 'ChangeMe',
}
# You can test this connection with ldapsearch first to ensure it works.
# This was tested against a FreeIPA box, you will likely need to change the
# attributes to match your configuration.
class { 'keystone:ldap':
identity_driver => 'keystone.identity.backends.ldap.Identity',
url => 'ldap://ldap.example.com:389',
user => 'uid=bind,cn=users,cn=accounts,dc=example,dc=com',
password => 'SecretPass',
suffix => 'dc=example,dc=com',
query_scope => 'sub',
user_tree_dn => 'cn=users,cn=accounts,dc=example,dc=com',
user_id_attribute => 'uid',
user_name_attribute => 'uid',
user_mail_attribute => 'mail',
user_allow_create => 'False',
user_allow_update => 'False',
user_allow_delete => 'False'
}

View File

@@ -99,6 +99,7 @@ Puppet::Type.type(:keystone_user).provide(
end
def tenant
return resource[:tenant] if resource[:ignore_default_tenant]
user_id = user_hash[resource[:name]][:id]
begin
tenantId = self.class.get_keystone_object('user', user_id, 'tenantId')

View File

@@ -16,6 +16,11 @@ Puppet::Type.newtype(:keystone_user) do
newvalues(/\S+/)
end
newparam(:ignore_default_tenant, :boolean => true) do
newvalues(:true, :false)
defaultto false
end
newproperty(:enabled) do
newvalues(/(t|T)rue/, /(f|F)alse/)
defaultto('True')

View File

@@ -6,29 +6,175 @@
# == Authors
#
# Dan Bode dan@puppetlabs.com
# Matt Fischer matt.fischer@twcable.com
#
# == Copyright
#
# Copyright 2012 Puppetlabs Inc, unless otherwise noted.
#
class keystone::ldap(
$url = 'ldap://localhost',
$user = 'dc=Manager,dc=example,dc=com',
$password = 'None',
$suffix = 'cn=example,cn=com',
$user_tree_dn = 'ou=Users,dc=example,dc=com',
$tenant_tree_dn = 'ou=Roles,dc=example,dc=com',
$role_tree_dn = 'dc=example,dc=com'
$url = undef,
$user = undef,
$password = undef,
$suffix = undef,
$query_scope = undef,
$page_size = undef,
$user_tree_dn = undef,
$user_filter = undef,
$user_objectclass = undef,
$user_id_attribute = undef,
$user_name_attribute = undef,
$user_mail_attribute = undef,
$user_enabled_attribute = undef,
$user_enabled_mask = undef,
$user_enabled_default = undef,
$user_attribute_ignore = undef,
$user_default_project_id_attribute = undef,
$user_allow_create = undef,
$user_allow_update = undef,
$user_allow_delete = undef,
$user_pass_attribute = undef,
$user_enabled_emulation = undef,
$user_enabled_emulation_dn = undef,
$user_additional_attribute_mapping = undef,
$tenant_tree_dn = undef,
$tenant_filter = undef,
$tenant_objectclass = undef,
$tenant_id_attribute = undef,
$tenant_name_attribute = undef,
$tenant_mail_attribute = undef,
$tenant_enabled_attribute = undef,
$tenant_domain_id_attribute = undef,
$tenant_attribute_ignore = undef,
$tenant_allow_create = undef,
$tenant_allow_update = undef,
$tenant_allow_delete = undef,
$tenant_enabled_emulation = undef,
$tenant_enabled_emulation_dn = undef,
$tenant_additional_attribute_mapping = undef,
$role_tree_dn = undef,
$role_filter = undef,
$role_objectclass = undef,
$role_id_attribute = undef,
$role_name_attribute = undef,
$role_member_attribute = undef,
$role_attribute_ignore = undef,
$role_allow_create = undef,
$role_allow_update = undef,
$role_allow_delete = undef,
$role_additional_attribute_mapping = undef,
$group_tree_dn = undef,
$group_filter = undef,
$group_objectclass = undef,
$group_id_attribute = undef,
$group_name_attribute = undef,
$group_member_attribute = undef,
$group_desc_attribute = undef,
$group_attribute_ignore = undef,
$group_allow_create = undef,
$group_allow_update = undef,
$group_allow_delete = undef,
$group_additional_attribute_mapping = undef,
$tenant_tree_dn = undef,
$role_tree_dn = undef,
$use_tls = undef,
$tls_cacertdir = undef,
$tls_cacertfile = undef,
$tls_req_cert = undef,
$identity_driver = undef,
$assignment_driver = undef,
) {
package { 'python-ldap':
ensure => present,
}
# check for some common driver name mistakes
if ($assignment_driver != undef) {
if ! ($assignment_driver =~ /^keystone.assignment.backends.*Assignment$/) {
fail('assigment driver should be of the form \'keystone.assignment.backends.*Assignment\'')
}
}
if ($identity_driver != undef) {
if ! ($identity_driver =~ /^keystone.identity.backends.*Identity$/) {
fail('identity driver should be of the form \'keystone.identity.backends.*Identity\'')
}
}
if ($tls_cacertdir != undef) {
file { $tls_cacertdir:
ensure => directory
}
}
keystone_config {
'ldap/url': value => $url;
'ldap/user': value => $user;
'ldap/password': value => $password;
'ldap/suffix': value => $suffix;
'ldap/user_tree_dn': value => $user_tree_dn;
'ldap/tenant_tree_dn': value => $tenant_tree_dn;
'ldap/role_tree_dn': value => $role_tree_dn;
# 'ldap/tree_dn': value => "dc=example,dc=com";
'ldap/url': value => $url;
'ldap/user': value => $user;
'ldap/password': value => $password, secret => true;
'ldap/suffix': value => $suffix;
'ldap/query_scope': value => $query_scope;
'ldap/page_size': value => $page_size;
'ldap/user_tree_dn': value => $user_tree_dn;
'ldap/user_filter': value => $user_filter;
'ldap/user_objectclass': value => $user_objectclass;
'ldap/user_id_attribute': value => $user_id_attribute;
'ldap/user_name_attribute': value => $user_name_attribute;
'ldap/user_mail_attribute': value => $user_mail_attribute;
'ldap/user_enabled_attribute': value => $user_enabled_attribute;
'ldap/user_enabled_mask': value => $user_enabled_attribute;
'ldap/user_enabled_default': value => $user_enabled_attribute;
'ldap/user_attribute_ignore': value => $user_enabled_attribute;
'ldap/user_default_project_id_attribute': value => $user_enabled_attribute;
'ldap/user_allow_create': value => $user_allow_create;
'ldap/user_allow_update': value => $user_allow_update;
'ldap/user_allow_delete': value => $user_allow_delete;
'ldap/user_pass_attribute': value => $user_pass_attribute;
'ldap/user_enabled_emulation': value => $user_enabled_emulation;
'ldap/user_enabled_emulation_dn': value => $user_enabled_emulation_dn;
'ldap/tenant_tree_dn': value => $tenant_tree_dn;
'ldap/tenant_filter': value => $tenant_filter;
'ldap/tenant_objectclass': value => $tenant_objectclass;
'ldap/tenant_id_attribute': value => $tenant_id_attribute;
'ldap/tenant_name_attribute': value => $tenant_name_attribute;
'ldap/tenant_mail_attribute': value => $tenant_mail_attribute;
'ldap/tenant_enabled_attribute': value => $tenant_enabled_attribute;
'ldap/tenant_attribute_ignore': value => $tenant_attribute_ignore;
'ldap/tenant_domain_id_attribute': value => $tenant_domain_id_attribute;
'ldap/tenant_allow_create': value => $tenant_allow_create;
'ldap/tenant_allow_update': value => $tenant_allow_update;
'ldap/tenant_allow_delete': value => $tenant_allow_delete;
'ldap/tenant_enabled_emulation': value => $tenant_enabled_emulation;
'ldap/tenant_enabled_emulation_dn': value => $tenant_enabled_emulation_dn;
'ldap/tenant_additional_attribute_mapping': value => $tenant_additional_attribute_mapping;
'ldap/role_tree_dn': value => $role_tree_dn;
'ldap/role_filter': value => $role_filter;
'ldap/role_objectclass': value => $role_objectclass;
'ldap/role_id_attribute': value => $role_id_attribute;
'ldap/role_name_attribute': value => $role_name_attribute;
'ldap/role_member_attribute': value => $role_member_attribute;
'ldap/role_attribute_ignore': value => $role_attribute_ignore;
'ldap/role_allow_create': value => $role_allow_create;
'ldap/role_allow_update': value => $role_allow_update;
'ldap/role_allow_delete': value => $role_allow_delete;
'ldap/role_additional_attribute_mapping': value => $role_additional_attribute_mapping;
'ldap/group_tree_dn': value => $group_tree_dn;
'ldap/group_filter': value => $group_filter;
'ldap/group_objectclass': value => $group_objectclass;
'ldap/group_id_attribute': value => $group_id_attribute;
'ldap/group_name_attribute': value => $group_name_attribute;
'ldap/group_member_attribute': value => $group_member_attribute;
'ldap/group_desc_attribute': value => $group_desc_attribute;
'ldap/group_attribute_ignore': value => $group_attribute_ignore;
'ldap/group_allow_create': value => $group_allow_create;
'ldap/group_allow_update': value => $group_allow_update;
'ldap/group_allow_delete': value => $group_allow_delete;
'ldap/group_additional_attribute_mapping': value => $group_additional_attribute_mapping;
'ldap/use_tls': value => $use_tls;
'ldap/tls_cacertdir': value => $tls_cacertdir;
'ldap/tls_cacertfile': value => $tls_cacertfile;
'ldap/tls_req_cert': value => $tls_req_cert;
'identity/driver': value => $identity_driver;
'assignment/driver': value => $assignment_driver;
}
}

View File

@@ -1,20 +1,27 @@
require 'spec_helper'
describe 'keystone::ldap' do
describe 'with default params' do
it 'should contain default params' do
should contain_keystone_config('ldap/url').with_value('ldap://localhost')
should contain_keystone_config('ldap/user').with_value('dc=Manager,dc=example,dc=com')
should contain_keystone_config('ldap/password').with_value('None')
should contain_keystone_config('ldap/suffix').with_value('cn=example,cn=com')
should contain_keystone_config('ldap/user_tree_dn').with_value('ou=Users,dc=example,dc=com')
should contain_keystone_config('ldap/tenant_tree_dn').with_value('ou=Roles,dc=example,dc=com')
should contain_keystone_config('ldap/role_tree_dn').with_value('dc=example,dc=com')
describe 'with basic params' do
let :params do
{
:url => 'ldap://foo',
:user => 'cn=foo,dc=example,dc=com',
:password => 'abcdefg',
:user_tree_dn => 'cn=users,dc=example,dc=com',
:user_allow_create => 'False',
:user_allow_update => 'False',
:user_allow_delete => 'False',
}
end
it { should contain_package('python-ldap') }
it 'should have basic params' do
should contain_keystone_config('ldap/url').with_value('ldap://foo')
should contain_keystone_config('ldap/user').with_value('cn=foo,dc=example,dc=com')
should contain_keystone_config('ldap/password').with_value('abcdefg').with_secret(true)
should contain_keystone_config('ldap/user_tree_dn').with_value('cn=users,dc=example,dc=com')
should contain_keystone_config('ldap/user_allow_create').with_value('False')
should contain_keystone_config('ldap/user_allow_update').with_value('False')
should contain_keystone_config('ldap/user_allow_delete').with_value('False')
end
end
end