In this chapter, we will cover:
Installing the OpenStack Identity Service
Configuring OpenStack Identity for SSL communication
Creating tenants in Keystone
Configuring roles in Keystone
Adding users to Keystone
Defining service endpoints
Creating the service tenant and service users
Configuring OpenStack Identity for LDAP Integration
The OpenStack Identity service, known as Keystone, provides services for authenticating and managing user accounts and role information for our OpenStack cloud environment. It is a crucial service that underpins the authentication and verification between all of our OpenStack cloud services and is the first service that needs to be installed within an OpenStack environment. The OpenStack Identity service authenticates users and tenants by sending a validated authorization token between all OpenStack services. This token is used for authentication and verification so that you can use that service, such as OpenStack Storage and Compute. Therefore, configuration of the OpenStack Identity service must be completed first, consisting of creating appropriate roles for users and services, tenants, the user accounts, and the service API endpoints that make up our cloud infrastructure.
In Keystone, we have the concepts of tenants, roles and users. A tenant is like a project and has resources such as users, images, and instances, as well as networks in it that are only known to that particular project. A user can belong to one or more tenants and is able to switch between these projects to gain access to those resources. Users within a tenant can have various roles assigned. In the most basic scenario, a user can be assigned either the role of admin or just be a member. When a user has admin privileges within a tenant, they are able to utilize features that can affect the tenant (such as modifying external networks), whereas a normal user is assigned the member role, which is generally assigned to perform user-related roles, such as spinning up instances, creating volumes, and creating tenant only networks.
We will be performing an installation and configuration of the OpenStack Identity service, known as Keystone, using the Ubuntu Cloud Archive. Once configured, connecting to our OpenStack cloud environment will be performed through our new OpenStack Identity service.
The backend datastore for our OpenStack Identity service will be a MariaDB database. The environment we will be installing is shown in the following figure. In this chapter, we will be concentrating on the Controller host.

To ensure that we're running the Ubuntu Cloud Archive, we must first configure our Ubuntu 14.04 installation to use this service. For more information, visit http://bit.ly/OpenStackCookbookCloudArchive.
Tip
All of the steps can be found at http://www.openstackcookbook.com/.
We will configure Keystone to use MariaDB as the database backend, so this needs to be installed prior to installing Keystone.
Tip
If MariaDB is not installed, visit http://bit.ly/OpenStackCookbookPreReqs for instructions on how to do this.
Ensure that you have a suitable server available for installation of the OpenStack Identity service components. If you are using the accompanying Vagrant environment, as described in the Preface, this will be the controller
node.
Make sure that you are logged in to the controller
node and ensure that it has Internet access to allow us to install the required packages in our environment for running Keystone. If you created this node with Vagrant, you can execute the following command:
vagrant ssh controller
The instructions here assume that the controller
node has two IP addresses. It will have a front-facing IP address, 192.168.100.200, and a backside IP address, 172.16.0.200, (which is also the address of the MariaDB server). The reason it has two addresses is that internal data will communicate over the backside IP address (for example, database traffic), and any Keystone traffic will traverse the front.
Carry out the following instructions to install the OpenStack Identity service:
Installation of the OpenStack Identity service is done by specifying the Keystone package in Ubuntu, and we do this as follows:
sudo apt-get update sudo apt-get install ntp keystone python-keyring
Once installed, we need to configure the backend database store, so we first create the
keystone
database in MariaDB. We do this as follows (here, we have a user in MariaDB calledroot
with the passwordopenstack
, which can create databases):MYSQL_ROOT_PASS=openstack mysql -uroot -p$MYSQL_ROOT_PASS -e "CREATE DATABASE \ keystone;"
It is good practice to create a user that is specific to our OpenStack Identity service, so we create a Keystone user in the database as follows:
MYSQL_KEYSTONE_PASS=openstack mysql -uroot -p$MYSQL_ROOT_PASS -e "GRANT ALL PRIVILEGES ON \keystone.* TO 'keystone'@'localhost' IDENTIFIED BY \'$MYSQL_KEYSTONE_PASS';" mysql -uroot -p$MYSQL_ROOT_PASS -e "GRANT ALL PRIVILEGES ON \keystone.* TO 'keystone'@'%' IDENTIFIED BY \'$MYSQL_KEYSTONE_PASS';"
We then need to configure the OpenStack Identity service by editing the
/etc/keystone/keystone.conf
file to have the following content:[DEFAULT] admin_token = ADMIN log_dir=/var/log/keystone [database] connection = mysql://keystone:openstack@172.16.0.200/keystone [extra_headers] Distribution = Ubuntu use_syslog = True syslog_log_facility = LOG_LOCAL0
We can now restart the
keystone
service to pick up these changes:sudo stop keystone sudo start keystone
With
keystone
started, we can now populate thekeystone
database with the required tables by issuing the following command:sudo keystone-manage db_sync
Congratulations! We have now installed the OpenStack Identity service and it is ready for use in our OpenStack environment.
A convenient way to install the OpenStack Identity service in our OpenStack environment is by using the Ubuntu packages. Once installed, we configure our MariaDB database server with a keystone
database and set up the keystone.conf
configuration file with the corresponding values. After starting the Keystone service, running the keystone-manage db_sync
command populates the keystone
database with the appropriate tables ready for us to add in the required users, roles, and tenants required in our OpenStack environment.
One of the many updates to this book will be a more hardened all-around approach. To that end, we begin by enabling SSL communication for services with Keystone by default. It is important to note that we will be doing this via self-signed certificates to illustrate how to configure the services. It is strongly recommended that you acquire the appropriate certificates from a Certificate Authority (CA) for deployment in production.
Ensure that you are logged in to the controller
node and that it has Internet access to allow us to install the required packages in our environment for running Keystone. If you created this node with Vagrant, you can execute the following command:
vagrant ssh controller
Carry out the following instructions to configure the Keystone service:
Before we can configure Keystone to use SSL, we need to generate the required OpenSSL Certificates. To do so, log in to the server that is running Keystone and issue the following commands:
sudo apt-get install python-keystoneclient keystone-manage ssl_setup --keystone-user keystone \--keystone-group keystone
Once our certificates are generated, we can use them when communicating with our Keystone service. We can refer to the generated CA file for our other services by placing this in an accessible place. To do so, issue the following commands:
sudo cp /etc/keystone/ssl/certs/ca.pem /etc/ssl/certs/ca.pem sudo c_rehash /etc/ssl/certs/ca.pem
We also take the same CA and CA Key file to use on our client, so copy these where you will be running the relevant
python-*client
tools. In our Vagrant environment, we can copy this to our host as follows:sudo cp /etc/keystone/ssl/certs/ca.pem /vagrant/ca.pem sudo cp /etc/keystone/ssl/certs/cakey.pem /vagrant/cakey.pem
We then need to edit the Keystone configuration file
/etc/keystone/keystone.conf
to include the following section:[ssl] enable = True certfile = /etc/keystone/ssl/certs/keystone.pem keyfile = /etc/keystone/ssl/private/keystonekey.pem ca_certs = /etc/keystone/ssl/certs/ca.pem cert_subject=/C=US/ST=Unset/L=Unset/O=Unset/CN=192.168.100.200 ca_key = /etc/keystone/ssl/certs/cakey.pem
Finally, restart the Keystone service:
sudo stop keystone sudo start keystone
The OpenStack services normally intercommunicate via standard HTTP requests. This provides a large degree of flexibility, but it comes at the cost of all communication happening in plain text. By adding SSL certificates and changing Keystone's configuration, all communication with Keystone will now be encrypted via HTTPS.
A tenant in OpenStack is a project, and the two terms are generally used interchangeably. Users can't be created without having a tenant assigned to them, so these must be created first. For this section, we will create a tenant called cookbook for our users.
We will be using the keystone
client to operate Keystone. If the python-keystoneclient
tool isn't available, follow the steps described at http://bit.ly/OpenStackCookbookClientInstall.
Ensure that we have our environment set correctly to access our OpenStack environment for administrative purposes:
export OS_TENANT_NAME=cookbook export OS_USERNAME=admin export OS_PASSWORD=openstack export OS_AUTH_URL=https://192.168.100.200:5000/v2.0/ export OS_NO_CACHE=1 export OS_KEY=/vagrant/cakey.pem export OS_CACERT=/vagrant/ca.pem
Tip
You can use the controller
node if no other machines are available on your network, as this has the python-keystoneclient
and the relevant access to the OpenStack environment. If you are using the Vagrant environment issue the following command to get access to the Controller:
vagrant ssh controller
To create a tenant in our OpenStack environment, perform the following steps:
We start by creating a tenant called cookbook:
keystone tenant-create \ --name cookbook \ --description "Default Cookbook Tenant" \ --enabled true
This will produce output similar to:
+-------------+----------------------------------+ | Property | Value | +-------------+----------------------------------+ | description | Default Cookbook Tenant | | enabled | True | | id | fba7b31689714d1ab39a751bc9483efd | | name | cookbook | +-------------+----------------------------------+
We also need an
admin
tenant so that when we create users in this tenant, they have access to our complete environment. We do this in the same way as in the previous step:keystone tenant-create \ --name admin \ --description "Admin Tenant" \ --enabled true
Creation of the tenants is achieved by using the keystone
client, specifying the tenant-create
option with the following syntax:
keystone tenant-create \ --name tenant_name \ --description "A description" \ --enabled true
The tenant_name
is an arbitrary string and must not contain spaces. On creation of the tenant, this returns an ID associated with it that we use when adding users to this tenant. To see a list of tenants and the associated IDs in our environment, we can issue the following command:
keystone tenant-list
Roles are the permissions given to users within a tenant. Here, we will configure two roles: an admin
role that allows for the administration of our environment, and a member role
that is given to ordinary users who will be using the cloud environment.
We will be using the keystone
client to operate Keystone. If the python-keystoneclient
tool isn't available, follow the steps described at http://bit.ly/OpenStackCookbookClientInstall.
Ensure that we have our environment set correctly to access our OpenStack environment for administrative purposes:
export OS_TENANT_NAME=cookbook export OS_USERNAME=admin export OS_PASSWORD=openstack export OS_AUTH_URL=https://192.168.100.200:5000/v2.0/ export OS_NO_CACHE=1 export OS_KEY=/vagrant/cakey.pem export OS_CACERT=/vagrant/ca.pem
Tip
You can use the controller
node if no other machines are available on your network, as this has the python-keystoneclient
and the relevant access to the OpenStack environment. If you are using the Vagrant environment, issue the following command to get access to the Controller:
vagrant ssh controller
To create the required roles in our OpenStack environment, perform the following steps:
Create the
admin
role as follows:# admin role keystone role-create --name admin You will get an output like this: +----------+----------------------------------+ | Property | Value | +----------+----------------------------------+ | id | 625b81ae9f024366bbe023a62ab8a18d | | name | admin | +----------+----------------------------------+
To create the
Member role
, we repeat the step and specify theMember role
:# Member role keystone role-create --name Member
Creation of the roles is simply achieved by using the keystone
client and specifying the role-create
option with the following syntax:
keystone role-create --name role_name
The role_name
attribute can't be arbitrary for admin
and Member roles
. The admin
role has been set by default in /etc/keystone/policy.json
as having administrative rights:
{ "admin_required": [["role:admin"], ["is_admin:1"]] }
The Member role
is also configured by default in the OpenStack Dashboard, Horizon, for a non-admin user created through the web interface.
On creation of the role, the ID associated with is returned, and we can use it when assigning roles to users. To see a list of roles and the associated IDs in our environment, we can issue the following command:
keystone role-list
Adding users to the OpenStack Identity service requires that the user has a tenant that they can exist in and there is a defined role that can be assigned to them. For this section, we will create two users. The first user will be named admin
and will have the admin
role assigned to them in the cookbook
tenant. The second user will be named demo
and will have the Member
role assigned to them in the same cookbook
tenant.
We will be using the keystone client
to operate Keystone. If the python-keystoneclient
tool isn't available, follow the steps described at http://bit.ly/OpenStackCookbookClientInstall.
Ensure that we have our environment set correctly to access our OpenStack environment for administrative purposes:
export OS_TENANT_NAME=cookbook export OS_USERNAME=admin export OS_PASSWORD=openstack export OS_AUTH_URL=https://192.168.100.200:5000/v2.0/ export OS_NO_CACHE=1 export OS_KEY=/vagrant/cakey.pem export OS_CACERT=/vagrant/ca.pem
Tip
You can use the controller
node if no other machines are available on your network, as this has the python-keystoneclient
and the relevant access to the OpenStack environment. If you are using the Vagrant environment, issue the following command to get access to the Controller:
vagrant ssh controller
To create the required users in our OpenStack environment, perform the following steps:
To create a user in the
cookbook
tenant, we first need to get thecookbook
tenant ID. To do this, issue the following command, which we conveniently store in a variable namedTENANT_ID
with thetenant-list
option:TENANT_ID=$(keystone tenant-list \ | awk '/\ cookbook\ / {print $2}')
Now that we have the tenant ID, the
admin
user in thecookbook
tenant is created using theuser-create
option and a password is chosen for the user:PASSWORD=openstack keystone user-create \ --name admin \ --tenant_id $TENANT_ID \ --pass $PASSWORD \ --email root@localhost \ --enabled true
The preceding code will produce the following output:
+----------+----------------------------------+ | Property | Value | +----------+----------------------------------+ | email | root@localhost | | enabled | True | | id | 2e23d0673e8a4deabe7c0fb70dfcb9f2 | | name | admin | | tenantId | 14e34722ac7b4fe298886371ec17cf40 | | username | admin | +----------+----------------------------------+
As we are creating the
admin
user, which we are assigning the admin role, we need the admin role ID. We pick out the ID of theadmin
role and conveniently store it in a variable to use it when assigning the role to the user with therole-list
option:ROLE_ID=$(keystone role-list \ | awk '/\ admin\ / {print $2}')
To assign the role to our user, we need to use the user ID that was returned when we created that user. To get this, we can list the users and pick out the ID for that particular user with the following user-list option:
USER_ID=$(keystone user-list \ | awk '/\ admin\ / {print $2}')
With the tenant ID, user ID, and an appropriate role ID available, we can assign that role to the user with the following user-role-add option:
keystone user-role-add \ --user $USER_ID \ --role $ROLE_ID \ --tenant_id $TENANT_ID
The
admin
user also needs to be in theadmin
tenant for us to be able to administer the complete environment. To do this, we need to get theadmin
tenant ID and then repeat the previous step using this new tenant ID:ADMIN_TENANT_ID=$(keystone tenant-list \ | awk '/\ admin\ / {print $2}') keystone user-role-add \ --user $USER_ID \ --role $ROLE_ID \ --tenant_id $ADMIN_TENANT_ID
To create the
demo
user in thecookbook
tenant with theMember role
assigned, we repeat the process defined in steps 1 to 5:# Get the cookbook tenant ID TENANT_ID=$(keystone tenant-list \ | awk '/\ cookbook\ / {print $2}') # Create the user PASSWORD=openstack keystone user-create \ --name demo \ --tenant_id $TENANT_ID \ --pass $PASSWORD \ --email demo@localhost \ --enabled true # Get the Member role ID ROLE_ID=$(keystone role-list \ | awk '/\ Member\ / {print $2}') # Get the demo user ID USER_ID=$(keystone user-list \ | awk '/\ demo\ / {print $2}') # Assign the Member role to the demo user in cookbook keystone user-role-add \ --user $USER_ID \ -–role $ROLE_ID \ --tenant_id $TENANT_ID
Adding users in the OpenStack Identity service involves a number of steps and dependencies. First, a tenant is required for the user to be part of. Once the tenant exists, the user can be added. At this point, the user has no role associated, so the final step is to designate the role to this user, such as Member
or admin
.
Use the following syntax to create a user with the user-create
option:
keystone user-create \ --name user_name \ --tenant_id TENANT_ID \ --pass PASSWORD \ --email email_address \ --enabled true
The user_name
attribute is an arbitrary name but cannot contain any spaces. A password
attribute must be present. In the previous examples, these were set to openstack
. The email_address
attribute must also be present.
To assign a role to a user with the user-role-add
option, use the following syntax:
keystone user-role-add \ --user USER_ID \ --role ROLE_ID \ --tenant_id TENANT_ID
This means that we need to have the ID of the user, the ID of the role, and the ID of the tenant in order to assign roles to users. These IDs can be found using the following commands:
keystone tenant-list keystone user-list keystone role-list
Each of the services in our cloud environment runs on a particular URL and port—these are the endpoint addresses for our services. When a client communicates with our OpenStack environment that runs the OpenStack Identity service, it is this service that returns the endpoint URLs that the user can use in an OpenStack environment. To enable this feature, we must define these endpoints. In a cloud environment, we can define multiple regions. Regions can be thought of as different datacenters, which would imply that they would have different URLs or IP addresses. Under the OpenStack Identity service, we can define these URL endpoints separately for each region. As we only have a single environment, we will reference this as RegionOne
.
We will be using the keystone
command line client to operate Keystone. If the python-keystoneclient
tool isn't available, follow the steps described at http://bit.ly/OpenStackCookbookClientInstall.
Ensure that we have our environment set correctly to access our OpenStack environment for administrative purposes:
export OS_TENANT_NAME=cookbook export OS_USERNAME=admin export OS_PASSWORD=openstack export OS_AUTH_URL=https://192.168.100.200:5000/v2.0/ export OS_NO_CACHE=1 export OS_KEY=/vagrant/cakey.pem export OS_CACERT=/vagrant/ca.pem
Tip
You can use the controller
node if no other machines are available on your network, as this has the python-keystoneclient
and has the relevant access to the OpenStack environment. If you are using the Vagrant environment, issue the following command to get access to the Controller:
vagrant ssh controller
Defining the services and their endpoints in the OpenStack Identity service involves running the keystone
client command. Although we might not have all services currently running in our environment, we will be configuring them within the OpenStack Identity service for future use. To define endpoints for services in our OpenStack environment, carry out the following steps:
We can now define the actual services that the OpenStack Identity service needs to know about in our environment:
# OpenStack Compute Nova API Endpoint keystone service-create \ --name nova \ --type compute \ --description 'OpenStack Compute Service' # OpenStack Compute EC2 API Endpoint keystone service-create \ --name ec2 \ --type ec2 \ --description 'EC2 Service' # Glance Image Service Endpoint keystone service-create \ --name glance \ --type image \ --description 'OpenStack Image Service' # Keystone Identity Service Endpoint keystone service-create \ --name keystone \ --type identity \ --description 'OpenStack Identity Service' # Neutron Networking Service Endpoint keystone service-create \ --name network \ --type network \ --description 'OpenStack Network Service' #Cinder Block Storage Endpoint keystone service-create \ --name volume \ --type volume \ --description 'Volume Service'
After we have done this, we can add in the service endpoint URLs that these services run on. To do this, we need the ID that was returned for each of the service endpoints created in the previous step. The ID is then used as a parameter when specifying the endpoint URLS for that service.
Tip
The OpenStack Identity service can be configured to service requests on three URLs: a public facing URL (that the end users use), an administration URL (that users with administrative access can use that might have a different URL), and an internal URL (that is appropriate when presenting the services on either side of a firewall to the public URL).
For the following services, we will configure separate public, admin, and internal service URLs to provide appropriate separation for our environment. The public endpoint in the accompanying lab environment will be the nominated public interface IP of our controller, which is 192.168.100.200. The internal endpoint will be 172.16.0.200. The
admin
endpoint will also be the public IP of 192.168.100.200. To do this run the following commands:# OpenStack Compute Nova API NOVA_SERVICE_ID=$(keystone service-list \ | awk '/\ nova\ / {print $2}') PUBLIC_ENDPOINT=192.168.100.200 ADMIN_ENDPOINT=192.168.100.200 INT_ENDPOINT=172.16.0.200 PUBLIC="http://$PUBLIC_ENDPOINT:8774/v2/\$(tenant_id)s" ADMIN="http://$ADMIN_ENDPOINT:8774/v2/\$(tenant_id)s" INTERNAL="http://$INT_ENDPOINT:8774/v2/\$(tenant_id)s" keystone endpoint-create \ --region RegionOne \ --service_id $NOVA_SERVICE_ID \ --publicurl $PUBLIC \ --adminurl $ADMIN \ --internalurl $INTERNAL
You will get output similar to what is shown below:
+-------------+------------------------------------------------+ | Property | Value | +-------------+------------------------------------------------+ | adminurl | http://192.168.100.200:8774/v2/$(tenant_id)s | | id | 87b59c5ce8314d8b9029bf1efd5044d7 | | internalurl | http://172.16.0.100:8774/v2/$(tenant_id)s | | publicurl | http://192.168.100.200:8774/v2/$(tenant_id)s | | region | RegionOne | | service_id | a3529dcbeab44d479d1f258ae6d202b4 | +-------------+------------------------------------------------+
We continue to define the rest of our service endpoints, as shown in the following steps:
# OpenStack Compute EC2 API EC2_SERVICE_ID=$(keystone service-list \ | awk '/\ ec2\ / {print $2}') PUBLIC="http://$PUBLIC_ENDPOINT:8773/services/Cloud" ADMIN="http://$ADMIN_ENDPOINT:8773/services/Admin" INTERNAL="http://$INT_ENDPOINT:8773/services/Cloud" keystone endpoint-create \ --region RegionOne \ --service_id $EC2_SERVICE_ID \ --publicurl $PUBLIC \ --adminurl $ADMIN \ --internalurl $INTERNAL # Glance Image Service GLANCE_SERVICE_ID=$(keystone service-list \ | awk '/\ glance\ / {print $2}') PUBLIC="http://$PUBLIC_ENDPOINT:9292/v1" ADMIN="http://$ADMIN_ENDPOINT:9292/v1" INTERNAL="http://$INT_ENDPOINT:9292/v1" keystone endpoint-create \ --region RegionOne \ --service_id $GLANCE_SERVICE_ID \ --publicurl $PUBLIC \ --adminurl $ADMIN \ --internalurl $INTERNAL # Keystone OpenStack Identity Service # Note we're using SSL HTTPS here KEYSTONE_SERVICE_ID=$(keystone service-list \ | awk '/\ keystone\ / {print $2}') PUBLIC="https://$PUBLIC_ENDPOINT:5000/v2.0" ADMIN="https://$ADMIN_ENDPOINT:35357/v2.0" INTERNAL="https://$INT_ENDPOINT:5000/v2.0" keystone endpoint-create \ --region RegionOne \ --service_id $KEYSTONE_SERVICE_ID \ --publicurl $PUBLIC \ --adminurl $ADMIN \ --internalurl $INTERNAL # Neutron Networking Service NEUTRON_SERVICE_ID=$(keystone service-list \ | awk '/\ network\ / {print $2}') PUBLIC="http://$PUBLIC_ENDPOINT:9696" ADMIN="http://$ADMIN_ENDPOINT:9696" INTERNAL="http://$INT_ENDPOINT:9696" keystone endpoint-create \ --region RegionOne \ --service_id $NEUTRON_SERVICE_ID \ --publicurl $PUBLIC \ --adminurl $ADMIN \ --internalurl $INTERNAL #Cinder Block Storage Service CINDER_SERVICE_ID=$(keystone service-list \ | awk '/\ volume\ / {print $2}') PUBLIC="http://$PUBLIC_ENDPOINT:8776/v1/%(tenant_id)s" ADMIN=$PUBLIC INTERNAL=$PUBLIC keystone endpoint-create \ --region RegionOne \ --service_id $CINDER_SERVICE_ID \ --publicurl $PUBLIC \ --adminurl $ADMIN \ --internalurl $INTERNAL
Configuring the services and endpoints within the OpenStack Identity service is done with the keystone
client command.
We first add the service definitions using the keystone
client and the service-create
option with the following syntax:
keystone service-create \ --name service_name \ --type service_type \ --description 'description'
In the service_name
is an arbitrary name or label defining our service of a particular type. We refer to the name when defining the endpoint to fetch the ID of the service.
The type
option can be one of the following: compute
, object-store
, image-service
, network
, and identity-service
. Note that we haven't configured the OpenStack Object Storage service (type object-store
) at this stage, as this is covered in later recipes in the book.
The description
field is again an arbitrary field describing the service.
Once we have added in our service definitions, we can tell OpenStack Identity service from where these services run by defining the endpoints using the keystone
client and the endpoint-create
option. The syntax is as follows:
keystone endpoint-create \ --region region_name \ --service_id service_id \ --publicurl public_url \ -–adminurl admin_url \ --internalurl internal_url
Here, service_id
is the ID of the service when we created the service definitions in the first step. The list of our services and IDs can be obtained by running the following command:
keystone service-list
As OpenStack is designed for global deployments, a region defines a physical datacenter or a geographical area that comprises of multiple connected datacenters. For our purpose, we define just a single region—RegionOne. This is an arbitrary name that we can reference when specifying what runs in what datacenter/area and we carry the region name through to when we configure our client for use with these regions.
All of our services can be configured to run on three different URLs, as follows, depending on how we want to configure our OpenStack cloud environment:
public_url
: This parameter is the URL that end users would connect on. In a public cloud environment, this would be a public URL that resolves to a public IP address.admin_url
: This parameter is a restricted address for conducting administration. In a public deployment, you would keep this separate from thepublic_url
by presenting the service you are configuring on a different, restricted URL. Some services have a different URI for the admin service, so this is configured using this attribute.internal_url
: This parameter would be the IP or URL that existed only within the private local area network. The reason for this is that you can connect to services from your cloud environment internally without connecting over a public IP address space, which could incur data charges for traversing the Internet. It is also potentially more secure and less complex to do so.
Now that the service endpoints are created, we can configure them so that our other OpenStack services can utilize them. To do this, each service is configured with a username and password within a special service
tenant. Configuring each service to have its own username and password allows for greater security, troubleshooting, and auditing within our environment. When setting up a service to use the OpenStack Identity service for authentication and authorization, we specify these details in their relevant configuration file. Each service itself has to authenticate with keystone
in order for it to be available within OpenStack. Configuration of that service is then done using these credentials. For example, for glance
, we specify the following lines in /etc/glance/glance-registry.conf
, when used with OpenStack Identity service, which matches what we created previously:
[keystone_authtoken] identity_uri = https://192.168.100.200:35357 admin_tenant_name = service admin_user = glance admin_password = glance insecure = True
Tip
The use of insecure = True
here is only required as self-signed certificates are used throughout this book. In production, we would use issued certificates and omit this option in our configs.
We will be using the keystone
client to operate Keystone. If the python-keystoneclient
tool isn't available, follow the steps described at http://bit.ly/OpenStackCookbookClientInstall.
Ensure that we have our environment set correctly to access our OpenStack environment for administrative purposes:
export OS_TENANT_NAME=cookbook export OS_USERNAME=admin export OS_PASSWORD=openstack export OS_AUTH_URL=https://192.168.100.200:5000/v2.0/ export OS_NO_CACHE=1 export OS_KEY=/vagrant/cakey.pem export OS_CACERT=/vagrant/ca.pem
Tip
You can use the controller
node if no other machines are available on your network, as this has the python-keystoneclient
and the relevant access to the OpenStack environment. If you are using the Vagrant environment, issue the following command to get access to the Controller:
vagrant ssh controller
To configure an appropriate service
tenant, carry out the following steps:
Create the
service
tenant as follows:keystone tenant-create \ --name service \ --description "Service Tenant" \ --enabled true
This produces output similar to what is shown as follows:
+-------------+----------------------------------+ | Property | Value | +-------------+----------------------------------+ | description | Service Tenant | | enabled | True | | id | 8e77d9c13e884bf4809077722003bba0 | | name | service | +-------------+----------------------------------+
Record the ID of the service tenant so that we can assign service users to this ID:
SERVICE_TENANT_ID=$(keystone tenant-list \ | awk '/\ service\ / {print $2}')
For each of the services in this section, we will create the user accounts to be named the same as the services and set the password to be the same as the service name too. For example, we will add a user called
nova
with a passwordnova
in theservice
tenant by using the user-create option:keystone user-create \ --name nova \ --pass nova \ --tenant_id $SERVICE_TENANT_ID \ --email nova@localhost \ --enabled true
The preceding code will produce an output similar to what is shown here:
+----------+----------------------------------+ | Property | Value | +----------+----------------------------------+ | email | nova@localhost | | enabled | True | | id | 50ea356a4b6f4cb7a9fa22c1fb08549b | | name | nova | | tenantId | 42e5c284de244e3190e12cc44fbbbe62 | | username | nova | +----------+----------------------------------+
We then repeat this for each of our other services that will use OpenStack Identity service:
keystone user-create \ --name glance \ --pass glance \ --tenant_id $SERVICE_TENANT_ID \ --email glance@localhost \ --enabled true keystone user-create \ --name keystone \ --pass keystone \ --tenant_id $SERVICE_TENANT_ID \ --email keystone@localhost \ --enabled true keystone user-create \ --name neutron \ --pass neutron \ --tenant_id $SERVICE_TENANT_ID \ --email neutron@localhost \ --enabled true keystone user-create \ --name cinder \ --pass cinder \ --tenant_id $SERVICE_TENANT_ID \ --email cinder@localhost \ --enabled true
We can now assign these users the
admin
role in theservice
tenant. To do this, we use theuser-role-add
option after retrieving the user ID of thenova
user. For example, to add the admin role to thenova
user in theservice
tenant, we use the following code:# Get the nova user id NOVA_USER_ID=$(keystone user-list \ | awk '/\ nova\ / {print $2}') # Get the admin role id ADMIN_ROLE_ID=$(keystone role-list \ | awk '/\ admin\ / {print $2}') # Assign the nova user the admin role in service tenant keystone user-role-add \ --user $NOVA_USER_ID \ --role $ADMIN_ROLE_ID \ --tenant_id $SERVICE_TENANT_ID
We then repeat this for our other service users,
glance
,keystone
,neutron
, andcinder
:# Get the glance user id GLANCE_USER_ID=$(keystone user-list \ | awk '/\ glance\ / {print $2}') # Assign the glance user the admin role in service tenant keystone user-role-add \ --user $GLANCE_USER_ID \ --role $ADMIN_ROLE_ID \ --tenant_id $SERVICE_TENANT_ID # Get the keystone user id KEYSTONE_USER_ID=$(keystone user-list \ | awk '/\ keystone\ / {print $2}') # Assign the keystone user the admin role in service tenant keystone user-role-add \ --user $KEYSTONE_USER_ID \ --role $ADMIN_ROLE_ID \ --tenant_id $SERVICE_TENANT_ID # Get the cinder user id NEUTRON_USER_ID=$(keystone user-list \ | awk '/\ neutron \ / {print $2}') # Assign the neutron user the admin role in service tenant keystone user-role-add \ --user $NEUTRON_USER_ID \ --role $ADMIN_ROLE_ID \ --tenant_id $SERVICE_TENANT_ID # Get the cinder user id CINDER_USER_ID=$(keystone user-list \ | awk '/\ cinder \ / {print $2}') # Assign the cinder user the admin role in service tenant keystone user-role-add \ --user $CINDER_USER_ID \ --role $ADMIN_ROLE_ID \ --tenant_id $SERVICE_TENANT_ID
Creation of the service
tenant, which is populated with the services required to run OpenStack, is no different from creating any other users on our system that require the admin
role. We create the usernames and passwords and ensure that they exist in the service
tenant with the admin
role assigned to each user. We then use these credentials when configuring the services to authenticate with the OpenStack Identity service.
Tip
Downloading the example code
You can download the example code files for this book at https://github.com/OpenStackCookbook/OpenStackCookbook. All the support files are available here.
The OpenStack Identity service that we have built so far provides you with a functional, but isolated, set up for your OpenStack environment. This is a useful setup for Proof of Concept and lab environments. However, it is likely that you will need to integrate OpenStack with your existing authentication system. OpenStack Identity provides a pluggable authentication back end for this, with LDAP being the most widely used.
We will be using the keystone
client to operate Keystone. If the python-keystoneclient
tool isn't available, follow the steps described at http://bit.ly/OpenStackCookbookClientInstall.
Ensure that we have our environment set correctly to access our OpenStack environment for administrative purposes:
export OS_TENANT_NAME=cookbook export OS_USERNAME=admin export OS_PASSWORD=openstack export OS_AUTH_URL=https://192.168.100.200:5000/v2.0/ export OS_NO_CACHE=1 export OS_KEY=/vagrant/cakey.pem export OS_CACERT=/vagrant/ca.pem
Tip
You can use the controller
node if no other machines are available on your network, as this has the python-keystoneclient
and the relevant access to the OpenStack environment. If you are using the Vagrant environment, issue the following command to get access to the Controller:
vagrant ssh controller
Additionally, to connect to an external LDAP service, you will need to possess the hostname or IP address of the LDAP server and have appropriate access to the server. You will also need to have the LDAP path information for an admin
user, and for the Organizational Units that contain the Users, Roles, and Tenants.
Note
We have provided a sample OpenLDAP server that is prepopulated with the required values as part of this book's supplementary materials, and instructions on how to use it located on our book blog at http://bit.ly/OpenStackCookbookLDAP
To configure OpenStack Identity to communicate with LDAP, perform the following steps:
Using your favorite editor, enable LDAP authentication in the
keystone.conf
file:[identity] driver=keystone.identity.backends.ldap.Identity
Next, create the
ldap
section and add the URL to your existing LDAP server:[ldap] url = ldap://openldap
On the following lines, specify the LDAP path for the
admin
user you will use, along with its password and the suffix, or where you would like Keystone to begin searching LDAP:user = cn=admin,dc=cook,dc=book password = openstack suffix = cn=cook,cn=book
In the same
[ldap]
section, we tell Keystone four pieces of information about how to find users.user_tree_dn
specifies which OU within the LDAP tree to search for users.user_objectclass
specifies how a user is represented within LDAP. user_id_attribute
tells Keystone which property of the user to use as a username. Similarly,user_mail_attribute
tells Keystone where to find the user's e-mail address. The code is as follows:user_tree_dn = ou=Users,dc=cook,dc=book user_objectclass = inetOrgPerson user_id_attribute = cn user_mail_attribute = mail
Next, add the same details for Tenants and Roles:
tenant_tree_dn = ou=Projects,dc=cook,dc=book tenant_objectclass = groupOfNames tenant_id_attribute = cn tenant_desc_attribute = description role_tree_dn = ou=Roles,dc=cook,dc=book role_objectclass = organizationalRole role_id_attribute = cn role_member_attribute = roleOccupant
Save the file and restart
keystone
:sudo stop keystone sudo start keystone
The OpenStack Identity service, like other OpenStack services, is based on plugins. In its default state, Keystone will store and access all user identity and authentication data from a SQL database. However, when integrating OpenStack into an existing environment, this is not always the most desirable or secure method. To accommodate this, we changed the identity back end to LDAP. This allows for integration with OpenLDAP, Active Directory, and many others. However, when configuring the backend, you need to pay special attention to the LDAP paths.