More AWX docs edits

This commit is contained in:
beeankha
2019-09-17 15:49:01 -04:00
parent e2be392f31
commit 860715d088
26 changed files with 860 additions and 499 deletions

View File

@@ -1,14 +1,14 @@
## Introduction
Starting from Tower 3.3, OAuth 2 will be used as the new means of token-based authentication. Users
will be able to manage OAuth 2 tokens as well as applications, a server-side representation of API
clients used to generate tokens. With OAuth 2, a user can authenticate by passing a token as part of
Starting from Tower 3.3, OAuth2 will be used as the new means of token-based authentication. Users
will be able to manage OAuth2 tokens as well as applications, a server-side representation of API
clients used to generate tokens. With OAuth2, a user can authenticate by passing a token as part of
the HTTP authentication header. The token can be scoped to have more restrictive permissions on top of
the base RBAC permissions of the user. Refer to [RFC 6749](https://tools.ietf.org/html/rfc6749) for
more details of OAuth 2 specification.
more details of OAuth2 specification.
## Basic Usage
To get started using OAuth 2 tokens for accessing the browsable API using OAuth 2, this document will walk through the steps of acquiring a token and using it.
To get started using OAuth2 tokens for accessing the browsable API using OAuth2, this document will walk through the steps of acquiring a token and using it.
1. Make an application with `authorization_grant_type` set to 'password'. HTTP POST the following to the `/api/v2/applications/` endpoint (supplying your own `organization-id`):
```
@@ -51,18 +51,18 @@ curl -H "Authorization: Bearer <token-value>" -X DELETE https://<awx>/api/v2/tok
## More Information
#### Managing OAuth 2 Applications and Tokens
#### Managing OAuth2 Applications and Tokens
Applications and tokens can be managed as a top-level resource at `/api/<version>/applications` and
`/api/<version>/tokens`. These resources can also be accessed respective to the user at
`/api/<version>/users/N/<resource>`. Applications can be created by making a POST to either `api/<version>/applications`
or `/api/<version>/users/N/applications`.
Applications and tokens can be managed as a top-level resource at `/api/v2/applications` and
`/api/v2/tokens`. These resources can also be accessed respective to the user at
`/api/v2/users/N/<resource>`. Applications can be created by making a POST to either `api/v2/applications`
or `/api/v2/users/N/applications`.
Each OAuth 2 application represents a specific API client on the server side. For an API client to use the API via an application token,
Each OAuth2 application represents a specific API client on the server side. For an API client to use the API via an application token,
it must first have an application and issue an access token.
Individual applications will be accessible via their primary keys:
`/api/<version>/applications/<pk>/`. Here is a typical application:
`/api/v2/applications/<pk>/`. Here is a typical application:
```
{
"id": 1,
@@ -105,8 +105,8 @@ Individual applications will be accessible via their primary keys:
```
In the above example, `user` is the primary key of the user associated to this application and `name` is
a human-readable identifier for the application. The other fields, like `client_id` and
`redirect_uris`, are mainly used for OAuth 2 authorization, which will be covered later in the 'Using
OAuth 2 Token System' section.
`redirect_uris`, are mainly used for OAuth2 authorization, which will be covered later in the 'Using
OAuth2 Token System' section.
Fields `client_id` and `client_secret` are immutable identifiers of applications, and will be
generated during creation; Fields `user` and `authorization_grant_type`, on the other hand, are
@@ -127,7 +127,7 @@ token scope; or POSTing to `/api/v2/applications/<pk>/tokens/` by providing only
the parent application will be automatically linked.
Individual tokens will be accessible via their primary keys at
`/api/<version>/tokens/<pk>/`. Here is a typical token:
`/api/v2/tokens/<pk>/`. Here is a typical token:
```
{
"id": 4,
@@ -162,7 +162,7 @@ Individual tokens will be accessible via their primary keys at
"scope": "read"
},
```
For an OAuth 2 token, the only fully mutable fields are `scope` and `description`. The `application`
For an OAuth2 token, the only fully mutable fields are `scope` and `description`. The `application`
field is *immutable on update*, and all other fields are totally immutable, and will be auto-populated
during creation.
* `user` - this field corresponds to the user the token is created for
@@ -181,8 +181,8 @@ endpoint. Personal access tokens can be identified by the `application` field b
- Other normal users will only be able to see and manipulate their own tokens.
> Note: Users can only see the token or refresh-token _value_ at the time of creation ONLY.
#### Using OAuth 2 Token System for Personal Access Tokens (PAT)
The most common usage of OAuth 2 is authenticating users. The `token` field of a token is used
#### Using OAuth2 Token System for Personal Access Tokens (PAT)
The most common usage of OAuth2 is authenticating users. The `token` field of a token is used
as part of the HTTP authentication header, in the format `Authorization: Bearer <token field value>`. This _Bearer_
token can be obtained by doing a curl to the `/api/o/token/` endpoint. For example:
```
@@ -195,17 +195,17 @@ Here is an example of using that PAT to access an API endpoint using `curl`:
curl -H "Authorization: Bearer kqHqxfpHGRRBXLNCOXxT5Zt3tpJogn" http://<awx>/api/v2/credentials/
```
According to OAuth 2 specification, users should be able to acquire, revoke and refresh an access
According to OAuth2 specification, users should be able to acquire, revoke and refresh an access
token. In AWX the equivalent, and easiest, way of doing that is creating a token, deleting
a token, and deleting a token quickly followed by creating a new one.
The specification also provides standard ways of doing this. RFC 6749 elaborates
on those topics, but in summary, an OAuth 2 token is officially acquired via authorization using
on those topics, but in summary, an OAuth2 token is officially acquired via authorization using
authorization information provided by applications (special application fields mentioned above).
There are dedicated endpoints for authorization and acquiring tokens. The `token` endpoint
is also responsible for token refresh, and token revoke can be done by the dedicated token revoke endpoint.
In AWX, our OAuth 2 system is built on top of
In AWX, our OAuth2 system is built on top of
[Django Oauth Toolkit](https://django-oauth-toolkit.readthedocs.io/en/latest/), which provides full
support on standard authorization, token revoke and refresh. AWX implements them and puts related
endpoints under `/api/o/` endpoint. Detailed examples on the most typical usage of those endpoints
@@ -215,9 +215,9 @@ are available as description text of `/api/o/`. See below for information on App
#### Token Scope Mask Over RBAC System
The scope of an OAuth 2 token is a space-separated string composed of keywords like 'read' and 'write'.
The scope of an OAuth2 token is a space-separated string composed of keywords like 'read' and 'write'.
These keywords are configurable and used to specify permission level of the authenticated API client.
For the initial OAuth 2 implementation, we use the most simple scope configuration, where the only
For the initial OAuth2 implementation, we use the most simple scope configuration, where the only
valid scope keywords are 'read' and 'write'.
Read and write scopes provide a mask layer over the RBAC permission system of AWX. In specific, a
@@ -226,7 +226,7 @@ scope gives the authenticated user only read permissions the RBAC system provide
For example, if a user has admin permission to a job template, he/she can both see and modify, launch
and delete the job template if authenticated via session or basic auth. On the other hand, if the user
is authenticated using OAuth 2 token, and the related token scope is 'read', the user can only see but
is authenticated using OAuth2 token, and the related token scope is 'read', the user can only see but
not manipulate or launch the job template, despite being an admin. If the token scope is
'write' or 'read write', she can take full advantage of the job template as its admin. Note that 'write'
implies 'read' as well.
@@ -234,10 +234,10 @@ implies 'read' as well.
## Application Functions
This page lists OAuth 2 utility endpoints used for authorization, token refresh and revoke.
This page lists OAuth2 utility endpoints used for authorization, token refresh and revoke.
Note endpoints other than `/api/o/authorize/` are not meant to be used in browsers and do not
support HTTP GET. The endpoints here strictly follow
[RFC specs for OAuth 2](https://tools.ietf.org/html/rfc6749), so please use that for detailed
[RFC specs for OAuth2](https://tools.ietf.org/html/rfc6749), so please use that for detailed
reference. Below are some examples to demonstrate the typical usage of these endpoints in
AWX context (note that the AWX net location defaults to `http://localhost:8013` in these examples).
@@ -392,10 +392,10 @@ at `/api/v2/tokens/`.
## Acceptance Criteria
* All CRUD operations for OAuth 2 applications and tokens should function as described.
* RBAC rules applied to OAuth 2 applications and tokens should behave as described.
* All CRUD operations for OAuth2 applications and tokens should function as described.
* RBAC rules applied to OAuth2 applications and tokens should behave as described.
* A default application should be auto-created for each new user.
* Incoming requests using unexpired OAuth 2 token correctly in authentication header should be able
* Incoming requests using unexpired OAuth2 token correctly in authentication header should be able
to successfully authenticate themselves.
* Token scope mask over RBAC should work as described.
* Tower configuration setting `OAUTH2_PROVIDER` should be configurable and function as described.

View File

@@ -1,43 +1,42 @@
## Introduction
Before Tower 3.3, auth token was used as the main authentication method. Starting from Tower 3.3,
session-based authentication will take the place as the main authentication method, and auth token
Before Tower 3.3, an auth token was used as the main authentication method. Starting from Tower 3.3,
session-based authentication will take its place as the main authentication method, and auth token
will be replaced by OAuth 2 tokens.
Session authentication is a safer way of utilizing HTTP(S) cookies:
Theoretically, the user can provide authentication information, like username and password, as part of the
Session authentication is a safer way of utilizing HTTP(S) cookies. Theoretically, the user can provide authentication information, like username and password, as part of the
`Cookie` header, but this method is vulnerable to cookie hijacks, where crackers can see and steal user
information from cookie payload.
information from the cookie payload.
Session authentication, on the other hand, sets a single `session_id` cookie. The session_id
Session authentication, on the other hand, sets a single `session_id` cookie. The `session_id`
is *a random string which will be mapped to user authentication informations by server*. Crackers who
hijack cookies will only get the session_id itself, which does not imply any critical user info, is valid only for
hijack cookies will only get the `session_id` itself, which does not imply any critical user info, is valid only for
a limited time, and can be revoked at any time.
> Note: The CSRF token will by default allow HTTP. To increase security, the `CSRF_COOKIE_SECURE` setting should
> Note: The CSRF token will by default allow HTTP. To increase security, the `CSRF_COOKIE_SECURE` setting should
be set to False.
## Usage
In session authentication, users log in using the `/api/login/` endpoint. A GET to `/api/login/` displays the
log in page of API browser:
login page of API browser:
![Example session log in page](../img/auth_session_1.png?raw=true)
Users should enter correct username and password before clicking on 'LOG IN' button, which fires a POST
Users should enter correct username and password before clicking on the 'LOG IN' button, which fires a POST
to `/api/login/` to actually log the user in. The return code of a successful login is 302, meaning upon
successful login, the browser will be redirected, the redirected destination is determined by `next` form
successful login, the browser will be redirected; the redirected destination is determined by the `next` form
item described below.
It should be noted that POST body of `/api/login/` is *not* in JSON, but HTTP form format. 4 items should
It should be noted that the POST body of `/api/login/` is *not* in JSON, but in HTTP form format. Four items should
be provided in the form:
* `username`: The username of the user trying to log in.
* `password`: The password of the user trying to log in.
* `next`: The path of the redirect destination, in API browser `"/api/"` is used.
* `csrfmiddlewaretoken`: The CSRF token, usually populated by using Django template `{% csrf_token %}`.
The session_id is provided as a return `Set-Cookie` header. Here is a typical one:
The `session_id` is provided as a return `Set-Cookie` header. Here is a typical one:
```
Set-Cookie: sessionid=lwan8l5ynhrqvps280rg5upp7n3yp6ds; expires=Tue, 21-Nov-2017 16:33:13 GMT; httponly; Max-Age=1209600; Path=/
```
@@ -47,40 +46,42 @@ session cookie value, expiration date, duration, etc.
The duration of the cookie is configurable by Tower Configuration setting `SESSION_COOKIE_AGE` under
category `authentication`. It is an integer denoting the number of seconds the session cookie should
live. The default session cookie age is 2 weeks.
live. The default session cookie age is two weeks.
After a valid session is acquired, a client should provide the session_id as a cookie for subsequent requests
After a valid session is acquired, a client should provide the `session_id` as a cookie for subsequent requests
in order to be authenticated. For example:
```
Cookie: sessionid=lwan8l5ynhrqvps280rg5upp7n3yp6ds; ...
```
User should use `/api/logout/` endpoint to log out. In API browser, a logged in user can do that by
simply clicking logout button on the nav bar. Under the hood the click issues a GET to '/api/logout/',
Upon success, server will invalidate current session and the response header will indicate client
to delete the session cookie. User should no longer try using this invalid session.
User should use the `/api/logout/` endpoint to log out. In the API browser, a logged-in user can do that by
simply clicking logout button on the nav bar. Under the hood, the click issues a GET to `/api/logout/`.
Upon success, the server will invalidate the current session and the response header will indicate for the client
to delete the session cookie. The user should no longer try using this invalid session.
The duration of a session is constant. However, user can extend the expiration date of a valid session
The duration of a session is constant. However, a user can extend the expiration date of a valid session
by performing session acquire with the session provided.
A Tower configuration setting, `SESSIONS_PER_USER` under category `authentication`, is used to set the
maximum number of valid sessions a user can have at the same time. For example, if `SESSIONS_PER_USER`
is set to 3 and the same user is logged in from 5 different places, the earliest 2 sessions created will be invalidated. Tower will try
is set to three and the same user is logged in from five different places, the earliest two sessions created will be invalidated. Tower will try
broadcasting, via websocket, to all available clients. The websocket message body will contain a list of
invalidated sessions. If a client finds its session in that list, it should try logging out.
Unlike tokens, sessions are meant to be short-lived and UI-only, therefore whenever a user's password
Unlike tokens, sessions are meant to be short-lived and UI-only; therefore, whenever a user's password
is updated, all sessions she owned will be invalidated and deleted.
## Acceptance Criteria
* User should be able to log in via `/api/login/` endpoint by correctly providing all necessary fields.
* Logged in users should be able to authenticate themselves by providing correct session auth info.
* Logged in users should be able to log out via `/api/logout/`.
* Users should be able to log in via the `/api/login/` endpoint by correctly providing all necessary fields.
* Logged-in users should be able to authenticate themselves by providing correct session auth info.
* Logged-in users should be able to log out via `/api/logout/`.
* The duration of a session cookie should be configurable by `SESSION_COOKIE_AGE`.
* The maximum number of concurrent login for one user should be configurable by `SESSIONS_PER_USER`,
and over-limit user sessions should be warned by websocket.
* When a user's password is changed, all her sessions should be invalidated and deleted.
* User should not be able to authenticate by HTTPS(S) request nor websocket connect using invalid
* User should not be able to authenticate by HTTPS(S) request nor websocket connection using invalid
sessions.
* No existing behavior, like job run, inventory update or callback receiver, should be affected
* No existing behavior, like job runs, inventory updates or callback receiver, should be affected
by session auth.

View File

@@ -1,7 +1,7 @@
# TACACS+
[Terminal Access Controller Access-Control System Plus (TACACS+)](https://en.wikipedia.org/wiki/TACACS) is a protocol developed by Cisco to handle remote authentication and related services for networked access control through a centralized server. In specific, TACACS+ provides authentication, authorization and accounting (AAA) services. Ansible Tower currently utilizes its authentication service.
TACACS+ is configured by Tower configuration and is available under `/api/<version #>/settings/tacacsplus/`. Here is a typical configuration with every configurable field included:
TACACS+ is configured by Tower configuration and is available under `/api/v2/settings/tacacsplus/`. Here is a typical configuration with every configurable field included:
```
{
"TACACSPLUS_HOST": "127.0.0.1",
@@ -11,7 +11,7 @@ TACACS+ is configured by Tower configuration and is available under `/api/<versi
"TACACSPLUS_AUTH_PROTOCOL": "ascii"
}
```
Below explains each field:
Each field is explained below:
| Field Name | Field Value Type | Field Value Default | Description |
|------------------------------|---------------------|---------------------|--------------------------------------------------------------------|
@@ -19,28 +19,31 @@ Below explains each field:
| `TACACSPLUS_PORT` | Integer | 49 | Port number of TACACS+ server. |
| `TACACSPLUS_SECRET` | String | '' (empty string) | Shared secret for authenticating to TACACS+ server. |
| `TACACSPLUS_SESSION_TIMEOUT` | Integer | 5 | TACACS+ session timeout value in seconds. |
| `TACACSPLUS_AUTH_PROTOCOL` | String with choices | 'ascii' | The authentication protocol used by TACACS+ client. Choices are `ascii` and `pap` |
| `TACACSPLUS_AUTH_PROTOCOL` | String with choices | 'ascii' | The authentication protocol used by TACACS+ client (choices are `ascii` and `pap`). |
Under the hood, Tower uses [open-source TACACS+ python client](https://github.com/ansible/tacacs_plus) to communicate with the remote TACACS+ server. During authentication, Tower passes username and password to TACACS+ client, which packs up auth information and send to TACACS+ server. Based on what the server returns, Tower will invalidate login attempt if authentication fails. If authentication passes, Tower will create a user if she does not exist in database, and log the user in.
Under the hood, Tower uses [open-source TACACS+ python client](https://github.com/ansible/tacacs_plus) to communicate with the remote TACACS+ server. During authentication, Tower passes username and password to TACACS+ client, which packs up auth information and sends it to the TACACS+ server. Based on what the server returns, Tower will invalidate login attempt if authentication fails. If authentication passes, Tower will create a user if she does not exist in database, and log the user in.
## Test environment setup
## Test Environment Setup
The suggested TACACS+ server for testing is [shrubbery TACACS+ daemon](http://www.shrubbery.net/tac_plus/). It is supposed to run on a centos machine. A verified candidate is centos 6.3 AMI in AWS EC2 Community AMIs (search for 'Centos 6.3 x86_64 HVM - Minimal with cloud-init aws-cfn-bootstrap and ec2-api-tools'). Note it is required to keep TCP port 49 open, since it's the default port used by TACACS+ daemon.
The suggested TACACS+ server for testing is [shrubbery TACACS+ daemon](http://www.shrubbery.net/tac_plus/). It is supposed to run on a CentOS machine. A verified candidate is CentOS 6.3 AMI in AWS EC2 Community AMIs (search for `CentOS 6.3 x86_64 HVM - Minimal with cloud-init aws-cfn-bootstrap and ec2-api-tools`). Note that it is required to keep TCP port 49 open, since it's the default port used by the TACACS+ daemon.
We provide [a playbook](https://github.com/jangsutsr/ansible-role-tacacs) to install a working TACACS+ server. Here is a typical test setup using the provided playbook.
1. In AWS EC2, spawn the centos 6 machine.
We provide [a playbook](https://github.com/jangsutsr/ansible-role-tacacs) to install a working TACACS+ server. Here is a typical test setup using the provided playbook:
1. In AWS EC2, spawn the CentOS 6 machine.
2. In Tower, create a test project using the stand-alone playbook inventory.
3. In Tower, create a test inventory with the only host to be the spawned centos machine.
4. In Tower, create and run a job template using the created project and inventory with parameters setup as below.
3. In Tower, create a test inventory with the only host to be the spawned CentOS machine.
4. In Tower, create and run a job template using the created project and inventory with parameters setup as below:
![Example tacacs+ setup jt parameters](../img/auth_tacacsplus_1.png?raw=true)
The playbook creates a user named 'tower' with ascii password default to 'login' and modifiable by extra_var `ascii_password` and pap password default to 'papme' and modifiable by extra_var `pap_password`. In order to configure TACACS+ server to meet custom test needs, we need to modify server-side file `/etc/tac_plus.conf` and `sudo service tac_plus restart` to restart the daemon. Details on how to modify config file can be found [here](http://manpages.ubuntu.com/manpages/xenial/man5/tac_plus.conf.5.html).
The playbook creates a user named 'tower' with ascii password default to 'login' and modifiable by `extra_var` `ascii_password` and pap password default to 'papme' and modifiable by `extra_var` `pap_password`. In order to configure TACACS+ server to meet custom test needs, we need to modify server-side file `/etc/tac_plus.conf` and `sudo service tac_plus restart` to restart the daemon. Details on how to modify config file can be found [here](http://manpages.ubuntu.com/manpages/xenial/man5/tac_plus.conf.5.html).
## Acceptance Criteria
## Acceptance criteria
* All specified Tower configuration fields should be shown and configurable as documented.
* User defined by TACACS+ server should be able to log in Tower.
* User not defined by TACACS+ server should not be able to log in Tower via TACACS+.
* A user existing in TACACS+ server but not in Tower should be created after the first success log in.
* TACACS+ backend should stop authentication attempt after configured timeout and should not block the authentication pipeline in any case.
* A user defined by the TACACS+ server should be able to log into Tower.
* User not defined by TACACS+ server should not be able to log into Tower via TACACS+.
* A user existing in TACACS+ server but not in Tower should be created after the first successful log in.
* TACACS+ backend should stop an authentication attempt after configured timeout and should not block the authentication pipeline in any case.
* If exceptions occur on TACACS+ server side, the exception details should be logged in Tower, and Tower should not authenticate that user via TACACS+.