Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Add Proposal for dynamic privileges #23224

Merged
merged 21 commits into from
Mar 19, 2021

Conversation

morgo
Copy link
Contributor

@morgo morgo commented Mar 10, 2021

What problem does this PR solve?

Issue Number: Design doc for #22439

Problem Summary:

What is changed and how it works?

Adds a proposal for dynamic privileges.

This was proposed earlier, but rejected for sprint 2. I am re-adding it because it was clarified that if features can be disabled by default behind a feature flag they are still permitted.

Related changes

Check List

Tests

  • No code

Side effects

  • None

Release note

  • No release note

@ti-chi-bot ti-chi-bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Mar 10, 2021
@morgo morgo requested review from SunRunAway and bb7133 March 10, 2021 02:07

## Impact & Risks

In its initial release, dynamic privilege usage will be controlled by an experimental feature flag. The implementation will be via restricting GRANT and REVOKE statements from creating dynamic privileges (it is too invasive to conditionally modify the ast visitor functionaliy).
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This text is new from the original proposal.

@ti-chi-bot ti-chi-bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Mar 11, 2021
Comment on lines +32 to +33
* Privileges can only be global scoped.
* Privileges are stored in the table `mysql.global_grants` and not `mysql.user`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which privilege, dynamic or static?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These points are all describing dynamic privileges. See above where it says "dynamic privileges are different from static privileges in the following ways".

For TiDB, we can use the same table structure as MySQL:

```sql
CREATE TABLE `global_grants` (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the host field in mysql.user table is defined as char(64), which is smaller than this table, which is char(2455):

| Host                   | char(64)      | NO   | PRI  | NULL    |       |

I'm curious which one is correct, should we unify the length of this field for different tables?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use the same format as MySQL, since this supports the use case of restoring a mysqldump (which overwrites these tables). The example here for global_grants is identical to MySQL 8.0, but the mysql.user table is not.

There are several reasons why the mysql.user table is not:

  • TiDB adds privileges like Config (really, this should be a dynamic Priv)
  • TiDB stores TLS settings in global_priv, not mysql.user.
  • TiDB does not yet support authentication plugins.

So yes, the mysql.user table is incorrect. In MySQL 8.0 this is:

| Host                     | char(255)                         | NO   | PRI |                       |       |

);
```

There is an existing table called “global_priv” which initially looked like it provided similar functionality, except:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

global_priv and global_grants might confuse the users, IMHO, it's better to merge them or have distinguishing names based on their purposes.

@lysu, seems like the global_priv table was introduced by you, do you have any idea about how to merge these two tables? Or can we rename this table to another name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The global_priv table does not exist in MySQL. As far as I can tell these columns are stored in mysql.user in MySQL.

I think it should be cleaned up to be MySQL compatible so restoring mysqldump can work as expected, but would suggest we handle it outside of this proposal, since for storage this follows MySQL exactly.


This document was created to discuss the design of Dynamic Privileges. It is intended to be implemented in combination with Security Enhanced Mode, but there no interdependencies between the two features.

## Motivation or Background
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you make a specific example problem to help users have a better understanding of this proposal?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the following "Audit Admin" is the example: suppose we want some administrators to be able to change audit settings, but before Dynamic Priviligies, the only way is to grant "SUPER" because the privilige is too coarse.

BTW, IMHO the naming of 'Dyanmic Priviligies' is kind of misleading, the core intention of it is make the priviligies 'fine grained' and 'dynamic'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is maybe an implementation detail, but I don't think it is misleading. In my original proposal I started it with a section called 'terminology', but this is not part of the new standard template, so I removed it.

The implementation detail is more relevant to MySQL, because it has quite a number of plugins. It is less relevant to TiDB, but it is refered to as dynamic privileges in the documentation, so I don't recommend changing it.

I am happy to add an example to make it clearer though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a paste of a testcase. There are additional examples in the linked MySQL worklog WL#8131, which is in the first sentence.


