-
Notifications
You must be signed in to change notification settings - Fork 279
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
Changes to make PIT security model granular #2053
Changes from 3 commits
d5c482e
953748f
dd830b4
eeff45e
4a8ad4c
4380e77
e440c35
54d80cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -233,8 +233,10 @@ manage_point_in_time: | |
static: true | ||
allowed_actions: | ||
- "indices:data/read/point_in_time/create" | ||
- "cluster:admin/point_in_time/delete" | ||
- "cluster:admin/point_in_time/read*" | ||
- "indices:data/read/point_in_time/delete" | ||
- "indices:data/read/point_in_time/readall" | ||
- "indices:data/read/search" | ||
- "cluster:admin/point_in_time/read_from_nodes" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, for my understanding what is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the parent action that basically reads all active Point in time searches from nodes. This the action for NodesGetAllPitAction. We can rename it as well, if the name is confusing. |
||
- "indices:monitor/point_in_time/segments" | ||
type: "cluster" | ||
type: "index" | ||
description: "Manage point in time actions" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
/* | ||
bharath-techie marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* Copyright 2015-2018 _floragunn_ GmbH | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
/* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* The OpenSearch Contributors require contributions made to | ||
* this file be licensed under the Apache-2.0 license or a | ||
* compatible open source license. | ||
* | ||
* Modifications Copyright OpenSearch Contributors. See | ||
* GitHub history for details. | ||
*/ | ||
package org.opensearch.security; | ||
|
||
import org.apache.http.HttpStatus; | ||
import org.junit.Assert; | ||
import org.junit.Test; | ||
|
||
import org.opensearch.action.index.IndexRequest; | ||
import org.opensearch.action.support.WriteRequest; | ||
import org.opensearch.client.Client; | ||
import org.opensearch.common.xcontent.XContentType; | ||
import org.opensearch.security.test.SingleClusterTest; | ||
import org.opensearch.security.test.helper.rest.RestHelper; | ||
|
||
/** | ||
* Integration tests to test point in time APIs permission model | ||
*/ | ||
public class PitIntegrationTests extends SingleClusterTest { | ||
|
||
@Test | ||
public void pitCreateWithDeleteAll() throws Exception { | ||
setup(); | ||
RestHelper rh = nonSslRestHelper(); | ||
|
||
// Create two indices | ||
try (Client tc = getClient()) { | ||
tc.index(new IndexRequest("pit_1").id("1").setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE). | ||
source("{\"content\":1}", XContentType.JSON)).actionGet(); | ||
tc.index(new IndexRequest("pit_2").id("2").setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE). | ||
source("{\"content\":2}", XContentType.JSON)).actionGet(); | ||
} | ||
|
||
RestHelper.HttpResponse resc; | ||
|
||
// Create point in time in index should be successful since the user has permission for index | ||
resc = rh.executePostRequest("/pit_1/_search/point_in_time?keep_alive=100m", "", | ||
encodeBasicHeader("pit-1", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_OK, resc.getStatusCode()); | ||
|
||
// Create point in time in index for which the user does not have permission | ||
resc = rh.executePostRequest("/pit_2/_search/point_in_time?keep_alive=100m", "", | ||
encodeBasicHeader("pit-1", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_FORBIDDEN, resc.getStatusCode()); | ||
|
||
// Create point in time in index for which the user has permission for | ||
resc = rh.executePostRequest("/pit_2/_search/point_in_time?keep_alive=100m", "", | ||
encodeBasicHeader("pit-2", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_OK, resc.getStatusCode()); | ||
|
||
// Delete all PITs should work since there is atleast one PIT for which user has access for | ||
resc = rh.executeDeleteRequest("/_search/point_in_time/_all", | ||
encodeBasicHeader("pit-1", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_OK, resc.getStatusCode()); | ||
|
||
// Delete all PITs should throw error since there are no PITs for which the user has access for | ||
resc = rh.executeDeleteRequest("/_search/point_in_time/_all", | ||
encodeBasicHeader("pit-1", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_FORBIDDEN, resc.getStatusCode()); | ||
|
||
// Delete all PITs should work since there is atleast one PIT for which user has access for | ||
resc = rh.executeDeleteRequest("/_search/point_in_time/_all", | ||
encodeBasicHeader("pit-2", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_OK, resc.getStatusCode()); | ||
|
||
// Delete all PITs throws forbidden error since there are no PITs in the cluster | ||
resc = rh.executeDeleteRequest("/_search/point_in_time/_all", | ||
encodeBasicHeader("pit-1", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_FORBIDDEN, resc.getStatusCode()); | ||
} | ||
|
||
@Test | ||
public void pitCreateWithGetAll() throws Exception { | ||
setup(); | ||
RestHelper rh = nonSslRestHelper(); | ||
|
||
// Create two indices | ||
try (Client tc = getClient()) { | ||
tc.index(new IndexRequest("pit_1").id("1").setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE). | ||
source("{\"content\":1}", XContentType.JSON)).actionGet(); | ||
tc.index(new IndexRequest("pit_2").id("2").setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE). | ||
source("{\"content\":2}", XContentType.JSON)).actionGet(); | ||
} | ||
|
||
RestHelper.HttpResponse resc; | ||
|
||
// Create point in time in index should be successful since the user has permission for index | ||
resc = rh.executePostRequest("/pit_1/_search/point_in_time?keep_alive=100m", "", | ||
encodeBasicHeader("pit-1", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_OK, resc.getStatusCode()); | ||
bharath-techie marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Create point in time in index for which the user does not have permission | ||
resc = rh.executePostRequest("/pit_2/_search/point_in_time?keep_alive=100m", "", | ||
encodeBasicHeader("pit-1", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_FORBIDDEN, resc.getStatusCode()); | ||
|
||
// Create point in time in index for which the user has permission for | ||
resc = rh.executePostRequest("/pit_2/_search/point_in_time?keep_alive=100m", "", | ||
encodeBasicHeader("pit-2", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_OK, resc.getStatusCode()); | ||
|
||
// List all PITs should work since there is atleast one PIT for which user has access for | ||
resc = rh.executeGetRequest("/_search/point_in_time/_all", | ||
encodeBasicHeader("pit-1", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_OK, resc.getStatusCode()); | ||
|
||
// PIT segments should work since there is atleast one PIT for which user has access for | ||
resc = rh.executeGetRequest("/_cat/pit_segments/_all", | ||
encodeBasicHeader("pit-1", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_OK, resc.getStatusCode()); | ||
|
||
// Delete all PITs should work since there is atleast one PIT for which user has access for | ||
resc = rh.executeDeleteRequest("/_search/point_in_time/_all", | ||
encodeBasicHeader("pit-1", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_OK, resc.getStatusCode()); | ||
|
||
|
||
// List all PITs should throw error since there are no PITs for which the user has access for | ||
resc = rh.executeGetRequest("/_search/point_in_time/_all", | ||
encodeBasicHeader("pit-1", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_FORBIDDEN, resc.getStatusCode()); | ||
|
||
// PIT segments should throw error since there are PITs in system but no PIT for which user has access for | ||
resc = rh.executeGetRequest("/_cat/pit_segments/_all", | ||
encodeBasicHeader("pit-1", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_FORBIDDEN, resc.getStatusCode()); | ||
|
||
// List all PITs should work since there is atleast one PIT for which user has access for | ||
resc = rh.executeGetRequest("/_search/point_in_time/_all", | ||
encodeBasicHeader("pit-2", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_OK, resc.getStatusCode()); | ||
|
||
// PIT segments should work since there is atleast one PIT for which user has access for | ||
resc = rh.executeGetRequest("/_cat/pit_segments/_all", | ||
encodeBasicHeader("pit-2", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_OK, resc.getStatusCode()); | ||
|
||
// Delete all PITs should work since there is atleast one PIT for which user has access for | ||
resc = rh.executeDeleteRequest("/_search/point_in_time/_all", | ||
encodeBasicHeader("pit-2", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_OK, resc.getStatusCode()); | ||
|
||
// List all PITs throws forbidden error since there are no PITs in the cluster | ||
resc = rh.executeGetRequest("/_search/point_in_time/_all", | ||
encodeBasicHeader("pit-1", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_FORBIDDEN, resc.getStatusCode()); | ||
|
||
// PIT segments API throws forbidden error since there are no PITs in the cluster | ||
resc = rh.executeGetRequest("/_search/point_in_time/_all", | ||
encodeBasicHeader("pit-1", "nagilum")); | ||
Assert.assertEquals(HttpStatus.SC_FORBIDDEN, resc.getStatusCode()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1128,7 +1128,37 @@ data_stream_3: | |
- "*" | ||
allowed_actions: | ||
- "DATASTREAM_ALL" | ||
point_in_time_1: | ||
reserved: true | ||
hidden: false | ||
description: "Migrated from v6 (all types mapped)" | ||
cluster_permissions: | ||
- "cluster:admin/point_in_time/read_from_nodes" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am concerned about adding cluster level permission it blurs the line between the index based permissions and PIT which are tightly coupled to indices, I know there is some discussion around it and I'd like to focus that discussion separately from the rest of this work to help get this PR merged more quickly - is that possible? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without cluster level permission we'd not be able to get all PITs from the cluster, as the request doesn't have indices as part of it. Any suggestions ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a place where all of the different Rest APIs are documented in the form below? I would like to be able to cross-reference the actions and associated permissions that are needed to perform them, I think that might help our understanding. Create point in time
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. opensearch-project/OpenSearch#3960 -- is the design doc There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The doc and the comments on this PR have evolved over time and it is not clear to me what the permission setup, user action, and result should be for the many scenarios embodied - please make this as clear as possible. Not only would this help us understand the specific scope and bounds of your request, this would be of great value for writing the end-user facing permissions documentation for this feature |
||
- "cluster_monitor" | ||
index_permissions: | ||
- index_patterns: | ||
- "pit_1" | ||
dls: null | ||
fls: null | ||
masked_fields: null | ||
allowed_actions: | ||
- "manage_point_in_time" | ||
|
||
point_in_time_2: | ||
reserved: true | ||
hidden: false | ||
description: "Migrated from v6 (all types mapped)" | ||
cluster_permissions: | ||
- "cluster:admin/point_in_time/read_from_nodes" | ||
- "cluster_monitor" | ||
index_permissions: | ||
- index_patterns: | ||
- "pit_2" | ||
dls: null | ||
fls: null | ||
masked_fields: null | ||
allowed_actions: | ||
- "manage_point_in_time" | ||
hidden_test: | ||
cluster_permissions: | ||
- SGS_CLUSTER_COMPOSITE_OPS | ||
|
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 avoid the format changes if not necessary.