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

Introduce new read_security cluster privilege #89790

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog/89790.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 89790
summary: Introduce the new `read_security` cluster privilege
area: Authorization
type: feature
issues: []
5 changes: 3 additions & 2 deletions x-pack/docs/en/rest-api/security/get-api-keys.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ Retrieves information for one or more API keys.
[[security-api-get-api-key-prereqs]]
==== {api-prereq-title}

* To use this API, you must have at least the `manage_own_api_key` cluster privilege.
* To use this API, you must have at least the `manage_own_api_key` or the `read_security`
cluster privileges.
* If you have only the `manage_own_api_key` privilege, this API returns only
the API keys that you own. If you have the `manage_api_key` or greater
the API keys that you own. If you have `read_security`, `manage_api_key` or greater
privileges (including `manage_security`), this API returns all API keys
regardless of ownership.

Expand Down
6 changes: 3 additions & 3 deletions x-pack/docs/en/rest-api/security/get-app-privileges.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ Retrieves <<application-privileges,application privileges>>.

`GET /_security/privilege/<application>` +

`GET /_security/privilege/<application>/<privilege>`
`GET /_security/privilege/<application>/<privilege>`


[[security-api-get-privileges-prereqs]]
==== {api-prereq-title}

To use this API, you must have either:

- the `manage_security` cluster privilege (or a greater privilege such as `all`); _or_
- the `read_security` cluster privilege (or a greater privilege such as `manage_security` or `all`); _or_
- the _"Manage Application Privileges"_ global privilege for the application being referenced
in the request

Expand Down Expand Up @@ -51,7 +51,7 @@ To check a user's application privileges, use the
[[security-api-get-privileges-example]]
==== {api-examples-title}

The following example retrieves information about the `read` privilege for the
The following example retrieves information about the `read` privilege for the
`app01` application:

[source,console]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ available in this version of {es}.
[[security-api-get-builtin-privileges-prereqs]]
==== {api-prereq-title}

* To use this API, you must have - the `manage_security` cluster privilege
(or a greater privilege such as `all`).
* To use this API, you must have the `read_security` cluster privilege
(or a greater privilege such as `manage_security` or `all`).

[[security-api-get-builtin-privileges-desc]]
==== {api-description-title}
Expand Down Expand Up @@ -102,6 +102,7 @@ A successful call returns an object with "cluster" and "index" fields.
"read_ccr",
"read_ilm",
"read_pipeline",
"read_security",
"read_slm",
"transport_client"
],
Expand Down
14 changes: 7 additions & 7 deletions x-pack/docs/en/rest-api/security/get-role-mappings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ Retrieves role mappings.

`GET /_security/role_mapping` +

`GET /_security/role_mapping/<name>`
`GET /_security/role_mapping/<name>`

[[security-api-get-role-mapping-prereqs]]
==== {api-prereq-title}

* To use this API, you must have at least the `manage_security` cluster privilege.
* To use this API, you must have at least the `read_security` cluster privilege.

[[security-api-get-role-mapping-desc]]
==== {api-description-title}

Role mappings define which roles are assigned to each user. For more information,
Role mappings define which roles are assigned to each user. For more information,
see <<mapping-roles>>.

The role mapping APIs are generally the preferred way to manage role mappings
Expand All @@ -36,16 +36,16 @@ in role mapping files.
`name`::
(Optional, string) The distinct name that identifies the role mapping. The name
is used solely as an identifier to facilitate interaction via the API; it does
not affect the behavior of the mapping in any way. You can specify multiple
not affect the behavior of the mapping in any way. You can specify multiple
mapping names as a comma-separated list. If you do not specify this
parameter, the API returns information about all role mappings.
parameter, the API returns information about all role mappings.

[[security-api-get-role-mapping-response-body]]
==== {api-response-body-title}

A successful call retrieves an object, where the keys are the
names of the request mappings, and the values are the JSON representation of
those mappings. For more information, see
names of the request mappings, and the values are the JSON representation of
those mappings. For more information, see
<<role-mapping-resources>>.

[[security-api-get-role-mapping-response-codes]]
Expand Down
11 changes: 5 additions & 6 deletions x-pack/docs/en/rest-api/security/get-roles.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ Retrieves roles in the native realm.
[[security-api-get-role-prereqs]]
==== {api-prereq-title}

* To use this API, you must have at least the `manage_security` cluster
privilege.
* To use this API, you must have at least the `read_security` cluster privilege.

[[security-api-get-role-desc]]
==== {api-description-title}
Expand All @@ -31,10 +30,10 @@ API cannot retrieve roles that are defined in roles files.
==== {api-path-parms-title}

