-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Add table functions support to File-based access control #13713
Add table functions support to File-based access control #13713
Conversation
Thank you for your pull request and welcome to our community. We could not parse the GitHub identity of the following contributors: Hubert Łojek.
|
00a16fb
to
710d83f
Compare
Thank you for your pull request and welcome to our community. We could not parse the GitHub identity of the following contributors: Hubert Łojek.
|
710d83f
to
67de34c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can continue with testing.
looks good to me
...plugin-toolkit/src/main/java/io/trino/plugin/base/security/FileBasedSystemAccessControl.java
Show resolved
Hide resolved
...ugin-toolkit/src/main/java/io/trino/plugin/base/security/TableFunctionAccessControlRule.java
Outdated
Show resolved
Hide resolved
@@ -273,6 +284,7 @@ private static SystemAccessControl create(String configFileName) | |||
.setTableRules(rules.getTableRules().orElse(ImmutableList.of(CatalogTableAccessControlRule.ALLOW_ALL))) | |||
.setSessionPropertyRules(rules.getSessionPropertyRules().orElse(ImmutableList.of(SessionPropertyAccessControlRule.ALLOW_ALL))) | |||
.setCatalogSessionPropertyRules(rules.getCatalogSessionPropertyRules().orElse(ImmutableList.of(CatalogSessionPropertyAccessControlRule.ALLOW_ALL))) | |||
.setTableFunctionRules(rules.getTableFunctionRules().orElse(ImmutableList.of(CatalogTableFunctionAccessControlRule.ALLOW_ALL))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -953,7 +965,7 @@ public void checkCanExecuteFunction(SystemSecurityContext systemSecurityContext, | |||
@Override | |||
public void checkCanExecuteFunction(SystemSecurityContext systemSecurityContext, FunctionKind functionKind, CatalogSchemaRoutineName functionName) | |||
{ | |||
if (functionKind == TABLE) { | |||
if (functionKind == TABLE && !checkTableFunctionPermission(systemSecurityContext, functionName)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be that's good enough for table functions, but IIRC the eventual goal is to use CatalogSchemaRoutineName
for functionName
for other FunctionKind
s too.
The proposed config syntax is too specific to table functions too:
{
"table_functions": [
{
"user": "admin",
"catalog": "postgresql",
"schema": "system",
"table_function": "query"
}
]
}
I think it worth to go with something like
{
"function": [
{
"user": "admin",
"function_kind": "TABLE",
"catalog": "postgresql",
"schema": "system",
"function": "query"
}
]
}
I'd base code for functions on the code for tables, e.g.
@Override
public void checkCanExecuteFunction(SystemSecurityContext systemSecurityContext, FunctionKind functionKind, CatalogSchemaRoutineName function)
{
// TODO config to disable for old function kinds
AccessMode requiredCatalogAccess = FunctionKind.TABLE.equals(functionKind) ? ALL : READ_ONLY;
if (!checkFunctionPermission(systemSecurityContext, function, requiredCatalogAccess, FunctionPrivilege.SELECT)) {
denyExecuteFunction(function.toString());
}
}
private boolean checkFunctionPermission(SystemSecurityContext context, CatalogSchemaRoutineName function, AccessMode requiredCatalogAccess, FunctionPrivilege checkPrivilege)
{
if (!canAccessCatalog(context, function.getCatalogName(), requiredCatalogAccess)) {
return false;
}
if (INFORMATION_SCHEMA_NAME.equals(function.getSchemaName())) {
return true;
}
Identity identity = context.getIdentity();
for (CatalogFunctionAccessControlRule rule : functionRules) {
if (rule.matches(identity.getUser(), identity.getEnabledRoles(), identity.getGroups(), function)) {
return rule.getPrivileges().contains(checkPrivilege);
}
}
return false;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a valid concern. If the plan is to have other catalog/schema function kinds in the future then the current syntax would require backward incompatible change or keeping TABLE
as the default function kind. Neither of which is desired.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lukasz-walkiewicz I confirm that the discussed method checkCanExecuteFunction()
will be used for all function kinds in the future.
@ssheikin, regarding this part:
AccessMode requiredCatalogAccess = FunctionKind.TABLE.equals(functionKind) ? ALL : READ_ONLY;
if (!checkFunctionPermission(systemSecurityContext, function, requiredCatalogAccess, FunctionPrivilege.SELECT)) {
denyExecuteFunction(function.toString());
}
requiring catalog access ALL
is safe, but might be unnecessarily restrictive for some Table Functions (think: sequence generator, random generator etc. which do not access any data even for reading).
I also wonder how it fits the future model where all built-in functions are provided by the Global catalog. The built-in table functions should be easily available to anyone, without granting them that level of access to the catalog.
Ideally, the required catalog access should be set for each table function independently.
What does FunctionPrivilege.SELECT
refer to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugly initial draft based on file based access control of tables: #13903 . NOT to review. Only for sake of history.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dain your suggestions would be very helpful here:
- What catalog access should we require for table functions? How about the built-in functions provided by the Global catalog?
- Could we possibly specify the required access per table function? Some functions read data (query pass-through), some might modify the catalog, and some don't touch anything (sequence).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I add support for every function kind
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally, the required catalog access should be set for each table function independently.
Now I think this makes sense in case of UDFs as well.
I will take a look into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In theory user might prepare UDF which will make some modifications - this is such edge case probably we should not take care of this. Also we do not have an information which catalog would be modified in such UDF.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it's time for that eventually
#12544 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or at least
this is such edge case probably we should not take care of this
.... YET
...trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/FileBasedAccessControl.java
Outdated
Show resolved
Hide resolved
67de34c
to
2cd9937
Compare
...trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/FileBasedAccessControl.java
Outdated
Show resolved
Hide resolved
...no-plugin-toolkit/src/main/java/io/trino/plugin/base/security/FunctionAccessControlRule.java
Outdated
Show resolved
Hide resolved
...plugin-toolkit/src/main/java/io/trino/plugin/base/security/FileBasedSystemAccessControl.java
Outdated
Show resolved
Hide resolved
...trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/FileBasedAccessControl.java
Show resolved
Hide resolved
...no-plugin-toolkit/src/main/java/io/trino/plugin/base/security/FunctionAccessControlRule.java
Outdated
Show resolved
Hide resolved
...no-plugin-toolkit/src/main/java/io/trino/plugin/base/security/FunctionAccessControlRule.java
Outdated
Show resolved
Hide resolved
...trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/FileBasedAccessControl.java
Outdated
Show resolved
Hide resolved
2cd9937
to
a39b483
Compare
This PR resolves #12833 |
1a2553b
to
a47bfe9
Compare
{ | ||
this.schemaRules = schemaRules.orElse(ImmutableList.of(SchemaAccessControlRule.ALLOW_ALL)); | ||
this.tableRules = tableRules.orElse(ImmutableList.of(TableAccessControlRule.ALLOW_ALL)); | ||
this.sessionPropertyRules = sessionPropertyRules.orElse(ImmutableList.of(SessionPropertyAccessControlRule.ALLOW_ALL)); | ||
this.functionRules = functionRules.orElse(ImmutableList.of(FunctionAccessControlRule.ALLOW_ALL)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before this PR with File-based access control enabled every table functions was denied.
By default every rule kind (access to catalogs, schemas, tables) is allow when user does not specify any rule.
The same behavior is also here. After upgrading Trino to newer version and without making any changes to access rules, access to every table function will change and by default it will be allow. Is that good behavior? Maybe in case of table functions new default should be deny but this makes those new rules inconsistent with the rest.
Let's discuss this in the separate thread.
Before this PR with File-based access control enabled every table functions was denied.
I think it's a correct implementation, fast one, but which was not really thought that deep to be very compatible with FBAC.
Maybe in case of table functions new default should be deny but this makes those new rules inconsistent with the rest.
I guess access to ptf should obey the same rules as other entities of FBAC do.
By default every rule kind (access to catalogs, schemas, tables) is allow when user does not specify any rule.
The same behavior is also here. After upgrading Trino to newer version and without making any changes to access rules, access to every table function will change and by default it will be allow. Is that good behavior?
ptf were just introduced and with only one built in ptf.Query
function. It's questionable if there are cases where FBAC with PTF is used by someone.
Consistency it's a long term thing.
I finally got to reviewing this PR ;) As I understand it, it's blocked on adding additional methods to the access control interfaces, right? Also, tests will be needed. |
dc3ff73
to
8528641
Compare
...in-toolkit/src/main/java/io/trino/plugin/base/security/CatalogFunctionAccessControlRule.java
Outdated
Show resolved
Hide resolved
8528641
to
c4059fd
Compare
...no-plugin-toolkit/src/main/java/io/trino/plugin/base/security/FunctionAccessControlRule.java
Outdated
Show resolved
Hide resolved
42f0289
to
fb19a4d
Compare
...no-plugin-toolkit/src/main/java/io/trino/plugin/base/security/FunctionAccessControlRule.java
Outdated
Show resolved
Hide resolved
...no-plugin-toolkit/src/main/java/io/trino/plugin/base/security/FunctionAccessControlRule.java
Outdated
Show resolved
Hide resolved
...trino-plugin-toolkit/src/test/resources/file-based-disallow-function-rule-combination-2.json
Outdated
Show resolved
Hide resolved
...in-toolkit/src/main/java/io/trino/plugin/base/security/CatalogFunctionAccessControlRule.java
Show resolved
Hide resolved
...in-toolkit/src/main/java/io/trino/plugin/base/security/CatalogFunctionAccessControlRule.java
Outdated
Show resolved
Hide resolved
067f379
to
36ac692
Compare
I added more real case scenario test |
36ac692
to
2d7a769
Compare
@Test | ||
public void testPtfViewsCreatedByAlice() | ||
{ | ||
QueryError queryError = executeAsUser("CREATE VIEW blackhole.default.view_ptf_alice_security_definer SECURITY DEFINER AS SELECT * FROM TABLE(mock.system.simple_table_function())", ALICE_USER); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inline everywhere except where it is reused.
380877c
to
ce723a3
Compare
...rino-tests/src/test/java/io/trino/security/TestViewsWithPtfFileBasedSystemAccessControl.java
Outdated
Show resolved
Hide resolved
ce723a3
to
5e5e563
Compare
5e5e563
to
4db3ca7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
assertQuerySucceeds(BOB_USER, "CREATE VIEW blackhole.default.view_ptf_bob_security_definer SECURITY DEFINER AS SELECT * FROM TABLE(mock.system.simple_table_function())"); | ||
String securityDefinerQuery = "SELECT * FROM blackhole.default.view_ptf_bob_security_definer"; | ||
assertAccessDenied(ALICE_USER, securityDefinerQuery, "View owner does not have sufficient privileges: 'bob' cannot grant 'mock\\.system\\.simple_table_function' execution to user 'alice'"); | ||
assertQuerySucceeds(BOB_USER, securityDefinerQuery); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's an interesting behaviour, that Bob
himself can actually query the view but no one else can. It's probably because view owner = view invoker.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
io.trino.sql.analyzer.StatementAnalyzer.Visitor#analyzeView
🎉 |
Description
This PR adds File-based access control support for table functions.
Before this PR with File-based access control enabled every table functions was denied.
By default every rule kind (access to catalogs, schemas, tables) is allow when user does not specify any rule.
The same behavior is also here. After upgrading Trino to newer version and without making any changes to access rules, access to every table function will change and by default it will be
allow
. To restore previous behavior user needs to add:Examples System-level access control file
postgresql.system.query
foradmin
user.query
table function from every catalog & schema foradmin
user.mysql.system.query
for anyone.privileges
values:EXECUTE
andGRANT_EXECUTE
- the second one allows to execute a function fromSECURITY DEFINER
viewfunction_kinds
values:SCALAR
,AGGREGATE
,WINDOW
andTABLES
, it's required to provide at least one value, also when user define a rule forAGGREGATE
,SCALAR
orWINDOW
function,catalog
andschema
are disallowedDocumentation
( ) No documentation is needed.
( ) Sufficient documentation is included in this PR.
(x) Documentation PR is available with #14774.
( ) Documentation issue #issuenumber is filed, and can be handled later.
Release notes
( ) No release notes entries required.
(x) Release notes entries required with the following suggested text: