зеркало из https://github.com/mozilla/doorman.git
Merge docs (fixes #84)
This commit is contained in:
Родитель
856c41d532
Коммит
2c9b506574
|
@ -4,7 +4,8 @@ coverage.txt
|
|||
policies.yaml
|
||||
vendor/
|
||||
node_modules/
|
||||
api-docs/
|
||||
docs/_build
|
||||
.venv
|
||||
__pycache__/
|
||||
*.pyc
|
||||
examples/python/records/*.json
|
||||
|
|
13
Makefile
13
Makefile
|
@ -62,10 +62,15 @@ docker-build: main
|
|||
docker-run:
|
||||
docker run --name doorman --rm mozilla/doorman
|
||||
|
||||
api-docs: api/openapi.yaml
|
||||
# https://github.com/sourcey/spectacle
|
||||
spectacle --target-dir api-docs api/openapi.yaml
|
||||
.venv/bin/sphinx-build:
|
||||
virtualenv .venv
|
||||
.venv/bin/pip install -r docs/requirements.txt
|
||||
|
||||
api-docs-publish: api-docs
|
||||
docs: .venv/bin/sphinx-build docs/*.rst
|
||||
.venv/bin/sphinx-build -a -W -n -b html -d docs/_build/doctrees docs docs/_build/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(SPHINX_BUILDDIR)/html/index.html"
|
||||
|
||||
docs-publish: docs
|
||||
# https://github.com/tschaub/gh-pages
|
||||
gh-pages -d api-docs
|
||||
|
|
201
README.md
201
README.md
|
@ -1,210 +1,15 @@
|
|||
Doorman
|
||||
=======
|
||||
# Doorman
|
||||
|
||||
![](logo.svg)
|
||||
![](docs/logo.svg)
|
||||
|
||||
*Doorman* is an **authorization micro-service**.
|
||||
|
||||
- [API Documentation](https://mozilla.github.io/doorman/)
|
||||
- [Examples](examples/)
|
||||
- [Documentation](https://doorman.readthedocs.io)
|
||||
|
||||
[![Build Status](https://travis-ci.org/mozilla/doorman.svg?branch=master)](https://travis-ci.org/mozilla/doorman)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/mozilla/doorman/badge.svg?branch=master)](https://coveralls.io/github/mozilla/doorman?branch=master)
|
||||
[![Go Report](https://goreportcard.com/badge/github.com/mozilla/doorman)](https://goreportcard.com/report/github.com/mozilla/doorman)
|
||||
|
||||
*Doorman* responds to authorization requests based on a set of rules (policies files).
|
||||
|
||||
Having a centralized access control service has several advantages:
|
||||
|
||||
- it clearly dissociates authentication from authorization
|
||||
- it provides a standard and generic permissions system to services developers
|
||||
- it facilitates permissions management across services (eg. makes revocation easier)
|
||||
- it allows authorizations monitoring, metrics, anomaly detection
|
||||
|
||||
## Run
|
||||
|
||||
```
|
||||
docker run \
|
||||
-e POLICIES=/config \
|
||||
-v ./examples/python:/config \
|
||||
-p 8000:8080 \
|
||||
--name doorman \
|
||||
mozilla/doorman
|
||||
```
|
||||
|
||||
*Doorman* is now ready to respond authorization requests on `http://localhost:8080`. See [API docs](https://mozilla.github.io/doorman/).
|
||||
|
||||
## Policies
|
||||
|
||||
Policies are defined in YAML files for each consuming service, locally or in remote (private) Github repos, as follow:
|
||||
|
||||
```yaml
|
||||
service: https://service.stage.net
|
||||
identityProvider: https://auth.mozilla.auth0.com/
|
||||
tags:
|
||||
superusers:
|
||||
- userid:maria
|
||||
- group:admins
|
||||
policies:
|
||||
-
|
||||
id: authors-superusers-delete
|
||||
description: Authors and superusers can delete articles
|
||||
principals:
|
||||
- role:author
|
||||
- tag:superusers
|
||||
actions:
|
||||
- delete
|
||||
resources:
|
||||
- article
|
||||
effect: allow
|
||||
```
|
||||
|
||||
* **service**: the unique identifier of the service
|
||||
* **identityProvider** (*optional*): when the identify provider is not empty, *Doorman* will verify the Access Token or the ID Token provided in the authorization request to authenticate the request and obtain the subject profile information (*principals*)
|
||||
* **tags**: Local «groups» of principals in addition to the ones provided by the Identity Provider
|
||||
* **actions**: a domain-specific string representing an action that will be defined as allowed by a principal (eg. `publish`, `signoff`, …)
|
||||
* **resources**: a domain-specific string representing a resource. Preferably not a full URL to decouple from service API design (eg. `print:blackwhite:A4`, `category:homepage`, …).
|
||||
* **effect**: Use `effect: deny` to deny explicitly. Requests that don't match any rule are denied.
|
||||
|
||||
### Principals
|
||||
|
||||
The principals is a list of prefixed strings to refer to the «user» as the combination of ids, emails, groups, roles…
|
||||
|
||||
Supported prefixes:
|
||||
|
||||
* ``userid:``: provided by Identity Provider (IdP)
|
||||
* ``tag:``: local tags
|
||||
* ``role:``: provided in context of authorization request (see below)
|
||||
* ``email:``: provided by IdP
|
||||
* ``group:``: provided by IdP
|
||||
|
||||
Example: `["userid:ldap|user", "email:user@corp.com", "group:Employee", "group:Admins", "role:editor"]`
|
||||
|
||||
## Settings
|
||||
|
||||
Via environment variables:
|
||||
|
||||
* ``POLICIES``: space separated locations of YAML files with policies. They can be **single files**, **folders** or **Github URLs** (default: ``./policies.yaml``)
|
||||
* ``GITHUB_TOKEN``: Github API token to be used when fetching policies files from private repositories
|
||||
|
||||
Advanced:
|
||||
|
||||
* ``PORT``: listen (default: ``8080``)
|
||||
* ``GIN_MODE``: server mode (``release`` or default ``debug``)
|
||||
* ``LOG_LEVEL``: logging level (``fatal|error|warn|info|debug``, default: ``info`` with ``GIN_MODE=release`` else ``debug``)
|
||||
* ``VERSION_FILE``: location of JSON file with version information (default: ``./version.json``)
|
||||
|
||||
> Note: the ``Dockerfile`` contains different default values, suited for production.
|
||||
|
||||
## Advanced policies rules
|
||||
|
||||
### Regular expressions
|
||||
|
||||
Regular expressions begin with ``<`` and end with ``>``.
|
||||
|
||||
```yaml
|
||||
principals:
|
||||
- userid:<[peter|ken]>
|
||||
resources:
|
||||
- /page/<.*>
|
||||
```
|
||||
|
||||
> Note: regular expressions are not supported in tags members definitions.
|
||||
|
||||
### Conditions
|
||||
|
||||
The conditions are **optional** on policies and are used to match field values from the authorization request context.
|
||||
|
||||
The context value ``remoteIP`` is forced by the server.
|
||||
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
policies:
|
||||
-
|
||||
description: Allow everything from dev environment
|
||||
conditions:
|
||||
env:
|
||||
type: StringEqualCondition
|
||||
options:
|
||||
equals: dev
|
||||
```
|
||||
|
||||
There are several ``type``s of conditions:
|
||||
|
||||
**Field comparison**
|
||||
|
||||
* type: ``StringEqualCondition``
|
||||
|
||||
For example, match ``request.context["country"] == "catalunya"``:
|
||||
|
||||
```yaml
|
||||
conditions:
|
||||
country:
|
||||
type: StringEqualCondition
|
||||
options:
|
||||
equals: catalunya
|
||||
```
|
||||
|
||||
**Field pattern**
|
||||
|
||||
* type: ``StringMatchCondition``
|
||||
|
||||
For example, match ``request.context["bucket"] ~= "blocklists-.*"``:
|
||||
|
||||
```yaml
|
||||
conditions:
|
||||
bucket:
|
||||
type: StringMatchCondition
|
||||
options:
|
||||
matches: blocklists-.*
|
||||
```
|
||||
|
||||
**Match principals**
|
||||
|
||||
* type: ``MatchPrincipalsCondition``
|
||||
|
||||
For example, allow requests where ``request.context["owner"]`` is in principals:
|
||||
|
||||
```yaml
|
||||
conditions:
|
||||
owner:
|
||||
type: MatchPrincipalsCondition
|
||||
```
|
||||
|
||||
> Note: This also works when a the context field is list (e.g. list of collaborators).
|
||||
|
||||
**IP/Range**
|
||||
|
||||
* type: ``CIDRCondition``
|
||||
|
||||
For example, match ``request.context["remoteIP"]`` with [CIDR notation](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation):
|
||||
|
||||
```yaml
|
||||
conditions:
|
||||
remoteIP:
|
||||
type: CIDRCondition
|
||||
options:
|
||||
# mask 255.255.0.0
|
||||
cidr: 192.168.0.1/16
|
||||
```
|
||||
|
||||
## Run from source
|
||||
|
||||
make serve -e POLICIES=sample.yaml
|
||||
|
||||
## Run tests
|
||||
|
||||
make test
|
||||
|
||||
## Generate API docs
|
||||
|
||||
make api-docs
|
||||
|
||||
## Build docker container
|
||||
|
||||
make docker-build
|
||||
|
||||
## License
|
||||
|
||||
* MPLv2.0
|
||||
|
|
115
api/openapi.yaml
115
api/openapi.yaml
|
@ -3,101 +3,6 @@ info:
|
|||
title: "Mozilla Doorman"
|
||||
description: |
|
||||
*Doorman* is an **authorization micro-service** that allows to checks if an arbitrary subject is allowed to perform an action on a resource, based on a set of rules (policies).
|
||||
|
||||
It takes a set of YAML files like the one below and answers authorization requests by matching the rules:
|
||||
|
||||
```YAML
|
||||
service: https://api.service.org
|
||||
identityProvider: https://auth.mozilla.auth0.com/
|
||||
policies:
|
||||
-
|
||||
id: crud-articles
|
||||
description: Editors can CRUD articles
|
||||
principals:
|
||||
- role:editor
|
||||
actions:
|
||||
- create
|
||||
- read
|
||||
- delete
|
||||
- update
|
||||
resources:
|
||||
- article
|
||||
effect: allow
|
||||
```
|
||||
|
||||
### Workflow with OpenID
|
||||
|
||||
When a service takes advantage of *Doorman*, a typical workflow is:
|
||||
|
||||
1. Users obtain an access token from an Identity Provider (eg. Auth0)
|
||||
1. They use it to call a service API endpoint
|
||||
1. The service posts an authorization request on *Doorman* to check if the user is allowed to perform a specific action
|
||||
1. *Doorman* uses the `Origin` request header to select the set of policies to match
|
||||
1. *Doorman* fetches the user infos using the provided access token and builds a list of strings (principals) to characterize this user
|
||||
1. *Doorman* matches the policies and returns true or allowed, along with the list of principals
|
||||
1. Based on the *Doorman* response, the service denies the original request or executes it
|
||||
|
||||
*Doorman* will verify that the specified Access token (or ID token) is valid.
|
||||
|
||||
The authorization request **principals** will be built from the user profile information like this:
|
||||
|
||||
* `"sub"`: `userid:{}`
|
||||
* `"email"`: `email:{}` (*optional*)
|
||||
* `"groups"`: `group:{}, group:{}, ...` (*optional*)
|
||||
|
||||
|
||||
### Without authentication/OpenID
|
||||
|
||||
If the identity provider is not configured for a service, no authentication is required and the principals
|
||||
are posted in the authorization body.
|
||||
|
||||
It is not especially recommended, but it can give a certain amount of flexibility when authentication is fully managed on the service.
|
||||
|
||||
A typical workflow in this case would be:
|
||||
|
||||
1. Users call the service API endpoint
|
||||
1. The service authenticates the user and builds the list of principals
|
||||
1. The service posts an authorization request on *Doorman* containing the list of principals to check if the user is allowed
|
||||
|
||||
|
||||
### API Summary
|
||||
|
||||
Basically, use **POST /allowed** to check authorization requests.
|
||||
|
||||
**Request**:
|
||||
|
||||
```HTTP
|
||||
|
||||
POST /allowed HTTP/1.1
|
||||
Origin: https://api.service.org
|
||||
Authorization: Bearer f2457yu86yikhmbh
|
||||
|
||||
{
|
||||
"action" : "delete",
|
||||
"resource": "articles/doorman-introduce",
|
||||
"context": {
|
||||
"env": "stage",
|
||||
"roles": ["editor"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response**:
|
||||
|
||||
```HTTP
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"allowed": true,
|
||||
"principals": [
|
||||
"role:editor",
|
||||
"userid:myself"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
version: "0.1"
|
||||
contact:
|
||||
url: "irc://irc.mozilla.org:6696/#product-delivery"
|
||||
|
@ -117,7 +22,7 @@ paths:
|
|||
post:
|
||||
summary: Check authorization request
|
||||
description: |
|
||||
Are those `principals` allowed to perform this `action` on this `resource` in this `context`?
|
||||
Are those ``principals`` allowed to perform this ``action`` on this ``resource`` in this ``context``?
|
||||
|
||||
With authentication enabled, the principals are either read from the Identity Provider user info endpoint or directly from the JSON Web Token payload
|
||||
if an ID token is provided.
|
||||
|
@ -132,13 +37,13 @@ paths:
|
|||
name: Origin
|
||||
type: string
|
||||
description: |
|
||||
The service identifier (eg. `https://api.service.org`). It must match one of the known service from the policies files.
|
||||
The service identifier (eg. ``https://api.service.org``). It must match one of the known service from the policies files.
|
||||
|
||||
- in: header
|
||||
name: Authorization
|
||||
type: string
|
||||
description: |
|
||||
With OpenID enabled, a valid Access token (or JSON Web ID Token) must be provided in the `Authorization` request header.
|
||||
With OpenID enabled, a valid Access token (or JSON Web ID Token) must be provided in the ``Authorization`` request header.
|
||||
(eg. `Bearer eyJ0eXAiOiJKV1QiLCJhbG...9USXpOalEzUXpV`)
|
||||
|
||||
- in: body
|
||||
|
@ -155,22 +60,22 @@ paths:
|
|||
description: |
|
||||
**Only without authentication**
|
||||
|
||||
Arbitrary list of strings (eg. `userid:alice`, `group:editors`).
|
||||
Arbitrary list of strings (eg. ``userid:alice``, ``group:editors``).
|
||||
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
action:
|
||||
description: Any domain specific action (eg. `read`, `delete`, `signoff`)
|
||||
description: Any domain specific action (eg. ``read``, ``delete``, ``signoff``)
|
||||
type: string
|
||||
resource:
|
||||
description: Any resource (eg. `blocklist`, `/update/rules/35`)
|
||||
description: Any resource (eg. ``blocklist``, ``rules-<.*>``)
|
||||
type: string
|
||||
context:
|
||||
description: |
|
||||
The context can contain any extra information to be matched in policies conditions.
|
||||
The context field `remoteIP` will be forced by the server.
|
||||
The values provided in the `roles` context field will expand the principals with extra `role:{}` values.
|
||||
The context field ``remoteIP`` will be forced by the server.
|
||||
The values provided in the ``roles`` context field will expand the principals with extra ``role:{}`` values.
|
||||
|
||||
type: object
|
||||
properties:
|
||||
|
@ -196,7 +101,7 @@ paths:
|
|||
message:
|
||||
type: string
|
||||
example:
|
||||
message: Missing `Origin` request header
|
||||
message: Missing ``Origin`` request header
|
||||
"401":
|
||||
description: "OpenID token is invalid."
|
||||
"200":
|
||||
|
@ -220,7 +125,7 @@ paths:
|
|||
post:
|
||||
summary: "Reload the policies"
|
||||
description: |
|
||||
Reload the policies (synchronously). This endpoint is meant to be used as a Web hook when policies files were changed.
|
||||
Reload the policies (synchronously). This endpoint is meant to be used as a Web hook when policies files were changed upstream.
|
||||
|
||||
> It would be wise to limit the access to this endpoint (e.g. by IP on reverse proxy)
|
||||
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
.. _api:
|
||||
|
||||
API
|
||||
===
|
||||
|
||||
Summary
|
||||
-------
|
||||
|
||||
Basically, authorization requests are checked using **POST /allowed**.
|
||||
|
||||
* The ``Origin`` request header specifies the service to match policies from.
|
||||
* The ``Authorization`` request header provides the OpenID :term:`Access Token` to authenticate the request.
|
||||
|
||||
**Request**:
|
||||
|
||||
.. code-block:: HTTP
|
||||
|
||||
POST /allowed HTTP/1.1
|
||||
Origin: https://api.service.org
|
||||
Authorization: Bearer f2457yu86yikhmbh
|
||||
|
||||
{
|
||||
"action" : "delete",
|
||||
"resource": "articles/doorman-introduce",
|
||||
}
|
||||
|
||||
**Response**:
|
||||
|
||||
.. code-block:: HTTP
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"allowed": true,
|
||||
"principals": [
|
||||
"userid:ada",
|
||||
"email:ada.lovelace@eff.org",
|
||||
"group:scientists",
|
||||
"group:history"
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Principals
|
||||
----------
|
||||
|
||||
The authorization request :term:principals will be built from the user profile information like this:
|
||||
|
||||
* ``"sub"``: ``userid:{}``
|
||||
* ``"email"``: ``email:{}`` (*optional*)
|
||||
* ``"groups"``: ``group:{}, group:{}, ...`` (*optional*)
|
||||
|
||||
They will be matched against those specified in the policies rules to determine if the authorization request is denied or allowed.
|
||||
|
||||
|
||||
Authentication
|
||||
--------------
|
||||
|
||||
*Doorman* relies on OpenID to authenticate requests.
|
||||
|
||||
It will use the ``service`` and ``identityProvider`` fields from the service policies file to fetch the user profile information.
|
||||
|
||||
The ``Origin`` request header should match one of the services defined in the policies files.
|
||||
|
||||
The ``Authorization`` request header should contain a valid :term:`Access Token`, prefixed with ``Bearer ``.
|
||||
This access token must have been requested with the ``openid profile`` scope for *Doorman* to be able to fetch the profile information (See `Auth0 docs <https://auth0.com/docs/tokens/access-token#access-token-format>`_).
|
||||
|
||||
The userinfo URI endpoint is then obtained from the metadata available at ``{identityProvider}/.well-known/openid-configuration``.
|
||||
|
||||
If the obtention of user infos is denied by the :term:`Identity Provider`, the authorization request is obviously denied.
|
||||
|
||||
|
||||
Using ID tokens
|
||||
'''''''''''''''
|
||||
|
||||
*Doorman* can verify and read user information from JWT :term:`ID tokens`. Since the ID token payload contains the user information, it saves a roundtrip to the Identity Provider when handling authorization requests.
|
||||
|
||||
For this to work, the ``service`` value in the policies file must match the ``audience`` value configured on the Identity Provider — the unique identifier of the target API. For example, in `Auth0 <https://auth0.com>`_ it can look like this: ``SLocf7Sa1ibd5GNJMMqO539g7cKvWBOI``.
|
||||
|
||||
.. important::
|
||||
|
||||
When using JWT :term:`ID tokens`, only the validity of the token will be checked. In other words, users that are revoked from the Identity Provider after their ID token was issued will still considered authenticated until the token expires.
|
||||
|
||||
|
||||
Without authentication
|
||||
''''''''''''''''''''''
|
||||
|
||||
If the identity provider is not configured for a service (explicit empty value), no authentication is required and the principals are posted in the authorization body.
|
||||
|
||||
.. code-block:: HTTP
|
||||
|
||||
POST /allowed HTTP/1.1
|
||||
Origin: https://api.service.org
|
||||
Authorization: Bearer f2457yu86yikhmbh
|
||||
|
||||
{
|
||||
"action" : "delete",
|
||||
"resource": "articles/doorman-introduce",
|
||||
"principals": [
|
||||
"userid:mickaeljfox",
|
||||
"email:mj@fox.com",
|
||||
"group:actors"
|
||||
]
|
||||
}
|
||||
|
||||
It is not especially recommended, but it can give a certain amount of flexibility when authentication is fully managed on the service.
|
||||
|
||||
A typical workflow in this case would be:
|
||||
|
||||
1. Users call the service API endpoint
|
||||
1. The service authenticates the user and builds the list of principals
|
||||
1. The service posts an authorization request on *Doorman* containing the list of principals to check if the user is allowed
|
||||
|
||||
|
||||
.. _api-context:
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
Authorization requests can carry additional information contain any extra information to be matched in :ref:`policies conditions <policies-conditions>`.
|
||||
|
||||
The values provided in the ``roles`` context field will expand the principals with extra ``role:{}`` values.
|
||||
|
||||
.. code-block:: HTTP
|
||||
|
||||
POST /allowed HTTP/1.1
|
||||
Origin: https://api.service.org
|
||||
Authorization: Bearer f2457yu86yikhmbh
|
||||
|
||||
{
|
||||
"action" : "delete",
|
||||
"resource": "articles/doorman-introduce",
|
||||
"context": {
|
||||
"env", "stage",
|
||||
"roles": ["editor"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
API Endpoints
|
||||
-------------
|
||||
|
||||
(Automatically generated from `the OpenAPI specs <https://github.com/mozilla/doorman/blob/master/api/openapi.yaml>`_)
|
||||
|
||||
.. openapi:: ../api/openapi.yaml
|
|
@ -0,0 +1,176 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Doorman documentation build configuration file, created by
|
||||
# sphinx-quickstart on Tue Jan 30 15:41:49 2018.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- Custom
|
||||
|
||||
from recommonmark.parser import CommonMarkParser
|
||||
|
||||
source_parsers = {
|
||||
'.md': CommonMarkParser,
|
||||
}
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinxcontrib.openapi',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
source_suffix = ['.rst', '.md']
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Doorman'
|
||||
copyright = u'2018, Mozilla'
|
||||
author = u'Mozilla'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = u'1.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'1.0.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'alabaster'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# This is required for the alabaster theme
|
||||
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
|
||||
html_sidebars = {
|
||||
'**': [
|
||||
'relations.html', # needs 'show_related': True theme option to display
|
||||
'searchbox.html',
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'Doormandoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'Doorman.tex', u'Doorman Documentation',
|
||||
u'Mozilla', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'doorman', u'Doorman Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'Doorman', u'Doorman Documentation',
|
||||
author, 'Doorman', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 238 KiB |
|
@ -0,0 +1,50 @@
|
|||
Welcome to Doorman's documentation!
|
||||
===================================
|
||||
|
||||
.. image:: logo.svg
|
||||
|
||||
*Doorman* is an **authorization micro-service** that allows to checks if an arbitrary subject is allowed to perform an action on a resource, based on a set of rules (policies).
|
||||
|
||||
Having a centralized access control service has several advantages:
|
||||
|
||||
- it clearly dissociates authentication from authorization
|
||||
- it provides a standard and generic permissions system to services developers
|
||||
- it facilitates permissions management across services (eg. makes revocation easier)
|
||||
- it allows authorizations monitoring, metrics, anomaly detection
|
||||
|
||||
|
||||
Workflow
|
||||
========
|
||||
|
||||
.. image:: flow.png
|
||||
|
||||
It relies on `OpenID Connect <https://en.wikipedia.org/wiki/OpenID_Connect>`_ to authenticate requests. The policies are defined per service and loaded in memory. Authorization requests are logged out.
|
||||
|
||||
When a service takes advantage of *Doorman*, a typical workflow is:
|
||||
|
||||
#. Users obtain an access token from an Identity Provider (eg. Auth0)
|
||||
#. They use it to call a service API endpoint
|
||||
#. The service posts an authorization request on *Doorman* to check if the user is allowed to perform a specific action
|
||||
#. *Doorman* uses the ``Origin`` request header to select the set of policies to match
|
||||
#. *Doorman* fetches the user infos using the provided access token and builds a list of strings (*principals*) to characterize this user
|
||||
#. *Doorman* matches the policies and returns if allowed or not, along with the list of principals
|
||||
#. Based on the *Doorman* response, the service denies the original request or executes it
|
||||
|
||||
|
||||
Contents
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
quickstart
|
||||
policies
|
||||
api
|
||||
misc
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
До Ширина: | Высота: | Размер: 5.7 KiB После Ширина: | Высота: | Размер: 5.7 KiB |
|
@ -0,0 +1,104 @@
|
|||
Misc
|
||||
====
|
||||
|
||||
.. _misc-run-source:
|
||||
|
||||
Run from source
|
||||
---------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
make serve -e "POLICIES=sample.yaml /etc/doorman"
|
||||
|
||||
|
||||
Run tests
|
||||
---------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
make test
|
||||
|
||||
|
||||
Generate API docs
|
||||
-----------------
|
||||
|
||||
We use `Sphinx <http://www.sphinx-doc.org>`_, therefore the Python ``virtualenv`` command is required.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
make docs
|
||||
|
||||
|
||||
Build docker container
|
||||
----------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
make docker-build
|
||||
|
||||
|
||||
Advanced settings
|
||||
-----------------
|
||||
|
||||
* ``PORT``: listen (default: ``8080``)
|
||||
* ``GIN_MODE``: server mode (``release`` or default ``debug``)
|
||||
* ``LOG_LEVEL``: logging level (``fatal|error|warn|info|debug``, default: ``info`` with ``GIN_MODE=release`` else ``debug``)
|
||||
* ``VERSION_FILE``: location of JSON file with version information (default: ``./version.json``)
|
||||
|
||||
|
||||
Frequently Asked Questions
|
||||
--------------------------
|
||||
|
||||
Why did you do this like that?
|
||||
''''''''''''''''''''''''''''''
|
||||
|
||||
If something puzzles you, looks bad, or is not crystal clear, we would really appreciate your feedback! Please `file an issue <https://github.com/mozilla/doorman/issues>`_! — yes, even if you feel uncertain :)
|
||||
|
||||
|
||||
Why should I use Doorman?
|
||||
'''''''''''''''''''''''''
|
||||
|
||||
*Doorman* saves you the burden of implementing a fined-grained permission system into your service. Plus, it can centralize and track authorizations accross multiple services, which makes permissions management a lot easier.
|
||||
|
||||
|
||||
How is it different than OpenID servers (like Hydra, etc.)?
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
*Doorman* is not responsible of managing users. It relies on an Identity Provider to authenticate requests and focuses on authorization.
|
||||
|
||||
|
||||
What is the difference with my Identity Provider authorizations?
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
Identity Providers may have some authorization/permissions system that allow to restrict access using user groups, audience and scopes.
|
||||
|
||||
This kind of access control is global for the whole service. *Doorman* provides advanced policies rules that can be matched per action, resource, or any domain specific context.
|
||||
|
||||
|
||||
Why YAML?
|
||||
'''''''''
|
||||
|
||||
Policies files are meant to be edited or at least reviewed by humans. And YAML is relatively human-friendly.
|
||||
Plus, YAML allows to add comments.
|
||||
|
||||
|
||||
Glossary
|
||||
--------
|
||||
|
||||
.. glossary::
|
||||
|
||||
Identity Provider
|
||||
An identity provider (abbreviated IdP) is a service in charge of managing identity information, and providing authentication endpoints (login forms, tokens manipulation etc.)
|
||||
|
||||
Access Token
|
||||
Access Tokens
|
||||
An access token is an opaque string that is issued by the Identity Provider.
|
||||
|
||||
ID Token
|
||||
ID Tokens
|
||||
The ID token is a JSON Web Token (JWT) that contains user profile information (like the user's name, email, and so forth), represented in the form of claims.
|
||||
|
||||
Principal
|
||||
Principals
|
||||
In *Doorman*, the *principals* is the list of strings that characterize a user. It is built from the user information, tags from the policies file and roles from the authorization request. (see `Wikipedia <https://en.wikipedia.org/wiki/Principal_(computer_security)>`_)
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
Policies
|
||||
========
|
||||
|
||||
Policies are defined in YAML files for each consuming service as follow:
|
||||
|
||||
.. code-block:: YAML
|
||||
|
||||
service: https://service.stage.net
|
||||
identityProvider: https://auth.mozilla.auth0.com/
|
||||
tags:
|
||||
superusers:
|
||||
- userid:maria
|
||||
- group:admins
|
||||
policies:
|
||||
-
|
||||
id: authors-superusers-delete
|
||||
description: Authors and superusers can delete articles
|
||||
principals:
|
||||
- role:author
|
||||
- tag:superusers
|
||||
actions:
|
||||
- delete
|
||||
resources:
|
||||
- article
|
||||
effect: allow
|
||||
|
||||
- **service**: the unique identifier of the service
|
||||
- **identityProvider** (*optional*): when the identify provider is not empty, *Doorman* will verify the Access Token or the ID Token provided in the authorization header to authenticate the request and obtain the subject profile information (*principals*)
|
||||
- **tags**: Local «groups» of principals in addition to the ones provided by the Identity Provider
|
||||
- **actions**: a domain-specific string representing an action that will be defined as allowed by a principal (eg. ``publish``, ``signoff``, …)
|
||||
- **resources**: a domain-specific string representing a resource. Preferably not a full URL to decouple from service API design (eg. `print:blackwhite:A4`, `category:homepage`, …).
|
||||
- **effect**: Use ``effect: deny`` to deny explicitly. Requests that don't match any rule are denied.
|
||||
|
||||
|
||||
Settings
|
||||
--------
|
||||
|
||||
Policies can be read locally or in remote (private) Github repos.
|
||||
|
||||
Settings are set via environment variables:
|
||||
|
||||
* ``POLICIES``: space separated locations of YAML files with policies. They can be **single files**, **folders** or **Github URLs** (default: ``./policies.yaml``)
|
||||
* ``GITHUB_TOKEN``: Github API token to be used when fetching policies files from private repositories
|
||||
|
||||
.. note::
|
||||
|
||||
The ``Dockerfile`` contains different default values, suited for production.
|
||||
|
||||
|
||||
Principals
|
||||
----------
|
||||
|
||||
The principals is a list of prefixed strings to refer to the «user» as the combination of ids, emails, groups, roles…
|
||||
|
||||
Supported prefixes:
|
||||
|
||||
* ``userid:``: provided by Identity Provider (IdP)
|
||||
* ``tag:``: local tags from policies file
|
||||
* ``role:``: provided in :ref:`context of authorization requests <api-context>`
|
||||
* ``email:``: provided by IdP
|
||||
* ``group:``: provided by IdP
|
||||
|
||||
Example: ``["userid:ldap|user", "email:user@corp.com", "group:Employee", "group:Admins", "role:editor"]``
|
||||
|
||||
|
||||
Advanced policies rules
|
||||
-----------------------
|
||||
|
||||
Regular expressions
|
||||
'''''''''''''''''''
|
||||
|
||||
Regular expressions begin with ``<`` and end with ``>``.
|
||||
|
||||
.. code-block:: YAML
|
||||
|
||||
principals:
|
||||
- userid:<[peter|ken]>
|
||||
resources:
|
||||
- /page/<.*>
|
||||
|
||||
.. note::
|
||||
|
||||
Regular expressions are not supported in tags members definitions.
|
||||
|
||||
.. _policies-conditions:
|
||||
|
||||
Conditions
|
||||
''''''''''
|
||||
|
||||
The conditions are **optional** on policies and are used to match field values from the :ref:`authorization request context <api-context>`.
|
||||
|
||||
The context value ``remoteIP`` is forced by the server.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: YAML
|
||||
|
||||
policies:
|
||||
-
|
||||
description: Allow everything from dev environment
|
||||
conditions:
|
||||
env:
|
||||
type: StringEqualCondition
|
||||
options:
|
||||
equals: dev
|
||||
|
||||
There are several types of conditions:
|
||||
|
||||
**Field comparison**
|
||||
|
||||
* type: ``StringEqualCondition``
|
||||
|
||||
For example, match ``request.context["country"] == "catalunya"``:
|
||||
|
||||
.. code-block:: YAML
|
||||
|
||||
conditions:
|
||||
country:
|
||||
type: StringEqualCondition
|
||||
options:
|
||||
equals: catalunya
|
||||
|
||||
**Field pattern**
|
||||
|
||||
* type: ``StringMatchCondition``
|
||||
|
||||
For example, match ``request.context["bucket"] ~= "blocklists-.*"``:
|
||||
|
||||
.. code-block:: YAML
|
||||
|
||||
conditions:
|
||||
bucket:
|
||||
type: StringMatchCondition
|
||||
options:
|
||||
matches: blocklists-.*
|
||||
|
||||
**Match principals**
|
||||
|
||||
* type: ``MatchPrincipalsCondition``
|
||||
|
||||
For example, allow requests where ``request.context["owner"]`` is in principals:
|
||||
|
||||
.. code-block:: YAML
|
||||
|
||||
conditions:
|
||||
owner:
|
||||
type: MatchPrincipalsCondition
|
||||
|
||||
.. note::
|
||||
|
||||
This also works when a the context field is list (e.g. list of collaborators).
|
||||
|
||||
**IP/Range**
|
||||
|
||||
* type: ``CIDRCondition``
|
||||
|
||||
For example, match ``request.context["remoteIP"]`` with [CIDR notation](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation):
|
||||
|
||||
.. code-block:: YAML
|
||||
|
||||
conditions:
|
||||
remoteIP:
|
||||
type: CIDRCondition
|
||||
options:
|
||||
# mask 255.255.0.0
|
||||
cidr: 192.168.0.1/16
|
|
@ -0,0 +1,63 @@
|
|||
Quickstart
|
||||
==========
|
||||
|
||||
Policies
|
||||
--------
|
||||
|
||||
Policies are defined in YAML files for each consuming service, locally or in remote (private) Github repos, as follow:
|
||||
|
||||
.. code-block:: YAML
|
||||
|
||||
service: https://api.service.org
|
||||
identityProvider: https://api.auth0.com/
|
||||
policies:
|
||||
- id: alice-bob-create-keys
|
||||
description: Alice and Bob can create keys
|
||||
principals:
|
||||
- userid:alice
|
||||
- userid:bob
|
||||
actions:
|
||||
- create
|
||||
resources:
|
||||
- key
|
||||
effect: allow
|
||||
-
|
||||
id: crud-articles
|
||||
description: Editors can CRUD articles
|
||||
principals:
|
||||
- role:editor
|
||||
actions:
|
||||
- create
|
||||
- read
|
||||
- delete
|
||||
- update
|
||||
resources:
|
||||
- article
|
||||
effect: allow
|
||||
|
||||
Save it to ``config/api-policies.yaml`` for example.
|
||||
|
||||
Run
|
||||
---
|
||||
|
||||
*Doorman* is available as a Docker image (but can also be :ref:`ran from source <misc-run-source>`).
|
||||
|
||||
In order to read the local files from the container, we will mount the local ``config`` folder to ``/config``.
|
||||
We'll then use ``/config`` as the ``POLICIES`` location.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run \
|
||||
-e POLICIES=/config \
|
||||
-v ./config:/config \
|
||||
-p 8000:8080 \
|
||||
--name doorman \
|
||||
mozilla/doorman
|
||||
|
||||
*Doorman* is now ready to respond authorization requests on `http://localhost:8080`. See :ref:`API docs <api>`!
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
See the `examples folder <https://github.com/mozilla/doorman/tree/master/examples>`_ on Github.
|
|
@ -0,0 +1,3 @@
|
|||
sphinx
|
||||
sphinxcontrib-openapi
|
||||
recommonmark
|
Загрузка…
Ссылка в новой задаче