diff --git a/docs/config.json b/docs/config.json
index 0da4ce3d097b8..53353e86076d0 100644
--- a/docs/config.json
+++ b/docs/config.json
@@ -1273,7 +1273,17 @@
},
{
"title": "Access Controls",
- "slug": "/database-access/rbac/"
+ "slug": "/database-access/rbac/",
+ "entries": [
+ {
+ "title": "RBAC",
+ "slug": "/database-access/rbac/configuring-access/"
+ },
+ {
+ "title": "Automatic User Provisioning (Preview)",
+ "slug": "/database-access/rbac/configuring-auto-user-provisioning/"
+ }
+ ]
},
{
"title": "Architecture",
diff --git a/docs/cspell.json b/docs/cspell.json
index df15c76339e81..3261d54050364 100644
--- a/docs/cspell.json
+++ b/docs/cspell.json
@@ -298,6 +298,7 @@
"cqlsh",
"createkey",
"createnongalleryapp",
+ "createrole",
"creds",
"crond",
"customizability",
@@ -752,5 +753,7 @@
"znmqk",
"zxvf"
],
- "flagWords": ["hte"]
-}
+ "flagWords": [
+ "hte"
+ ]
+}
\ No newline at end of file
diff --git a/docs/pages/database-access/guides/postgres-self-hosted.mdx b/docs/pages/database-access/guides/postgres-self-hosted.mdx
index f6572dd3d1577..d9b0b826a083c 100644
--- a/docs/pages/database-access/guides/postgres-self-hosted.mdx
+++ b/docs/pages/database-access/guides/postgres-self-hosted.mdx
@@ -157,3 +157,7 @@ $ tsh db logout example-postgres
# Remove credentials for all database instances.
$ tsh db logout
```
+
+## Next steps
+
+- Set up [automatic database user provisioning](../rbac/configuring-auto-user-provisioning.mdx).
diff --git a/docs/pages/database-access/guides/rds.mdx b/docs/pages/database-access/guides/rds.mdx
index ce65405fcc1fd..f98d1ded9bce7 100644
--- a/docs/pages/database-access/guides/rds.mdx
+++ b/docs/pages/database-access/guides/rds.mdx
@@ -215,3 +215,4 @@ $ tsh db logout postgres-rds
## Next steps
(!docs/pages/includes/database-access/guides-next-steps.mdx!)
+- Set up [automatic database user provisioning](../rbac/configuring-auto-user-provisioning.mdx).
diff --git a/docs/pages/database-access/rbac.mdx b/docs/pages/database-access/rbac.mdx
index 28c5237d85342..738df75e6d164 100644
--- a/docs/pages/database-access/rbac.mdx
+++ b/docs/pages/database-access/rbac.mdx
@@ -1,135 +1,13 @@
---
-title: Database Role-Based Access Controls
-description: Role-based access control (RBAC) for Teleport database access.
+title: Database Access Control Guides
+description: Role-based access control guides for Teleport database access.
---
-Role-based access control (or RBAC, for short) allows administrators to set up
-granular access policies for databases connected to Teleport.
+These guides cover configuring access control policies for database users.
-An example of a policy could be, *"database administrators have access to
-everything, QA team and engineers have full access to staging databases, and
-engineers can gain temporary access to the production database in case of
-emergency"*.
+Read the [RBAC](./rbac/configuring-access.mdx) guide to get a general understanding
+of how to configure Teleport roles to grant or deny access to your database users.
-For a more general description of Teleport roles and examples see [RBAC](../access-controls/introduction.mdx), as
-this section focuses on configuring RBAC for database access.
-
-## Role configuration
-
-Teleport's "role" resource provides the following instruments for restricting
-database access:
-
-```yaml
-kind: role
-version: v5
-metadata:
- name: developer
-spec:
- allow:
- # Label selectors for database instances this role has access to.
- #
- # These will be matched against the static/dynamic labels set on the
- # database service.
- db_labels:
- environment: ["dev", "stage"]
-
- # Database account names this role can connect as.
- db_users: ["viewer", "editor"]
-
- # Database names this role will be able to connect to.
- #
- # Note, this is not the same as the "name" field in "db_service", this is
- # the database names within a particular database instance.
- #
- # Also note, this setting has effect only for PostgreSQL. It does not
- # currently have any effect on MySQL databases/schemas.
- db_names: ["main", "metrics", "postgres"]
-```
-
-It is possible to use wildcards to match any database names/users.
-
-For example, the following role permits access to any database/user within a
-production database except for the internal "postgres" database/user:
-
-```yaml
-kind: role
-version: v5
-metadata:
- name: developer
-spec:
- allow:
- db_labels:
- environment: ["prod"]
- db_users: ["*"]
- db_names: ["*"]
- deny:
- db_users: ["postgres"]
- db_names: ["postgres"]
-```
-
-
- Deny rules will match greedily. In the example above, a database connection
- attempting to use "postgres" database account (regardless of database instance
- or database name) or "postgres" database name (regardless of database instance
- or database account) will be rejected.
-
-
-## Database names
-
-There's a distinction in how different database servers handle logical databases
-which leads to a difference in how `db_names` role field is applied to a connection
-attempt.
-
-PostgreSQL supports multiple logical databases, and each logical database can
-contain multiple schemas. In order to change to a different database, a user
-disconnects from the current one and establishes a new connection. During a
-PostgreSQL connection attempt, `db_names` field is checked against the name
-of the logical database that the user is connecting to.
-
-In MySQL a logical "database" and a "schema" are synonyms for each other, and
-the scope of permissions a user has once connected is determined by the permission
-grants set on the account within the database. As such, `db_names` role field
-is not currently enforced on MySQL connection attempts.
-
-## Template variables
-
-Similar to other role fields, `db_*` fields support templating variables.
-
-The `{{external.xyz}}` variables are replaced with values from external [SSO](../access-controls/sso.mdx)
-providers. For OIDC, they will be expanded with a value of an "xyz" claim; for
-SAML — with an "xyz" assertion value.
-
-For example, here is what a role may look like if you want to assign allowed
-database names from the user's Okta `databases` assertion:
-
-```yaml
-spec:
- allow:
- db_names: ["{{external.databases}}"]
-```
-
-The `{{internal.db_users}}` and `{{internal.db_names}}` variables permit sharing
-allowed database accounts and names with remote clusters. They will be replaced
-with the respective properties of a remote user connecting from a root cluster.
-
-For example, suppose a user in the root cluster has the following role:
-
-```yaml
-spec:
- allow:
- db_users: ["postgres"]
- db_names: ["postgres"]
-```
-
-The role on the leaf cluster can be set up to use the user's allowed database
-accounts and names:
-
-```yaml
-spec:
- allow:
- db_users: ["{{internal.db_users}}"]
- db_names: ["{{internal.db_names}}"]
-```
+The [Automatic User Provisioning](./rbac/configuring-auto-user-provisioning.mdx)
+guide explains how to get Teleport to create accounts for your PostgreSQL users
+on-demand.
diff --git a/docs/pages/database-access/rbac/configuring-access.mdx b/docs/pages/database-access/rbac/configuring-access.mdx
new file mode 100644
index 0000000000000..f90d2d8b9ac7b
--- /dev/null
+++ b/docs/pages/database-access/rbac/configuring-access.mdx
@@ -0,0 +1,135 @@
+---
+title: Database Access RBAC
+description: Role-based access control (RBAC) for Teleport database access.
+---
+
+Role-based access control (or RBAC, for short) allows administrators to set up
+granular access policies for databases connected to Teleport.
+
+An example of a policy could be, *"database administrators have access to
+everything, QA team and engineers have full access to staging databases, and
+engineers can gain temporary access to the production database in case of
+emergency"*.
+
+For a more general description of Teleport roles and examples see [RBAC](../../access-controls/introduction.mdx), as
+this section focuses on configuring RBAC for database access.
+
+## Role configuration
+
+Teleport's "role" resource provides the following instruments for restricting
+database access:
+
+```yaml
+kind: role
+version: v5
+metadata:
+ name: developer
+spec:
+ allow:
+ # Label selectors for database instances this role has access to.
+ #
+ # These will be matched against the static/dynamic labels set on the
+ # database service.
+ db_labels:
+ environment: ["dev", "stage"]
+
+ # Database account names this role can connect as.
+ db_users: ["viewer", "editor"]
+
+ # Database names this role will be able to connect to.
+ #
+ # Note, this is not the same as the "name" field in "db_service", this is
+ # the database names within a particular database instance.
+ #
+ # Also note, this setting has effect only for PostgreSQL. It does not
+ # currently have any effect on MySQL databases/schemas.
+ db_names: ["main", "metrics", "postgres"]
+```
+
+It is possible to use wildcards to match any database names/users.
+
+For example, the following role permits access to any database/user within a
+production database except for the internal "postgres" database/user:
+
+```yaml
+kind: role
+version: v5
+metadata:
+ name: developer
+spec:
+ allow:
+ db_labels:
+ environment: ["prod"]
+ db_users: ["*"]
+ db_names: ["*"]
+ deny:
+ db_users: ["postgres"]
+ db_names: ["postgres"]
+```
+
+
+ Deny rules will match greedily. In the example above, a database connection
+ attempting to use "postgres" database account (regardless of database instance
+ or database name) or "postgres" database name (regardless of database instance
+ or database account) will be rejected.
+
+
+## Database names
+
+There's a distinction in how different database servers handle logical databases
+which leads to a difference in how `db_names` role field is applied to a connection
+attempt.
+
+PostgreSQL supports multiple logical databases, and each logical database can
+contain multiple schemas. In order to change to a different database, a user
+disconnects from the current one and establishes a new connection. During a
+PostgreSQL connection attempt, `db_names` field is checked against the name
+of the logical database that the user is connecting to.
+
+In MySQL a logical "database" and a "schema" are synonyms for each other, and
+the scope of permissions a user has once connected is determined by the permission
+grants set on the account within the database. As such, `db_names` role field
+is not currently enforced on MySQL connection attempts.
+
+## Template variables
+
+Similar to other role fields, `db_*` fields support templating variables.
+
+The `{{external.xyz}}` variables are replaced with values from external [SSO](../../access-controls/sso.mdx)
+providers. For OIDC, they will be expanded with a value of an "xyz" claim; for
+SAML — with an "xyz" assertion value.
+
+For example, here is what a role may look like if you want to assign allowed
+database names from the user's Okta `databases` assertion:
+
+```yaml
+spec:
+ allow:
+ db_names: ["{{external.databases}}"]
+```
+
+The `{{internal.db_users}}` and `{{internal.db_names}}` variables permit sharing
+allowed database accounts and names with remote clusters. They will be replaced
+with the respective properties of a remote user connecting from a root cluster.
+
+For example, suppose a user in the root cluster has the following role:
+
+```yaml
+spec:
+ allow:
+ db_users: ["postgres"]
+ db_names: ["postgres"]
+```
+
+The role on the leaf cluster can be set up to use the user's allowed database
+accounts and names:
+
+```yaml
+spec:
+ allow:
+ db_users: ["{{internal.db_users}}"]
+ db_names: ["{{internal.db_names}}"]
+```
diff --git a/docs/pages/database-access/rbac/configuring-auto-user-provisioning.mdx b/docs/pages/database-access/rbac/configuring-auto-user-provisioning.mdx
new file mode 100644
index 0000000000000..136467349c364
--- /dev/null
+++ b/docs/pages/database-access/rbac/configuring-auto-user-provisioning.mdx
@@ -0,0 +1,181 @@
+---
+title: Database Automatic User Provisioning (Preview)
+description: Configure automatic user provisioning for databases.
+---
+
+
+ Automatic user provisioning for PostgreSQL is available starting from
+ Teleport 13.1.
+
+
+Teleport can automatically create users in your database, removing the need for
+having to create each individual user account in advance, or using the same set
+of shared database accounts for all users.
+
+
+Currently, automatic user provisioning is only supported for self-hosted and
+RDS PostgreSQL databases.
+
+
+## Prerequisites
+
+- Teleport cluster with a configured [self-hosted PostgreSQL](../guides/postgres-self-hosted.mdx)
+ or [RDS PostgreSQL](../guides/rds.mdx) database.
+- Ability to connect to and create user accounts in the target database.
+
+## Step 1/3. Configure database admin
+
+Teleport should be able to connect to the database as a user that can create
+other users and assign them roles. We recommend creating a separate user
+designated specifically for Teleport automatic user provisioning. Let's call it
+`teleport-admin`.
+
+Teleport will use the same authentication mechanism when connecting as an admin
+user as for regular user connections: X.509 for self-hosted databases and AWS
+IAM for RDS. The admin user must have privileges within the database to create
+users and grant them privileges.
+
+
+
+The RDS PostgreSQL admin user must have the `rds_iam` role attached to allow IAM
+authentication:
+
+```sql
+CREATE USER "teleport-admin" login createrole;
+GRANT rds_iam TO "teleport-admin";
+```
+
+Note that the RDS database must have IAM authentication enabled.
+
+Refer to the [AWS documentation](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/UsingWithRDS.IAMDBAuth.DBAccounts.html) to make sure you are using the `rds_iam` role correctly.
+for more information.
+
+
+The self-hosted PostgreSQL admin user must have X.509 authentication configured.
+
+```sql
+CREATE USER "teleport-admin" login createrole;
+```
+
+Note that the database must be configured to accept client certificate auth
+for the admin user by having the following entries in `pg_hba.conf`:
+
+```conf
+hostssl all all ::/0 cert
+hostssl all all 0.0.0.0/0 cert
+```
+
+Refer to the [self-hosted PostgreSQL guide](../guides/postgres-self-hosted.mdx#step-35-configure-your-postgresql-server)
+to ensure that your configuration is correct.
+
+
+
+Users created by Teleport will be placed in the `teleport-auto-users` group in
+the database, which will be created automatically if it doesn't exist.
+
+Teleport will not delete the automatically created user at the end of the session.
+Instead, the user will be stripped of all roles, updated with `nologin` trait
+and reactivated during the next connection.
+
+Next, enable the database admin on the Teleport database configuration:
+
+
+
+```yaml
+db_service:
+ enabled: "yes"
+ databases:
+ - name: "example"
+ protocol: "postgres"
+ uri: "localhost:5432"
+ admin_user:
+ name: "teleport-admin"
+```
+
+
+```yaml
+kind: db
+version: v3
+metadata:
+ name: example
+spec:
+ protocol: "postgres"
+ uri: "localhost:5432"
+ admin_user:
+ name: "teleport-admin"
+```
+
+
+
+
+For auto-discovered cloud databases, the name of the admin user is taken from
+the `teleport.dev/db-admin` label.
+
+
+## Step 2/3. Configure Teleport role
+
+To specify the database roles a user should be assigned within the database,
+use the `db_roles` role option:
+
+```yaml
+kind: role
+version: v6
+metadata:
+ name: auto-db-users
+spec:
+ options:
+ # create_db_user enables automatic user provisioning for matching databases
+ create_db_user: true
+ allow:
+ db_labels:
+ "*": "*"
+ db_names:
+ - "*"
+ # db_roles is a list of roles the database user will be assigned
+ db_roles:
+ - reader
+ - "{{internal.db_roles}}"
+ - "{{external.db_roles}}"
+```
+
+With automatic user provisioning, users always connect to the database with
+their Teleport username so the `db_users` role field is ignored for roles
+that have database user provisioning enabled.
+
+User created within the database will:
+
+- Have the same name as Teleport username.
+- Be a part of the `teleport-auto-users` role.
+- Be assigned all roles from the Teleport user's role set that match the database.
+ The role names must be valid and exist in the database. See PostgreSQL
+ [CREATE ROLE](https://www.postgresql.org/docs/current/sql-createrole.html)
+ for information on how to create database roles.
+
+Note that in case of a name conflict where a user with the same name already
+exists in the database and is not managed by Teleport (i.e. not a part of the
+`teleport-auto-users` group), the connection will be aborted.
+
+## Step 3/3. Connect to the database
+
+Now, log into your Teleport cluster and connect to the database:
+
+```
+$ tsh login --proxy=teleport.example.com
+$ tsh db connect example
+```
+
+If using a GUI database client like pgAdmin, make sure to use your Teleport
+username as a database username. `tsh db connect` will default to it automatically
+when connecting to a database with user provisioning enabled.
+
+## Next steps
+
+- Connect using your [GUI database client](../../connect-your-client/gui-clients.mdx).
+- Learn about [role templating](../../access-controls/guides/role-templates.mdx#interpolation-rules).
+- Read automatic user provisioning [RFD](https://github.com/gravitational/teleport/blob/master/rfd/0113-automatic-database-users.md).
diff --git a/docs/pages/database-access/reference/configuration.mdx b/docs/pages/database-access/reference/configuration.mdx
index c9e644c8a5498..9d144c7ed9728 100644
--- a/docs/pages/database-access/reference/configuration.mdx
+++ b/docs/pages/database-access/reference/configuration.mdx
@@ -116,6 +116,11 @@ spec:
...
-----END CERTIFICATE-----
+ # Database admin user for automatic user provisioning.
+ admin_user:
+ # Database admin user name.
+ name: "teleport-admin"
+
# MySQL only options.
mysql:
# The MySQL server version reported by the Teleport Proxy Service.
diff --git a/docs/pages/includes/role-spec.mdx b/docs/pages/includes/role-spec.mdx
index 5cff6f23e7a6f..3ecdb82b34931 100644
--- a/docs/pages/includes/role-spec.mdx
+++ b/docs/pages/includes/role-spec.mdx
@@ -97,8 +97,10 @@ spec:
mode: extension
name: login@github.com
value: "{{ external.github_login }}"
- # Controls whether this role supports auto provisioning of users.
+ # Controls whether this role supports auto provisioning of SSH users.
create_host_user: true
+ # Controls whether this role requires automatic database user provisioning.
+ create_db_user: true
# Specifies role specific options for identity provider access.
idp:
# Specifies role specific options for SAML identity provider access.
@@ -171,6 +173,7 @@ spec:
# Functions transform variables.
db_users: ['{{email.local(external.email)}}']
db_names: ['{{external.db_names}}']
+ db_roles: ['{{external.db_roles}}']
db_labels:
'env': '{{regexp.replace(external.access["env"], "^(staging)$", "$1")}}'