### Scenario Tests

The use-cases required by the DBaaS team should be validated when combined with `security-enhanced-mode`. They are:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to add scenario tests for:

  • all the dynamic privileges
  • several user-defined dynamic privileges

By validating what they can and can't do to ensure the dynamic privilege works as expected.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I've added it.


### Compatibility Tests

The introduction of `DYNAMIC` privileges is not expected to introduce any compatibility issues, because backwards compatibility is ensured. However, plugins should migrate to registering their own dynamic privileges and not rely on the use of `SUPER`. This is considered an enhancement, and not included in-scope for the initial introduction of dynamic privileges (which introduces the framework for plugins to use).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Should BR, lightning use the new dynamic privilege as well?
  • We need to ensure the cluster can be downgraded in case the upgrading is failed due to some reasons, how to downgrade the cluster to an older version?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Downgrade should work, but I can explain why/how. The reason is that the code requests for a specific privilege (such as "BACKUP_ADMIN"), which TIDB also allows SUPER. In an earlier version of the code the privilege check just requires SUPER.

However, if they don't have SUPER and explicitly grant BACKUP ADMIN, then downgrade will cause a privilege check failure becaues they don't have SUPER.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The built-in BACKUP command will be changed to BACKUP_ADMIN. Currently lightning is not a server-plugin (IMHO it should be) so it can't register new dynamic privileges, but maybe the recommended credentials required to do a lightning restore could change to be more fine grained.

We should always recommend the minimum set of privileges, so this makes sense to me. But it is not specifically a compatibility problem because backwards compatibility is ensured.


## Impact & Risks

In its initial release, dynamic privilege usage will be controlled by an experimental feature flag. The implementation will be via restricting `GRANT` and `REVOKE` statements from creating dynamic privileges (it is too invasive to conditionally modify the ast visitor functionaliy).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you describe more about the feature flag? is it a global variable that can or can't be seen by users via show variables?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I added tidb_enable_dynamic_privileges in b7809f6


In its initial release, dynamic privilege usage will be controlled by an experimental feature flag. The implementation will be via restricting `GRANT` and `REVOKE` statements from creating dynamic privileges (it is too invasive to conditionally modify the ast visitor functionaliy).

For backwards compatibility, the MySQL-compatible dynamic privileges will also permit `SUPER`. This helps prevent upgrade issues, such a when TiDB was bootstrapped `GRANT ALL ON *.*` would not have granted all the dynamic privileges. There might be some impact on Upgrade/Downgrade story if eventually the `BACKUP_ADMIN` privilege is used instead of `SUPER`, but for the initial release I am planning to allow either.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious whether there are requirements for MySQL compatible dynamic privileges at present, @IANTHEREAL do you have any idea?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To paraphrase your question: is there a requirement where a user with SUPER but not a DYNAMIC privilege will be denied access to perform a task such as BACKUP. The main difference is:

  • In MySQL, you can not GRANT a dynamic privilege foo unless you have the dynamic privilege foo with grant_option.
  • In TiDB you need either the dynamic privilege foo with grant option or super with grant option.

This caters for the case that the root user already has super, but not each of the dynamic privileges. There is an existing incompatibility in TiDB where grant all does not actually truly grant all. I don't plan to fix it.

(Note: Slightly contradicting this, if SEM is enabled, there will be cases where super is locked down and a tidb-specific dynamic privilege is required. This is the main goal of SEM: restrict SUPER.)

Copy link
Contributor

@SunRunAway SunRunAway Mar 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @zz-jason’s question is,

is there a scenario where a user with BACKUP_ADMIN but not a SUPER privilege?

Yes, it has. On cloud, SRE should have the ability to perform BACKUP, without a SUPER privilege. So the BACKUP_ADMIN privilege should be granted to SRE’s account.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay. Yes, consider the case that the backup is encrypted. You might have permission to configure the backup and restore, but no visibility into the data. This is a good feature to have.

| Account Name | root | cloudAdmin |
| --------------- | --------------- | --------------- |
| Backup & Restore to cloud | Y | Y |
| File privilege | N | N |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another question is currently cloudAdmin does not have FILE privilege, but if SREs do want this privilege in the future, how will they grant it to themselves.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible by starting the server up in skip-grant-tables mode. I would say for security reasons they should avoid needing FILE though. Instead of using SELECT INTO OUTFILE, they can use the client to write the file:

mysql -BNe "SELECT * FROM db.table" > output.txt

This is a lot less vulnerable to privilege escalations.

Copy link
Contributor

@SunRunAway SunRunAway Mar 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can cloudAdmin insert into some information_schema tables to obtain some privileges?

I just point FILE as an example, in the future we may implement more dynamic privileges and SRE may want to use some of them.

Copy link
Contributor Author

@morgo morgo Mar 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Information_schema is always non-insertable. I think we would have to write a session/bootstrap.go task to essentially "split" a privilege to say if you have XYZ now you have XYZ and ZYX.

The problem with allowing cloudAdmin to extend their privileges is that it is essentially a privilege escalation, since you are only supposed to be able to grant privileges that you already have. There is one such "legal" privilege escalation that is hard coded into this design (SUPER always satisfies a non-restricted dynamic privilege*). The design of this legal escalation is to get around a limitation:

visitorInfo does not currently support the concept of an OR for permissions, so while in MySQL it is possible to require either BACKUP_ADMIN or SUPER the actual implementation in TiDB is that it requires BACKUP_ADMIN, but the privilege check API will explicitly fallback and check if the SUPER privilege is assigned.

* Exception = Restricted privileges

Copy link
Contributor

@SunRunAway SunRunAway Mar 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, I said the wrong table before. cloudAdmin can insert mysql.user table to extend their privilege by GRANT SELECT, INSERT, UPDATE ON mysql.* TO 'cloudAdmin'@'%%'; when initializing the account.

The requirement is reasonable because in the future we may implement more privileges like XYZ and cloudAdmin needs that.
I know there's no design for privilege escalation so maybe inserting into mysql.user is the best solution.
And I'm happy if you put this solution into your design doc and future user doc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be mysql.user to extend static privileges or mysql.global_grants for XYZ since it is a dynamic priv, followed by FLUSH PRIVILEGES. I can add a section on extending privileges; it's actually a risk to grant SELECT, INSERT, UPDATE ON mysql.*

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been added to unanswered questions here: 0ea98a1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "split" a privilege is too hacking in bootstrap.go. If you like this option, I say why not we maintain the cloudAdmin account in bootstrap.go


### Plugin API

There will need to be a way for plugins to register new dynamic privileges via their OnInit method. I propose the following:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dynamic privilege is bind with the plugin?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plugin registers the permission, but the binding is loose. If the plugin is uninstalled there could be users who still have grants assigned to those dynamic names. I checked the intended behavior in MySQL, which is to report error ErrDynamicPrivilegeNotRegistered = 3929 in revoke context, and parse error in GRANT context.

My plan is to implement a technically incompatble (but improved behavior) or returning 3929 in both instances. For example see: https://github.com/pingcap/tidb/pull/22778/files#diff-83d52377771c642f1bbe6ecaf9a98e6d3787f57c715fb468e26abce2f3d51dadR437-R442 and https://github.com/pingcap/tidb/pull/22778/files#diff-fc0b54ba2dcfe653ca33434b6eabd9d5a06e87883827b29deddc134f6941fb05R193-R195

In MySQL, uninstalling a plugin is only effective upon server restart. I believe the same is true of TiDB plugins, but effectively because there are multiple TiDB instances we need to expect that some servers may effectively not have all plugins loaded.

