Skip to main content

Database Access RBAC

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, as this section focuses on configuring RBAC for database access.

Role configuration

Teleport's "role" resource provides the following instruments for restricting database access:

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:

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

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 traits are replaced with values from external single sign-on providers. For OIDC, they will be replaced with the value of an "xyz" claim. For SAML, they are replaced with an "xyz" assertion value.

For full details on how traits work in Teleport roles, see the Teleport Access Controls Reference.

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:

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:

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:

spec:
allow:
db_users: ["{{internal.db_users}}"]
db_names: ["{{internal.db_names}}"]