zuul/doc/source/discussion/tenant-scoped-rest-api.rst

132 lines
4.5 KiB
ReStructuredText

:title: Tenant Scoped REST API
.. _tenant-scoped-rest-api:
Tenant Scoped REST API
======================
Users can perform some privileged actions at the tenant level through protected
endpoints of the REST API, if these endpoints are activated.
The supported actions are **autohold**, **enqueue/enqueue-ref**,
**dequeue/dequeue-ref** and **promote**. These are similar to the ones available
through Zuul's CLI.
The protected endpoints require a bearer token, passed to Zuul Web Server as the
**Authorization** header of the request. The token and this workflow follow the
JWT standard as established in this `RFC <https://tools.ietf.org/html/rfc7519>`_.
Important Security Considerations
---------------------------------
Anybody with a valid token can perform privileged actions exposed
through the REST API. Furthermore revoking tokens, especially when manually
issued, is not trivial.
As a mitigation, tokens should be generated with a short time to
live, like 10 minutes or less. If the token contains authorization Information
(see the ``zuul.admin`` claim below), it should be generated with as little a scope
as possible (one tenant only) to reduce the surface of attack should the
token be compromised.
Exposing administration tasks can impact build results (dequeue-ing buildsets),
and pose potential resources problems with Nodepool if the ``autohold`` feature
is abused, leading to a significant number of nodes remaining in "hold" state for
extended periods of time. As always, "with great power comes great responsibility"
and tokens should be handed over with discernment.
Configuration
-------------
To enable tenant-scoped access to privileged actions, see the Zuul Web Server
component's section.
To set access rules for a tenant, see :ref:`the documentation about tenant
definition <admin_rule_definition>`.
Most of the time, only one authenticator will be needed in Zuul's configuration;
namely the configuration matching a third party identity provider service like
dex, auth0, keycloak or others. It can be useful however to add another
authenticator similar to this one:
.. code-block:: ini
[auth zuul_operator]
driver=HS256
allow_authz_override=true
realm=zuul.example.com
client_id=zuul.example.com
issuer_id=zuul_operator
secret=exampleSecret
With such an authenticator, a Zuul operator can use Zuul's CLI to
issue tokens overriding a tenant's access rules if need
be. A user can then use these tokens with Zuul's CLI to perform protected actions
on a tenant temporarily, without having to modify a tenant's access rules.
.. _jwt-format:
JWT Format
----------
Zuul can consume JWTs with the following minimal set of claims:
.. code-block:: javascript
{
'iss': 'jwt_provider',
'aud': 'my_zuul_deployment',
'exp': 1234567890,
'iat': 1234556780,
'sub': 'alice'
}
* **iss** is the issuer of the token. It can be used to filter
Identity Providers.
* **aud**, as the intended audience, is usually the client id as registered on
the Identity Provider.
* **exp** is the token's expiry timestamp.
* **iat** is the token's date of issuance timestamp.
* **sub** is the default, unique identifier of the user.
JWTs can be extended arbitrarily with other claims. Zuul however can look for a
specific **zuul** claim, if the ``allow_authz_override`` option was set to True
in the authenticator's configuration. This claim has the following format:
.. code-block:: javascript
{
'zuul': {
'admin': ['tenant-one', 'tenant-two']
}
}
The **admin** field is a list of tenants on which the token's bearer is granted
the right to perform privileged actions.
Manually Generating a JWT
-------------------------
An operator can generate a JWT by using the settings of a configured authenticator
in ``zuul.conf``.
For example, in Python, and for an authenticator using the ``HS256`` algorithm:
.. code-block:: python
>>> import jwt
>>> import time
>>> jwt.encode({'sub': 'user1',
'iss': <issuer_id>,
'aud': <client_id>,
'iat': time.time(),
'exp': time.time() + 300,
'zuul': {
'admin': ['tenant-one']
}
}, <secret>, algorithm='HS256')
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ6dXVsIjp7ImFkbWluIjpbInRlbmFudC1vbmUiXX0sInN1YiI6InZlbmttYW4iLCJpc3MiOiJtYW51YWwiLCJleHAiOjE1NjAzNTQxOTcuMTg5NzIyLCJpYXQiOjE1NjAzNTM4OTcuMTg5NzIxLCJhdWQiOiJ6dXVsIn0.Qqb-ANmYv8slNUVSqjCJDL8HlH9L7nnLtLU2HBGzQJk'
Online resources like https://jwt.io are also available to generate, decode and
debug JWTs.