Keystone is an OpenStack service that provides API client authentication, service discovery, and distributed multi-tenant authorization by implementing OpenStack’s Identity API. Keystone is organized as a group of internal services exposed on one or many endpoints. Many of these services are used in a combined fashion by the frontend. For example, an authenticate call will validate user/project credentials with the Identity service and, upon success, create and return a token with the Token service.
Authentication is the process of confirming the identity of a user. To confirm an incoming request, OpenStack Identity validates a set of credentials users supply. Initially, these credentials are a user name and password, or a user name and API key. When OpenStack Identity validates user credentials, it issues an authentication token. Users provide the token in subsequent requests.
Credentials are the data that confirms the identity of the user. For example, user name and password, user name and API key, or an authentication token that the Identity service provides.
- Identity service
The Identity service provides auth credential validation and data about users and groups. In the basic case, this data is managed by the Identity service, allowing it to also handle all CRUD operations associated with this data. In more complex cases, the data is instead managed by an authoritative backend service. An example of this would be when the Identity service acts as a frontend for LDAP. In that case the LDAP server is the source of truth and the role of the Identity service is to relay that information accurately.
Users => A digital representation of a person, system, or service that uses OpenStack cloud services. The Identity service validates that incoming requests are made by the user who claims to be making the call. Users have a login and can access resources by using assigned tokens. Users can be directly assigned to a particular project and behave as if they are contained in that project.
Groups => Groups are a collection of users owned by a domain. A group role, granted to a domain or project, applies to all users in the group. Adding or removing users to or from a group grants or revokes their role and authentication to the associated domain or project.
- Resource service
The Resource service provides data about projects and domains.
Projects => represent the base unit of ownership
in OpenStack, in that all resources in OpenStack should be owned by a specific project. Project is a container that groups or isolates resources or identity objects. Depending on the service operator, a project might map to a customer, account, organization, or tenant.
Domains => are a high-level container for projects, users and groups. Each is owned by exactly one domain. Each domain defines a namespace where an API-visible name attribute exists. Keystone provides a default domain, aptly named ‘Default’. Domains are a collection of projects and users that define administrative boundaries for managing Identity entities. Domains can represent an individual, company, or operator-owned space. They expose administrative activities directly to system users. Users can be granted the administrator role for a domain. A domain administrator can create projects, users, and groups in a domain and assign roles to users and groups in a domain.
- Assignment service
The Assignment service provides data about roles and role assignments.
Roles => dictate the level of authorization the end user can obtain. Roles can be granted at either the domain or project level. A role can be assigned at the individual user or group level.
Role assignments => A 3-tuple that has a Role
, a Resource
and an Identity
.
Role is a personality with a defined set of user rights and privileges to perform a specific set of operations. The Identity service issues a token to a user that includes a list of roles. When a user calls a service, that service interprets the user role set, and determines to which operations or resources each role grants access.
A user can have different roles in different projects. For example, Alice might also have the admin
role in the Cyberdyne
project. A user can also have multiple roles in the same project.
In the Identity v3 API, the uniqueness of attributes is as follows:
- Domain Name. Globally unique across all domains.
- Role Name. Unique within the owning domain.
- User Name. Unique within the owning domain.
- Project Name. Unique within the owning domain.
- Group Name. Unique within the owning domain.
Due to their container architecture, domains may be used as a way to delegate management of OpenStack resources. A user in a domain may still access resources in another domain, if an appropriate assignment is granted.
- Token service
The Token service validates and manages tokens used for authenticating requests once a user’s credentials have already been verified.
Token is an alpha-numeric text string that enables access to OpenStack APIs and resources. A token may be revoked at any time and is valid for a finite duration. While OpenStack Identity supports token-based authentication in this release, it intends to support additional protocols in the future. OpenStack Identity is an integration service that does not aspire to be a full-fledged identity store and management solution.
In order for a user to call any OpenStack API they need to (a) prove who they are, and (b) that they should be allowed to call the API in question. The way they achieve that is by passing an OpenStack token into the API call—and Keystone is the OpenStack service responsible for generating these tokens. A user receives this token upon successful authentication against Keystone. The token also carries with it authorization. It contains the authorization a user has on the cloud. A token has both an ID and a payload. The ID of a token is guaranteed to be unique per cloud, and the payload contains data about the user.
The payload can be seen below:
- Catalog service
The service catalog is essential for an OpenStack cloud. It contains the URLs and endpoints of the different Cloud services. Without the catalog, users and applications would not know where to route requests to create VMs or store objects. The service catalog is broken up into a list of endpoints, and each endpoint is broken down into an admin URL, internal URL, and public URL, which may be the same.
Endpoint is a network-accessible address, usually a URL, through which you can access a service. If you are using an extension for templates, you can create an endpoint template that represents the templates of all consumable services that are available across the regions.
Approach to Authorization (Policy)
Various components in the system require that different actions are allowed based on whether the user is authorized to perform that action.
For the purposes of keystone there are only a couple levels of authorization being checked for:
- Require that the performing user is considered an admin.
- Require that the performing user matches the user being referenced.
Other systems wishing to use the policy engine will require additional styles of checks and will possibly write completely custom backends. By default, keystone leverages policy enforcement that is maintained in oslo.policy (An OpenStack library providing support for RBAC policy enforcement across all OpenStack services).
The /etc/[SERVICE_CODENAME]/policy.json
file controls the tasks that users can perform for a given service. For example, the /etc/nova/policy.json
file specifies the access policy for the Compute service, the /etc/glance/policy.json
file specifies the access policy for the Image service, and the /etc/keystone/policy.json
file specifies the access policy for the Identity service.
The default policy.json
files in the Compute, Identity, and Image services recognize only the admin
role. Any user with any role in a project can access all operations that do not require the admin
role.
To restrict users from performing operations in, for example, the Compute service, you must create a role in the Identity service and then modify the /etc/nova/policy.json
file so that this role is required for Compute operations.
For example, the following line in the /etc/cinder/policy.json
file does not restrict which users can create volumes:
If the user has any role in a project, he can create volumes in that project.
To restrict the creation of volumes to users who have the compute-user
role in a particular project, you add "role:compute-user"
:
Here is another example:
Rules
Given a list of matches to check for, simply verify that the credentials contain the matches. For example:
Credentials are generally built from the user metadata in the ‘extras’ part of the Identity API. So, adding a ‘role’ to the user just means adding the role to the user metadata.
Capability RBAC
Another approach to authorization can be action-based, with a mapping of roles to which capabilities are allowed for that role. For example:
In the backend this would look up the policy for ‘action:nova:add_network’ and then do what is effectively a ‘Simple Match’ style match against the credentials.
Approach to Authentication
Keystone provides several authentication plugins that inherit from keystone.auth.plugins.base
. The following is a list of available plugins.
keystone.auth.plugins.external.Base
keystone.auth.plugins.mapped.Mapped
keystone.auth.plugins.oauth1.OAuth
keystone.auth.plugins.password.Password
keystone.auth.plugins.token.Token
keystone.auth.plugins.totp.TOTP
In the most basic plugin password
, two pieces of information are required to authenticate with keystone, a bit of Resource
information and a bit of Identity
.
Take the following call POST data for instance:
Authenticating with a Password via CLI
To authenticate with keystone using a password and python-openstackclient
, set the following flags, note that the following user referenced below should be granted the admin
role.
--os-username OS_USERNAME
: Name of your user--os-password OS_PASSWORD
: Password for your user--os-project-name OS_PROJECT_NAME
: Name of your project--os-auth-url OS_AUTH_URL
: URL of the keystone authentication server
You can also set these variables in your environment so that they do not need to be passed as arguments each time: