From fc44c42a22fef1616f8d78d70fbceea3c8f9953b Mon Sep 17 00:00:00 2001 From: Paul Gottschling Date: Tue, 4 Jun 2024 12:19:49 -0400 Subject: [PATCH] [v15] Refactor the Database Object Permissions guide (#42361) * Refactor the Database Object Permissions guide Closes #41917 Merge the Database Object Permissions guide into the Database Access RBAC guide for greater discoverability and a clearer division of labor between the two guides. This change also includes the following edits to make the refactor cleaner, since we can include each troubleshooting step as a separate H3 in the dateabase object permissions H2: - Remove an unnecessary troubleshooting step: One step indicates that import rules are validated, which is unnecessary to document, since validation errors are self explanatory. - Instead of mentioning the admin user as a troubleshooting step, add a separate H3 for the admin user and describe the `admin_user` field, which was not mentioned in the original database object permissions guide. * Respond to Tener feedback - Clarify the placing of the `admin_user` field * Restore intro section Per Tener and r0mant feedback, integrate the introduction from the Database Access Controls page into the newly merged RBAC guide. Frame Database Access Controls as encompassing both databases and database objects. * Respond to r0mant feedback * Fix spelling * Fix linter issues --- docs/config.json | 4 - .../auto-user-provisioning.mdx | 2 - .../database-access-controls.mdx | 213 ------------- .../auto-user-provisioning/postgres.mdx | 4 +- docs/pages/database-access/rbac.mdx | 281 +++++++++++++++++- docs/pages/reference/resources.mdx | 2 +- 6 files changed, 272 insertions(+), 234 deletions(-) delete mode 100644 docs/pages/database-access/auto-user-provisioning/database-access-controls.mdx diff --git a/docs/config.json b/docs/config.json index f87a6b086c272..c0195b5251b5d 100644 --- a/docs/config.json +++ b/docs/config.json @@ -1554,10 +1554,6 @@ { "title": "PostgreSQL", "slug": "/database-access/auto-user-provisioning/postgres/" - }, - { - "title": "Database Access Controls", - "slug": "/database-access/auto-user-provisioning/database-access-controls/" } ] }, diff --git a/docs/pages/database-access/auto-user-provisioning.mdx b/docs/pages/database-access/auto-user-provisioning.mdx index 8d65cdfd302b1..400a05ebbe731 100644 --- a/docs/pages/database-access/auto-user-provisioning.mdx +++ b/docs/pages/database-access/auto-user-provisioning.mdx @@ -5,8 +5,6 @@ description: Configure automatic user provisioning for databases. (!docs/pages/includes/database-access/auto-user-provisioning/intro.mdx!) -Automatically created users will either receive a predefined set of roles, or can be granted permissions to specific database objects based on their required level of access using [Database Access Controls](./auto-user-provisioning/database-access-controls.mdx) feature. - Currently, automatic user provisioning is supported for the following databases: - [PostgreSQL databases (self-hosted and AWS RDS)](./auto-user-provisioning/postgres.mdx) - [MySQL databases (self-hosted and AWS RDS)](./auto-user-provisioning/mysql.mdx) diff --git a/docs/pages/database-access/auto-user-provisioning/database-access-controls.mdx b/docs/pages/database-access/auto-user-provisioning/database-access-controls.mdx deleted file mode 100644 index 4229967ad055c..0000000000000 --- a/docs/pages/database-access/auto-user-provisioning/database-access-controls.mdx +++ /dev/null @@ -1,213 +0,0 @@ ---- -title: Database Access Controls -description: Understand the concepts behind Database Access Controls managed by Teleport. ---- - -{/*lint ignore messaging*/} -**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: - -```yaml -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. - -```yaml -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`). - -```yaml -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. - -{/* spell-checker: disable */} -```code -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 -``` -{/* spell-checker: enable */} - -### 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. - -```bash -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: - -```yaml -... - mappings: - - add_labels: - invalid_label: '{{' -... -``` - -Will cause error: - -```shell -> 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](https://github.com/gravitational/teleport/blob/master/rfd/0113-automatic-database-users.md). -- Read database permission management [RFD](https://github.com/gravitational/teleport/blob/master/rfd/0151-database-permission-management.md) - diff --git a/docs/pages/database-access/auto-user-provisioning/postgres.mdx b/docs/pages/database-access/auto-user-provisioning/postgres.mdx index d5a9bbc07990e..c8cb3d0dd1526 100644 --- a/docs/pages/database-access/auto-user-provisioning/postgres.mdx +++ b/docs/pages/database-access/auto-user-provisioning/postgres.mdx @@ -61,7 +61,7 @@ to ensure that your configuration is correct. -When [Database Access Controls](./database-access-controls.mdx) feature is in use, the `teleport-admin` should have permissions to relevant database objects. For example: +When [Database Access Controls](../rbac.mdx) feature is in use, the `teleport-admin` should have permissions to relevant database objects. For example: ```sql GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA schema1, schema2, schema3 TO "teleport-admin"; @@ -148,7 +148,7 @@ version: v7 You can define your own labels for database objects, applying them based on customizable import rules. These custom labels, such as `owner` or `environment`, can then be utilized when granting permissions. -For additional information, refer to the [Database Access Controls](./database-access-controls.mdx) page. +For additional information, refer to the [Database Access Controls](../rbac.mdx) page. diff --git a/docs/pages/database-access/rbac.mdx b/docs/pages/database-access/rbac.mdx index b4dfbb86bc1b6..d56a7dd5761f8 100644 --- a/docs/pages/database-access/rbac.mdx +++ b/docs/pages/database-access/rbac.mdx @@ -1,22 +1,45 @@ --- -title: Database Access RBAC +title: Database Access Controls 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. +**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. -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"*. +Access Controls encompasses two levels of granularity: -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. +- **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](../access-controls/introduction.mdx), 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 +Teleport's role resource provides the following instruments for restricting database access: ```yaml @@ -77,7 +100,7 @@ spec: or database account) will be rejected. -## Database names +### 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 @@ -94,7 +117,7 @@ the scope of permissions a user has once connected is determined by the permissi grants set on the account within the database. As such, `db_names` role field is not currently enforced on MySQL connection attempts. -## Template variables +### Template variables Similar to other role fields, `db_*` fields support templating variables. @@ -138,3 +161,237 @@ spec: 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: + +```yaml +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: + +```yaml +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: + + + + +```yaml +kind: db +version: v3 +metadata: + # ... +spec: + # ... + admin_user: "teleport-admin" +``` + + + + +```yaml +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: + +```code +$ 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 to `off` or + `spec.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`): + +```yaml +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: + +{/* spell-checker: disable */} +```text +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 +``` +{/* spell-checker: enable */} diff --git a/docs/pages/reference/resources.mdx b/docs/pages/reference/resources.mdx index ce8df7f663bbf..f1e236ec80476 100644 --- a/docs/pages/reference/resources.mdx +++ b/docs/pages/reference/resources.mdx @@ -191,7 +191,7 @@ Login rules contain logic to transform SSO user traits during login. Database object import rule define the labels to be applied to database objects imported into Teleport. -See [Database Access Controls](../database-access/auto-user-provisioning/database-access-controls.mdx) for more details. +See [Database Access Controls](../database-access/rbac.mdx) for more details. (!docs/pages/includes/database-access/auto-user-provisioning/database-object-import-rule-spec.mdx!)