Scaling Privileged Access for Modern Infrastructure: Real-World Insights
Apr 25
Virtual
Register Today
Teleport logoTry For Free
Fork me on GitHub

Teleport

Database Access Controls

Database Access Controls is a Teleport feature that lets you configure role-based access controls for database objects. A database object can be a table, view, or stored procedure. With Database Access Controls, you can ensure that users only have permissions to manage the data they need.

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 database object 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.

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.

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.

Feel free to modify this rule with tctl edit to meet your specific requirements or add more rules. 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

Save the rule to a file and execute tctl create -f ownership_nonprod.yaml to create it in Teleport.

Database permissions in roles

To grant user 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 should be enabled (spec.options.create_db_user_mode not set to off or spec.options.create_db_user: true).
  • The label key/value pairs in spec.allow.db_permissions.match should correspond to the labels on the specific database object.

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).

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
version: v7

Permissions lifecycle and consistency

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.

Troubleshooting

Checking the logs

To diagnose the import process, refer to the Database Service logs to find details such as the number of objects fetched from the database, the number of imported objects (the difference comprising objects not matched by any import rule), and finally, 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:212INFO [DB:SERVIC] Database objects imported (table:75). db:my-postgres err_count:0 id:b4a33740-1d82-4a8d-b2be-2aa90ae9d2eb total:75 postgres/users.go:216INFO [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

Invalid database admin user permissions

The database admin user, referred to as teleport-admin in this documentation, is responsible for granting permissions to end users. Ensure that the admin user possesses the necessary permissions; otherwise, this action might fail.

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

Invalid import rules

Import rules undergo validation upon creation. An invalid rule will trigger an error during tctl create. For instance:

...
  mappings:
  - add_labels:
      invalid_label: '{{'
...

Will cause error:

> tctl create -f import_all_objects_invalid.yaml
ERROR: validating rule
	mapping value failed to parse as template
		"{{" is using template brackets '{{' or '}}', however expression does not parse, make sure the format is {{expression}}

Next steps

  • Read automatic user provisioning RFD.
  • Read database permission management RFD