如需转载,请标明原文出处以及作者

陈锐 RuiChen @kiwik

2013/07/09 23:16:50


写在最前面:

以下内容在openstack G版2013.1代码和ubuntu 12.04 LTS环境验证

LDAP版本为openldap-2.4.28

安装LDAP

apt-get install ldap-utils
apt-get install slapd

验证LDAP登录

ldap安装默认根据当前主机的域名,生成登陆的DN

查看 /etc/hosts

所以这个环境上的登陆DN为 cn=admin,dc=openstack,dc=org

使用此命令验证是否配置成功

ldapsearch -x -LLL -H ldap:/// -b dc=openstack,dc=org dn

修改LDAP的默认schema

LDAP的默认schema不能直接和openstack配合使用,有些openstack的用户、角色、租户需要的属性默认schema中没有,例如:enable,description等等,需要修改;其次,需要添加存储openstack相关模型(user,tenant,group,role,domain)的dn,以便保存数据。 我自己写了两个ldif文件,以便完成上面两件事,内容如下:

modify.ldif


dn: cn={0}core,cn=schema,cn=config  
changetype: modify  
add: olcAttributeTypes  
olcAttributeTypes: {52}( 2.5.4.66 NAME 'enabled' DESC 'RFC2256: enabled of a group' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )  
  
dn: cn={0}core,cn=schema,cn=config  
changetype: modify  
delete: olcObjectClasses  
olcObjectClasses: {7}( 2.5.6.9 NAME 'groupOfNames' DESC 'RFC2256: a group of names (DNs)' SUP top STRUCTURAL MUST ( member $ cn ) MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )  
-  
add: olcObjectClasses  
olcObjectClasses: {7}( 2.5.6.9 NAME 'groupOfNames' DESC 'RFC2256: a group of names (DNs)' SUP top STRUCTURAL MUST ( member $ cn ) MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description $ enabled) )  
  
