Plugin static credentials RFD. (#26599)

* Plugin static credentials RFD.

The RFD for supporting plugin static credentials has been created. This RFD
describes how static credentials such as API tokens and username/passwords
should be stored within Teleport.

* Incorporating feedback. Removed the CLI, clarified security/access control considerations, improved details on implementation plan.

* Use labels instead of name matching, adjust names and respond to other feedback.

* Noted that Teleport Assist's API token must be interpreted as a file location.

* Revert Assist API token must be interpreted as a file.

* Use true label matching, clarify security related concerns, add in some clarity to the plugin label fields.

* Remove explicit references to the plugin-label and have it become an auto-generated internal label within the metadata.

* Label and naming updates.

* Note that we won't use existing credentials objects.
This commit is contained in:
Michael Wilson
2023-05-30 15:04:20 +00:00
committed by GitHub
parent 623f8c17c9
commit f511de6630
+176
View File
@@ -0,0 +1,176 @@
---
authors: Michael Wilson ([email protected])
state: draft
---
# RFD 124 - Plugin static credentials
### Required Approvers
* Engineering @r0mant, @justinas
* Security @reed
* Product: @klizhentas
## What
Allow storage of plugin static credentials within Teleport in a safe and secure way.
## Why
As we grow our plugin support, we have discovered that the various services we
hope to integrate do not offer a uniform mechanism for configuration. For instance,
Slack uses oauth2, but Okta requires an API token, and Jamf requires a username and
password.
Today, the plugin houses a credentials object that allows for this sort of storage.
However, unlike an oauth authorization code, static credentials pose a much greater risk of
exposure, and rotating credentials can be a time consuming process. To reduce the risks associated
with storing static credentials within Teleport and to allow for easier credentials rotation,
we would like to create a new resource within Teleport that is handled in an explicitly secure
way.
## Details
### The `PluginStaticCredentials` object
A new object will be needed to house static credentials. At present it will support:
- API tokens
- Usernames and passwords
- OAuth client ID and secret
This object has very strict access control requirements that will be explained in detail
in the **Access Control** section. On creation, the plugin and static credentials will
receive a UUID called the `plugin-label`. The static credentials will have an internal
label that receives this value. Additionally, one plugin may have _many_ credentials
for the purposes of credentials rotation.
```yaml
kind: plugin_static_credentials
version: v1
metadata:
name: credentials-name
labels:
# This is a unique plugin label generated randomly at plugin creation.
# It cannot be modified by the user.
teleport.internal/plugin: 48398071-9860-4be6-9f29-ca6ca5bc7155
# additional labels to uniquely identify the credentials.
label1: value1
type: slack
spec:
credentials:
# Only one of these credential types must be defined at a time. All values in this
# are string literals and not file locations. None of the existing credentials objects
# will be used for this, and all new objects will be created.
api_token: example-token
basic_auth:
username: example-user
password: example-password
oauth_client_secret:
client_id: example-client-id
client_secret: example-client-secret
```
If a `Plugin` is using the oauth authorization code flow, however, it will not need any
`PluginStaticCredentials` objects.
### Changes to the `Plugin` object
The `Plugin` object's `Credentials` field will have a new type of credential called
`CredentialsRef` that contains a reference to a static plugin label. More than
one static credential may match this label, in which case when starting the plugin, the most
recently created credential will be used.
```yaml
credentials_ref:
labels:
# This label is the same label generated at plugin creation. This field will be
# injected by Teleport at creation.
teleport.internal/plugin: 48398071-9860-4be6-9f29-ca6ca5bc7155
env: prod
type: slack
```
### Access control
`PluginStaticCredentials` can be written to and deleted by `RoleProxy`. At introduction,
creating credentials is a flow that will only happen through the web UI, so only `RoleProxy`
is needed. Future work may determine that we want to open up writing through the CLI.
The object will be only readable by the `RoleAdmin` role (with one exception).
This is because plugins run on the auth server, so it's the only role that needs to be
able to actually read the static credentials.
One `Plugin` object can refer to multiple static credentials and a `Plugin` can't refer
to existing static credentials. Static credentials must be associated with one and only
one plugin.
The one exception here is Teleport Assist, which runs in the proxy. The proxy will be
able to read plugin credentials with the name of `openai-default`, which is the name of
the Assist plugin.
### Lifecycle of the `PluginStaticCredentials` object
#### Creation
A `PluginStaticCredentials` object must be created at the same time that the `Plugin` is created.
#### Deletion
On deletion, the associated `Plugin` will be stopped and related `PluginStaticCredentials`
objects will be deleted when deleting its associated plugin.
### UX
#### Web UI
The web UI will remain largely the same with respect to entering credentials for specific
plugins. This will largely depend on the specific application.
### Audit events
A number of new audit events will be created as part of this effort:
| Event Name | Description |
|------------|-------------|
| `plugin.credentials.create` | Emitted when plugin credentials have been created. |
| `plugin.credentials.delete` | Emitted when plugin credentials have been deleted. |
### Security
* Only the auth server is able to read plugin credentials. The proxy will be able to create
them, and admins will be able to delete them.
* The credentials will be stored in DynamoDB, which is encrypted at rest. This will provide
a layer of protection for the stored credentials.
* The credentials will not be cached, so they won't be sitting in an in-memory cache to be
exfiltrated.
### Implementation plan
#### `PluginStaticCredentials` object and backend service
- The `PluginStaticCredentials` object
- The local service to manage the `PluginStaticCredentials` objects in the backend.
#### Modifications to the `Plugin` object
- A new `PluginStaticCredentialsRefs` type.
- `PluginStaticCredentials` objects are created during `Plugin` creation.
- `PluginStaticCredentials` objects are deleted during `Plugin` deletion.
#### Implement `PluginStaticCredentials` permissions
- gRPC methods in the auth service to support reading the
`PluginStaticCredentials`, ensuring that reading can only be done by `RoleAdmin`
and, for the specific case of Teleport Assist, `RoleProxy`.
- Any updates to RBAC to support the creation/deletion of the `PluginStaticCredentials`
object.
#### Integrate `PluginStaticCredentials` with enterprise plugin manager
- Look up `PluginStaticCredentials` objects when starting plugins that require them in the
plugin manager.
#### Add audit events
- Add audit events for the creation and deletion of `PluginStaticCredentials`.