keystone-specs/specs/keystone/backlog/application-credentials.rst

25 KiB

Application Credentials

bp application-credentials

Implement application-specific credentials as a new credential type in order to improve security by limiting access and not embedding User credentials in configuration files.

Problem Description

Currently, automated API interactions -- such as service-to-service communication, deployment tooling, and cloud-native applications -- must authenticate with keystone as keystone Users in order to be granted access to the resources they need to automate. This model, while convenient for keystone, increases the risk of account compromise by requiring the distribution of unencrypted passwords. It also exacerbates the potential damage an account compromise can have since an application using a User's credentials has, as a result, all the User's permissions. The model hinders mitigation of a compromise because changing the compromised password necessitates downtime for distributed applications using the password. The following use cases demonstrate the situation faced by operators and end users today and the need for an alternate model for authentication of applications.

Note

To avoid confusion, in this document User will be used to refer to the Keystone User Resource, Consumer will be used to refer to a Human who is consuming resources from an OpenStack Cloud, Deployer to a Human who manages an OpenStack Deployment and Application as non-Human consumer of OpenStack APIs. While the word "application" may carry connotations, it should be understood here to mean any amount of code or automation expected to interact with the OpenStack APIs in the absence of direct human interaction.

Use Cases

  • As an OpenStack Consumer, I want to create Applications that programmatically request a token and make API calls for resources in my project.

To accomplish this, one will typically store User credentials in a configuration file, such as clouds.yaml so that scripts can access the OpenStack API without Human interaction. Having User credentials that are potentially used for other systems, such as with federated identity, in configuration files and/or embedding them into a virtual machine, creates a potential security risk.

  • As an OpenStack Consumer, I want to limit the actions that an Application can make to a pre-defined subset of what my User otherwise has access to do.

By using a User's credentials, the Application will have all of that User's access. This is likely more access than needed. For instance, a regular Consumer cannot set up an application that can only upload images to Glance but cannot create or delete servers in Nova.

  • As an OpenStack Consumer and an OpenStack Deployer, I need to be able to gracefully rotate application credentials.

The current system of Users and Passwords requires simultaneously changing the Password and updating any Application configuration. For a Deployer this means updating all of the config files for all of the OpenStack services at the same time. During the period between the Password being changed and config being updated, the Application will not be able to talk to the OpenStack API and will be down. The Application Credential should allow for the creation of a new credential, rolling the new credential out, then deleting the old credential for credential rotation with no downtime.

  • As a team of OpenStack Consumers, I want to be able to make Applications that will not stop working when one of my Team Members leaves.

As the use of Automation increases in the world, more and more teams have problems with automation that was tied to a specific Consumer's User credentials. The application credentials should be managed as Project level resources so that all Consumers who have Users with write-allowed roles on the Project can rotate or delete them as they see fit if membership in their Team changes.

  • As an OpenStack Deployer, I need to configure some OpenStack Services to be able to make API calls to other OpenStack Services.

Information about Service Users are currently stored in configuration files. For example, the nova Service User is currently in the configuration of every nova-api, nova-compute and neutron configuration file. At run time, those services use those User Credentials to perform service-to-service actions.

From a security perspective, it can be considered unfavorable to have User credentials written to a file on disk, especially if the User has elevated privileges on a Project. It should be possible to apply the principle of least privilege (POLP) and limit access to the minimum level required to complete the task. For a Consumer this means being able to choose to not use the full User credentials for automation. For a Deployer this means being able to easily make service-specific authorizations to go into the config files.

Proposed Change

Implement a new restricted credential type (Application Credentials) to be used by Applications. Application Credentials will be assigned the same roles the Creating User has at creation time.

Note

This idea was originally going to be called "API Keys" because the idea is similar to other industry usage around generating a secret for applications to use with an API. This plan was discontinued because the term, while not well-defined in the industry, carries specific connotations about its usage and implementation that this specification does not match. The name 'Application Credentials' is chosen instead to be a generic term describing vaguely what this is intended to be, which is identification information intended for use only by applications.

Application Credentials will have the following characteristics:

  • Immutable.
  • Allow for optionally setting limits, e.g. 5 Application Credentials per User or Project, to prevent abuse of the resource.
  • Assigned the curent roles the creating User has on the Project at creation time, or optionally a list of roles that is a subset of the creating User's roles on the Project.
  • Secret exposed only once at creation time in the create API response.
  • Limited ability to manipulate identity objects (see Limitations Imposed)
  • Support expiration.
  • Support deletion by any user with a write-allowed role in the project.
  • Will be deleted when the associated User is deleted.

Application Credentials will be treated as credentials and not authorization tokens, as this fits within the keystone model and is consistent with others APIs providing application authentication. It also avoids the security and performance implications of creating a new token type that would potentially never expire and have custom validation.

Note

In the future, it will be possible for a Consumer to further limit, at creation time, the operations the Application Credential can perform. The intent is that such a further limitation will be expressed at a granularity of REST calls. That functionality is not described or implemented here, but is required to fully meet the Use Case associated with pre-defined subset of User actions.

Note

In the future, it may be possible to create an Application Credential that can persist past the lifecycle of the User. That functionality is not described or implemented here, but is required to fully meet the Use Case associated with automation not ceasing to work when a human leaves a team.

Application Credential Management

By default, any User with at least a member role on a Project should be able to list, add, and delete Application Credentials for that project. For example, adding an Application Credentials:

POST /v3/projects/{project_id}/application_credentials
{
    "application_credential": {
        "name:" "backup",
        "description": "Backup job...",
        "expires_at": "2017-11-06T15:32:17.000000",
        "roles": ["Member"]
    }
}

name must be unique within a given Project, but name is only guaranteed to be unique within its Project. This is consistent with how the other keystone resources operate. name may be useful for Consumers who want human readable config files.

description is a long description for storing information about the purpose of the Application Credential. It is mostly useful in reports or listings of Application Credential.

expires_at is when the Application Credential expires. 'null' means that the Application Credential does not automatically expire. expires_at is in ISO Date Time Format and is assumed to be in UTC if an explicit timezone offset is not included.

roles is an optional list of role names that is a subset of the roles the Creating User has on the Project. Roles that the Creating User does not have on a project are an error.

In the initial implementation, the Application Credential will assume the roles of the Creating User or the given subset and we will not implement fine-grained access controls beyond that.

Response example:

{
    "application_credential": {
        "id": "aa4541d9-0bc0-44f5-b02d-a9d922df7cbd",
        "secret": "a49670c3c18b9e079b9cfaf51634f563dc8ae3070db2...",
        "name:" "backup",
        "description": "Backup job...",
        "expires_at": "2017-11-06T15:32:17.000000",
        "project_id": "1a6f968a-cebe-4265-9b36-f3ca2801296c",
        "user_id": "9ac4bbe2-36c7-49ee-b296-59ce7a4d3edf",
        "roles": ["Member"]
    }
}

The id in the response is the Application Credential identifier and would be returned in get or list API calls. An id is globally unique to the cloud.

secret is a random string and only returned via the create API call. Keystone will only store a hash of the secret and not the secret itself, so a lost secret is unrecoverable. Subsequent queries of an Application Credential will not return the secret field.

Note

Identifying the correct way to generate an acceptable secret needs to be done. Nova generates admin passwords on server creation, which is probably a good place to start. If that approach is taken, use of random.choice should be replaced for Python 3 with secrets.choice.

roles is a list of role names. It is informational and can be used by the Consumer to verify that the Application Credential inherited the roles from the User that the Consumer expected. This is not a policy enforcement, it is simply for human validation.

user_id contains the id of the Creating User. It can be used by other Consumers who have a User with access to the Project in question to manage and audit Application Credentials that were created by other Team members.

If the Consumer prefers to generate their own secret, they can do so and provide it in the create call. Keystone will store a hash of the given secret. Keystone will return the secret once upon creation in the same way it would if it was generated, but will not store the secret itself nor return it after the initial creation.

A Consumer can list the existing Application Credentials for a Project:

GET /v3/projects/{project_id}/application_credentials
{
  "application_credentials": [
    {
        "id": "aa4541d9-0bc0-44f5-b02d-a9d922df7cbd",
        "name:" "backup",
        "description": "Backup job...",
        "expires_at": "2017-11-06T15:32:17.000000",
        "project_id": "1a6f968a-cebe-4265-9b36-f3ca2801296c",
        "user_id": "9ac4bbe2-36c7-49ee-b296-59ce7a4d3edf",
        "roles": ["Member"]
    }
  ]
}

A Consumer can get information about a specific existing Application Credential:

GET /v3/projects/{project_id}/application_credentials/{application_credential_id}
{
  "application_credentials": [
    {
        "id": "aa4541d9-0bc0-44f5-b02d-a9d922df7cbd",
        "name:" "backup",
        "description": "Backup job...",
        "expires_at": "2017-11-06T15:32:17.000000",
        "project_id": "1a6f968a-cebe-4265-9b36-f3ca2801296c",
        "user_id": "9ac4bbe2-36c7-49ee-b296-59ce7a4d3edf",
        "roles": ["Member"]
    }
  ]
}

A Consumer can delete an existing Application Credential to invalidate it:

DELETE /v3/projects/{project_id}/application_credentials/{credential_id}

Note

Application Credentials that expire will be deleted. The alternative would be to allow them to accumulate for forever in the hopes that keeping them around will make investigation as to why an Application is not working harder, but the only real benefit to this is providing a different error message. More thought and feedback on this are needed, but are not essential for the first round of work.

When the Creating User for an Application Credential is deleted, that Application Credential is also deleted.

Note

In the future there may be a way to create a persistent credential, but that mechanism is not defined.

Aside from deletion, Application Credentials are immutable and may not be modified.

Using an Application Credential to Obtain a Token

An Application Credential can be used for authentication to request a scoped token following Keystone's normal authorization flow. For example:

POST /v3/auth/tokens
{
    "auth": {
        "identity": {
            "methods": [
                "application_credential"
            ],
            "application_credential": {
                "id": "aa4541d9-0bc0-44f5-b02d-a9d922df7cbd",
                "secret": "a49670c3c18b9e079b9cfaf51634f563dc8ae3070db2..."
            }
        }
    }
}

Keystone will validate the Application Credential by matching a hash of the key secret associated with the id using passlib similar to how Keystone does Password authentication currently.

This improves security as the Application Credentials can have Consumer-controlled limited lifespan and can be rotated and safely stored in configuration files. For Consumers that do not currently have a User with privileges to create Users, this will provide both security and additional flexibility in how they can manage Applications.

If the Application Credential is referred to by name, it will be necessary to provide either project_id or the combination of project_name and project_domain_name so that Keystone can look up the Application Credential in the appropriate Project.

POST /v3/auth/tokens
{
    "auth": {
        "identity": {
            "methods": [
                "application_credential"
            ],
            "application_credential": {
                "name": "backup",
                "project": {
                    "id": "1a6f968a-cebe-4265-9b36-f3ca2801296c"
                },
                "secret": "a49670c3c18b9e079b9cfaf51634f563dc8ae3070db2..."
            }
        }
    }
}

As an alternative to the current use of Service Users, a Deployer could create a single Service User and an Application Credential for each service. Or even create a Nova user and then give each nova instance it's own Application Credential. Although at this point the Application Credential does not have the ability to further limit API use, the ability to start assigning Application Credentials per-service and performing expiration and rotation may be a desirable step forward that can be further enhanced with the addition of restricting an Application Credential's API Access.

Limitations Imposed

Since API Access Lists are not implemented at this stage, Keystone will explicitly block tokens generated from an Application Credential from doing the following:

  • POST /projects/{}/application_credentials
  • DELETE /projects/{}/application_credentials/{}
  • POST /users
  • PATCH /users/{}
  • DELETE /users/{}
  • POST /projects
  • PATCH /projects/{}
  • DELETE /projects/{}
  • PUT /projects/{}/users/{}/roles/{}
  • PUT /domains/{}/users/{}/roles/{}
  • PUT /projects/{}/groups/{}/roles/{}
  • PUT /domains/{}/groups/{}/roles/{}

Note

It might be simpler and safer for now to just block a token generated from an Application Credential from doing any action in Keystone altogether. This would check for an "application_credential" value in the "methods" key of a token object. This would be a temporary measure until the followup API action exclusion support is implemented.

In the future, when the Consumer can expess additional REST API limitations at Application Credential creation time, the built-in identity blacklist should be migrated to being content in that system. It is entirely reasonable that a Consumer desire to grant the ability to automate Identity operations. However, until the the additional system is in place, it is safer to block the operations altogether.

Design Justifications

Implementing Application Credential management as normal CRUD with default policy that normal Users have access to adds the ability without requiring the Deployer to perform additional setup or manage additional external services.

Implementing Application Credentials consumption as an auth-type plugin means that any Client code that supports pluggable auth in any way should be able to easily consume the new feature. Client code that doesn't yet implement support for pluggable authentication should have a compelling motivation to add it.

Alternatives

Enhance tokens by allowing delegation of subsets of roles to a token. This solves the problem of granting too much access to an application, but it still necessitates tying an application to a User, and token expiry makes it insufficient for use by applications.

