make sort/ro commands validate external keys access patterns (#10106)#10340
make sort/ro commands validate external keys access patterns (#10106)#10340oranagra merged 24 commits intoredis:unstablefrom
Conversation
…redis#10106) Currently the sort and sort_ro can access external keys via 'get' and 'by' in order to make sure the user cannot violate the authorization ACL rules, the decision is to match the external keys access patterns as literals to the acl key patterns. redis#10106
madolson
left a comment
There was a problem hiding this comment.
@oranagra Want to get your opinion on this approach over the original one discussed in the PR. This draws inspiration from how we handle channel patterns to have a simpler ACL check that happens before command execution as opposed to during.
|
@madolson I did't read the code, but after reading the top comment, i must say i don't like option [1]. I think of SORT BY as being the same as EVAL which didn't declare all the key-names it accessed. I.e I think that during the collection of the data when processing the GET and BY argument, we should call some ACL function that will take the command name ("SORT" in this case), and the key name as argument, run though all the selectors and call ACLSelectorCheckKey (on the ones that are allowed to use the command given), if the check fails, it'll return an error which will cause the rest of the sorting operation to abort and fail (replying with a standard ACL permission error reply). In some sense it's similar to option [3], but i think it's slightly simpler to implement (multiple calls to ACL instead of collecting the key names). @yossigo @itamarhaber please share your thoughts too. |
@oranagra Just to support Option 1 - it is does have the less effect over SORT performance. So while sorting the list some keys will fall in the first selector, while others in the second one. |
I think this isn't quite correct, because EVAL generates fully formed commands to execute which is what ACLs match against anyways. These commands can be arbitrary, so you have to fully validate everything. Here we can actually declare most of what we're actually interacting with ahead of time. |
|
[edit, this is a response to Ran's last post] I disagree about the desired outcome of the example you gave. I do think it should pass. I'll use the analogy of scripts, imagine an ACL rule that grants full permission to EVAL for all keys (since we don't know how it'll use them, if for read or for write), and then restricts SET to use some keys and GET to use others. I'd even argue that if we have one selector allowing SUNION to access some keys, and another selector allowing SUNION to access other keys, when we block an SUNION that attempts to access both, I might consider it a bug. |
We DO BLOCK this SUNION example though. ACLs work by having independent sets of rules verifying a command and keys as a unit. We have sort of hijacked them in a couple of places like the modules code, which allows viewing of keys in isolation. Saying that SORT is basically eval that does a GET + sort in an EVAL is fairly inconsistent with the rest of Redis. My opinion is that there are two consistent options:
|
|
I know we block my SUNION example, but I think from a certain respective it's odd. I guess we must wait for other team members opinion.. |
|
I agree with @madolson about [3] being consistent. I don't consider [1] a consistent option though, because we only applied it as a specific workaround for channels, but not for key access. I also think it will be pretty odd and unexpected for users. That said, given that Also, if we're willing to make a big compromises here, another option is to completely reject |
|
Thank you @yossigo and @oranagra for your feedback! |
|
I'm willing to leave DRYRUN outside the scope (will also not do the right thing for certain scripts). |
I am also personally totally okay with this, FWIW. I would like to call attention to the fact that in cluster mode, these options are already disallowed since we didn't know the keys ahead of time. |
|
I think the majority supports the idea of restricting sort to require all keys read access (or allkeys) as was suggested by @yossigo. |
|
i don't like it that much. i'll be willing let it go. but we didn't hear from other team members, so i think you should wait before implementing. |
|
@ranshid The core group met. We decided to go with the option that Yossi proposed, to only allow the GET and BY arguments when the user has all key permissions with the SORT command. The reason being that it is not supported in cluster mode since it doesn't declare keys. If in the fullness of time someone comes and complains about wanting fine grain access support for SORT, we would implement 3. If you can, please post the temp code you had so that it's available for if we decide to with option 3. |
|
please also mention this plan and reasoning in the top comment. |
…ions with the SORT command.
|
haven't reviewed the code yet, but the top comment seems off, the TLDR part mentioned matching patterns as literals (option 1), but the text below it said we'll completely block it when ACL has key restrictions. I edited the top comment (modifying the TLDR part, the justification, and mentioning an optimization in option 3). |
Co-authored-by: Madelyn Olson <[email protected]>
Co-authored-by: Madelyn Olson <[email protected]>
madolson
left a comment
There was a problem hiding this comment.
minor comments, lgtm otherwise.
Co-authored-by: Madelyn Olson <[email protected]>
madolson
left a comment
There was a problem hiding this comment.
LGTM @redis/core-team Need your approval.
This is a POC implementation for Option 3 as suggested in redis#10340. Please note: 1. Code still might need refactoring 2. Need to add tests as this implementation does not support Dryrun acl 3. Need to run prformance tests on sort in order to verify potential performance degradation
This reverts commit 79e7d8f.
This reverts commit 5025434.
This reverts commit 7fa2f40.
This reverts commit 8cfb89a.
… permissions with the SORT command." This reverts commit c96e930.
This reverts commit ab35a73.
… changes" This reverts commit cfa6a0f.
This reverts commit 3852f8e.
This reverts commit a97e8cd.
…patterns (redis#10106)" This reverts commit 45f651e.
oranagra
left a comment
There was a problem hiding this comment.
LGTM. (what we decided, which is a bad solution but with low complexity and impact on common use cases, and limitations on uncommon ones)
merging.
TL;DR
Currently the sort and sort_ro can access external keys via
GETandBYin order to make sure the user cannot violate the authorization ACL
rules, the decision is to reject external keys access patterns unless ACL allows SORT full access to all keys.
I.e. for backwards compatibility, SORT with GET/BY keeps working, but if ACL has restrictions to certain keys, these features get permission denied.
see issue: #10106
Implemented solution
We have discussed several potential solutions and decided to only allow the GET and BY arguments when the user has all key permissions with the SORT command. The reasons being that SORT with GET or BY is problematic anyway, for instance it is not supported in cluster mode since it doesn't declare keys, and we're not sure the combination of that feature with ACL key restriction is really required.
HOWEVER If in the fullness of time we will identify a real need for fine grain access support for SORT, we would implement the complete solution which is Option [3]
Proposed solutions
1. (this PR) Only allow use of "GET" and "BY" patterns in sort in case the user has full key access
In the scope of this solution we will only allow sort and sort_ro to use "get" and "by" key patterns ('get #' is NOT considered key access pattern, as it does not access any key)
2. treat restricted keys as "not-exist"
In the scope of this solution we will have to "keep" the selector which was matched to validate the sort command, and use it to verify every key access during the actual sort execution. in case of an unauthorized access to a key, the command will NOT fail, but treat that key as "not exist" and null be be used for the value.
example:
calling
sort mylist by w* get v*will return:the downside of this solution is that the first selector matching the sort command might not be the optimal selector.
for example in case in the above scenario:
calling
sort mylist by w* get v*will return:which is sub-optimal.
3. Check sort ACL rules after executing it and before commiting output (either via store or to COB)
This is the most complicated of the 3 solutions. it would require making several changes to the sort command itself. and would potentially cause performance degradation since we will have to collect all the get keys instead of just applying them to a temp array and then scan the access keys against the ACL selectors.
This solution can include an optimization to avoid the overheads of collecting the key names, in case the ACL rules grant SORT full key-access, or if the ACL key pattern literal matches the one used in GET/BY (see option 1).
It would also mean that authorization would be O(nlogn) since we will have to complete most of the command execution before we can perform verification
Suggested implementation (still needs some refactoring): https://github.com/ranshid/redis/tree/oss-sort-acl-option3
todo: