rfd/0124-plugin-secrets.md
Allow storage of plugin static credentials within Teleport in a safe and secure way.
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.
PluginStaticCredentials objectA new object will be needed to house static credentials. At present it will support:
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.
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.
Plugin objectThe 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.
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
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.
PluginStaticCredentials objectA PluginStaticCredentials object must be created at the same time that the Plugin is created.
On deletion, the associated Plugin will be stopped and related PluginStaticCredentials
objects will be deleted when deleting its associated plugin.
The web UI will remain largely the same with respect to entering credentials for specific plugins. This will largely depend on the specific application.
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. |
PluginStaticCredentials object and backend servicePluginStaticCredentials objectPluginStaticCredentials objects in the backend.Plugin objectPluginStaticCredentialsRefs type.PluginStaticCredentials objects are created during Plugin creation.PluginStaticCredentials objects are deleted during Plugin deletion.PluginStaticCredentials permissionsPluginStaticCredentials, ensuring that reading can only be done by RoleAdmin
and, for the specific case of Teleport Assist, RoleProxy.PluginStaticCredentials
object.PluginStaticCredentials with enterprise plugin managerPluginStaticCredentials objects when starting plugins that require them in the
plugin manager.PluginStaticCredentials.