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

Feature activation for multi-tenancy #2568

Closed
wants to merge 3 commits into from

Conversation

peternied
Copy link
Member

Description

Reusing saveAnUpdateConfigs to perform specific updates on the multitenancy_enabled configuration flag.

New APIs

  • GET /_plugins/_security/config/tenancy/multitenancy_enabled
  • PUT /_plugins/_security/config/tenancy/multitenancy_enabled

New Permissions

  • securityconfig:admin/config/tenancy/multitenancy_enabled/read
  • securityconfig:admin/config/tenancy/multitenancy_enabled/update

Issues Resolved

Testing

New integration tests have been included that exercise the new actions functionality.

Check List

  • New functionality includes testing
  • New functionality has been documented
  • Commits are signed per the DCO using --signoff

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

Reusing saveAnUpdateConfigs to perform specific updates on the `multitenancy_enabled` configuration flag.

New APIs
 - GET /_plugins/_security/config/tenancy/multitenancy_enabled
 - PUT /_plugins/_security/config/tenancy/multitenancy_enabled

New Permissions
 - securityconfig:admin/config/tenancy/multitenancy_enabled/read
 - securityconfig:admin/config/tenancy/multitenancy_enabled/update

Signed-off-by: Peter Nied <[email protected]>
Copy link
Member Author

@peternied peternied left a comment

Choose a reason for hiding this comment

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

Added some inline comments if we look to move forward with this as dynamic configuration via a 'feature activate' pattern.

import org.opensearch.core.xcontent.ToXContentObject;
import org.opensearch.core.xcontent.XContentBuilder;

