Understanding Keystone Endpoints

(OpenStacks Identity Service)

OpenStack Identity (Keystone) provides a central directory of users mapped to the OpenStack services they can access. It acts as a common authentication system across the cloud operating system and can integrate with existing backend directory services like LDAP. It supports multiple forms of authentication including standard username and password credentials, token-based systems and AWS-style (i.e. Amazon Web Services) logins. Additionally, the catalog provides a queryable list of all of the services deployed in an OpenStack cloud in a single registry. Users and third-party tools can programmatically determine which resources they can access.   http://en.wikipedia.org/wiki/OpenStack#Identity_Service_.28Keystone.29

In OpenStack before we can start utilizing the the vast ecosystem of services and applications that are available ie: (Nova, Swift, Neutron, Glance, etc), we first have to authorize our users.  There are some very important terms that we need to understand when working with OpenStack Identity (keystone).

I would like to take a moment to address one of the biggest confusions when setting up endpoints in keystone today.  First let’s start out by defining what an endpoint even is.  An endpoint in keystone is just a URL that can be used to access a service within OpenStack.  An endpoint is just like a point of contact for YOU (the user) to use an OpenStack service.  The adminurl (we will show these further down) is for the admin users, the internalurl are what the other services use to talk to each other.  And the publicurl is what everyone else accessing the service endpoint uses.

Lets understand the following terms:

A service is any OpenStack service such as Nova, Swift, and even keystone itself.
A role is the level of authorization that a user has.
Tokens are an alphanumeric string that allows us access to services depending on it’s access level or the (see above role).
Users are just people that are going to be accessing the service.  This can also traditionally be used as a (service account) that the service itself uses.
And finally tenants are really just a group of users.

(part 1)
1)  First we need to actually create two tenants that we are going to simply name admin (this will be the Administrators tenant remember tenants are just groups of users) and the other tenant will be called service (this is the Service Group ie: tenant for our services.. in our example here we use the nova service).

$ keystone tenant-create --name=admin --description="Admin Tenant"
$ keystone tenant-create --name=service --description="Service Tenant"

2)  Now we need to create the administrative user called admin using the password linuxacademy123

# keystone user-create --name=admin --pass=linuxacademy123 
   --email=admin@linuxacedmy123

3)  We now need to create a new role for our administrative task in OpenStack called admin.  This default policy for the admin policy allows access to most services.

# keystone role-create --name=admin

4)  We have to add roles to users.  Users always log in with a tenant, and roles are assigned to users WITHIN these tenants.  Here we are going to add the admin role to the admin user when logging in with the admin tenant.

# keystone user-role-add --user=admin --tenant=admin --role=admin

(part 2)
In the following example we are going to create a Nova user and then link it to our tenant called service, then we link it to our admin role.  We are then going to create the actual compute (nova) service.  Finally we are then going to create our endpoint using the returned ID value of our newly created nova service.

5)  Create a user called nova.  We are going to define our password as linuxacademy123.

$ keystone user-create --name nova --pass linuxacademy123
+----------+----------------------------------+
| Property |              Value               |
+----------+----------------------------------+
|  email   |                                  |
| enabled  |               True               |
|    id    | f1a06c73141a441da5df57c46c3b69c5 |
|   name   |               nova               |
| username |               nova               |
+----------+----------------------------------+

6) Now we are going to link this new user nova to the service tenant that we created in part1 as well as the role that we also named admin.

$ keystone user-role-add --user nova --tenant service --role admin

7) It is now time to create our actual service that will be called nova in which its type of service is the NOVA compute service.

$ keystone service-create --name nova --type compute 
  --description "OpenStack Compute"
+-------------+----------------------------------+
|   Property  |              Value               |
+-------------+----------------------------------+
| description |        OpenStack Compute         |
|   enabled   |               True               |
|      id     | 5844875f25c54e52a0d5c7f6076bff86 |
|     name    |               nova               |
|     type    |             compute              |
+-------------+----------------------------------+

8)  We have now reached the actual portion of our setup in which we create the actual endpoint for the nova compute service.

But first I think it’s very important to mention a common mistake I see when users are following along on OpenStacks documentation when creating these endpoints.  Most of the documentation uses the following for example:

$ keystone endpoint-create 
  --service-id $(keystone service-list | awk '/ compute / {print $2}') 
  --publicurl http://controller:8774/v2/%(tenant_id)s 
  --internalurl http://controller:8774/v2/%(tenant_id)s 
  --adminurl http://controller:8774/v2/%(tenant_id)s 
  --region regionOne
+-------------+-----------------------------------------+
|   Property  |                  Value                  |
+-------------+-----------------------------------------+
|   adminurl  | http://controller:8774/v2/%(tenant_id)s |
|      id     |    c397438bd82c41198ec1a9d85cb7cc74     |
| internalurl | http://controller:8774/v2/%(tenant_id)s |
|  publicurl  | http://controller:8774/v2/%(tenant_id)s |
|    region   |                regionOne                |
|  service_id |    6c7854f52ce84db795557ebc0373f6b9     |
+-------------+-----------------------------------------+

Let’s go over this line by line.  In the first line we are using the endpoint-create command to start creating the endpoint.  In line two we are using the –service-id to return the service id of the nova service that we are creating this actual URL authentication endpoint with.  However, almost all of the newer versions of OpenStack Documentation is using the following search string in which we see as well on line two:
$(keystone service-list | awk ‘/ compute / {print $2}’)

In a nutshell the above string is opening up a background sub-shell within the $().  Within the () we run the actual search string with a shell scripting language known as awk.  So first it’s calling the keystone command keystone service-list which list all of the available services in rows and columns that has the name, the actual service id, description etc.  We then pipe that out | using a search string of / compute / because we want to work with that line to pull what the service id is FOR nova compute.  {print $2} is pulling from that line the second column (2) which happens to be the id of the service compute service.  The first line would be the | character.  For example if we did the following command:
keystone service-list

Then we would see:
+———————————-+————+—————-+——————————+
|                id                |    name    |      type      |         description          |
+———————————-+————+—————-+——————————+
| 9b1737a7632241cd8b38ba6f141bbffe | ceilometer |    metering    |          Telemetry           |
| 5844875f25c54e52a0d5c7f6076bff86 |    nova    |    compute     |      OpenStack Compute       |

Notice the first return on the nova compute line is | the second return which again is the service id using {print $2} is the service ID itself:   5844875f25c54e52a0d5c7f6076bff86

While this is a great way to quickly breeze through when setting up all the services in order and following a setup guide this sometimes causes issues if for example you setup services in a different order.  Therefore I recommend that when setting up your endpoints with keystone endpoint-create that you manually use the service id rather that search for it by doing the following:

$ keystone endpoint-create 
  --service-id=5844875f25c54e52a0d5c7f6076bff86 
  --publicurl=http://controller:8774/v2/%(tenant_id)s 
  --internalurl=http://controller:8774/v2/%(tenant_id)s 
  --adminurl=http://controller:8774/v2/%(tenant_id)s 
  --region=regionOne

Lastly I want to mention the –region flag which specifies your region name.  The other thing that trips up endpoints not working is when you fail to use this flag it will sometimes create a region name for you that doesn’t exit or the case of that region name might look different as well.  For example regionOne, RegionOne, and regionone are all different regions because the case of the name matters.

I hope this post helps some of you that come across this issue that I see quite often.  New to OpenStack?  Check out LinuxAcademy.com OpenStack courses at https://linuxacademy.com/openstack and check back often for more courses in the future!

Stephen Smith

Stephen Smith is a Systems Infrastructure Security Engineer with over 16 years of architecting experience. He has been with Linux Academy since the beginning and teaches courses on Linux, AWS, Azure, and OpenStack. Stephen's passion is OpenStack and holds many certifications and is very active within the OpenStack Foundation's community.

2 thoughts on “Understanding Keystone Endpoints

  1. Hi Stephen,

    This is a GREAT tutorial and I learned a bunch of stuff I hadn’t known before. It’s clear, thorough, and well written. Thank you for writing this up. I have a few suggestions:

    1. Putting a date on the article will situate the information provided in the OpenStack release cycles and therefore reduce confusion as various concepts (e.g., ‘tenant’ in favor of ‘project’) and APIs are deprecated.
    2. I suggest including information on what authz one needs to have in order to execute the administrative commands. Among other things, this will answer the question of bootstrapping.
    3. To reduce confusion, I suggest using 5844875f25c54e52a0d5c7f6076bff86 rather than 6c7854f52ce84db795557ebc0373f6b9 as the returned service_id in the `endpoint-create` example.
    4. I suggest describing policy.json in order to answer questions I suspect most readers will have about, for instance, what privileges a user gets when she is granted the admin role over a tenant.
    5. Related, I suggest describing what utility the ‘admin’ tenant itself affords. It would help to answer the question of why one would create an ‘admin’ tenant when one can assign someone the admin role over a tenant.

    These are just suggestions i thought of when reading and thinking about what you wrote. Thanks again for this really helpful post.

    Margaret

Leave a Reply

Your email address will not be published. Required fields are marked *