`name`::
(Optional, string) The name of the role. You can specify multiple roles as a
comma-separated list. If you do not specify this parameter, the API
(Optional, string) The name of the role. You can specify multiple roles as a
comma-separated list. If you do not specify this parameter, the API
returns information about all roles.

[[security-api-get-role-response-body]]
==== {api-response-body-title}

Expand All @@ -49,7 +48,7 @@ If the role is not defined in the native realm, the request returns 404.
[[security-api-get-role-example]]
==== {api-examples-title}

The following example retrieves information about the `my_admin_role` role in
The following example retrieves information about the `my_admin_role` role in
the native realm:

[source,console]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ Retrieves all service credentials for a <<service-accounts,service account>>.

Use this API to retrieve a list of credentials for a service account.
The response includes service account tokens that were created with the
<< create service account API >> as well as file-backed tokens from all
nodes of the cluster.
<<security-api-create-service-token,create service account tokens API>>
as well as file-backed tokens from all nodes of the cluster.
albertzaharovits marked this conversation as resolved.
Show resolved Hide resolved

NOTE: For tokens backed by the `service_tokens` file, the API collects
them from all nodes of the cluster. Tokens with the same name from
Expand Down
12 changes: 6 additions & 6 deletions x-pack/docs/en/rest-api/security/get-users.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,27 @@
<titleabbrev>Get users</titleabbrev>
++++

Retrieves information about users in the native realm and built-in users.
Retrieves information about users in the native realm and built-in users.


[[security-api-get-user-request]]
==== {api-request-title}

`GET /_security/user` +

`GET /_security/user/<username>`
`GET /_security/user/<username>`

[[security-api-get-user-prereqs]]
==== {api-prereq-title}

* To use this API, you must have at least the `manage_security` cluster privilege.
* To use this API, you must have at least the `read_security` cluster privilege.


[[security-api-get-user-desc]]
==== {api-description-title}

For more information about the native realm, see
<<realms>> and <<native-realm>>.
For more information about the native realm, see
<<realms>> and <<native-realm>>.

[[security-api-get-user-path-params]]
==== {api-path-parms-title}
Expand Down Expand Up @@ -60,7 +60,7 @@ GET /_security/user/jacknich

