2021-02-19 20:23:07 +00:00
|
|
|
---
|
|
|
|
authors: Andrej Tokarčík (andrej@goteleport.com)
|
|
|
|
state: draft
|
|
|
|
---
|
|
|
|
|
|
|
|
# RFD 16 - Dynamic Configuration
|
|
|
|
|
|
|
|
## What
|
|
|
|
|
|
|
|
This RFD presents several possible scenarios involving the interaction of
|
2021-03-29 13:28:52 +00:00
|
|
|
explicitly-managed dynamic and static configuration. Design decisions are made
|
|
|
|
as to which branches of these scenarios are to be supported by Teleport.
|
|
|
|
Finally, the actual implementation is discussed.
|
2021-02-19 20:23:07 +00:00
|
|
|
|
|
|
|
## Why
|
|
|
|
|
2021-06-04 20:29:31 +00:00
|
|
|
Some resources like `types.AuthPreference` or `services.ClusterConfig` are
|
2021-03-29 13:28:52 +00:00
|
|
|
live representations of parts of the `auth_service` configuration section.
|
|
|
|
These resources can be understood to constitute *dynamic* configuration of
|
|
|
|
an auth server, as opposed to *static* configuration defined by the
|
|
|
|
`teleport.yaml` file.
|
|
|
|
|
|
|
|
The current behaviour is that Teleport creates dynamic configuration implicitly
|
|
|
|
by deriving it from static configuration during auth server initialization.
|
|
|
|
This RFD allows the dynamic configuration to be created/updated explicitly via
|
|
|
|
`tctl`, independently of static configuration, for two main reasons:
|
|
|
|
|
|
|
|
1. To faciliate automated/programmatic management of Teleport clusters.
|
2021-02-19 20:23:07 +00:00
|
|
|
|
2021-03-29 13:28:52 +00:00
|
|
|
2. To add configuration capability to Teleport-as-a-service offerings that do
|
|
|
|
not allow direct access to `teleport.yaml` files.
|
2021-02-19 20:23:07 +00:00
|
|
|
|
|
|
|
## Scenarios
|
|
|
|
|
|
|
|
We use the example of the `authentication` subsection of `auth_service`
|
|
|
|
in `teleport.yaml` (as "the" static configuration) and the corresponding
|
2021-06-04 20:29:31 +00:00
|
|
|
resource `types.AuthPreference` (as "the" dynamic configuration).
|
2021-02-19 20:23:07 +00:00
|
|
|
The latter is assumed to be manipulable via `tctl` using the identifier `cap`.
|
|
|
|
|
|
|
|
### Scenario 1: static configuration specified
|
|
|
|
|
|
|
|
1. The `authentication` section is specified in `teleport.yaml`.
|
|
|
|
The backend can have any `AuthPreference` data stored from the last
|
|
|
|
auth server run.
|
|
|
|
|
|
|
|
2. The auth server initialization procedure MUST commit data derived from the
|
|
|
|
static configuration to the backend, overwriting any potential resource data
|
|
|
|
already stored there.
|
|
|
|
|
|
|
|
3. `tctl get cap` returns the resource data in line with `teleport.yaml`.
|
|
|
|
|
|
|
|
Therefore, static configuration is always given precedence. This should also
|
|
|
|
ensure backward compatibility with the already established workflows.
|
|
|
|
|
|
|
|
### Scenario 2: static never specified & dynamic not updated by user
|
|
|
|
|
|
|
|
1. The `authentication` section has never been specified in `teleport.yaml`.
|
|
|
|
No user changes have been made to the dynamic configuration.
|
|
|
|
|
|
|
|
2. The auth server initialization procedure MAY or MAY NOT commit the default
|
|
|
|
settings to the backend (in the latter case a structure holding the default
|
|
|
|
settings is returned in place of the missing resource when the resource
|
|
|
|
is requested).
|
|
|
|
|
|
|
|
#### Choice 2.A
|
|
|
|
|
|
|
|
In this option, dynamic-configuration resources are understood to exist only
|
|
|
|
if they have been committed as a result of having been specified in static
|
|
|
|
configuration or via `tctl create`.
|
|
|
|
|
|
|
|
3. The command `tctl get cap` would therefore return an error saying
|
|
|
|
"authentication preference not found". To view the default state, `tctl
|
|
|
|
get` would have to be invoked with a new CLI flag.
|
|
|
|
|
|
|
|
#### Choice 2.B
|
|
|
|
|
|
|
|
3. `tctl get cap` returns the resource data corresponding to the default
|
|
|
|
settings.
|
|
|
|
|
|
|
|
### Scenario 3: static reverted to unspecified & dynamic not updated by user
|
|
|
|
|
|
|
|
1. The `authentication` section used to be specified in `teleport.yaml` but
|
|
|
|
it has been removed and left unspecified since the last auth server init.
|
|
|
|
No user changes have been made to the dynamic configuration.
|
|
|
|
|
|
|
|
#### Choice 3.A
|
|
|
|
|
|
|
|
2. The auth server initialization procedure retains the last stored dynamic
|
|
|
|
configuration which had been derived from the last specified static
|
|
|
|
configuration. In particular, the backend MUST NOT be overwritten
|
|
|
|
with the default settings.
|
|
|
|
|
|
|
|
3. `tctl get cap` returns the resource data corresponding to the last specified
|
|
|
|
static configuration.
|
|
|
|
|
|
|
|
#### Choice 3.B
|
|
|
|
|
|
|
|
2. The auth server initialization procedure MUST NOT retain the last stored
|
|
|
|
dynamic configuration. The resource data are either overwritten with the
|
|
|
|
default settings or deleted (in the latter case a structure holding the
|
|
|
|
default settings is returned in place of the missing resource when the
|
|
|
|
resource is requested).
|
|
|
|
|
|
|
|
3. `tctl get cap` then behaves as in Scenario 2.
|
|
|
|
|
|
|
|
### Scenario 4: static never specified & first `tctl create`
|
|
|
|
|
|
|
|
1. The `authentication` section has never been specified in `teleport.yaml`.
|
|
|
|
No user changes have been made to the dynamic configuration.
|
|
|
|
|
|
|
|
2. A user issues the command `tctl create authpref.yaml` with valid
|
|
|
|
authentication preferences stored in the YAML file.
|
|
|
|
(Issuing `tctl create -f authpref.yaml` would have the same effect.)
|
|
|
|
|
|
|
|
3. The dynamic configuration is updated: the resource data read from
|
|
|
|
`authpref.yaml` MUST be written to the backend (potentially overwriting
|
|
|
|
the default data already stored there).
|
|
|
|
|
|
|
|
4. The command returns with success.
|
|
|
|
|
|
|
|
5. Upon the next auth server restart with `authentication` still unspecified
|
|
|
|
in `teleport.yaml`, the auth server initialization procedure retains
|
|
|
|
the last stored dynamic configuration, i.e. the one from `authpref.yaml`.
|
|
|
|
|
|
|
|
6. `tctl get cap` returns the resource data corresponding to `authpref.yaml`.
|
|
|
|
|
|
|
|
### Scenario 5: static never specified & repeated `tctl create`
|
|
|
|
|
|
|
|
1. The `authentication` section has never been specified in `teleport.yaml`.
|
|
|
|
A user has already made explicit changes to the dynamic configuration
|
|
|
|
using `tctl create`.
|
|
|
|
|
|
|
|
2. A user issues the command `tctl create authpref.yaml` with valid
|
|
|
|
authentication preferences stored in the YAML file.
|
|
|
|
|
|
|
|
#### Choice 5.A
|
|
|
|
|
|
|
|
3. The command is rejected with an "already exists" error, recommending
|
|
|
|
to use the `-f`/`--force` flag to overwrite the already existing
|
|
|
|
`AuthPreference` resource.
|
|
|
|
|
|
|
|
#### Choice 5.B
|
|
|
|
|
|
|
|
3. The command is accepted and returns with success.
|
|
|
|
|
|
|
|
### Scenario 6: static specified & `tctl create` attempt
|
|
|
|
|
|
|
|
1. The `authentication` section is specified in `teleport.yaml`.
|
|
|
|
The auth server is running with static configuration as in Scenario 1.
|
|
|
|
|
|
|
|
2. `tctl create authpref.yaml` returns with an error since the command
|
|
|
|
cannot be used to overwrite non-default configuration.
|
|
|
|
|
|
|
|
#### Choice 6.A
|
|
|
|
|
|
|
|
3. `tctl create -f authpref.yaml` allows the user to temporarily set the
|
|
|
|
dynamic configuration until it gets replaced by the static configuration
|
|
|
|
during a restart as in Scenario 1. In case the static configuration section
|
|
|
|
is removed before the restart, the dynamic configuration corresponding to
|
|
|
|
`authpref.yaml` is retained.
|
|
|
|
|
|
|
|
#### Choice 6.B
|
|
|
|
|
|
|
|
3. `tctl create -f authpref.yaml` is rejected as it constitutes a security
|
|
|
|
risk and may cause consistency issues in HA environments.
|
|
|
|
|
|
|
|
## Configuration source preferred by auth server init
|
|
|
|
|
|
|
|
The following table summarily depicts a key aspect of the scenarios elaborated
|
|
|
|
above, namely the question of which configuration source is to be preferred by the
|
|
|
|
auth server initialization procedure:
|
|
|
|
|
|
|
|
| | **dynamic updated by user** | **dynamic not updated by user** |
|
|
|
|
| :---: | :---: | :---: |
|
|
|
|
| **static specified** | static | static |
|
|
|
|
| **static unspecified** | dynamic | defaults OR last static [?] |
|
|
|
|
|
|
|
|
(The state marked [?] depends on the resolution of Scenario 3.)
|
|
|
|
|
|
|
|
## Implementation
|
|
|
|
|
2021-04-12 17:57:37 +00:00
|
|
|
The resource label `teleport.dev/origin` (below shortened to `origin` for
|
|
|
|
brevity) is used as the key indicator when determining the configuration
|
|
|
|
sources and their precedence.
|
2021-02-19 20:23:07 +00:00
|
|
|
|
2021-04-12 17:57:37 +00:00
|
|
|
The label can be associated with three values:
|
2021-02-19 20:23:07 +00:00
|
|
|
|
2021-04-12 17:57:37 +00:00
|
|
|
1. `defaults`: for hard-coded resource objects consisting of default settings;
|
|
|
|
2. `config-file`: for resource objects derived from static configuration;
|
|
|
|
3. `dynamic`: for resource objects created "dynamically" (e.g. via `tctl`).
|
2021-02-19 20:23:07 +00:00
|
|
|
|
|
|
|
The following table captures the ordinary means of performing the "fastest"
|
|
|
|
transition between a pair of `origin` values. The leftmost column is the
|
|
|
|
current/source `origin` value of a resource while the top row is the
|
|
|
|
desired/target `origin` value:
|
|
|
|
|
2021-04-12 17:57:37 +00:00
|
|
|
| *from \ to* | **`defaults`** | **`config-file`** | **`dynamic`** |
|
2021-02-19 20:23:07 +00:00
|
|
|
| :---: | :---: | :---: | :---: |
|
|
|
|
| **`defaults`** | n/a | specify in `teleport.yaml` & restart | `tctl create` |
|
2021-03-29 13:28:52 +00:00
|
|
|
| **`config-file`** | remove from `teleport.yaml` | change in `teleport.yaml` & restart | `tctl create --force --confirm` |
|
2021-04-12 17:57:37 +00:00
|
|
|
| **`dynamic`** | `tctl rm` | specify in `teleport.yaml` & restart | `tctl create --force` |
|
2021-02-19 20:23:07 +00:00
|
|
|
|
2021-04-12 17:57:37 +00:00
|
|
|
The `teleport.dev/origin` label is reserved for system use. Resources derived
|
|
|
|
from `teleport.yaml` are necessarily labelled either as `defaults` (when the
|
|
|
|
relevant section is left unspecified) or as `config-file` (when the section is
|
|
|
|
explicitly specified). Auth server API handlers automatically disregard the
|
|
|
|
supplied `origin` value and reset it to `dynamic`.
|
2021-02-19 20:23:07 +00:00
|
|
|
|
|
|
|
### Auth server initialization
|
|
|
|
|
|
|
|
1. If `teleport.yaml` section is specified, store it as a resource in the
|
|
|
|
backend with `origin: config-file`.
|
|
|
|
|
|
|
|
2. If `teleport.yaml` section is not specified, attempt to fetch the resource
|
|
|
|
currently stored in the backend.
|
|
|
|
- If the fetching attempt fails with a not-found error, store the default
|
|
|
|
resource in the backend with `origin: defaults`.
|
|
|
|
- If the fetching attempt fails for another reason, return the error
|
|
|
|
immediately.
|
|
|
|
- If the fetched resource has `origin: config-file` or `origin: defaults`,
|
|
|
|
store the default resource in the backend with `origin: defaults`.
|
|
|
|
- If the fetched resource has another `origin` value, keep the backend as-is.
|
|
|
|
|
|
|
|
This logic implies Choices 2.B and 3.B.
|
|
|
|
|
|
|
|
### `tctl create`
|
|
|
|
|
|
|
|
1. Fetch the resource currently stored in the backend; on error return
|
|
|
|
immediately.
|
|
|
|
|
|
|
|
2. If called without `--force` and the fetched resource does not have
|
2021-03-29 13:28:52 +00:00
|
|
|
`origin: defaults` then print an error:
|
2021-02-19 20:23:07 +00:00
|
|
|
```
|
2021-03-29 13:28:52 +00:00
|
|
|
non-default cluster auth preference already exists, use -f or --force flag
|
|
|
|
to overwrite
|
2021-02-19 20:23:07 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
3. If called with `--force` and the fetched resource does not have `origin:
|
|
|
|
config-file` then store the resource specified in the provided YAML file
|
|
|
|
in the backend.
|
|
|
|
|
|
|
|
4. If called with `--force` and the fetched resource has `origin: config-file`
|
2021-03-29 13:28:52 +00:00
|
|
|
then print an error:
|
2021-02-19 20:23:07 +00:00
|
|
|
```
|
2021-03-29 13:28:52 +00:00
|
|
|
This resource is managed by static configuration. We recommend removing
|
|
|
|
configuration from teleport.yaml, restarting the servers and trying this
|
|
|
|
command again.
|
2021-02-19 20:23:07 +00:00
|
|
|
|
2021-04-26 18:27:34 +00:00
|
|
|
If you would still like to proceed, re-run the command with both --force and
|
2021-02-19 20:23:07 +00:00
|
|
|
--confirm flags.
|
|
|
|
```
|
|
|
|
|
2021-03-29 13:28:52 +00:00
|
|
|
Invocation with both `--force` and `--confirm` will replace the
|
|
|
|
stored resource with the YAML one until the auth server restart.
|
2021-02-19 20:23:07 +00:00
|
|
|
|
|
|
|
This logic implies Choice 5.A and an adaptation of Choice 6.A.
|
2021-03-29 13:28:52 +00:00
|
|
|
|
|
|
|
### `tctl rm`
|
|
|
|
|
|
|
|
The `tctl rm` subcommand can be used to reset dynamic resources back to their defaults.
|
|
|
|
|
|
|
|
1. Fetch the resource currently stored in the backend; on error return
|
|
|
|
immediately.
|
|
|
|
|
|
|
|
2. If the fetched resource does not have `origin: config-file`, replace the
|
|
|
|
stored resource with the default one.
|
|
|
|
|
|
|
|
3. If the fetched resource has `origin: config-file` then print an error:
|
|
|
|
```
|
|
|
|
This resource is managed by static configuration. We recommend removing
|
|
|
|
configuration from teleport.yaml and restarting the servers in order to
|
|
|
|
reset the resource to its default.
|
|
|
|
```
|
2021-04-27 13:43:34 +00:00
|
|
|
|
|
|
|
### RBAC verbs
|
|
|
|
|
|
|
|
Reading any configuration resource requires the RBAC verb `read`.
|
|
|
|
|
|
|
|
Performing any dynamic overwrite of a configuration resource requires the RBAC
|
|
|
|
verb `update`. In addition, if the overwrite is to replace a resource with
|
|
|
|
`origin: config-file`, the RBAC verb `create` is also required.
|
|
|
|
|
|
|
|
| | **`read`** | **`update`** | **`create`** |
|
|
|
|
| :---: | :---: | :---: | :---: |
|
|
|
|
| **`tctl get`** | :heavy_check_mark: | | |
|
|
|
|
| **`tctl create`** | | :heavy_check_mark: | |
|
|
|
|
| **`tctl create --force`** | | :heavy_check_mark: | |
|
|
|
|
| **`tctl create --force --confirm`** | | :heavy_check_mark: | :heavy_check_mark: |
|
|
|
|
| **`tctl rm`** | | :heavy_check_mark: | |
|