Skip to content

Commit 8d59880

Browse files
authored
Introduced setting for disabling denormalized privilege data structures (#5465)
Signed-off-by: Nils Bandener <[email protected]>
1 parent da7d66a commit 8d59880

File tree

6 files changed

+85
-6
lines changed

6 files changed

+85
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
1616
* Create a mechanism for plugins to explicitly declare actions they need to perform with their assigned PluginSubject ([#5341](https://github.com/opensearch-project/security/pull/5341))
1717
* Moves OpenSAML jars to a Shadow Jar configuration to facilitate its use in FIPS enabled environments ([#5400](https://github.com/opensearch-project/security/pull/5404))
1818
* Replaced the standard distribution of BouncyCastle with BC-FIPS ([#5439](https://github.com/opensearch-project/security/pull/5439))
19-
19+
* Introduced setting `plugins.security.privileges_evaluation.precomputed_privileges.enabled` ([#5465](https://github.com/opensearch-project/security/pull/5465))
2020
### Bug Fixes
2121

2222
* Fix compilation issue after change to Subject interface in core and bump to 3.2.0 ([#5423](https://github.com/opensearch-project/security/pull/5423))

src/integrationTest/java/org/opensearch/security/privileges/actionlevel/RoleBasedActionPrivilegesTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,6 +1015,25 @@ public void aliasesOnDataStreamBackingIndices() throws Exception {
10151015
);
10161016
assertThat(resultForIndexNotCoveredByAlias, isForbidden());
10171017
}
1018+
1019+
@Test
1020+
public void statefulDisabled() throws Exception {
1021+
SecurityDynamicConfiguration<RoleV7> roles = SecurityDynamicConfiguration.fromYaml(
1022+
"test_role:\n" + " index_permissions:\n" + " - index_patterns: ['test_*']\n" + " allowed_actions: ['indices:*']",
1023+
CType.ROLES
1024+
);
1025+
Map<String, IndexAbstraction> metadata = indices("test_1", "test_2", "test_3")//
1026+
.build()
1027+
.getIndicesLookup();
1028+
1029+
RoleBasedActionPrivileges subject = new RoleBasedActionPrivileges(
1030+
roles,
1031+
FlattenedActionGroups.EMPTY,
1032+
Settings.builder().put(RoleBasedActionPrivileges.PRECOMPUTED_PRIVILEGES_ENABLED.getKey(), false).build()
1033+
);
1034+
subject.updateStatefulIndexPrivileges(metadata, 1);
1035+
assertEquals(0, subject.getEstimatedStatefulIndexByteSize());
1036+
}
10181037
}
10191038

10201039
/**

src/integrationTest/java/org/opensearch/security/privileges/dlsfls/DocumentPrivilegesTest.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import org.opensearch.security.privileges.PrivilegesConfigurationValidationException;
5656
import org.opensearch.security.privileges.PrivilegesEvaluationContext;
5757
import org.opensearch.security.privileges.PrivilegesEvaluationException;
58+
import org.opensearch.security.privileges.actionlevel.RoleBasedActionPrivileges;
5859
import org.opensearch.security.resolver.IndexResolverReplacer;
5960
import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration;
6061
import org.opensearch.security.securityconf.impl.v7.RoleV7;
@@ -540,7 +541,13 @@ private DocumentPrivileges createSubject(SecurityDynamicConfiguration<RoleV7> ro
540541
roleConfig,
541542
statefulness == Statefulness.STATEFUL ? INDEX_METADATA.getIndicesLookup() : Map.of(),
542543
xContentRegistry,
543-
Settings.builder().put("plugins.security.dfm_empty_overrides_all", this.dfmEmptyOverridesAll).build()
544+
Settings.builder()
545+
.put("plugins.security.dfm_empty_overrides_all", this.dfmEmptyOverridesAll)
546+
.put(
547+
RoleBasedActionPrivileges.PRECOMPUTED_PRIVILEGES_ENABLED.getKey(),
548+
statefulness == Statefulness.STATEFUL || statefulness == Statefulness.NON_STATEFUL
549+
)
550+
.build()
544551
);
545552
}
546553
}
@@ -856,7 +863,13 @@ private DocumentPrivileges createSubject(SecurityDynamicConfiguration<RoleV7> ro
856863
roleConfig,
857864
statefulness == Statefulness.STATEFUL ? INDEX_METADATA.getIndicesLookup() : Map.of(),
858865
xContentRegistry,
859-
Settings.builder().put("plugins.security.dfm_empty_overrides_all", this.dfmEmptyOverridesAll).build()
866+
Settings.builder()
867+
.put("plugins.security.dfm_empty_overrides_all", this.dfmEmptyOverridesAll)
868+
.put(
869+
RoleBasedActionPrivileges.PRECOMPUTED_PRIVILEGES_ENABLED.getKey(),
870+
statefulness == Statefulness.STATEFUL || statefulness == Statefulness.NON_STATEFUL
871+
)
872+
.build()
860873
);
861874
}
862875
}
@@ -1108,7 +1121,13 @@ private DocumentPrivileges createSubject(SecurityDynamicConfiguration<RoleV7> ro
11081121
roleConfig,
11091122
statefulness == Statefulness.STATEFUL ? INDEX_METADATA.getIndicesLookup() : Map.of(),
11101123
xContentRegistry,
1111-
Settings.builder().put("plugins.security.dfm_empty_overrides_all", this.dfmEmptyOverridesAll).build()
1124+
Settings.builder()
1125+
.put("plugins.security.dfm_empty_overrides_all", this.dfmEmptyOverridesAll)
1126+
.put(
1127+
RoleBasedActionPrivileges.PRECOMPUTED_PRIVILEGES_ENABLED.getKey(),
1128+
statefulness == Statefulness.STATEFUL || statefulness == Statefulness.NON_STATEFUL
1129+
)
1130+
.build()
11121131
);
11131132
}
11141133

@@ -1236,7 +1255,8 @@ public String toString() {
12361255
*/
12371256
static enum Statefulness {
12381257
STATEFUL,
1239-
NON_STATEFUL
1258+
NON_STATEFUL,
1259+
DISABLED
12401260
}
12411261

12421262
/**

src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2180,6 +2180,7 @@ public List<Setting<?>> getSettings() {
21802180

21812181
// Privileges evaluation
21822182
settings.add(RoleBasedActionPrivileges.PRECOMPUTED_PRIVILEGES_MAX_HEAP_SIZE);
2183+
settings.add(RoleBasedActionPrivileges.PRECOMPUTED_PRIVILEGES_ENABLED);
21832184

21842185
// Resource Sharing
21852186
settings.add(

src/main/java/org/opensearch/security/privileges/actionlevel/RoleBasedActionPrivileges.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,24 @@ public class RoleBasedActionPrivileges extends RuntimeOptimizedActionPrivileges
7676
Setting.Property.NodeScope
7777
);
7878

79+
/**
80+
* This setting controls whether the precomputed/denormalized index privileges (in the inner class StatefulIndexPrivileges)
81+
* will be created or not. This is on by default to provide the best action throughput. It can make sense to
82+
* disable this when it is seen that the initialisation process takes so much time/resources that it negatively
83+
* affects the cluster performance. This come at the price of a reduced action throughput.
84+
*/
85+
public static Setting<Boolean> PRECOMPUTED_PRIVILEGES_ENABLED = Setting.boolSetting(
86+
"plugins.security.privileges_evaluation.precomputed_privileges.enabled",
87+
true,
88+
Setting.Property.NodeScope
89+
);
90+
7991
private static final Logger log = LogManager.getLogger(RoleBasedActionPrivileges.class);
8092

8193
private final SecurityDynamicConfiguration<RoleV7> roles;
8294
private final FlattenedActionGroups actionGroups;
8395
private final ByteSizeValue statefulIndexMaxHeapSize;
96+
private final boolean statefulIndexEnabled;
8497

8598
private final AtomicReference<StatefulIndexPrivileges> statefulIndex = new AtomicReference<>();
8699

@@ -89,6 +102,7 @@ public RoleBasedActionPrivileges(SecurityDynamicConfiguration<RoleV7> roles, Fla
89102
this.roles = roles;
90103
this.actionGroups = actionGroups;
91104
this.statefulIndexMaxHeapSize = PRECOMPUTED_PRIVILEGES_MAX_HEAP_SIZE.get(settings);
105+
this.statefulIndexEnabled = PRECOMPUTED_PRIVILEGES_ENABLED.get(settings);
92106
}
93107

94108
/**
@@ -101,6 +115,10 @@ public RoleBasedActionPrivileges(SecurityDynamicConfiguration<RoleV7> roles, Fla
101115
* the async method updateStatefulIndexPrivilegesAsync(). Should be preferred.
102116
*/
103117
public void updateStatefulIndexPrivileges(Map<String, IndexAbstraction> indices, long metadataVersion) {
118+
if (!this.statefulIndexEnabled) {
119+
return;
120+
}
121+
104122
StatefulIndexPrivileges statefulIndex = this.statefulIndex.get();
105123

106124
indices = StatefulIndexPrivileges.relevantOnly(indices);
@@ -632,6 +650,8 @@ static class StatefulIndexPrivileges extends RuntimeOptimizedActionPrivileges.St
632650
long metadataVersion,
633651
ByteSizeValue statefulIndexMaxHeapSize
634652
) {
653+
long startTime = System.currentTimeMillis();
654+
635655
Map<
636656
String,
637657
CompactMapGroupBuilder.MapBuilder<String, DeduplicatingCompactSubSetBuilder.SubSetBuilder<String>>> actionToIndexToRoles =
@@ -753,6 +773,14 @@ static class StatefulIndexPrivileges extends RuntimeOptimizedActionPrivileges.St
753773

754774
this.indices = ImmutableMap.copyOf(indices);
755775
this.metadataVersion = metadataVersion;
776+
777+
long duration = System.currentTimeMillis() - startTime;
778+
779+
if (duration > 30000) {
780+
log.warn("Creation of StatefulIndexPrivileges took {} ms", duration);
781+
} else {
782+
log.debug("Creation of StatefulIndexPrivileges took {} ms", duration);
783+
}
756784
}
757785

758786
/**

src/main/java/org/opensearch/security/privileges/dlsfls/AbstractRuleBasedPrivileges.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.opensearch.security.privileges.PrivilegesConfigurationValidationException;
3131
import org.opensearch.security.privileges.PrivilegesEvaluationContext;
3232
import org.opensearch.security.privileges.PrivilegesEvaluationException;
33+
import org.opensearch.security.privileges.actionlevel.RoleBasedActionPrivileges;
3334
import org.opensearch.security.resolver.IndexResolverReplacer;
3435
import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration;
3536
import org.opensearch.security.securityconf.impl.v7.RoleV7;
@@ -91,6 +92,11 @@ abstract class AbstractRuleBasedPrivileges<SingleRule, JoinedRule extends Abstra
9192
*/
9293
private final boolean dfmEmptyOverridesAll;
9394

95+
/**
96+
* Corresponds to the setting plugins.security.privileges_evaluation.precomputed_privileges.enabled
97+
*/
98+
private final boolean statefulIndexEnabled;
99+
94100
public AbstractRuleBasedPrivileges(
95101
SecurityDynamicConfiguration<RoleV7> roles,
96102
Map<String, IndexAbstraction> indexMetadata,
@@ -101,7 +107,8 @@ public AbstractRuleBasedPrivileges(
101107
this.roleToRuleFunction = roleToRuleFunction;
102108
this.staticRules = new StaticRules<>(roles, roleToRuleFunction);
103109
this.dfmEmptyOverridesAll = settings.getAsBoolean(ConfigConstants.SECURITY_DFM_EMPTY_OVERRIDES_ALL, false);
104-
this.statefulRules = new StatefulRules<>(roles, indexMetadata, roleToRuleFunction);
110+
this.statefulIndexEnabled = RoleBasedActionPrivileges.PRECOMPUTED_PRIVILEGES_ENABLED.get(settings);
111+
this.statefulRules = this.statefulIndexEnabled ? new StatefulRules<>(roles, indexMetadata, roleToRuleFunction) : null;
105112
}
106113

107114
/**
@@ -524,6 +531,10 @@ protected abstract JoinedRule compile(PrivilegesEvaluationContext context, Colle
524531
throws PrivilegesEvaluationException;
525532

526533
synchronized void updateIndices(Map<String, IndexAbstraction> indexMetadata) {
534+
if (!this.statefulIndexEnabled) {
535+
return;
536+
}
537+
527538
StatefulRules<SingleRule> statefulRules = this.statefulRules;
528539

529540
if (statefulRules == null || !statefulRules.indexMetadata.keySet().equals(indexMetadata.keySet())) {

0 commit comments

Comments
 (0)