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

Fix change detection condition on KeeperMap read-only step #256

Merged
merged 1 commit into from
Nov 7, 2024

Conversation

aris-aiven
Copy link
Contributor

@aris-aiven aris-aiven commented Nov 5, 2024

Fix change detection condition on KeeperMap read-only step

Unfortunately looking at system.grants to check whether specific grants have
been successfully revoked in ClickHouse is not perfect.

Using the system table or parsing the output or SHOW GRANTS FOR <user> makes
the step more brittle, and doesn't necessarily lead to better garantees. The fix
is to remove the watcher.

More details:

Let a user with a set of initial grants, including some ALTER statements. Doing
REVOKE INSERT, ALTER UPDATE, ALTER DELETE ON <user> FROM <table> on this
user creates rows in system.grants for each of the grants with is_partial_revoke=1.

If the user doesn't have ALTER statements in their initial grants, then
after executing REVOKE the system.grants table simply has no
corresponding rows.

@aris-aiven aris-aiven force-pushed the aris-fix-keepermap-readonly branch 3 times, most recently from f984c95 to e156304 Compare November 5, 2024 20:47
@aris-aiven aris-aiven marked this pull request as ready for review November 5, 2024 21:25
@aris-aiven aris-aiven requested a review from a team November 6, 2024 09:12
Copy link
Contributor

@joelynch joelynch left a comment

Choose a reason for hiding this comment

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

Doesn't look like it works but I might be misunderstanding.

@@ -191,36 +191,42 @@ async def revoke_write_on_table(self, table: Table, user_name: bytes) -> None:
f"REVOKE INSERT, ALTER UPDATE, ALTER DELETE ON {table.escaped_sql_identifier} FROM {escaped_user_name}"
)
await asyncio.gather(*(client.execute(revoke_statement.encode()) for client in self.clients))
await self.wait_for_access_type_grant(user_name=user_name, table=table, expected_count=0)
await self.wait_for_access_type_grant(user_name=user_name, table=table, expected_count=0, filter_partial_revoke=True)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this return if the user has a grant on the database but before the revoke goes through?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the user has an explicit grant for any of INSERT, ALTER UPDATE,ALTER DELETE the count will be greater than zero and the waiter won't return directly no.

Copy link
Contributor Author

@aris-aiven aris-aiven Nov 6, 2024

Choose a reason for hiding this comment

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

Ok actually checking that the revoke statement is in the response returned by SHOW GRANTS FOR user might be better.

Copy link
Contributor

@joelynch joelynch Nov 6, 2024

Choose a reason for hiding this comment

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

If I comment out

# await asyncio.gather(*(client.execute(revoke_statement.encode()) for client in self.clients))

this line still returns in the test test_keeper_map_table_read_only_step.

Would it make more sense to actually just check for the partial revoke. Rather than filtering out those rows.

Copy link
Contributor

@joelynch joelynch Nov 6, 2024

Choose a reason for hiding this comment

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

sql = """
SELECT access_type
FROM system.grants
WHERE ...
AND is_partial_revoke
"""
revokes = (await client.execute(sql)).data
for type in ('INSERT', 'ALTER UPDATE', 'ALTER DELETE'):
    assert type in revokes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well not really either. Here is the result for SHOW GRANTS after the execution of the grant altering statement during tests.integration.coordinator.plugins.clickhouse.test_steps.test_keeper_map_table_read_only_step