public class BooleanSettingRetrieveResponse extends ActionResponse implements ToXContentObject {
Copy link
Member Author

Choose a reason for hiding this comment

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

If there are additional actions that reuse this pattern { "value": {VALUE} } these names might need to be made more generic and moved outside of the tenancy package. The same is true for the Request types as well.

@@ -92,8 +92,6 @@
import org.opensearch.security.test.helper.cluster.ClusterInfo;
import org.opensearch.security.test.helper.file.FileHelper;

import static org.junit.jupiter.api.Assertions.fail;
Copy link
Member Author

Choose a reason for hiding this comment

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

I was getting missing class exception when this assertion was triggered at runtime.

Copy link
Member

Choose a reason for hiding this comment

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

Interesting. I checked out your branch and restored the original code and it worked fine for me. ./gradlew test --tests TenancyActionsTests

Package Tests Failures Ignored Duration Success rate
org.opensearch.security.multitenancy.test 2 0 0 12.698s 100%

Signed-off-by: Peter Nied <[email protected]>
Copy link
Member

@DarshitChanpura DarshitChanpura left a comment

Choose a reason for hiding this comment

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

Nice work @peternied !

public class MultiTenancyRetrieveAction extends ActionType<BooleanSettingRetrieveResponse> {

public static final MultiTenancyRetrieveAction INSTANCE = new MultiTenancyRetrieveAction();
public static final String NAME = "securityconfig:admin/config/tenancy/multitenancy_enabled/read";
Copy link
Member

Choose a reason for hiding this comment

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

What do you think about using cluster:admin/config/tenancy/multitenancy_enabled/read?
This is currently being used in ConfigUpdateAction.java

public static final String NAME = "cluster:admin/opendistro_security/config/update";

Copy link
Member Author

@peternied peternied Mar 20, 2023

Choose a reason for hiding this comment

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

I was thinking about making a new prefix instead of 'cluster'. What would you think about feature:cluster/tenancy/multitenancy_enabled/(read|update) instead?

I'd like it to be unassociated from where the setting is stored, it should be abstract enough it could move to another plugin, it should indicate the scope (e.g. cluster wide!), and then the local namespace tenancy followed by feature name.

What do you think, other recommendations?

Copy link
Contributor

Choose a reason for hiding this comment

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

What do you think about swapping the order of feature:cluster to be cluster:feature? Unless there is a reason to put feature first, I am generally in favor of broadest-->granlur(est) ordering for the route. What do you think?

Copy link
Member

Choose a reason for hiding this comment

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

I like the idea of cluster:feature/... This should be clear in reading and will identify the scopes in the decreasing order.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've updated it to cluster:feature/tenancy/multitenancy_enabled/update - but it seems like we should also update the rest request url to be inline with this, otherwise the coupling is still in place.

public class MultiTenancyUpdateAction extends ActionType<BooleanSettingRetrieveResponse> {

public static final MultiTenancyUpdateAction INSTANCE = new MultiTenancyUpdateAction();
public static final String NAME = "securityconfig:admin/config/tenancy/multitenancy_enabled/update";
Copy link
Member

Choose a reason for hiding this comment

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

What do you think about using cluster:admin/config/tenancy/multitenancy_enabled/update?
This is currently being used in ConfigUpdateAction.java

public static final String NAME = "cluster:admin/opendistro_security/config/update";

Copy link
Member Author

Choose a reason for hiding this comment

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

The point of these new actions is they can be permissioned separately from the security config, if I make them the same this removes its benefit, see the related issue for details

@@ -92,8 +92,6 @@
import org.opensearch.security.test.helper.cluster.ClusterInfo;
import org.opensearch.security.test.helper.file.FileHelper;

import static org.junit.jupiter.api.Assertions.fail;
Copy link
Member

Choose a reason for hiding this comment

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

Interesting. I checked out your branch and restored the original code and it worked fine for me. ./gradlew test --tests TenancyActionsTests

Package Tests Failures Ignored Duration Success rate
org.opensearch.security.multitenancy.test 2 0 0 12.698s 100%

Copy link
Contributor

@stephen-crawford stephen-crawford left a comment

Choose a reason for hiding this comment

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

Overall I think this looks good.

public class MultiTenancyRetrieveAction extends ActionType<BooleanSettingRetrieveResponse> {

public static final MultiTenancyRetrieveAction INSTANCE = new MultiTenancyRetrieveAction();
public static final String NAME = "securityconfig:admin/config/tenancy/multitenancy_enabled/read";
Copy link
Contributor

Choose a reason for hiding this comment

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

What do you think about swapping the order of feature:cluster to be cluster:feature? Unless there is a reason to put feature first, I am generally in favor of broadest-->granlur(est) ordering for the route. What do you think?

@cwperks
Copy link
Member

cwperks commented Mar 20, 2023

@peternied IMO An action like securityconfig:admin/config/tenancy/multitenancy_enabled/update is overly narrow and won't scale well for all of the possible values that could be placed within config.yml.

What do you think about going one step up to say securityconfig:admin/config/opensearch_dashboards/edit which would allow the user of the API to PATCH the whole dynamic OSD config or PATCH a specific value using the same pattern as the PATCH configuration endpoint: https://opensearch.org/docs/2.6/security/access-control/api/#patch-configuration

Something like

PATCH /_plugins/_security/api/securityconfig/opensearch_dashboards
[
  {
    "op": "replace", "path": "/config/dynamic/kibana/multitenancy_enabled", "value": "true"
  }
]

And then this endpoint can be supported without having plugins.security.unsupported.restapi.allow_securityconfig_modification: true setting in opensearch.yml

Signed-off-by: Peter Nied <[email protected]>
@codecov-commenter
Copy link

codecov-commenter commented Mar 20, 2023

Codecov Report

Merging #2568 (d861441) into main (ca4d752) will increase coverage by 0.04%.
The diff coverage is 73.33%.

📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more

@@             Coverage Diff              @@
##               main    #2568      +/-   ##
============================================
+ Coverage     61.28%   61.32%   +0.04%     
- Complexity     3333     3360      +27     
============================================
  Files           260      268       +8     
  Lines         18509    18598      +89     
  Branches       3269     3269              
============================================
+ Hits          11344    11406      +62     
- Misses         5573     5594      +21     
- Partials       1592     1598       +6     
Impacted Files Coverage Δ
...earch/security/dlic/rest/api/MigrateApiAction.java 4.30% <0.00%> (ø)
...action/tenancy/BooleanSettingRetrieveResponse.java 57.14% <57.14%> (ø)
...ensearch/security/action/tenancy/EmptyRequest.java 60.00% <60.00%> (ø)
...ty/action/tenancy/BooleanSettingUpdateRequest.java 61.11% <61.11%> (ø)
...ion/tenancy/MultiTenancyUpdateTransportAction.java 76.00% <76.00%> (ø)
...curity/action/tenancy/MutliTenancyRestHandler.java 77.77% <77.77%> (ø)
.../opensearch/security/OpenSearchSecurityPlugin.java 80.00% <100.00%> (+0.12%) ⬆️
...ity/action/tenancy/MultiTenancyRetrieveAction.java 100.00% <100.00%> (ø)
...n/tenancy/MultiTenancyRetrieveTransportAction.java 100.00% <100.00%> (ø)
...urity/action/tenancy/MultiTenancyUpdateAction.java 100.00% <100.00%> (ø)
... and 6 more

... and 7 files with indirect coverage changes

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@peternied
Copy link
Member Author

IMO An action like securityconfig:admin/config/tenancy/multitenancy_enabled/update is overly narrow and won't scale well for all of the possible values that could be placed within config.yml.

Thanks for the comment @cwperks - I do not think every configuration setting should be exposed this way; however, this granularity allows for control over a subset of the values around the tenancy feature settings.

Circling back to the original problem from #2444 the OpenSearch Managed Service does not provide access to modify the security configuration by its users. So when there is a value that is controlled by that configuration that could be allowed there is no way to expose access to it. In PR #2444 the multitenancy_enabled value is duplicated and synchronized.

This draft pull request was created to granularize the access to that setting so it could be modified by users that are not running as super admin.

What do you think about ... PATCH!

I think this is another approach that could be taken on to support the user scenarios for #2444. However, I didn't create a POC around this scenario for a couple of reasons:

  • Lack of Abstraction, There is a strong desire to decouple tenancy setup/configuration from the security plugin. Reusing security API features will effectively need to be deprecated and migration will need to be undertaken vs a new abstracted API for enabling/disabling the feature could avoid this user migration even if the underlying APIs shift to a new plugin/extension.
  • Security Risks, Limiting the write/read surface area of a tenancy-focused patch request needs solid error checking. Path traversal or other kinds of actions could result in a CVE - a pretty urgent one. While this is likely very doable I didn't want to risk it for a feature that is targeting the next release.
  • No Authorization in SecurityConfigAction, the existing action is built off of AbstractApiAction which is only in REST Layer. We would need to build a new AuthZ system/connector to use the same kinds of permissions that are assignable via role/role mapping."

@peternied
Copy link
Member Author

@abhivka7 I am not planning on iterating on this pull request any more. There are a couple of outstanding items - I think you could pull this draft PR in to your change in #2444 to get unblocked or maybe pivot with some of he ideas here. Feel free to @mention me if you have questions.

@peternied
Copy link
Member Author

Closing out this reference pull request, thanks everyone for the discussion and review!

@peternied peternied closed this Apr 1, 2023
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.

5 participants