[source,console-result]
--------------------------------------------------
{
{
"jacknich": {
"username": "jacknich",
"roles": [
Expand Down
6 changes: 3 additions & 3 deletions x-pack/docs/en/rest-api/security/query-api-key.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ in a <<paginate-search-results,paginated>> fashion.
[[security-api-query-api-key-prereqs]]
==== {api-prereq-title}

* To use this API, you must have at least the `manage_own_api_key` cluster
privilege.
* To use this API, you must have at least the `manage_own_api_key` or the `read_security`
cluster privileges.
* If you have only the `manage_own_api_key` privilege, this API returns only
the API keys that you own. If you have the `manage_api_key` or greater
the API keys that you own. If you have the `read_security`, `manage_api_key` or greater
privileges (including `manage_security`), this API returns all API keys
regardless of ownership.

Expand Down
16 changes: 14 additions & 2 deletions x-pack/docs/en/security/authorization/privileges.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ ability to manage security.
`manage_api_key`::
All security-related operations on {es} API keys including
<<security-api-create-api-key,creating new API keys>>,
<<security-api-get-api-key,retrieving information about API keys>>, and
<<security-api-get-api-key,retrieving information about API keys>>,
<<security-api-query-api-key,querying API keys>>, and
<<security-api-invalidate-api-key,invalidating API keys>>.
albertzaharovits marked this conversation as resolved.
Show resolved Hide resolved
+
--
Expand Down Expand Up @@ -89,7 +90,8 @@ to initiate and manage OpenID Connect authentication on behalf of other users.
All security-related operations on {es} API keys that are owned by the current
authenticated user. The operations include
<<security-api-create-api-key,creating new API keys>>,
<<security-api-get-api-key,retrieving information about API keys>>, and
<<security-api-get-api-key,retrieving information about API keys>>,
<<security-api-query-api-key,querying API keys>>, and
<<security-api-invalidate-api-key,invalidating API keys>>.
albertzaharovits marked this conversation as resolved.
Show resolved Hide resolved

`manage_pipeline`::
Expand Down Expand Up @@ -176,6 +178,16 @@ Read-only access to ingest pipline (get, simulate).
All read-only {slm-init} actions, such as getting policies and checking the
{slm-init} status.

`read_security`::
All read-only security-related operations, such as getting users, user profiles,
{es} API keys, {es} service accounts, roles and role mappings.
Allows <<security-api-query-api-key,querying>> and <<security-api-get-api-key,retrieving information>>
on all {es} API keys.
It also allows checking the user and user profile privileges with the
<<security-api-has-privileges,user has privileges API>> and the
<<security-api-has-privileges-user-profile,user profile has privileges API>>
respectively.
albertzaharovits marked this conversation as resolved.
Show resolved Hide resolved

`transport_client`::
All privileges necessary for a transport client to connect. Required by the remote
cluster to enable <<cross-cluster-configuring,{ccs}>>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,23 @@
import org.elasticsearch.xpack.core.ilm.action.StartILMAction;
import org.elasticsearch.xpack.core.ilm.action.StopILMAction;
import org.elasticsearch.xpack.core.security.action.DelegatePkiAuthenticationAction;
import org.elasticsearch.xpack.core.security.action.apikey.GetApiKeyAction;
import org.elasticsearch.xpack.core.security.action.apikey.GrantApiKeyAction;
import org.elasticsearch.xpack.core.security.action.apikey.QueryApiKeyAction;
import org.elasticsearch.xpack.core.security.action.privilege.GetBuiltinPrivilegesAction;
import org.elasticsearch.xpack.core.security.action.privilege.GetPrivilegesAction;
import org.elasticsearch.xpack.core.security.action.profile.GetProfilesAction;
import org.elasticsearch.xpack.core.security.action.profile.SuggestProfilesAction;
import org.elasticsearch.xpack.core.security.action.role.GetRolesAction;
import org.elasticsearch.xpack.core.security.action.rolemapping.GetRoleMappingsAction;
import org.elasticsearch.xpack.core.security.action.saml.SamlSpMetadataAction;
import org.elasticsearch.xpack.core.security.action.service.GetServiceAccountAction;
import org.elasticsearch.xpack.core.security.action.service.GetServiceAccountCredentialsAction;
import org.elasticsearch.xpack.core.security.action.token.InvalidateTokenAction;
import org.elasticsearch.xpack.core.security.action.token.RefreshTokenAction;
import org.elasticsearch.xpack.core.security.action.user.GetUsersAction;
import org.elasticsearch.xpack.core.security.action.user.HasPrivilegesAction;
import org.elasticsearch.xpack.core.security.action.user.ProfileHasPrivilegesAction;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.slm.action.GetSnapshotLifecycleAction;

Expand Down Expand Up @@ -174,6 +186,24 @@ public class ClusterPrivilegeResolver {
ALL_SECURITY_PATTERN,
Set.of(DelegatePkiAuthenticationAction.NAME)
);
public static final NamedClusterPrivilege READ_SECURITY = new ActionClusterPrivilege(
"read_security",
Set.of(
GetApiKeyAction.NAME,
QueryApiKeyAction.NAME,
GetBuiltinPrivilegesAction.NAME,
GetPrivilegesAction.NAME,
GetProfilesAction.NAME,
ProfileHasPrivilegesAction.NAME,
SuggestProfilesAction.NAME,
GetRolesAction.NAME,
GetRoleMappingsAction.NAME,
GetServiceAccountAction.NAME,
GetServiceAccountCredentialsAction.NAME + "*",
GetUsersAction.NAME,
HasPrivilegesAction.NAME
)
albertzaharovits marked this conversation as resolved.
Show resolved Hide resolved
);
public static final NamedClusterPrivilege MANAGE_SAML = new ActionClusterPrivilege("manage_saml", MANAGE_SAML_PATTERN);
public static final NamedClusterPrivilege MANAGE_OIDC = new ActionClusterPrivilege("manage_oidc", MANAGE_OIDC_PATTERN);
public static final NamedClusterPrivilege MANAGE_API_KEY = new ActionClusterPrivilege("manage_api_key", MANAGE_API_KEY_PATTERN);
Expand Down Expand Up @@ -239,6 +269,7 @@ public class ClusterPrivilegeResolver {
READ_PIPELINE,
TRANSPORT_CLIENT,
MANAGE_SECURITY,
READ_SECURITY,
MANAGE_SAML,
MANAGE_OIDC,
MANAGE_API_KEY,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ private HasPrivilegesRequest randomRequest() {
ClusterPrivilegeResolver.MANAGE,
ClusterPrivilegeResolver.MANAGE_ML,
ClusterPrivilegeResolver.MANAGE_SECURITY,
ClusterPrivilegeResolver.READ_SECURITY,
ClusterPrivilegeResolver.MANAGE_PIPELINE,
ClusterPrivilegeResolver.ALL
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void testClusterPermissionBuilder() {
assertNotNull(builder);
assertThat(builder.build(), is(ClusterPermission.NONE));

builder = ClusterPrivilegeResolver.MANAGE_SECURITY.buildPermission(builder);
builder = ClusterPrivilegeResolver.READ_SECURITY.buildPermission(builder);
builder = ClusterPrivilegeResolver.MANAGE_ILM.buildPermission(builder);
final MockConfigurableClusterPrivilege mockConfigurableClusterPrivilege1 = new MockConfigurableClusterPrivilege(
r -> r == mockTransportRequest
Expand All @@ -69,7 +69,7 @@ public void testClusterPermissionBuilder() {
assertThat(
privileges,
containsInAnyOrder(
ClusterPrivilegeResolver.MANAGE_SECURITY,
ClusterPrivilegeResolver.READ_SECURITY,
ClusterPrivilegeResolver.MANAGE_ILM,
mockConfigurableClusterPrivilege1,
mockConfigurableClusterPrivilege2
Expand Down Expand Up @@ -156,7 +156,7 @@ public void testNoneClusterPermissionIsImpliedByNone() {

public void testNoneClusterPermissionIsImpliedByAny() {
ClusterPermission.Builder builder = ClusterPermission.builder();
builder = ClusterPrivilegeResolver.MANAGE_SECURITY.buildPermission(builder);
builder = ClusterPrivilegeResolver.READ_SECURITY.buildPermission(builder);
builder = ClusterPrivilegeResolver.MANAGE_ILM.buildPermission(builder);
final MockConfigurableClusterPrivilege mockConfigurableClusterPrivilege1 = new MockConfigurableClusterPrivilege(
r -> r == mockTransportRequest
Expand Down Expand Up @@ -253,14 +253,30 @@ public void testClusterPermissionSubsetIsImpliedByAllClusterPermission() {
assertThat(allClusterPermission.implies(otherClusterPermission), is(true));
}

public void testReadSecurityPrivilegeNoImplyApiKeyManagement() {
assertFalse(ClusterPrivilegeResolver.READ_SECURITY.permission().implies(ClusterPrivilegeResolver.MANAGE_API_KEY.permission()));
assertFalse(ClusterPrivilegeResolver.MANAGE_API_KEY.permission().implies(ClusterPrivilegeResolver.READ_SECURITY.permission()));
assertFalse(ClusterPrivilegeResolver.READ_SECURITY.permission().implies(ClusterPrivilegeResolver.MANAGE_OWN_API_KEY.permission()));
assertFalse(ClusterPrivilegeResolver.MANAGE_OWN_API_KEY.permission().implies(ClusterPrivilegeResolver.READ_SECURITY.permission()));
}

public void testImpliesOnSecurityPrivilegeHierarchy() {
final List<ClusterPermission> highToLow = List.of(
List<ClusterPermission> highToLow = List.of(
ClusterPrivilegeResolver.ALL.permission(),
ClusterPrivilegeResolver.MANAGE_SECURITY.permission(),
ClusterPrivilegeResolver.MANAGE_API_KEY.permission(),
ClusterPrivilegeResolver.MANAGE_OWN_API_KEY.permission()
);
assertImpliesHierarchy(highToLow);
highToLow = List.of(
ClusterPrivilegeResolver.ALL.permission(),
ClusterPrivilegeResolver.MANAGE_SECURITY.permission(),
ClusterPrivilegeResolver.READ_SECURITY.permission()
);
assertImpliesHierarchy(highToLow);
}

private void assertImpliesHierarchy(List<ClusterPermission> highToLow) {
for (int i = 0; i < highToLow.size(); i++) {
ClusterPermission high = highToLow.get(i);
for (int j = i; j < highToLow.size(); j++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,28 @@

public class ClusterPrivilegeResolverTests extends ESTestCase {

public void testSortByAccessLevel() throws Exception {
public void testSortByAccessLevel() {
final List<NamedClusterPrivilege> privileges = new ArrayList<>(
List.of(
ClusterPrivilegeResolver.ALL,
ClusterPrivilegeResolver.MONITOR,
ClusterPrivilegeResolver.MANAGE,
ClusterPrivilegeResolver.MANAGE_OWN_API_KEY,
ClusterPrivilegeResolver.MANAGE_API_KEY,
ClusterPrivilegeResolver.READ_SECURITY,
ClusterPrivilegeResolver.MANAGE_SECURITY
)
);
Collections.shuffle(privileges, random());
final SortedMap<String, NamedClusterPrivilege> sorted = ClusterPrivilegeResolver.sortByAccessLevel(privileges);
// This is:
// "manage_own_api_key", "monitor" (neither of which grant anything else in the list), sorted by name
// "manage_own_api_key", "monitor", "read_security" (neither of which grant anything else in the list), sorted by name
// "manage" and "manage_api_key",(which each grant 1 other privilege in the list), sorted by name
// "manage_security" and "all", sorted by access level ("all" implies "manage_security")
assertThat(sorted.keySet(), contains("manage_own_api_key", "monitor", "manage", "manage_api_key", "manage_security", "all"));
assertThat(
sorted.keySet(),
contains("manage_own_api_key", "monitor", "read_security", "manage", "manage_api_key", "manage_security", "all")
);
}

}
Loading