Integrating PISTON OPENSTACK 3.0 with Microsoft Active Directory
May 21, 2014 This edition of this document applies to Piston OpenStack 3.0. To send us your comments about this document, e-mail documentation@pistoncloud.com. We look forward to hearing from you. When you send information to Piston Cloud Computing, Inc., you grant Piston Cloud Computing, Inc. a nonexclusive right to use or distribute the information in any way it believes appropriate without incurring any obligation to you. Copyright Piston Cloud Computing, Inc 2014. All rights reserved. US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with Piston Cloud Computing, Inc. 2
Table of Contents Understanding Active Directory and Piston OpenStack... 4 Satisfying Prerequisites.... 7 Modifying the Active Directory Schema...7 Planning Your LDAP Objects.... 10 Configuring and Installing Piston OpenStack... 14 Configuring Piston OpenStack...14 Installing Piston OpenStack...20 Creating Objects in Active Directory.... 21 Creating Users in Active Directory...21 Creating Piston OpenStack Objects in ADSI Edit...22 Validating the Integration... 32 Appendix A: Example LDAP Objects.... 33 Appendix B: Example LDAP Configuration... 36 3
Understanding Active Directory and Piston OpenStack This technical support bulletin describes how to integrate the Keystone authentication service with Microsoft Active Directory. Active Directory implements Lightweight Directory Access Protocol (LDAP) distributed-directory services, Kerberos authentication services, and Domain Name Service (DNS) distributed-naming services to manage objects such as users and computers in an enterprise. Integrating Keystone with Active Directory enables you to maintain user information in a single enterprise-wide repository to perform authentication and authorization of users in your Piston OpenStack cloud. Active Directory has three partitions also referred to as naming contexts in which it stores information: The domain partition contains users, groups, contacts, computers, organizational units, and other types of objects The schema partition contains classes and attribute definitions that describe the objects The configuration partition includes configuration data for services, partitions, and sites Active Directory stores objects hierarchically. Most companies, for instance, are broken up into organizational units such as Marketing, Sales, Business Development, and so on in order to group employees by their job function. Users are the entities that use the virtual machines and compute, networking, and storage services provided by a Piston OpenStack installation. Their ability to perform actions is based on permissions defined by roles. Users can be a member of multiple projects and have different roles within each. In this document users are represented by the organizationalperson object class, though other object classes can be used. Projects are high level groupings that group zero or more users and own resources such as block storage in Ceph and virtual machines in Nova. In the context of integrating Active Directory and Piston OpenStack, the groupofnames object class is used to represent projects, which are also referred to as tenants. 4
Roles are groupings of user or service privileges that specify the actions a user can perform in the context of the project. In this document roles are represented by the organizationalrole object class, though other object classes can be used. If you are using Active Directory you will probably have many users in your project. This document is not a comprehensive guide to implementing Active Directory, but for the purposes of the examples shown in the document you will create the objects shown in Figure 1: Active Directory Objects on page 6. 5
Figure 1: Active Directory Objects 6
Satisfying Prerequisites Important Make sure that the LDAP server does not have any of the projects or roles to be used for the Piston OpenStack cloud configured prior to successfully installing your cluster. Note that if you have to reinstall the cluster and any roles or projects exist already, the reinstallation process will fail. If you have to reinstall your cluster please contact Piston Advanced Technical Support. If you are using the hostname to connect to the Active Directory Domain Controller for LDAP then DNS must be able to resolve the hostname. You can also specify an Internet Protocol (IP) address for the Uniform Resource Locator (URL). Entering a root domain name should also work so long as the DNS Service (SRV) records exist that direct the Keystone service to a valid Active Directory server. Do the following to determine the IP address of your Active Directory server 1. Select Start > Server Manager. 2. Select DNS. 3. The Server column displays the name of the server; the fully-qualified domain name would be that value combined with the domain name, such as: ad01.example.com 4. The IPv4 Address column displays the IP address of the server, such as: 10.34.1.100 Either value can be used to configure Piston OpenStack for integration with Active Directory. Modifying the Active Directory Schema Active Directory Service Interfaces (ADSI) is a set of Component Object Model (COM) interfaces in Active Directory that presents a single tool to manage multiple distributed resources. 7
In Active Directory the organizationalunit object class contains the User object class it is said to be a possible superior. This relationship is maintained through an attribute of the User object named posssuperiors, which is set to a value that contains organizationalunit as well as any other object classes that are above the User class in the relational hierarchy. In order to integrate Keystone with Active Directory the groupofnames class must be configured as a possible superior of the organizationrole class. Do the following: 1. Select Start > Administrative Tools. 2. Double-click ADSI Edit. 3. Select ADSI Edit. 4. Select Action > Connect to from the menu bar. 5. Make sure the Select a well known Naming Context radio button is enabled, then select Schema from the drop-down menu. 6. Click OK. 7. Expand Schema. 8. Select the appropriate schema. 9. Select the CN=Organizational-Role class; it should appear approximately three-quarters of the way down the list by default. 10. Select Action > Properties from the menu bar. 11. If the posssuperiors attribute is displayed, select it then click Edit; if it is not, do the following: A. Click Filter. B. Click Show only attributes that have values to de-select it. C. Select the posssuperiors attribute, then click Edit. 12. Type groupofnames in the Value to add field, then click Add. 13. Click OK to close the Multi-valued String Editor dialog. 14. Click OK to close the CN=Organizational-Role Properties dialog. 8
Notes Moving groupofnames objects that contain child objects such as organizationalrole objects within the Active Directory Users and Computers snap-in will result in child objects not displaying properly in any Microsoft Management Console (MMC) snap-ins. Changing the schema of the organizationalrole object to enable groupofnames as a possible superior must be done before creating any groupofnames objects or else MMC snap-ins will not display them as containers and it will therefore it be impossible to add organizationalrole objects to them. 9
Planning Your LDAP Objects To integrate Active Directory with Piston OpenStack you must configure Piston OpenStack first as described in Configuring and Installing Piston OpenStack on page 14 and then create the users and organizational units as described in Creating Objects in Active Directory on page 21. To facilitate this process, plan the objects you will be creating. In Table 1: Environment-Specific LDAP Properties on page 10, the values in the column named Property on page 10 are configuration options you will have to provide values for during the process described in Configuring and Installing Piston OpenStack on page 14. The column named Description on page 10 describes how you will determine what values to set each property to. Record the planned value in the column named Value in Your Environment on page 10 for use in Configuring and Installing Piston OpenStack on page 14. Table 1: Environment-Specific LDAP Properties Property Description Value in Your Environment url Record here the value ldap:// followed by the name or IP address of your Active Directory Server Example: ldap://10.34.0.100 10
Property Description Value in Your Environment bind_dn Record here the distinguished name of a user account that has the permissions required to search the appropriate Active Directory tree Example: CN=ldapadmin,CN=Users, DC=EXAMPLE,DC=COM bind_password suffix Record here the password for the user specified for bind_dn on page 11 Set this to the distinguished name of the domaindns object in your Active Directory tree Example: DC=EXAMPLE,DC=COM 11
Property Description Value in Your Environment dumb_member The member attribute of groupofnames objects is required, making it impossible to have an empty group; if any groups in the tree are empty you will need to specify a dummy member to be automatically added Record here the distinguished name of a dummy user Example: CN=dumbmember, CN=Users,DC=EXAMPLE, DC=COM user_tree_dn Record here the distinguished name of the Users container Example: CN=Users,DC=EXAMPLE, DC=COM 12
Property Description Value in Your Environment user_objectclass Set this to the name of the object class that represents users Example: organizationalperson inetorgperson tenant_tree_dn Record here the distinguished name of the organizationalunit object you will create to represent projects Example: OU=Projects, OU=OpenStack, DC=EXAMPLE,DC=COM role_tree_dn Record here the distinguished name of the organizationalunit object you will create to represent projects Example: OU=Roles, OU=OpenStack, DC=EXAMPLE,DC=COM 13
Configuring and Installing Piston OpenStack Configuring Piston OpenStack Edit the cloud.conf file on your Piston CloudKey so that it is configured to use Active Directory. Appendix B: Example LDAP Configuration on page 36 contains a sample section, though the structure will be different in your environment. Table 2: LDAP Configuration Properties on page 14 describes the properties and what to set them to; some values are unique to your environment and were recorded in Table 1: Environment-Specific LDAP Properties on page 10. Do the following: 1. In the [auth] section set the type property to the value ldap: type=ldap 2. Set the properties in the [ldap_auth] section according to the recommendations made in Table 2: LDAP Configuration Properties on page 14: Table 2: LDAP Configuration Properties Property Description Value allow_self_signed_certs If you have created your own Secure Socket Layer (SSL) certificate using a program such as OpenSSL, set this property to True True If not, set this property to False 14
Property Description Value url Set this to the value planned for in Table 1: Environment- Specific LDAP Properties on page 10 ldap://10.34.0.100 bind_dn bind_password suffix use_dumb_member Set this to the value planned for in Table 1: Environment- Specific LDAP Properties on page 10 Set this to the value planned for in Table 1: Environment- Specific LDAP Properties on page 10 Set this to the value planned for in Table 1: Environment- Specific LDAP Properties on page 10 The member attribute of the groupofnames object is required, making it impossible to have an empty group; if a group is empty, set this property to true to have a dummy member added CN=ldapadmin,CN=Users, DC=EXAMPLE,DC=COM DC=EXAMPLE,DC=COM True 15
Property Description Value dumb_member query_scope Set this to the value planned for in Table 1: Environment- Specific LDAP Properties on page 10 Set this to the value one to configure the LDAP query scope for only one level CN=dumbmember,CN=Users, DC=EXAMPLE,DC=COM one user_tree_dn user_objectclass Set this to the value sub to configure the LDAP query scope for a subtree Set this to the value planned for in Table 1: Environment- Specific LDAP Properties on page 10 Set this to the value planned for in Table 1: Environment- Specific LDAP Properties on page 10 CN=Users,DC=EXAMPLE, DC=COM organizationalperson user_id_attribute In this document users are of type organizationalperson Set this to the name of the attribute that uniquely identifies a user in the person object class cn 16
Property Description Value user_name_attribute user_mail_attribute user_enabled_attribute user_enabled_mask Set this to the name of the attribute that identifies the name of a user in the user object class Set this to the name of the attribute that identifies the email address of a user in the user object class Set this to the name of the attribute in the user object class that identifies whether or not a user is disabled Set this to 2 to indicate the bit that the value stored in the LDAP server represents enabled as a bit on an integer rather than a boolean cn mail useraccountcontrol 2 A value of 0 indicates the mask is not used. user_enabled_default Set this to the value 512 512 user_attribute_ignore Set this to a commadelimited list of attributes in the user object class to be ignored during update operations password,tenant_id, tenants 17
Property Description Value tenant_tree_dn tenant_objectclass tenant_id_attribute tenant_member_ attribute tenant_desc_attribute tenant_enabled_ attribute Set this to the value planned for in Table 1: Environment- Specific LDAP Properties on page 10 Set this to the object class that represents projects Set this to the name of the attribute that uniquely identifies a project in the project object class Set this to the name of the attribute that identifies the name of a project in the project object class Set this to the name of the attribute that describes a project in the project object class Set this to the name of the attribute that specifies if a project is enabled or not in the project object class OU=Projects, OU=OpenStack, DC=EXAMPLE,DC=COM groupofnames cn displayname description extensionname 18
Property Description Value tenant_attribute_ignore role_tree_dn role_objectclass role_id_attribute role_name_attribute role_member_attribute modify_users Set this to a commadelimited list of attributes in the project object class to be ignored during update operations Set this to the value planned for in Table 1: Environment- Specific LDAP Properties on page 10 Set this to the name of the object class that represents roles Set this to the name of the attribute that uniquely identifies a role in the role object class Set this to the name of the attribute that identifies the name of the attribute that will be displayed in Dashboard Set this to the name of the attribute that identifies the membership of the users that occupy the role Set this to the value true OU=Roles,OU=OpenStack, DC=EXAMPLE,DC=COM organizationalrole cn displayname roleoccupant True 19
Property Description Value modify_tenants modify_roles Set this to the value true Set this to the value true True True 3. Save and close the file. Installing Piston OpenStack Make sure that all of the nodes and switches in your environment are powered off, then insert the CloudKey into your Arista switch or your boot node and power them on. The CloudBoot process begins and should take between 10 and 20 minutes, depending on the number of nodes in your cloud. 20
Creating Objects in Active Directory Have the Active Directory administrator use the Active Directory Users and Computers interface to create users for your Piston OpenStack, and use ADSI Edit to create projects and roles. If you are performing an installation of Piston OpenStack and are not familiar with the Active Directory tools, perform the instructions in the following sections: Creating Users in Active Directory on page 21 Creating Piston OpenStack Objects in ADSI Edit on page 22 Note that this document should not be used as an authoritative resource on creating objects in Active Directory; see the Microsoft Active Directory documentation. Creating Users in Active Directory Use the Active Directory Users and Computers interface to create users for your Piston OpenStack. Do the following: 1. Select the user container in the console tree that equates to the value you specified for the user_ tree_dn configuration parameter, such as the default Users container. 2. Do the following to create a user as a project member: A. Select Action > New > User from the menu bar. B. Type a value in the Full name field. C. Type a value in the User logon name field. D. Click Next. E. Type a value in the Password field. F. Type the same value in the Confirm password field. G. Click the User must change password at next logon checkbox to disable it. H. Click Next. I. Click Finish. 21
3. Select the users container again, then repeat the actions performed in step 2 to create a user that will have administrative privileges. Creating Piston OpenStack Objects in ADSI Edit Next use the ADSI Editor to create the necessary objects. Appendix A: Example LDAP Objects on page 33 contains a sample LDIF of these objects, though the structure will be different in your environment. You will create an organizationalunit object to contain all your OpenStack objects, as well as organizationalunit objects for your OpenStack projects and roles. You will also create organizationalrole objects to represent the roles of administrator and basic project member, specifying values for their cn and displayname attributes, and setting their roleoccupant attribute to the distinguishedname of the appropriate user in your Active Directory Users container. And you will create groupofnames objects for projects and roles in their respective organizationalunit objects. Do the following: 1. In ADSI Editor, select ADSI Edit. 2. Select Action > Connect to from the menu bar. 3. Make sure the Select a well known Naming Context radio button is enabled, then select Default naming context from the drop-down menu. 4. Click OK. 5. Expand Default naming context. 6. Expand the folder for the domaindns object. 7. Do the following to create an organizationalunit object to contain the organizational units for projects and roles: A. Select the folder for the domaindns object B. Select Action > New > Object from the menu bar. C. Select organizationalunit in the Select a class list, then click Next. D. At the ou attribute dialog, type a name for the organizational unit in the Value field, then click Next. E. Click Finish. 22
F. Confirm that the object appears as in Figure 2: OU=OpenStack Properties on page 23. Figure 2: OU=OpenStack Properties 8. Do the following to create an organizationalunit object named Roles that belongs to the OpenStack organizational unit: A. Select the OpenStack object created in step 7. B. Repeat the instructions in step 7 to create another organizationalunit object; specify Roles for the value of the ou attribute. C. Confirm that the object appears as in Figure 6: OU=Projects Properties on page 27. 23
Figure 3: OU=Roles Properties 9. Do the following to create an organizationalrole object named Role_admin that belongs to the Roles organizational unit: A. Select the Roles organizational unit created in step 8. B. Select Action > New > Object from the menu bar. C. Select organizationalrole in the Select a class list, then click Next. D. At the cn attribute dialog, type Role_admin in the Value field, then click Next. E. Click Finish. F. Select the Role_admin organizational role, then select Action > Properties from the menu bar. G. Select the displayname attribute, then click Edit. H. Type admin in the Value field, click Add, then click OK. 24
I. In Active Directory Users and Computers, select the user account that has administrative privileges. J. Select Action > Properties from the menu bar. K. Select the Attribute Editor tab. L. Select the distinguishedname attribute, then click View. M. Copy the value in the Value field. N. Click OK, then click OK again. O. In ADSI Edit, select the roleoccupant attribute, then click Edit. P. Paste the copied distinguished name in the Value to add field, then click Add. Q. Click OK, then click OK again. R. Confirm that the object appears as in Figure 4: CN=Role_admin Properties on page 25. Figure 4: CN=Role_admin Properties 25
10. Repeat the actions performed in step 9 on page 24 to create a basic project member, with the following distinctions: -- At the cn attribute dialog, specify Role_member in the Value field -- Set the displayname attribute to the value _member_ -- Set the roleoccupant attribute to the distinguished name of the non-administrative user 11. Confirm that the object appears as in Figure 5: CN=Role_member Properties on page 26. Figure 5: CN=Role_member Properties 12. Do the following to create an organizationalunit object named Projects that belongs to the OpenStack organizational unit: A. Select the OpenStack object created in step 7. B. Repeat the instructions in step 7 to create another organizationalunit object; specify Projects for the value of the ou attribute. 26
C. Confirm that the object appears as in Figure 6: OU=Projects Properties on page 27. Figure 6: OU=Projects Properties 13. Do the following to create a groupofnames object named Project_admin that belongs to the Projects organizational unit: A. Select the Projects organizational unit you created in step 10. B. Select Action > New > Object from the menu bar. C. Select groupofnames in the Select a class list, then click Next. D. At the cn attribute dialog, type Project_admin in the Value field, then click Next. E. At the member attribute dialog, type the distinguished name of the administrative user in the Value field. F. Click Next. G. Click Finish. 27
H. Confirm that the object appears as in Figure 7: CN=Project_admin Properties on page 28. Figure 7: CN=Project_admin Properties 14. Do the following to create an organizationalrole object named Role_admin belonging to the Project_admin group of names object: A. Select the Project_admin group of names object created in step 13. B. Select Action > New > Object from the menu bar. C. Select organizationalrole in the Select a class list, then click Next. D. At the cn attribute dialog, type Role_admin in the Value field, then click Next. E. Click Finish. 28
F. Select the Role_admin organizational role, then select Action > Properties from the menu bar. G. Select the displayname attribute, then click Edit. H. Type admin in the Value to add field, then click Add. I. Select the roleoccupant attribute, then click Edit. J. Type the distinguished name of the administrative user in the Value to add field, then click Add. K. Confirm that the object appears as in Figure 8: CN=Role_admin Properties on page 29. Figure 8: CN=Role_admin Properties L. Click OK, then click OK again. 15. Repeat the actions performed in step 13 on page 27 to create a groupofnames object for non-administrative members, with the following distinctions: 29
-- At the cn attribute dialog, specify Project_x in the Value field -- Set the displayname attribute to a value such as x -- At the member attribute dialog, type the distinguished name of the non-administrative user in the Value field 16. Confirm that the object appears as in Figure 9: CN=Project_x Properties on page 30. Figure 9: CN=Project_x Properties 17. Repeat the actions performed in step 14 on page 28 to create an organizationalrole object for non-administrative members: -- At the cn attribute dialog, specify Role_member in the Value field -- Set the displayname attribute to _member_ -- Set the roleoccupant attribute to the distinguished name of the non-administrative user 18. Confirm that the object appears as in Figure 10: CN=Role_member Properties on page 31. 30
Figure 10: CN=Role_member Properties 31
Validating the Integration Do the following to validate that Piston OpenStack is successfully integrated with Active Directory: 1. In a web browser, navigate to the address of the Piston OpenStack dashboard. 2. Type the name of an Active Directory user in your Piston OpenStack organizational unit in the User Name field. 3. Type the password for the username in the Password field. 4. Click Sign In. Figure 11: Login Screen Dashboard displays the Overview tab. 32
Appendix A: Example LDAP Objects // LDAP User used for logging into/reading Active Directory via LDAP dn: CN=dumbmemberuser,CN=Users,DC=EXAMPLE,DC=COM objectclass: organizationalperson cn: dumbmemberuser name: dumbmemberuser mail: dumbmemberuser@example.com // Example Piston Admin user that will be used to log in to Dashboard dn: CN=pistonadmin,CN=Users,DC=EXAMPLE,DC=COM objectclass: organizationalperson cn: pistonadmin name: pistonadmin mail: pistonadmin@example.com // organizationalunit, organizationalrole, groupofnames structure dn: OU=OpenStack,DC=EXAMPLE,DC=COM objectclass: organizationalunit ou: OpenStack name: OpenStack dn: OU=Roles,OU=OpenStack,DC=EXAMPLE,DC=COM objectclass: organizationalunit ou: Roles name: Roles dn: CN=Role_admin,OU=Roles,OU=OpenStack,DC=EXAMPLE,DC=COM objectclass: organizationalrole cn: Role_admin roleoccupant: CN=pistonadmin,CN=Users,DC=EXAMPLE,DC=COM name: Role_admin displayname: admin 33
dn: CN=Role_member,OU=Roles,OU=OpenStack,DC=EXAMPLE,DC=COM objectclass: organizationalrole cn: Role_member roleoccupant: CN=user_X,CN=Users,DC=EXAMPLE,DC=COM name: member displayname: _member_ dn: OU=Projects,OU=OpenStack,DC=EXAMPLE,DC=COM objectclass: organizationalunit ou: Projects name: Projects dn: CN=Project_admin,OU=Projects,OU=OpenStack,DC=EXAMPLE,DC=COM objectclass: groupofnames cn: Project_admin member: CN=pistonadmin,CN=Users,DC=EXAMPLE,DC=COM name: Project_admin displayname: admin dn: CN=Role_admin,CN=Project_admin,OU=Projects,OU=OpenStack,DC=EXAMPLE,DC=COM objectclass: organizationalrole cn: Role_admin roleoccupant: CN=pistonadmin,CN=Users,DC=EXAMPLE,DC=COM name: Role_admin displayname: admin dn: CN=Project_x,OU=Projects,OU=OpenStack,DC=EXAMPLE,DC=COM objectclass: groupofnames cn: Project_x member: CN=user_X,CN=Users,DC=EXAMPLE,DC=COM name: Project_x displayname: x 34
dn: CN=Role_member,CN=Project_member,OU=Projects,OU=OpenStack,DC=EXAMPLE,DC=COM objectclass: organizationalrole cn: Role_member roleoccupant: CN=user_X,CN=Users,DC=EXAMPLE,DC=COM name: Role_member displayname: _member_ 35
Appendix B: Example LDAP Configuration [auth] type=ldap [ldap_auth] # Permit ldap server to have self signed cert allow_self_signed_certs = True # Url of ldap server url = ldap://nameoripaddressofldapserver # ldap server credentials bind_dn = CN=username,CN=Users,DC=EXAMPLE,DC=COM bind_password = password suffix = DC=EXAMPLE,DC=COM use_dumb_member = True dumb_member = CN=dumbmemberusername,CN=Users,DC=EXAMPLE,DC=COM user_tree_dn = CN=Users,DC=EXAMPLE,DC=COM user_objectclass = organizationalperson user_id_attribute = cn user_name_attribute = cn user_mail_attribute = mail user_enabled_attribute = useraccountcontrol user_enabled_mask = 2 user_enabled_default = 512 user_attribute_ignore = password,tenant_id,tenants tenant_tree_dn = ou=projects,ou=openstack,dc=example,dc=com tenant_objectclass = groupofnames tenant_id_attribute = cn tenant_member_attribute = member tenant_name_attribute = displayname tenant_desc_attribute = description tenant_enabled_attribute = extensionname 36
tenant_attribute_ignore = role_tree_dn = ou=roles,ou=openstack,dc=example,dc=com role_objectclass = organizationalrole role_id_attribute = cn role_name_attribute = displayname role_member_attribute = roleoccupant modify_users = True modify_tenants = True modify_roles = True 37