An alternative design would be to permanently retain registered DYNAMIC privileges in an internal table. The upside of this is fewer errors to clients. The downside is that it can produce a similar semantic to "parse but ignore", because it accepts input for which the plugins are not correctly loaded and will never be able to correctly use this functionality. i.e. it is a feature to return an error, not a bug.

@tiancaiamao
Copy link
Contributor

I like this design, DBaaS may benefit a lot from the fine-grained privileges. @tennix

@tiancaiamao
Copy link
Contributor

/LGTM

@ti-chi-bot ti-chi-bot added the status/LGT1 Indicates that a PR has LGTM 1. label Mar 17, 2021
@bb7133
Copy link
Member

bb7133 commented Mar 18, 2021

/lgtm

@ti-chi-bot
Copy link
Member

[REVIEW NOTIFICATION]

This pull request has been approved by:

  • bb7133
  • tiancaiamao

To complete the pull request process, please ask the reviewers in the list to review by filling /cc @reviewer in the comment.
After your PR has acquired the required number of LGTMs, you can assign this pull request to the committer in the list by filling /assign @committer in the comment to help you merge this pull request.

The full list of commands accepted by this bot can be found here.

Reviewer can indicate their review by writing /lgtm in a comment.
Reviewer can cancel approval by writing /lgtm cancel in a comment.

@ti-chi-bot ti-chi-bot added status/LGT2 Indicates that a PR has LGTM 2. and removed status/LGT1 Indicates that a PR has LGTM 1. labels Mar 18, 2021
@bb7133
Copy link
Member

bb7133 commented Mar 18, 2021

/merge

@ti-chi-bot
Copy link
Member

This pull request has been accepted and is ready to merge.

Commit hash: 5a0a102

@ti-chi-bot ti-chi-bot added the status/can-merge Indicates a PR has been approved by a committer. label Mar 18, 2021
@ti-chi-bot ti-chi-bot removed the status/can-merge Indicates a PR has been approved by a committer. label Mar 18, 2021
@morgo
Copy link
Contributor Author

morgo commented Mar 18, 2021

@bb7133 I added 5c92b62 because it was requested in #23223 (which canceled the merge). But it is ready to merge if you want to try again.

@SunRunAway
Copy link
Contributor

Please hold the merging, I have a few more comments. Sorry.

@breezewish
Copy link
Member

breezewish commented Mar 18, 2021

❤️ I like this feature. It is a must-have to securely serve TiDB Dashboard to users in TiDB Cloud. It also enables users to use TiDB Dashboard features without a dangerous SUPER privilege for on-premise deployments.

@SunRunAway
Copy link
Contributor

/lgtm

@bb7133
Copy link
Member

bb7133 commented Mar 19, 2021

/merge

@ti-chi-bot
Copy link
Member

This pull request has been accepted and is ready to merge.

Commit hash: 77c7b13

@ti-chi-bot ti-chi-bot added the status/can-merge Indicates a PR has been approved by a committer. label Mar 19, 2021
@bb7133
Copy link
Member

bb7133 commented Mar 19, 2021

/merge

@ti-chi-bot ti-chi-bot merged commit 520f2bb into pingcap:master Mar 19, 2021
@morgo morgo deleted the proposal-dynamic-privs branch March 22, 2021 15:43
SabaPing pushed a commit to SabaPing/tidb that referenced this pull request Mar 25, 2021
@qiancai
Copy link
Contributor

qiancai commented May 31, 2021

Hi @morgo, we are preparing the user docs for TiDB v5.1 and would like to know whether the doc changes of this PR apply to TiDB v5.1 or not. Would you please check and reply? Thanks!

@morgo
Copy link
Contributor Author

morgo commented May 31, 2021

Hi @morgo, we are preparing the user docs for TiDB v5.1 and would like to know whether the doc changes of this PR apply to TiDB v5.1 or not. Would you please check and reply? Thanks!

Yes it is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. status/can-merge Indicates a PR has been approved by a committer. status/LGT2 Indicates that a PR has LGTM 2.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants