The OpenStack Keystone service catalog

The OpenStack Keystone service catalog allows API clients to dynamically discover and navigate to cloud services. The service catalog may differ from deployment-to-deployment, user-to-user, and tenant-to-tenant.

The service catalog is the first hurdle that API consumers will need to grok after successfully authenticating with Keystone, making it a critical focal point for the overall user experience of OpenStack.

If you're integrating your OpenStack service with Keystone, then please follow the guidelines provided below.

If you're writing an OpenStack client, I hope this helps you navigate the service catalog that you're being presented so that you can quickly move on to the business of consuming cloud services.

An example service catalog

This is a service catalog that I fabricated. It actually excludes several common attributes such as ids, which are of no concern to end users, region_ids, which are a bit out of scope for this topic, and enabled, which is literally always true for end users.

This service catalog contains just one service, "Keystone", which is accessible via a single endpoint URL:

"catalog": [
    {
        "name": "Keystone",
        "type": "identity",
        "endpoints": [
            {
                "interface": "public",
                "url": "https://identity.example.com:35357/"
            }
        ]
    }
]

The service catalog itself may appear in a token creation response (POST /v3/auth/tokens), a token validation response (GET /v3/auth/tokens), or as a standalone resource (GET /v3/auth/catalog).

Services

The service catalog itself is composed of a list of services (the catalog might as well be called services).

Service entities represent web services in the OpenStack deployment. A service may have zero or more endpoints associated with it, although a service with zero endpoints is essentially useless in an OpenStack configuration. — Identity API v3 spec

In addition to the related endpoints, there are two attributes of services that important to end users:

  • name (string)

    User-facing name of the service. — Identity API v3 spec

    This attribute is not intended to be machine-parseable or otherwise meaningful beyond branding or name-recognition for end users. Logical values might include "Keystone" or maybe "HP Helion Public Cloud Identity Service". Deployers should be free to rename, and therefore rebrand, a service at will.

  • type (string)

    Describes the API implemented by the service. The following values are recognized within the OpenStack ecosystem: compute, image, ec2, identity, volume, network. To support non-core and future projects, the value should not be validated against this list. — Identity API v3 spec

    This should not convey the version of the API implemented by the service (as in Cinder's volumev2 service type) because both the volume service and volumev2 service provide "block storage as a service" which is what the service type is meant to convey. The underlying implementation is completely irrelevant here.

    In the general case, there should only be one service in a deployment per service type, although Keystone does not enforce this today. In the past, I've heard far-fetched use cases wherein deployers wanted to deploy multiple services of the same type, perhaps with different SLAs and thus distinct branding (service names), but I'm not aware of anyone actually doing this, nor any reason why you couldn't address such a use case using distinct regions instead.

Endpoints

Each service should have one or more related endpoints. An endpoint is essentially a base URL for an API, along with some metadata about the endpoint itself.

Endpoint entities represent URL endpoints for OpenStack web services. — Identity API v3 spec

  • interface (string)

    Describes the visibility of the endpoint according to one of the following values:

    • public: intended for consumption by end users, generally on a publicly available network interface
    • internal: intended for consumption by end users, generally on an unmetered internal network interface
    • admin: intended only for consumption by those needing administrative access to the service, generally on a secure network interface

    Identity API v3 spec

    Most services should not provide anything other than a public URL.

    You might also think of each interface value as the result of a matrix of use cases:

    • Public API on a public network: use a public interface.
    • Public API on an internal network: use an internal interface.
    • Privileged API on a public network: unsupported! Use access controls on your public endpoint instead.
    • Privileged API on an internal network: admin interface... but use access controls on your public endpoint instead.

    The notion of a "privileged API" endpoint makes security-conscious developers instantly lazy (security becomes someone else's problem), and is an obvious attack vector if someone were to infiltrate your internal network. It also adds more complexity to your API architecture which makes documentation, testing, and API evolution that much more difficult.

  • url (string)

    Fully qualified URL of the service endpoint. — Identity API v3 spec

    This should be unversioned base URL for an API. Good examples include https://identity.example.com:35357/ and https://keystone.example.com/.

    Conversely, https://identity.example.com:35357/v2.0/ is an unfortunate example because it directs all clients to connect to a versioned endpoint, regardless of which API versions they understand. This makes it hard for services to do any sort of API versioning, and for clients to dynamically discover additional available versions. Keystone, for example, is stuck in a position where it implements a /v3/ API, but for backwards compatibility with existing v2 clients, we're forced to continue advertising the /v2.0/ endpoint in the service catalog until we're confident that all clients in the ecosystem are capable of handling an unversioned URL. As a side effect, this has had a tremendous impact on the awareness of, and thus adoption of, Keystone's Identity API v3 (which has been enabled by default — and stable — since the 2013.1 Grizzly release). Don't put your project in that position!

    Similarly, https://object-store.example.com/v1/KEY_\$(tenant_id)s (which would ultimately be rendered to clients as a tenant-specific URL, such as https://object-store.example.com/v1/KEY_d12af07f4e2c4390a21acc31517ebec9) is an unfortunate example because not only does it hardcode an API version as in the above example, but it also exposes the client's tenancy directly to the client — which happens to be completely redundant with the authorization context provided to services by keystonemiddleware.auth_token using the client's authentication token. It's also far less cacheable than a URL that is neither tenant nor user specific, which is important given that every client needs access to consume the service catalog prior to nearly every API request.

This was produced as an action item from a related cross-project session at the OpenStack Liberty design summit in Vancouver, BC.