Enhance users by adding new credential types and then allowing role assignments to be assigned to credential types instead of users. This doesn't solve the problem of applications needing to continue running after a User has been decommissioned. Additionally, regular Consumers frequently do not have permission to create Users, especially in places that use an identity backend like LDAP or AD.

Just use OAuth. Keystone already supports OAuth-based authentication. However, adding OAuth on top of an existing Auth system is a deployer opt-in task that involves considerable deployer effort. If the goal is to add support for a concept that will always dependably exist, OAuth represents too high of a burden to be reasonable. Moreover, OAuth tokens have the same flaws as regular keystone tokens, namely that they are tied to a User, rather than a project, and that they are required to expire, rather than optionally expiring.

Enhance trusts by detaching them from Users. Trusts still require role assignments on projects to be created by administrators. Adding the ability to allow users to delegate their own roles to trusts would require a much more significant rework of the trusts model.

On naming: GCE uses the term "Service Account" and discusses the concept of "Application Access". Both could be useful alternate terms to Application Credential. Drawbacks are that "Service Account" uses the word "account" which may run afoul of understanding. "Application Access" is a good description of what we wish to provide but "Access" does not well-denote the unique unit of information that can be requested and submitted, where "Credential" does.

Github exposes a similar concept as GitHub App which are special accounts intended to be used for non-human API access, such as bots or other automation. They are similarly intended to be a project-level resource rather than a user-level resource. "App" could be a name for this. However, the Github concept goes hand-in-hand with a catalog of services that people can register to do things on their accounts, which is well out of scope for this proposal. Additionally the term "App" carries connotations that may not be appropriate for people who would use this construct as part of a general automation system. Using that term is likely to cause more confusion than good.

Security Impact

This would have a positive security impact:

  • Instead of having a Service User for each service, all services can use a single Service User and multiple Application Credentials. This decreases the attack vector of gaining access to privileged operations by reducing the number of accounts to attack.
  • User names and passwords are kept out of configuration files. While Application Credentials are still extremely sensitive, if compromised they do not allow attackers to glean service user password conventions from configuration.
  • Application Credentials will grow the ability to have limited access, so a move to them is a step towards limited access credentials.
  • Application Credentials can be gracefully rotated out of use and deleted periodically, allowing Consumers and Deployers a mechanism to prevent compromised Users without requiring swapping credentials in short amounts of time that might cause service interruption or downtime.

There is an inherent risk with adding a new credential type and changing authentication details. One such risk would be the allowing of many credentials for the same User account.

Notifications Impact

None

Other End User Impact

  • Consumers who have Applications that monitor or interact with OpenStack Services should be able to leverage this feature to improve the overall security and manageability of their Applications.
  • Consumers can gracefully rotate Application Credentials for an Application with no downtime by creating a new Application Credential, updating config files to use the new Application Credential, and finally deleting the old Application Credential.
  • Consumers who do not start using Application Credentials should experience no impact.

Performance Impact

This should have the same performance impact as username/password authentication does today, since the same mechanism will be used to compare hashes to obtain an answer.

Other Deployer Impact

Deployers should notice the following maintenance improvements:

  • Deployers only need to enforce security on a single Service User instead of multiple.
  • Password rotation policies for Service Users no longer require immediately redeploying service configuration files. A User password change does not affect the existing Application Credential in the various service configuration files.
  • Deployers can gracefully rotate Application Credentials through a deployment with no downtime.

Developer Impact

None

Implementation

Assignee(s)

Primary assignee:

  • Monty Taylor

Other contributors:

  • Ron De Rose
  • Anthony Washington
  • TBD

Work Items

  1. Develop backend to support Application Credentials
  2. Implement API, business logic, and validation for CRUD operations
  3. Add Credential deletion to User deletion
  4. Add new Application Credential authentication plugin
  5. Block access to Keystone CRUD
  6. Add consumption support to keystoneauth
  7. Documentation
  8. Notify deployment projects about using Application Credentials (Devstack, OpenStack-Ansible, Tripleo, OpenStack Puppet, etc)
  9. Notify non-Python SDKs about using Application Credentials (Fog, gophercloud, JClouds)

Dependencies

None

Documentation Impact

The documentation team, along with the documentation liaison for keystone should update the installation guide to account for Application Credentials and Service Users. The user guides should also be updated to reflect the ability for Users to use Application Credentials for application authentication.

References

None