-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Add an exclusive parameter for files entitlements #123087
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
Conversation
|
Pinging @elastic/es-core-infra (Team:Core/Infra) |
rjernst
left a 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.
A couple questions
| var paths = fileData.resolvePaths(pathLookup); | ||
| paths.forEach(path -> { | ||
| var normalized = normalizePath(path); | ||
| for (String exclusivePath : exclusivePaths) { |
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.
Shouldn't we normalize the exclusive path?
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.
This gets normalized as part of the work done in PolicyManager. However, we could pass in a List<Path> here as you suggested in a later comment and just do the same work again to be on the safe side. What do you think?
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.
Talked with @rjernst and I will change this to use Paths for validation here and normalize in FileAccessTree.
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.
Changed this to use Path via a record indicating component and module as well.
| * structures to indicate other modules aren't allowed to use these | ||
| * files in {@link FileAccessTree}s. | ||
| */ | ||
| private final List<String> exclusivePaths; |
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.
Doesn't this need to retain which module has access to the exclusive path, so that when that module's entitlements are initialized we can omit that exclusion?
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.
This list should already be validated, so that we can safely assume any read or read_write path when we constructor the module's entitlements found as an exclusive path is for that specific module already.
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 ended up adding component name and module name to check which exclusive paths should be added for each FileAccessTree to ensure paths are safely added instead of making tricky assumptions.
| if (fd.exclusive()) { | ||
| List<Path> paths = fd.resolvePaths(pathLookup).toList(); | ||
| for (Path path : paths) { | ||
| String pathStr = FileAccessTree.normalizePath(path); |
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.
Could we retain this as Path to pass into FileAccessTree, so that it can do the normalization internally?
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.
We have to normalize here to be able to validate. I'm certainly open to alternatives if you have a good one :)
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 will change this based on previous comments.
| FileData.ofPath(bootstrapArgs.logsDir(), READ_WRITE), | ||
| FileData.ofRelativePath(Path.of(""), FilesEntitlement.BaseDir.DATA, READ_WRITE), | ||
| FileData.ofPath(bootstrapArgs.repoDirResolver().apply(""), READ_WRITE), | ||
| FileData.ofPath(bootstrapArgs.tempDir(), READ_WRITE, 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.
This might benefit from an overload of ofPath that assumes 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 considered that, and I think you're right. I'll go ahead and add additional ofPaths.
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.
Instead of having a ton of overloads (which would fall to combinatorial overload if we add the platform parameter discussed separately), I wonder if FileData could have withExclusive(boolean). Then each of the 4 impls we have can recreate themselves with exclusive changed. But the ofXXX methods can still be simple as they are now. IMO this is preferable since setting exclusive to true is rare.
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 did end up changing this to @rjernst's suggestion.
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.
Yeah that's even better.
| prunedReadPaths.add(currentPath); | ||
| for (int i = 1; i < paths.size(); ++i) { | ||
| String nextPath = paths.get(i); | ||
| if (nextPath.equals(currentPath) == false && nextPath.startsWith(currentPath) == 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.
There's no need to check equals because startsWith includes that case.
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 will fix this.
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.
This change was merged as part of #123177 without the .equals
| private static boolean checkPath(String path, String[] paths) { | ||
| if (paths.length == 0) { | ||
| private boolean checkPath(String path, String[] paths) { | ||
| if (paths.length == 0 || Arrays.binarySearch(exclusivePaths, path) >= 0) { |
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.
Can someone configure exclusive access to a directory? If so, this check is insufficient I think.
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.
Please double check this logic for me -- I intend to throw in the constructor for FileAccessTree if we catch a read or read_write path that would require exclusive access to a directory for a read or read_write path. In which case, that leaves the exact match for an exclusive path in an existing read or read_write directory or it will already have thrown in the constructor.
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.
Gosh. Tricky.
Ok, suppose:
- X has read access to
/a - Y has exclusive access to
/a/b - X attempts to read
/a/b/c
I believe this combo would not be caught in the constructor (because it's valid) and we would fail to detect the violation because it's not an exact file name match.
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.
Ah, I will add this test and move the logic :)
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.
Fixed this. Thanks for showing me what was incorrect with a simple example.
exclusive path validation
prdoyle
left a 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.
Mindboggling
| + "] [" | ||
| + currentExclusivePath.moduleName() | ||
| + "] [" | ||
| + currentExclusivePath.path() |
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.
(Minor: I suppose it could be handy if we override ExclusivePath.toString to have this format.)
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.
Added.
| ExclusivePath currentExclusivePath = exclusivePaths.get(0); | ||
| for (int i = 1; i < exclusivePaths.size(); ++i) { | ||
| ExclusivePath nextPath = exclusivePaths.get(i); | ||
| if (currentExclusivePath.path().equals(nextPath.path) || isParent(currentExclusivePath.path(), nextPath.path())) { |
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.
Ah, this is pretty subtle.
Assuming the incoming list of paths has been sorted by PATH_ORDER, that does not ensure that a child is always immediately after its parent; but it does ensure that any list of paths containing one or more parent-child pairs will have at least one of those pairs adjacent, and that's enough!
For example:
/a
/a/b
/a/c
The child /a/c is not next to its parent /a, but for the sake of validation, that's ok, because to have something else (like /a/b) interleave, that must itself be a child (or descendant) of /a, and so the validation will fail on that.
I'm 95% sure this reasoning works and we're not missing a case.
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.
Should be path order and since that moves file separators to be the first character this should work. This works similarly to pruning and I think has the same guarantees here. Thanks for checking it :)
| private static boolean checkPath(String path, String[] paths) { | ||
| if (paths.length == 0) { | ||
| private boolean checkPath(String path, String[] paths) { | ||
| if (paths.length == 0 || Arrays.binarySearch(exclusivePaths, path) >= 0) { |
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.
Gosh. Tricky.
Ok, suppose:
- X has read access to
/a - Y has exclusive access to
/a/b - X attempts to read
/a/b/c
I believe this combo would not be caught in the constructor (because it's valid) and we would fail to detect the violation because it's not an exact file name match.
| this.entitlementsModule = entitlementsModule; | ||
| this.pathLookup = requireNonNull(pathLookup); | ||
| this.defaultFileAccess = FileAccessTree.of(FilesEntitlement.EMPTY, pathLookup); | ||
| this.defaultFileAccess = FileAccessTree.of("", "", FilesEntitlement.EMPTY, pathLookup, List.of()); |
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.
These empty strings give me the willies, but I'm not sure what to replace them with. 🤔
I'm fine with them if everyone else is.
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 switched this to use to the existing (unknown)
| String componentName, | ||
| String moduleName, | ||
| List<Entitlement> entitlements, | ||
| List<ExclusiveFileEntitlement> exclusiveFileEntitlements |
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.
It looks like this is an "out parameter"? That probably deserves a javadoc.
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.
Added.
rjernst
left a 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.
LGTM
| String modeAsString = (String) file.remove("mode"); | ||
| String platformAsString = (String) file.remove("platform"); | ||
| String ignoreUrlAsString = (String) file.remove("ignore_url"); | ||
| Boolean exclusiveBoolean = (Boolean) file.remove("exclusive"); |
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.
Can we have a better error message in case this is a string?
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.
Fixed.
This adds an exclusive parameter for FilesEntitlement where a path can be made exclusive for a certain module. Should two modules attempt to both specify the same path as exclusive an exception is thrown.
This adds an exclusive parameter for FilesEntitlement where a path can be made exclusive for a certain module. Should two modules attempt to both specify the same path as exclusive an exception is thrown.
This adds an exclusive parameter for FilesEntitlement where a path can be made exclusive for a certain module. Should two modules attempt to both specify the same path as exclusive an exception is thrown.
With the introduction of entitlements (elastic#120243) and exclusive file access (elastic#123087) it is no longer safe to watch a whole directory. In a lot of deployments, the parent directory for SSL config files will be the main config directory, which also contains exclusive files such as SAML realm metadata or File realm users. Watching that directory will cause entitlement warnings because it is not permissible for core/ssl-config to read files that are exclusively owned by the security module (or other modules)
With the introduction of entitlements (#120243) and exclusive file access (#123087) it is no longer safe to watch a whole directory. In a lot of deployments, the parent directory for SSL config files will be the main config directory, which also contains exclusive files such as SAML realm metadata or File realm users. Watching that directory will cause entitlement warnings because it is not permissible for core/ssl-config to read files that are exclusively owned by the security module (or other modules)
With the introduction of entitlements (#120243) and exclusive file access (#123087) it is no longer safe to watch a whole directory. In a lot of deployments, the parent directory for SSL config files will be the main config directory, which also contains exclusive files such as SAML realm metadata or File realm users. Watching that directory will cause entitlement warnings because it is not permissible for core/ssl-config to read files that are exclusively owned by the security module (or other modules)
With the introduction of entitlements (elastic#120243) and exclusive file access (elastic#123087) it is no longer safe to watch a whole directory. In a lot of deployments, the parent directory for SSL config files will be the main config directory, which also contains exclusive files such as SAML realm metadata or File realm users. Watching that directory will cause entitlement warnings because it is not permissible for core/ssl-config to read files that are exclusively owned by the security module (or other modules)
This adds an exclusive parameter for
FilesEntitlementwhere a path can be made exclusive for a certain module. Should two modules attempt to both specify the same path as exclusive an exception is thrown.ES-10845