Initial version of authorization doc
This is an initial version of the design doc for authentication and authorization in Senlin. There will be future improvements and revisions. Change-Id: I5f3d3dc1fb14237e357d1520ef1755626e2744ed
This commit is contained in:
parent
69e39f6b8b
commit
02cdcc7d71
|
@ -0,0 +1,268 @@
|
|||
..
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
not use this file except in compliance with the License. You may obtain
|
||||
a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Senlin Authorization
|
||||
====================
|
||||
|
||||
As a service to be consumed by end users and possibly other IT persons, Senlin
|
||||
has some basic components and strategies to manage access control. The design
|
||||
is meant to be as open as possible though the current focus as this document is
|
||||
drafted is on enabling Keystone-based (aka. token-based) OpenStack
|
||||
authorization.
|
||||
|
||||
This document presents an overview of the authentication and authorization
|
||||
mechanisms provided by the Senlin API and its service engine. The top-most
|
||||
design consideration of these mechanisms is to make it accommodating so that
|
||||
the interactions with different authentication engines can be done using the
|
||||
same framework. The reason behind this decision is to make Senlin cloud-backend
|
||||
agnostic so it can be used to support clustering of resources in a multi-cloud,
|
||||
or multi-region, or multi-availability-zone setups.
|
||||
|
||||
|
||||
----------------
|
||||
Major Components
|
||||
----------------
|
||||
|
||||
In the context of an OpenStack cloud, the most important components invovled in
|
||||
the authentication and the authorization process are:
|
||||
|
||||
- The Senlin client (i.e. the `python-senlinclient` package) which accepts
|
||||
user credentials provided through environment variables and/or the command
|
||||
line arguments and forwards them to the OpenStack SDK (i.e. the
|
||||
`python-openstacksdk` package) when making service requests to Senlin API.
|
||||
- The OpenStack SDK (`python-openstacksdk`) is used by Senlin engine to
|
||||
interact with any other OpenStack services. The Senlin client also uses the
|
||||
SDK to talk to the Senlin API. The SDK package translates the user-provided
|
||||
credentials into a token by invoking the Keystone service.
|
||||
- The Keystone middleware (i.e. `keystonemiddleware`) which backs the
|
||||
`auth_token` WSGI middleware in the Senlin API pipeline provides a basic
|
||||
validation filter. The filter is responsible to validate the token that
|
||||
exists in the HTTP request header and then populates the HTTP request header
|
||||
with detailed information for the downstream filters (including the API
|
||||
itself) to use.
|
||||
- The `context` WSGI middleware which is based on the `oslo.context` package
|
||||
provides a constructor of the `RequestContext` data structure that
|
||||
accompanies any requests down the WSGI application pipeline so that those
|
||||
downstream components don't have to access the HTTP request header.
|
||||
|
||||
|
||||
---------------
|
||||
Usage Scenarios
|
||||
---------------
|
||||
|
||||
There are several ways to raise a service request to the Senlin API, each of
|
||||
which has its own characteristics that will affect the way authentication
|
||||
and/or authorization is performed.
|
||||
|
||||
1) Users interact with Senlin service API using the Senlin client (i.e. the
|
||||
`python-senlinclient` package) which includes a command line interface (CLI)
|
||||
named `senlin`. The requests, after being preprocessed by the OpenStack SDK
|
||||
will contain a valid Keystone token that can be validated by the
|
||||
`auth_token` WSGI middleware.
|
||||
2) Users interact with Senlin service API directly by making HTTP requests
|
||||
where the requester's credentials have been validated by Keystone so the
|
||||
requests will carry a valid Keystone token for verification by the
|
||||
`auth_token` middleware as well.
|
||||
3) Users interact with Senlin service API directly by making HTTP requests, but
|
||||
the requests are "naked" ones which means that the requests do not contain
|
||||
credentials as expected by Senlin API (or other OpenStack services). In
|
||||
stead, the URI requested contains some special parameters for authentication
|
||||
and/or authorization's purposes.
|
||||
|
||||
Scenario 1) and 2) are the most common ways for users to use Senlin API. They
|
||||
share the same request format when the request arrives at the Senlin API
|
||||
endpoint. Scenario 3) is a little bit different. What Senlin wants to achieve
|
||||
is making no assumption where the service requests come from. That means it
|
||||
cannot assume that the requester (could be any program) will fill in the
|
||||
required headers in their service requests. One example of such use cases is
|
||||
the Webhook API Senlin provides that enables a user to trigger an action on an
|
||||
object managed by Senlin. Senlin provides a special support to these use cases.
|
||||
|
||||
|
||||
-----------------------------
|
||||
Operation Delegation (Trusts)
|
||||
-----------------------------
|
||||
|
||||
Since Senlin models most operations as "Actions" that can be executed by worker
|
||||
threads asynchronously, these operations have to be done on behalf of the
|
||||
requester so that they can be properly traced, authenticated, audited or logged.
|
||||
|
||||
|
||||
Credentials and Context
|
||||
-----------------------
|
||||
|
||||
A generic solution to the delegation problem is to ask users to provide their
|
||||
credentials to Senlin so Senlin can impersonate them when interacting with
|
||||
other services. In fact, this may be the only solution that can be applied on
|
||||
different cloud backends.
|
||||
|
||||
Senlin supports a `context` property for all "profile" types by default unless
|
||||
overriden by a profile type implementation. This context can be treated as a
|
||||
container for these credentials. Storing user credential in Senlin database
|
||||
does imply a security risk. In future, we hope Senlin can make use of the
|
||||
Barbican service for this purpose.
|
||||
|
||||
Senlin's implementation of context is based on the `oslo_context` package.
|
||||
There are still room for improvement thanks to the new enhancements to that
|
||||
package.
|
||||
|
||||
|
||||
Trusts: Dealing with Token Expiration
|
||||
-------------------------------------
|
||||
|
||||
In some cases, the solution above may be impractical because after the
|
||||
client-side processing and/or the front-end middleware filtering, Senlin
|
||||
cannot get the original user credentials (e.g. user name and password).
|
||||
Senlin can only get a "token", which expires in an hour by default. This means
|
||||
that after no more than one hour, Senlin won't be able to use this token for
|
||||
authentication/authorization.
|
||||
|
||||
The OpenStack identity service (a.k.a Keystone) has considered this situation
|
||||
and provided a solution. When a requester wants to delegate his/her roles in a
|
||||
project to a 3rd party, he or she can create a "Trust" relationship between
|
||||
him/her (the trustor) and that 3rd party (the trustee). The "Trust" has a
|
||||
unique ID that can be used by the trustee when authenticating with Keystone.
|
||||
Once trust ID is authenticated, the trustee can perform operations on behalf
|
||||
of the trustor.
|
||||
|
||||
The trust extension in Keystone V3 can be used to solve the token expiration
|
||||
problem. There are two ways to do this as shown below.
|
||||
|
||||
1) Requester Created Trusts: Before creating a profile, a requester can create
|
||||
a trust with the trustee set to the `senlin` user. He or she can customize
|
||||
the roles that can be assumed by `senlin`, which can be a subset of the
|
||||
roles the requester currently has in that project. When the requester later
|
||||
on creates a profile, he or she can provide the `trust_id` as a key of the
|
||||
`context` property. Senlin can later on use this trust for authentication
|
||||
and authorization's purpose.
|
||||
2) Senlin Created Trusts: The solution above adds some burdens for an end user.
|
||||
In order to make Senlin service easy of use, Senlin will do the trust
|
||||
creation in the background. Whenever a new request comes in, Senlin will
|
||||
check if there is an existing trust relationship between the requester and
|
||||
the `senlin` user. Senlin will "hijack" the user's token and create a trust
|
||||
with `senlin` as the trustee. This trust relationship is currently stored
|
||||
in Senlin database, and the management of this sensitive information can be
|
||||
delegated to Barbican as well in future.
|
||||
|
||||
|
||||
Precedence Consideration
|
||||
------------------------
|
||||
|
||||
Since there now exist more than one place for Senlin to get the credentials
|
||||
for use, Senlin needs to impose a precedence among the credential sources.
|
||||
|
||||
When Senlin tries to contact a cloud service via a driver, the requests are
|
||||
issued from a subclass of `Profile`. Senlin will check the `user` property of
|
||||
the targeted cluster or node and retrieve the trust record from database using
|
||||
the `user` as the key. By default, Senlin will try obtain a new token from
|
||||
Keystone using the `senlin` user's credentials (configured in `senlin.conf`
|
||||
file) and the `trust_id`. Before doing that, Senlin will check if the profile
|
||||
used has a "customized" `context`. If there are credentials such as `password`
|
||||
or `trust_id` in the context, Senlin deletes its current `trust_id` from the
|
||||
context, and adds the credentials found in the profile into the context.
|
||||
|
||||
In this way, a user can specify the credentials Senlin should use when talking
|
||||
to other cloud services by customizing the `context` property of a profile.
|
||||
The specified credentials may and may not belong to the requester.
|
||||
|
||||
|
||||
Trust Middleware
|
||||
----------------
|
||||
|
||||
When a service request arrives at Senlin API, Senlin API checks if there is a
|
||||
trust relationship built between the requester user and the `senlin` user. A
|
||||
new trust is created if no such record is found.
|
||||
|
||||
Once a trust is found or created, the `trust_id` is saved into the current
|
||||
`context` data structure. Down the invocation path, or during asynchronous
|
||||
action executions, the `trust_id` will be used for token generation when
|
||||
needed.
|
||||
|
||||
Senlin provides an internal database table to store the trust information. It
|
||||
may be removed in future when there are better ways to handle this sensitive
|
||||
information.
|
||||
|
||||
|
||||
----------------------
|
||||
Webhook Authentication
|
||||
----------------------
|
||||
|
||||
Senlin provides a group of APIs for the creation and management "Webhooks".
|
||||
A "Webhook" is a URI that can be accessed from any users or programs, provided
|
||||
they possess some credentials that can be authenticated.
|
||||
|
||||
Webhook Creation
|
||||
----------------
|
||||
|
||||
Webhooks are provided as a shortcut to trigger an action on an object on
|
||||
behalf of a user. A webhook can be seen as a tuple (`object`, `action`,
|
||||
`credentials`, `params`), where:
|
||||
|
||||
- `object`: an object which could be, e.g. a cluster, a node or a policy,
|
||||
(In implementation, this field is represented by the `obj_type` and the
|
||||
`obj_id` fields together);
|
||||
- `action`: an action that will be performed;
|
||||
- `credential`: on whom's behalf should the action be performed;
|
||||
- `params`: optional parameters that will be used as inputs to the action.
|
||||
|
||||
When creating a webhook, a user has to specify an `object` and an `action`.
|
||||
Optionally, the user can specify the `credential` to use when the action is
|
||||
executed as a result of the webhook gets triggered. When omitted, Senlin will
|
||||
use the `user` of the `object` and its associated trust saved in Senlin DB.
|
||||
The only restriction is that the requester must be either the owner or the
|
||||
project admin.
|
||||
|
||||
If the user does specify a `credential` for use, Senlin webhook middleware
|
||||
will use the fields contained in `credential` to get a token from Keystone.
|
||||
The newly created token will then be used for creating the webhook, as if the
|
||||
request was from the user represented by the `credential` rather than the real
|
||||
requester.
|
||||
|
||||
One special case is that the requester wants to use its own credential (which
|
||||
is barely a token when arriving at Senlin API middleware) for the webhook. In
|
||||
this case, the `credential` is specially formed by the client side.
|
||||
|
||||
In summary, the "requested user" can be one of 1) the requester; 2) the user
|
||||
represented by the `credential`; 3) the owner of the object. In all cases,
|
||||
the "requested user" must be either the owner of the object or the project
|
||||
admin. In other words, the requests are still subject to policy checkings.
|
||||
|
||||
|
||||
Encryption of Credentials
|
||||
-------------------------
|
||||
|
||||
Since Senlin is creating a trust for each user. This trust information should
|
||||
be treated as sensitive information. When storing them into database, it has
|
||||
better be encrypted, and that is exactly how Senlin is doing now. In future,
|
||||
this kind of data may be migrated to the Barbican service.
|
||||
|
||||
As of now, Senlin utilizes the `cryptography` package to do an encryption of
|
||||
the data. The encrypted data can be decrypted only using the generated key.
|
||||
Senlin will return the key to the requester, along with the UUID of the
|
||||
generated webhook.
|
||||
|
||||
|
||||
Triggering of Webhooks
|
||||
----------------------
|
||||
|
||||
When a user wants to trigger a webhook, Senlin webhook middleware will first
|
||||
verify if the referenced webook does exists. The middleware then use the key
|
||||
provided by the user to decrypt the stored credential, i.e. the trust info.
|
||||
By the way, the "key" data can appear as parameters on URI or data in the
|
||||
request body. Senlin supports both ways. Senlin API will also extract any
|
||||
parameters from the request for instantiating the action to execute.
|
||||
|
||||
When Senlin middleware has successfully decrypted the trust info, it will
|
||||
try obtain a trust-scoped token using the `senlin` user's credential along
|
||||
with the decrpted trust data. The returned trust-scoped token will then be
|
||||
used to eventually trigger the creation on an action.
|
|
@ -67,6 +67,7 @@ Developers Documentation
|
|||
|
||||
architecture
|
||||
plugin_guide
|
||||
authorization
|
||||
|
||||
API Documentation
|
||||
========================
|
||||
|
|
Loading…
Reference in New Issue