INFO     astacus.coordinator.plugins.clickhouse.steps:steps.py:227 Grants for user b'foobar': [['GRANT SHOW, SELECT, INSERT, ALTER UPDATE, ALTER DELETE, ALTER COLUMN, ALTER MODIFY COMMENT, ALTER INDEX, ALTER PROJECTION, ALTER CONSTRAINT, ALTER TTL, ALTER SETTINGS, ALTER VIEW, CREATE TABLE, DROP TABLE, TRUNCATE, OPTIMIZE, SYSTEM SYNC REPLICA ON keeperdata.* TO foobar WITH GRANT OPTION'], ['REVOKE INSERT, ALTER UPDATE, ALTER DELETE ON keeperdata.keepertable FROM foobar']]
INFO     astacus.coordinator.plugins.clickhouse.steps:steps.py:227 Grants for user b'alice': [['GRANT SELECT ON default.* TO alice'], ['GRANT bob TO alice']]
INFO     astacus.coordinator.plugins.clickhouse.steps:steps.py:227 Grants for user b'z_\x80_enjoyer': []
INFO     astacus.coordinator.plugins.clickhouse.steps:steps.py:227 Grants for user b'foobar': [['GRANT SHOW, SELECT, INSERT, ALTER UPDATE, ALTER DELETE, ALTER COLUMN, ALTER MODIFY COMMENT, ALTER INDEX, ALTER PROJECTION, ALTER CONSTRAINT, ALTER TTL, ALTER SETTINGS, ALTER VIEW, CREATE TABLE, DROP TABLE, TRUNCATE, OPTIMIZE, SYSTEM SYNC REPLICA ON keeperdata.* TO foobar WITH GRANT OPTION'], ['REVOKE GRANT OPTION FOR INSERT, ALTER UPDATE, ALTER DELETE ON keeperdata.keepertable FROM foobar']]
INFO     astacus.coordinator.plugins.clickhouse.steps:steps.py:227 Grants for user b'alice': [['GRANT SELECT ON default.* TO alice'], ['GRANT INSERT, ALTER UPDATE, ALTER DELETE ON keeperdata.keepertable TO alice'], ['GRANT bob TO alice']]
INFO     astacus.coordinator.plugins.clickhouse.steps:steps.py:227 Grants for user b'z_\x80_enjoyer': [['GRANT INSERT, ALTER UPDATE, ALTER DELETE ON keeperdata.keepertable TO `z_�_enjoyer`']]

Copy link
Contributor

Choose a reason for hiding this comment

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

Yea okay I see. Feels like it should be an upstream feature.

Copy link
Contributor Author

@aris-aiven aris-aiven Nov 6, 2024

Choose a reason for hiding this comment

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

But that's the catch, is_partial_revoke isn't a good discriminating variable. If you filter by it, and you have the grants as below (which will happen after the first backup has been taken), you might return before the grants are revoked (and those rows are gone).


user_name         role_name    access_type    database    table       column      is_partial_revoke    grant_option
----------------  -----------  -------------  ----------  ----------  --------  -------------------  --------------
aiven_monitoring               INSERT         default     keeper_map                              0               0
aiven_monitoring               ALTER UPDATE   default     keeper_map                              0               0
aiven_monitoring               ALTER DELETE   default     keeper_map                              0               0
alice                          INSERT         default     keeper_map                              0               0
alice                          ALTER UPDATE   default     keeper_map                              0               0
alice                          ALTER DELETE   default     keeper_map                              0               0
bob                            INSERT         default     keeper_map                              1               1
bob                            ALTER UPDATE   default     keeper_map                              1               1
bob                            ALTER DELETE   default     keeper_map                              1               1

@aris-aiven aris-aiven marked this pull request as draft November 6, 2024 14:44
Unfortunately looking at `system.grants` to check whether specific grants have
been successfully revoked in ClickHouse is not perfect.

Using the system table or parsing the output or ``SHOW GRANTS FOR <user>`` makes
the step more brittle, and doesn't necessarily lead to better garantees. The fix
is to remove the watcher.

More details:

Let a user with a set of initial grants, including some ALTER statements. Doing
``REVOKE INSERT, ALTER UPDATE, ALTER DELETE ON <user> FROM <table>`` on this
user creates rows in ``system.grants`` for each of the grants with ``is_partial_revoke=1``.

If the user doesn't have ``ALTER`` statements in their initial grants, then
after executing ``REVOKE`` the ``system.grants`` table simply has no
corresponding rows.
@aris-aiven aris-aiven force-pushed the aris-fix-keepermap-readonly branch from e156304 to 0a7b163 Compare November 6, 2024 15:04
@aris-aiven aris-aiven dismissed joelynch’s stale review November 6, 2024 15:07

Removed the watcher and improved the integration test

@aris-aiven aris-aiven requested review from joelynch and a team November 6, 2024 15:07
@aris-aiven aris-aiven marked this pull request as ready for review November 6, 2024 15:14
@joelynch joelynch merged commit 1ef305c into main Nov 7, 2024
2 checks passed
@joelynch joelynch deleted the aris-fix-keepermap-readonly branch November 7, 2024 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants