Database Access Controls
Database Access Controls is a Teleport feature that lets you configure role-based access controls for databases and the data within them. With Database Access Controls, you can ensure that users only have permissions to manage the data they need.
Access Controls encompasses two levels of granularity:
- Database servers: database resources enrolled with your Teleport cluster.
- Database objects: tables, views, or stored procedures.
For both database servers and database objects, Database Access Controls grants or denies access based on Teleport labels. When you enroll a database with Teleport, you can configure the labels associated with the database. For database objects, you can define import rules that instruct the Teleport Database Service to apply labels to database objects imported from databases that match labels configured within the import rule.
When a user connects to a database, the Database Service selectively grants permissions by checking labels against the user's Teleport roles.
The Database Service grants object-level permissions for the duration of a connection and revokes them automatically when the connection ends.
For a more general description of Teleport roles and examples see RBAC, as this section focuses on configuring RBAC for database access.
Database Access Controls for database objects only supports PostgreSQL databases.
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 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}}"]
Database object import rules
A database object import rule in Teleport is a resource that defines the labels to be applied to database objects imported into Teleport. If a specific object does not match any of the rules, it will not be imported.
Default import rule
By default, if no import rules are present (e.g. you create a fresh cluster or
delete all your rules), Teleport will automatically create the
import_all_objects
rule on startup:
kind: db_object_import_rule
metadata:
name: import_all_objects
spec:
# Priority determines how important the rule is, with lower number indicating lower priority.
# In case of conflicts, when the same label is applied by two rules,
# the label applied by rule with higher priority wins.
priority: 0
# database_labels is a filter specifying which database resources are in scope of this rule.
database_labels:
- name: '*'
values:
- '*'
# Each mapping, if matched, introduces a set of labels applied to database object.
# Database objects without labels are not imported.
mappings:
- add_labels:
database: '{{obj.database}}'
object_kind: '{{obj.object_kind}}'
name: '{{obj.name}}'
protocol: '{{obj.protocol}}'
schema: '{{obj.schema}}'
database_service_name: '{{obj.database_service_name}}'
# match adds objects to be imported; it cannot be empty.
match:
# list of all table names
table_names:
- '*'
# Additional mappings can be added here.
# - add_labels: ...
version: v1
This rule will import all objects and label them by their inherent properties using the template syntax.
Customizing the default import rule
You can modify the default db_object_import_rule
as you would any other
Teleport resource.
For instance, consider the following rule designed to designate particular tables as accessible to developers, either in a read-only or read-write capacity:
kind: db_object_import_rule
metadata:
name: ownership_nonprod
spec:
priority: 100
database_labels:
# Affect `dev` and `staging` environments.
# Prod environment may have a different rule.
- name: 'env'
values:
- 'staging'
- 'dev'
- 'prod'
mappings:
# Apply project label
- add_labels:
project: horizon
# match section is mandatory and must contain at least one non-empty subsection
match:
table_names:
- '*'
# scope is the optional section which enables further filtering of objects by database and schema names. When omitted, this filtering is disabled.
scope:
database_names:
- 'horizon'
- 'horizon_v2'
schema_names:
- 'application'
- 'data_import'
# Add `dept: hr` label for respective tables.
- add_labels:
dept: hr
match:
table_names:
- '*'
scope:
schema_names:
- 'recruitment'
- 'salaries'
- 'pto'
- 'hr_scratchpad'
version: v1
Database admin user
A database admin user is responsible for granting permissions to end users. You must specify a database admin user before using database object import rules. To specify a database admin user, add the following to a dynamic database resource or configuration file for an agent running the Teleport Database Service:
- Dynamic Resource
- Static Agent Configuration
kind: db
version: v3
metadata:
# ...
spec:
# ...
admin_user: "teleport-admin"
db_service:
enabled: "yes"
databases:
- name: "example"
# ...
admin_user:
name: "teleport-admin"
In this case, the Teleport Database Service expects to activate a user called
teleport-admin
in order to execute object import rules. Ensure that the admin
user possesses the necessary permissions to manage users in your database,
otherwise object import rules might fail, depending on how you have configured
the database:
$ tsh db connect postgres-db --db-name postgres --db-user teleport-user
psql: error: connection to server at "localhost" (::1), port 50800 failed: Connection refused
Is the server running on that host and accepting TCP/IP connections?
connection to server at "localhost" (127.0.0.1), port 50800 failed: your Teleport role requires automatic database user provisioning but an attempt to activate database user "teleport-user" failed due to the following error: ERROR: permission denied for table pg_subscription (SQLSTATE 42501)
ERROR: exit status 2
Executing database object permission rules
The Teleport Database Service checks the roles associated with a user before allowing that user to connect to a database.
To grant database object permissions during a database connection, the user must be associated with a role that meets specific criteria:
spec.allow.db_labels
must match the database labels of particular database.- Database user auto-provisioning must be enabled
(
spec.options.create_db_user_mode
not set tooff
orspec.options.create_db_user: true
). - The label key/value pairs in
spec.allow.db_permissions.match
must correspond to the labels on the specific database object.
A user can maintain multiple simultaneous connections to the same database. All connections must possess identical permissions; otherwise, a new connection will be rejected. Upon the termination of the last active connection, all user permissions are automatically revoked.
The labels on the table must be matched with an appropriate role. Here's an
example of a role that utilizes the dept
label, applied by the
ownership_nonprod
rule, granting read-only access to HR records in the
database. The hr_scratchpad
table is further made editable. On the other hand,
any objects labeled dept: sales
are made unavailable by removing all
permissions a user may have received for them. The wildcard permissions are only
allowed in the deny
part of the spec (spec.deny.db_permissions
):
version: v7
kind: role
metadata:
name: dept_hr_permissions
spec:
allow:
db_labels:
'*': '*'
db_names:
- '*'
db_permissions:
# default permission: read-only
- match:
object_kind: table
dept: hr
permissions:
- SELECT
# extra permissions for select tables
- match:
object_kind: table
dept: hr
name: hr_scratchpad
permissions:
- SELECT
- UPDATE
- DELETE
- INSERT
deny:
db_permissions:
# explicitly disallow any interaction with `dept: sales` tables.
- match:
dept: sales
permissions:
- '*'
options:
create_db_user_mode: keep
Troubleshooting object import rules
To diagnose issues with importing database objects, refer to the Teleport Database Service logs. These indicate the number of objects fetched from the database, the number of imported objects (the difference comprising objects not matched by any import rule), and the number of objects for which the user has been granted permissions:
INFO [DB:SERVIC] Database objects fetched from the database (table:75). db:my-postgres id:b4a33740-1d82-4a8d-b2be-2aa90ae9d2eb total:75 postgres/users.go:212
INFO [DB:SERVIC] Database objects imported (table:75). db:my-postgres err_count:0 id:b4a33740-1d82-4a8d-b2be-2aa90ae9d2eb total:75 postgres/users.go:216
INFO [DB:SERVIC] Calculated database permissions: "INSERT": 75 objects (table:75), "SELECT": 75 objects (table:75), "UPDATE": 75 objects (table:75). db:my-postgres id:b4a33740-1d82-4a8d-b2be-2aa90ae9d2eb user:teleport-user postgres/users.go:223