dn: cn={3}inetorgperson,cn=schema,cn=config  
changetype: modify  
delete: olcObjectClasses  
olcObjectClasses: {0}( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' DESC 'RFC2798: Internet Organizational Person' SUP organizationalPerson STRUCTURAL MAY ( audio $ businessCategory $ carLicense $ departmentNumber $ displayName $ employeeNumber $ employeeType $ givenName $ homePhone $ homePostalAddress $ initials $ jpegPhoto $ labeledURI $ mail $ manager $ mobile $ o $ pager $ photo $ roomNumber $ secretary $ uid $ userCertificate $ x500uniqueIdentifier $ preferredLanguage $ userSMIMECertificate $ userPKCS12 ) )  
-  
add: olcObjectClasses  
olcObjectClasses: {0}( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' DESC 'RFC2798: Internet Organizational Person' SUP organizationalPerson STRUCTURAL MAY ( audio $ businessCategory $ carLicense $ departmentNumber $ displayName $ employeeNumber $ employeeType $ givenName $ homePhone $ homePostalAddress $ initials $ jpegPhoto $ labeledURI $ mail $ manager $ mobile $ o $ pager $ photo $ roomNumber $ secretary $ uid $ userCertificate $ x500uniqueIdentifier $ preferredLanguage $ userSMIMECertificate $ userPKCS12 $ description $ enabled $ email ) )

将以上内容保存到对应的文件之后,执行如下命令:

ldapmodify -c -Y EXTERNAL -H ldapi:/// -f modify.ldif

add.ldif

dn: ou=users,dc=openstack,dc=org  
objectClass: top  
objectClass: organizationalUnit  
  
dn: ou=projects,dc=openstack,dc=org  
objectClass: top  
objectClass: organizationalUnit  
  
dn: ou=roles,dc=openstack,dc=org  
objectClass: top  
objectClass: organizationalUnit  
  
dn: ou=groups,dc=openstack,dc=org  
objectClass: top  
objectClass: organizationalUnit  
  
dn: ou=domains,dc=openstack,dc=org  
objectClass: top  
objectClass: organizationalUnit  

将以上内容保存到对应的文件之后,执行如下命令:

ldapadd -x -c -D"cn=admin,dc=openstack,dc=org" -w "Galax8800" -f add.ldif

注意Galax8800是安装LDAP的时候,输入的root密码

修改keystone的配置文件

/etc/keystone/keystone.conf

将Identity的后端配置为ldap

[identity]  
driver = keystone.identity.backends.ldap.Identity  

增加ldap段的配置,只需如下配置,其他可以使用默认值

[ldap]  
url = ldap://localhost  
user = cn=admin,dc=openstack,dc=org  
password = Galax8800  
suffix = dc=openstack,dc=org  
use_dumb_member = True  
allow_subtree_delete = False  
  
user_tree_dn = ou=users,dc=openstack,dc=org  
tenant_tree_dn = ou=projects,dc=openstack,dc=org  
role_tree_dn = ou=roles,dc=openstack,dc=org  
group_tree_dn = ou=groups,dc=openstack,dc=org  
domain_tree_dn = ou=domains,dc=openstack,dc=org  

注意:password = Galax8800 此密码为当时安装LDAP时,输入的root密码

配置完成之后,重启keystone

初始化keystone的基本用户

这个步骤网上的一些外国大牛已经提供了一些脚本,这里为了流程完整,就提供一个参考版本

keystone_basic.sh

#!/bin/sh  

ADMIN_PASSWORD=Galax8800  
SERVICE_PASSWORD=Galax8800  
SERVICE_TENANT_NAME=${SERVICE_TENANT_NAME:-service}  
  
get_id () {  
    echo `$@ | awk '/ id / { print $4 }'`  
}  
  
# Tenants  
ADMIN_TENANT=$(get_id keystone tenant-create --name=admin)  
SERVICE_TENANT=$(get_id keystone tenant-create --name=$SERVICE_TENANT_NAME)  
  
  
# Users  
ADMIN_USER=$(get_id keystone user-create --name=admin --pass="$ADMIN_PASSWORD" --email=admin@domain.com)  
  
  
# Roles  
ADMIN_ROLE=$(get_id keystone role-create --name=admin)  
KEYSTONEADMIN_ROLE=$(get_id keystone role-create --name=KeystoneAdmin)  
KEYSTONESERVICE_ROLE=$(get_id keystone role-create --name=KeystoneServiceAdmin)  
  
# Add Roles to Users in Tenants  
keystone user-role-add --user-id $ADMIN_USER --role-id $ADMIN_ROLE --tenant-id $ADMIN_TENANT  
keystone user-role-add --user-id $ADMIN_USER --role-id $KEYSTONEADMIN_ROLE --tenant-id $ADMIN_TENANT  
keystone user-role-add --user-id $ADMIN_USER --role-id $KEYSTONESERVICE_ROLE --tenant-id $ADMIN_TENANT  
  
# The Member role is used by Horizon and Swift  
MEMBER_ROLE=$(get_id keystone role-create --name=Member)  
  
# Configure service users/roles  
NOVA_USER=$(get_id keystone user-create --name=nova --pass="$SERVICE_PASSWORD" --email=nova@domain.com)  
keystone user-role-add --tenant-id $SERVICE_TENANT --user-id $NOVA_USER --role-id $ADMIN_ROLE  
  
GLANCE_USER=$(get_id keystone user-create --name=glance --pass="$SERVICE_PASSWORD" --email=glance@domain.com)  
keystone user-role-add --tenant-id $SERVICE_TENANT --user-id $GLANCE_USER --role-id $ADMIN_ROLE  
  
QUANTUM_USER=$(get_id keystone user-create --name=quantum --pass="$SERVICE_PASSWORD" --email=quantum@domain.com)  
keystone user-role-add --tenant-id $SERVICE_TENANT --user-id $QUANTUM_USER --role-id $ADMIN_ROLE  
  
CINDER_USER=$(get_id keystone user-create --name=cinder --pass="$SERVICE_PASSWORD" --email=cinder@domain.com)  
keystone user-role-add --tenant-id $SERVICE_TENANT --user-id $CINDER_USER --role-id $ADMIN_ROLE  

将以上内容保存到对应的文件之后,执行如下命令:

sh keystone_basic.sh

验证keystone

如果上述流程都已经执行成功了,需要验证一下keystone中的数据,执行

keystone user-list

keystone role-list

keystone tenant-list

keystone user-role-list

注意:keystone user-role-list如果执行失败,没有关系,这不是LDAP配置的问题,是一个keystone-client的bug,通过Rest Client重新验证一下就可以了

查看LDAP中的数据结构

我们再来看一下LDAP中的数据结构,如果和下图一致,就没有问题了

重启openstack的所有进程

配置keystone LDAP成功之后,需要重启openstack的所有进程,以nova为例,nova会缓存api-paste.ini中配置的admin_user的token,如果配置LDAP之前是使用的sql Identity后端,那么nova会使用这个缓存的admin_token去验证消息携带的token,keystone在判断admin_token是否可用时,会报错,造成认证失败,这个问题当时困扰了我很久,所以一定要重启openstack的所有进程,然后需要验证一下nova list,cinder list,glane image-list,quantum net-list是否可用。

将以上步骤浓缩为一个脚本

写了一个脚本将以上步骤全部实现

#!/bin/bash  
  
# ubunut 12.04 LTS keystone G 2013.1 openldap 2.4.28  
  
LDAP_PASS='Galax8800'  
  
KEYSTONE_CONF='/etc/keystone/keystone.conf'  
  
#step0 install ldap and set password  
function install_ldap()  
{  
    cat <<LDAP_PRESEED | debconf-set-selections   
slapd slapd/password1 password ${LDAP_PASS}  
slapd slapd/password2 password ${LDAP_PASS}  
LDAP_PRESEED  
  
    apt-get -y --force-yes install slapd  
    apt-get -y --force-yes install ldap-utils  
  
}  
  
#step1 check ldap login  
function check_ldap_login()  
{  
    local first_line=$(ldapsearch -x -LLL -H ldap:/// -b dc=openstack,dc=org dn | sed -n 1p)  
      
    if [ "${first_line}" == "dn: dc=openstack,dc=org" ]  
    then  
        echo "login success"  
    else  
        echo "login failed"  
        exit  
    fi  
}  
  
#step2 modify ldap schema  
function modify_ldap_schema()  
{  
    cat > ./modify.ldif <<EOF  
dn: cn={0}core,cn=schema,cn=config  
changetype: modify  
add: olcAttributeTypes  
olcAttributeTypes: {52}( 2.5.4.66 NAME 'enabled' DESC 'RFC2256: enabled of a group' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )  
  
dn: cn={0}core,cn=schema,cn=config  
changetype: modify  
delete: olcObjectClasses  
olcObjectClasses: {7}( 2.5.6.9 NAME 'groupOfNames' DESC 'RFC2256: a group of names (DNs)' SUP top STRUCTURAL MUST ( member $ cn ) MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )  
-  
add: olcObjectClasses  
olcObjectClasses: {7}( 2.5.6.9 NAME 'groupOfNames' DESC 'RFC2256: a group of names (DNs)' SUP top STRUCTURAL MUST ( member $ cn ) MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description $ enabled) )  
  
dn: cn={3}inetorgperson,cn=schema,cn=config  
changetype: modify  
delete: olcObjectClasses  
olcObjectClasses: {0}( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' DESC 'RFC2798: Internet Organizational Person' SUP organizationalPerson STRUCTURAL MAY ( audio $ businessCategory $ carLicense $ departmentNumber $ displayName $ employeeNumber $ employeeType $ givenName $ homePhone $ homePostalAddress $ initials $ jpegPhoto $ labeledURI $ mail $ manager $ mobile $ o $ pager $ photo $ roomNumber $ secretary $ uid $ userCertificate $ x500uniqueIdentifier $ preferredLanguage $ userSMIMECertificate $ userPKCS12 ) )  
-  
add: olcObjectClasses  
olcObjectClasses: {0}( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' DESC 'RFC2798: Internet Organizational Person' SUP organizationalPerson STRUCTURAL MAY ( audio $ businessCategory $ carLicense $ departmentNumber $ displayName $ employeeNumber $ employeeType $ givenName $ homePhone $ homePostalAddress $ initials $ jpegPhoto $ labeledURI $ mail $ manager $ mobile $ o $ pager $ photo $ roomNumber $ secretary $ uid $ userCertificate $ x500uniqueIdentifier $ preferredLanguage $ userSMIMECertificate $ userPKCS12 $ description $ enabled $ email ) )  
EOF  
  
    ldapmodify -c -Y EXTERNAL -H ldapi:/// -f modify.ldif > /dev/null 2>&1   
  
    if [ $? -eq 0 ]  
    then  
        echo "modify.ldif success"  
    else  
        echo "modify.ldif failed"  
        exit  
    fi  
      
    cat > ./add.ldif <<EOF  
dn: ou=users,dc=openstack,dc=org  
objectClass: top  
objectClass: organizationalUnit  
  
dn: ou=projects,dc=openstack,dc=org  
objectClass: top  
objectClass: organizationalUnit  
  
dn: ou=roles,dc=openstack,dc=org  
objectClass: top  
objectClass: organizationalUnit  
  
dn: ou=groups,dc=openstack,dc=org  
objectClass: top  
objectClass: organizationalUnit  
  
dn: ou=domains,dc=openstack,dc=org  
objectClass: top  
objectClass: organizationalUnit  
EOF  
  
    ldapadd -x -c -D "cn=admin,dc=openstack,dc=org" -w "${LDAP_PASS}" -f add.ldif > /dev/null 2>&1   
      
    if [ $? -eq 0 ]  
    then  
        echo "add.ldif success"  
    else  
        echo "add.ldif failed"  
        exit  
    fi  
      
    rm -rf ./modify.ldif  
    rm -rf ./add.ldif  
  
}  
  
#step3 modify keystone.conf  
function modify_keystone_conf()  
{  
    cat > ./keystone_ldap.conf <<EOF  
url = ldap://localhost  
user = cn=admin,dc=openstack,dc=org  
password = ${LDAP_PASS}  
suffix = dc=openstack,dc=org  
use_dumb_member = True  
allow_subtree_delete = False  
  
user_tree_dn = ou=users,dc=openstack,dc=org  
tenant_tree_dn = ou=projects,dc=openstack,dc=org  
role_tree_dn = ou=roles,dc=openstack,dc=org  
group_tree_dn = ou=groups,dc=openstack,dc=org  
domain_tree_dn = ou=domains,dc=openstack,dc=org  
EOF  
  
    if [ -w "${KEYSTONE_CONF}" ]  
    then  
        sed "s/^\(driver = keystone.identity.backends.\).*\(.Identity\)/\1ldap\2/" -i ${KEYSTONE_CONF}  
        sed "/^\[ldap\]$/r ./keystone_ldap.conf" -i ${KEYSTONE_CONF}  
    else  
        echo "modify keystone.conf failed"  
        exit  
    fi  
      
    rm -rf ./keystone_ldap.conf  
      
    stop keystone && start keystone > /dev/null 2>&1  
    if [ $? -eq 0 ]  
    then  
        echo "restart keystone success"  
    else  
        echo "restart keystone failed"  
        exit  
    fi  
    sleep 2  
}  
  
#step4 init keystone  
function init_keystone()  
{  
        cat > ./keystone_basic.sh <<EOF  
#!/bin/sh  
#  
# Keystone basic configuration   
  
# Mainly inspired by https://github.com/openstack/keystone/blob/master/tools/sample_data.sh  
  
# Modified by Bilel Msekni / Institut Telecom  
#  
# Support: openstack@lists.launchpad.net  
# License: Apache Software License (ASL) 2.0  
#  
#. /root/novarc  
#HOST_IP=\${MASTER}  
ADMIN_PASSWORD=Galax8800  
SERVICE_PASSWORD=Galax8800  
SERVICE_TENANT_NAME=\${SERVICE_TENANT_NAME:-service}  
  
get_id () {  
    echo \`\$@ | awk '/ id / { print \$4 }'\`  
}  
  
# Tenants  
ADMIN_TENANT=\$(get_id keystone tenant-create --name=admin)  
SERVICE_TENANT=\$(get_id keystone tenant-create --name=\$SERVICE_TENANT_NAME)  
  
  
# Users  
ADMIN_USER=\$(get_id keystone user-create --name=admin --pass="\$ADMIN_PASSWORD" --email=admin@domain.com)  
  
  
# Roles  
ADMIN_ROLE=\$(get_id keystone role-create --name=admin)  
KEYSTONEADMIN_ROLE=\$(get_id keystone role-create --name=KeystoneAdmin)  
KEYSTONESERVICE_ROLE=\$(get_id keystone role-create --name=KeystoneServiceAdmin)  
  
# Add Roles to Users in Tenants  
keystone user-role-add --user-id \$ADMIN_USER --role-id \$ADMIN_ROLE --tenant-id \$ADMIN_TENANT  
keystone user-role-add --user-id \$ADMIN_USER --role-id \$KEYSTONEADMIN_ROLE --tenant-id \$ADMIN_TENANT  
keystone user-role-add --user-id \$ADMIN_USER --role-id \$KEYSTONESERVICE_ROLE --tenant-id \$ADMIN_TENANT  
  
# The Member role is used by Horizon and Swift  
MEMBER_ROLE=\$(get_id keystone role-create --name=Member)  
  
# Configure service users/roles  
NOVA_USER=\$(get_id keystone user-create --name=nova --pass="\$SERVICE_PASSWORD" --email=nova@domain.com)  
keystone user-role-add --tenant-id \$SERVICE_TENANT --user-id \$NOVA_USER --role-id \$ADMIN_ROLE  
  
GLANCE_USER=\$(get_id keystone user-create --name=glance --pass="\$SERVICE_PASSWORD" --email=glance@domain.com)  
keystone user-role-add --tenant-id \$SERVICE_TENANT --user-id \$GLANCE_USER --role-id \$ADMIN_ROLE  
  
QUANTUM_USER=\$(get_id keystone user-create --name=quantum --pass="\$SERVICE_PASSWORD" --email=quantum@domain.com)  
keystone user-role-add --tenant-id \$SERVICE_TENANT --user-id \$QUANTUM_USER --role-id \$ADMIN_ROLE  
  
CINDER_USER=\$(get_id keystone user-create --name=cinder --pass="\$SERVICE_PASSWORD" --email=cinder@domain.com)  
keystone user-role-add --tenant-id \$SERVICE_TENANT --user-id \$CINDER_USER --role-id \$ADMIN_ROLE  
EOF  
      
    bash keystone_basic.sh > /dev/null 2>&1  
    if [ $? -eq 0 ]  
    then  
        echo "init keystone success"  
    else  
        echo "init keystone failed"  
        exit  
    fi  
      
    rm -rf ./keystone_basic.sh  
  
}  
  
#step5 check keystone  
function check_keystone()  
{  
    keystone user-list  
    keystone role-list  
    keystone tenant-list  
}  
  
  
#step6 restart openstack all service  
function restart_openstack_all_service()  
{  
    cd /etc/init.d/; for i in $( ls quantum-* ); do sudo service $i restart; done; cd -;  
    cd /etc/init.d/; for i in $( ls nova-* ); do sudo service $i restart; done; cd -;  
    cd /etc/init.d/; for i in $( ls cinder-* ); do sudo service $i restart; done; cd -;  
    cd /etc/init.d/; for i in $( ls glance-* ); do sudo service $i restart; done; cd -;  
    cd /etc/init.d/; for i in $( ls keystone ); do sudo service $i restart; done; cd -;  
}  
  
  
###################### main #######################  
install_ldap  
check_ldap_login  
modify_ldap_schema  
modify_keystone_conf  
init_keystone  
check_keystone  
restart_openstack_all_service

脚本中包括:

  • step0 install ldap and setpassword

  • step1 check ldap login

  • step2 modify ldap schema

  • step3 modify keystone.conf

  • step4 init keystone

  • step5 check keystone

  • step6 restartopenstack all service

最后一步重启所有openstack服务的步骤,会重启本节点的所有openstack进程,如果有其他节点需要手动重启

运行自动化脚本

bash config_keystone_ldap.sh

默认LDAP密码为Galax8800

最后附送ubuntu环境下完全删除LDAP的命令

apt-get purge slapd



Published

09 July 2013

Category

OpenStack

Tags