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:
tengqm 2015-04-10 05:56:38 -04:00
parent 69e39f6b8b
commit 02cdcc7d71
2 changed files with 269 additions and 0 deletions

View File

@ -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.

View File

@ -67,6 +67,7 @@ Developers Documentation
architecture
plugin_guide
authorization
API Documentation
========================