鉴于很多初学者苦于寻找keystone的最新V3信息,故贴出来,希望可以帮到你。
please see the update draft 2 athttps://docs.google.com/document/d/1_TkawQIa52eSBfS4pv_nx1SJeoBghIlGVZsRJJynKAM/edit
Proposed by: Joe Heck
Broad Discussion
General Theme
Themes for changes:
Querying by Name
PKI Support
Open Questions
API Resources
Users
Credentials
Tenants
Domains
Roles
Endpoint
Tokens
Policy
Actions
Rules
V3 CORE API
versions
tokens
Catalog
Identity
domains
tenants
users
credentials
roles
Policy
policies
Policy (extension? altenate?)
actions
The general theme of this proposal is a broad CRUD based API supporting authentication and authorization needs in OpenStack. Back-end implementations of Keystone may not support all components of the API, hence an API return may be NotImplemented. This is to support Keystone as a programmatic facade to a deployment’s existing authentication and authorization system(s).
different style of pagination that I hope will be more effective for UI work
consolidate CRUD operations currently in contrib into CORE
adding a "url" resource attribute that's the fully qualified resource location for the keystone service
flatten the service catalog structure
added in a domains (collection of tenants)
restructure role API calls to be specific to user->tenant or user->domain
tokens are now very explicit to user+tenant combinations
new API mechanisms to get tenants associated with a user
generalized credentials associated with a user/tenant combo (ec2, pki, ssh keys, etc)
propose an extended policy-implementation-specific API
From an interaction perspective, the REST resource should contain a canonically unique identifier; that means the id in this case. Since not all resource names are not guaranteed unique on their own this is actually a filter query, and needs to be addressed as such. Filter params definitely belong in GET request params. So something like GET /users?name=foo is the most valid. This should also be extensible to multiple params GET /users?name=foo&enabled=1.
After reviewing our current PKI approach, I'm pretty sure everything is backwards compatible with our existing token API, with the *potential* exception of the length of his "tokens" being too long for some tools to handle as valid URL's or header values.
A base64 encoded PKI token lands in the 1-2KB range, in his examples. This encrypted token can be handled as *unencrypted* by both clients and services that do not understand/support PKI (you can still GET /tokens/{token_id} the entire thing as an opaque string, and still pass it in an X-Auth-Token, etc).
Signed tokens can still have an ID, so the concept of ID:value for tokens will work well. The only thing that won't work is putting the signed tokens into the URL, and the avoiding-token-in-urls scheme obviates that.
Should we enable that in the API and resources?
Should we include in V3 core a policy implementation specific API?
POINTS OF DISCUSSION:
should the query parameters for the GET resource be added to the resource directly and allowed to happen, or put into a separate URI path (such as GET /users/search?name=foo) so that the implementation can be extended and manipulated with an extension in the future?
The consistent use of PUT/PATCH for updating portions of a REST resource. Should we allow PUT with it’s global “update/replace” functionality? Should we only allow patch (which can change the whole thing, or just update pieces)?
represent individual users
associated with 0 or more tenants (users are not exclusive to a tenant)
A user associated with no tenants is useless from the perspective of OpenStack and should not ever be authenticated to any resources. It is allowed, however, to create a workflow means of acquiring or loading users from other resources and mapping them to tenants.
Users can associated with one or more tenants, and therefore can also be in one or more domains, the association of the domain being strictly though the tenants that user is associated with.
resource attributes:
id (globaly unique - PRIMARY KEY/resource ID)
name (globaly unique)
url (fully qualified resource URL)
enabled (optional)
password (optional)
description (optional)
email (optional)
tenant_id (optional)
domain_id (optional)
domain_id is implied by tenant_id, as every tenant is in a domain, but is returned here for convenience.
arbitrary credentials associated with a user
a user may have 0 or more credentials associated
The type is a string, with the idea that an initially supported type will be “ec2”, but that more credentials could be supported in the future.
resource attributes:
id (globally unique - PRIMARY KEY/resource ID)
type (string) [ec2|?]
url (fully qualified resource URL)
tenant_id (optional)
data (blob of data)
base unit of "ownership" in OpenStack
may have 0 or more users
always associated with a single domain
A tenant can not be in two domains at once
roles may be granted to a user with a specific tenant
resource attributes:
id (globally unique - PRIMARY KEY/resource ID)
name (globally unique)
domain_id
url (fully qualified resource URL)
enabled (boolean: True or Falseoptional)
a collection of tenants (no tenant may be in two domains at once)
roles may be granted to a user within a domain
resource attributes:
name (globaly unique - PRIMARY KEY/resource ID)
id (globally unique)
url (fully qualified resource URL)
enabled (boolean: True or False)
a user-facing named identifier that is used to map a collection of actions from a user to either a specific tenant or an entire domain.
resource attributes:
id (globally unique - PRIMARY KEY/resource ID)
name (globally unique)
url (fully qualified resource URL)
an API endpoint for an OpenStack service
may have 0 or more policies associated with it
the “extra” resource attribute is intended to allow for additional tags or attributes associated with the endpoint to allow implementations to map regionality or location if it’s appropriate for their environment.
resource attributes:
id (globally unique - PRIMARY KEY/resource ID)
service [compute|image|ec2|identity|volume|network]
name
facing [public|admin|internal]
extra (optional) - json blob
url (fully qualified resource URL)
an authN/Z representation of a user/tenant pair with an expiration
passed between client and service APIs in HTTP request headers
resource attributes:
id (globally unique - PRIMARY KEY/resource ID)
expires
user_id
tenant_id
domain_id
url (fully qualified resource URL)
domain_id is implied by tenant_id, as every tenant is in a domain, but is returned here for convenience.
associated with a single endpoint
resource attributes:
id (globally unique - PRIMARY KEY/resource ID)
endpoint_id
policy (serialized blob)
url (fully qualified resource URL)
Actions and Rules are below are a potential means of extending Policy beyond what we discussed at the OpenStack Folsom design summit to provide an API that maps to the policy mechanism that is currently in use by Nova, Glance, and Keystone. An example policy file is available athttps://github.com/openstack/nova/blob/master/etc/nova/policy.json.
Service-facing representation of a specific action within a service
m2m mapping with Roles (user-facing collections of actions)
resource attributes:
id (globally unique - PRIMARY KEY/resource ID)
name (globally unique)
url (fully qualified resource URL)
Service-facing representation of a rule required to be satisfied to perform an action
Not sure this needs to be a first-class entity or just an attribute/collection of an Action; also not sure where the responsibility for parsing rules should land.
resource attributes:
id
value (non-unique, potentially string formatted)
url (fully qualified resource URL)
Values could be parsed by keystone and passed to the service (in which case, we need a documented list of support variable names). Alternately, it could be up to services to define their own syntax for rules, and parse them themselves.
(GET) / --> get version
The key use cases we need to cover:
given a user name & password, get a list of tenants for the user
given a user name, password, and tenant - get a token
given *JUST* a token, validate the token and return user, tenant, roles, and potential endpoints.
forced expiration of a token
The "just a token" has been the starting requirement, and with PKI coming online, it provides a resource path for the tokens independent of linkages to anything else.
(POST) /tokens ==> authenticate
{
"auth": {
"password_credentials": {
"username": "--username-here--",
"password": "--password-here--"
"user_id": "--user-id-here--" <--- optional
},
"tenant_name": "--tenant-name-here--"
}
returns token scoped to user/tenant
(example response to be placed here)
(POST) /tokens ==> authenticate
{
"auth": {
"password_credentials": {
"username": "--username-here--",
"password": "--password-here--"
"user_id": "--user-id-here--" <--- optional
}
}
returns list of tokens scoped to each valid tenant for the user
(example response to be placed here)
(POST) /tokens ==> authenticate
{
"auth": {
"token": {
"id": "--token-id-here--",
},
"tenant_name": "--tenant-name-here--"
}
(example response to be placed here)
(GET) /tokens ==> validate token
tokenID set in X-Subject-Token HTTP header
(example response to be placed here)
(HEAD) /tokens ==> validate token (head)
tokenID set in X-Subject-Token HTTP header
(example response to be placed here)
(DELETE) /tokens ==> remove token
tokenID set in X-Subject-Token HTTP header
(example response to be placed here)
(GET) /tokens/endpoints ==> endpoints_for_token
tokenID set in X-Subject-Token HTTP header
(example response to be placed here)
(GET) /tokens/tenants ==> get_tenants_for_token (public)
tokenID set in X-Subject-Token HTTP header
query_string: page (optional)
query_string: per_page (optional, default 30)
returns a list of tenant_id associated with the user identified by the the current token
(example response to be placed here)
The key use cases we need to cover:
CRUD for services
retrieving the endpoints of a given service, and/or with a given facing
(GET) /endpoints ==> get_endpoints
(POST) /endpoints ==> create_endpoint
{
"name": …
"url": …
"id": ...
"service": [compute|image|ec2|identity|volume|network]
"facing": [admin|public|internal]
"extra": ... (json blob)
}
(DELETE) /endpoints/{endpoint_id} ==> delete_endpoint
The key use cases we need to cover:
CRUD on a user
associating a user with a tenant
CRUD on a domain
CRUD on a tenant
(POST) /domains ==> create_domain
{
"name": …
“enabled”: ...
"id": ...
}
(GET) /domains ==> get_all_domains
query_string: page (optional)
query_string: per_page (optional, default 30)
(GET) /domains/{domain_id} ==> get_domain
(PUT) /domains/{domain_id} ==> update_domain
(PATCH) /domains/{domain_id} ==> update_domain
(DELETE) /domains/{domain_id} ==> delete_domain
(POST) /tenants ==> create_tenant
{
"name": ...
"description": ...
"enabled": ...
"domain_id": ...
}
(GET) /tenants ==> get_all_tenants (admin)
query_string: page (optional)
query_string: per_page (optional, default 30)
(GET) /tenants/{tenant_id} ==> get_tenants
(PUT) /tenants/{tenant_id} ==> replace_tenant_info
(PATCH) /tenants/{tenant_id} ==> update_tenant
(DELETE) /tenants/{tenant_id} ==> delete_tenant
(GET) /tenants/{tenant_id}/users ==> get_users_for_tenant
query_string: page (optional)
query_string: per_page (optional, default 30)
(POST) /users ==> create_user
{
"tenant_id": ...
"name": ...
"password": ...
"enabled": ...
"email": ...
"description": ...
}
(GET) /users ==> get_users
query_string: page (optional)
query_string: per_page (optional, default 30)
(GET) /users/{user_id} ==> get_user
(GET) /users/{user_id}/tenants ==> get_all_user_tenants
query_string: page (optional)
query_string: per_page (optional, default 30)
(PUT) /users/{user_id} ==> update_user
(PATCH) /users/{user_id} ==> update_user
(DELETE) /users/{user_id} ==> delete_user
Note: use (PATCH) to attempt to update user password or enable/disable the user. This may return a NotImplemented if the back-end driver doesn’t allow for the functionality.
The key use cases we need to cover:
CRUD on a credential
(POST) /users/{user_id}/credentials/ ==> create_credential
{
"type": ... (string: "ec2")
"tenant_id": ...
"access": ...
"secret": ...
}
(GET) /users/{user_id}/credentials/ ==> get_credentials
query_string: page (optional)
query_string: per_page (optional, default 30)
(GET) /users/{user_id}/credentials/{credential_id} ==> get_credential
(DELETE) /users/{user_id}/credentials/{credential_id} ==> delete_credential
The key use cases we need to cover:
CRUD on a role
Associating a role with a tenant or domain
(POST) /roles ==> create_role
{
"name": ...
}
(GET) /roles ==> get_roles
query_string: page (optional)
query_string: per_page (optional, default 30)
(GET) /roles/{role_id} ==> get_role
(DELETE) /roles/{role_id} ==> delete_role
(GET) /tenants/{tenant_id}/users/{user_id}/roles ==> get_user_roles
query_string: page (optional)
query_string: per_page (optional, default 30)
(GET) /domains/{domain_id}/users/{user_id}/roles ==> get_user_roles
query_string: page (optional)
query_string: per_page (optional, default 30)
(PUT) /tenants/{tenant_id}/users/{user_id}/roles/{role_id} ==> add_role_to_user
(DELETE) /tenants/{tenant_id}/users/{user_id}/roles/{role_id} ==> delete_role_from_user
(PUT) /domains/{domain_id}/users/{user_id}/roles/{role_id} ==> add_role_to_user
(DELETE) /domains/{domain_id}/users/{user_id}/roles/{role_id} ==> delete_role_from_user
(GET) /domains/{domainId}/users ==> get_domain_users
query_string: page (optional)
query_string: per_page (optional, default 30)
(GET) /domains/{domainId}/tenants ==> get_domain_tenants
query_string: page (optional)
query_string: per_page (optional, default 30)
The key use cases we need to cover:
CRUD on a policy
(POST) /policies ==> create_policy
(GET) /policies ==> get_all_policies
query_string: page (optional)
query_string: per_page (optional, default 30)
(GET) /policies/{policy_id} ==> get_policy
(PUT) /policies/{policy_id} ==> update_policy
(DELETE) /policies/{policy_id} ==> delete_policy
NOTE: The following sections are specific to the policy authorization mechanisms we have in place in Nova, Glance, and Keystone today. These may be more applicable to an API extension in contrib based on the implementation rather than a core API in order to keep from limiting Keystone from being an effective generic facade to an implementor’s authorization backend.
This would completely replace "policies" above, by breaking that model down into actions + m2m role/action mapping (and some sort of action/rule relationship?). policy.json currently implies a boolean-OR relationship among the set of required rules
(POST) /actions ==> create_action
{
"name": ...
}
(GET) /actions ==> get_all_actions
query_string: page (optional)
query_string: per_page (optional, default 30)
query_string: action_name (optional) ==> get_action (example of "Querying by Name" under "Broad Discussions")
(GET) /actions/{capability_id} ==> get_action
(PUT) /actions/{capability_id} ==> update_action
(DELETE) /actions/{capability_id} ==> delete_action
For this to be useful, you need to be able to collect actions into roles...
(PUT) /roles/{role_id}/actions/{action_id} ==> add_role_action
(empty request body)
(GET) /roles/{role_id}/actions ==> get_all_role_actions
(DELETE) /roles/{role_id}/actions/{action_id} ==> remove_role_action
And then, it's not necessarily required, but it seems useful to me that the admin API to be able to answer two questions (both requiring knowledge of a specific tenant):
"What actions does this token have on this tenant?"
(GET) /tokens/{token_id}/tenants/{tenant_id}/actions ==> get_token_actions
I imagine services could use this call, although the same information MUST be included in both the auth response and the token validation response.
“What actions would this user have on this tenant, if this user were to auth right now?"
(GET) /users/{user_id}/tenants/{tenant_id}/actions ==> get_user_actions
^ or flip around the resource to /tenants/.../users/... -- whatever makes more sense
I imagine the dashboard would utilize this call.