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

Add kibana-system service account #76449

Merged
merged 5 commits into from
Aug 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion rest-api-spec/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ def v7compatibilityNotSupportedTests = {
'search.aggregation/200_top_hits_metric/top_hits aggregation with sequence numbers', // #42809 the use nested path and filter sort throws an exception
'search/310_match_bool_prefix/multi_match multiple fields with cutoff_frequency throws exception', //#42654 cutoff_frequency, common terms are not supported. Throwing an exception


]
}
tasks.named("yamlRestCompatTest").configure {
Expand Down
14 changes: 9 additions & 5 deletions x-pack/docs/en/security/authentication/service-accounts.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ prevents credential sharing between multiple instances of the same
external service. Each instance can assume the same identity while using
their own distinct service token for authentication.

Service accounts provide flexibility over <<built-in-users,built-in users>>
Service accounts provide flexibility over <<built-in-users,built-in users>>
because they:

* Do not rely on the <<native-realm,internal `native` realm>>, and aren't
always required to rely on the `.security` index
* Use a role descriptor named after the service account principal instead of
* Use a role descriptor named after the service account principal instead of
traditional roles
* Support multiple credentials through service account tokens

Expand All @@ -40,11 +40,15 @@ the format of `<namespace>/<service>`, where the `namespace` is a top-level
grouping of service accounts, and `service` is the name of the service and
must be unique within its namespace.

Service accounts are predefined in code. Currently, only one service account is available:
Service accounts are predefined in code. The following service accounts are
available:

`elastic/fleet-server`:: The service account used by the {fleet} server to
communicate with {es}.

`elastic/kibana`:: The service account used by {kib} to communicate with
{es}.

// tag::service-accounts-usage[]
IMPORTANT: Do not attempt to use service accounts for authenticating individual
users. Service accounts can only be authenticated with service tokens, which are
Expand Down Expand Up @@ -83,11 +87,11 @@ the bearer token in the HTTP response

Both of these methods create a service token with a guaranteed secret string
length of `22`. The minimal, acceptable length of a secret string for a service
token is `10`. If the secret string doesn't meet this minimal length,
token is `10`. If the secret string doesn't meet this minimal length,
authentication with {es} will fail without even checking the value of the
service token.

Service tokens never expire. You must actively
Service tokens never expire. You must actively
<<security-api-delete-service-token,delete>> them if they are no longer needed.

[discrete]
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ def v7compatibilityNotSupportedTests = {

// a type field was added to cat.ml_trained_models #73660, this is a backwards compatible change.
// still this is a cat api, and we don't support them with rest api compatibility. (the test would be very hard to transform too)
'ml/trained_model_cat_apis/Test cat trained models'
'ml/trained_model_cat_apis/Test cat trained models',
'service_accounts/10_basic/Test get service accounts', //#76449, will remove upon backport
]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import org.elasticsearch.xpack.core.security.authz.privilege.ConfigurableClusterPrivilege;
import org.elasticsearch.xpack.core.security.authz.privilege.ConfigurableClusterPrivileges.ManageApplicationPrivileges;
import org.elasticsearch.xpack.core.security.support.MetadataUtils;
import org.elasticsearch.xpack.core.security.user.KibanaUser;
import org.elasticsearch.xpack.core.security.user.KibanaSystemUser;
import org.elasticsearch.xpack.core.security.user.UsernamesField;
import org.elasticsearch.xpack.core.transform.transforms.persistence.TransformInternalIndexConstants;
import org.elasticsearch.xpack.core.watcher.execution.TriggeredWatchStoreField;
Expand Down Expand Up @@ -125,78 +125,7 @@ private static Map<String, RoleDescriptor> initializeReservedRoles() {
null, null,
MetadataUtils.getDeprecatedReservedMetadata("Please use Kibana feature privileges instead"),
null))
.put(KibanaUser.ROLE_NAME, new RoleDescriptor(KibanaUser.ROLE_NAME,
new String[] {
"monitor", "manage_index_templates", MonitoringBulkAction.NAME, "manage_saml", "manage_token", "manage_oidc",
InvalidateApiKeyAction.NAME, "grant_api_key",
GetBuiltinPrivilegesAction.NAME, "delegate_pki", GetLifecycleAction.NAME, PutLifecycleAction.NAME,
// To facilitate ML UI functionality being controlled using Kibana security privileges
"manage_ml",
// The symbolic constant for this one is in SecurityActionMapper, so not accessible from X-Pack core
"cluster:admin/analyze",
// To facilitate using the file uploader functionality
"monitor_text_structure",
// To cancel tasks and delete async searches
"cancel_task"
},
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder()
.indices(".kibana*", ".reporting-*").privileges("all").build(),
RoleDescriptor.IndicesPrivileges.builder()
.indices(".monitoring-*").privileges("read", "read_cross_cluster").build(),
RoleDescriptor.IndicesPrivileges.builder()
.indices(".management-beats").privileges("create_index", "read", "write").build(),
// To facilitate ML UI functionality being controlled using Kibana security privileges
RoleDescriptor.IndicesPrivileges.builder()
.indices(".ml-anomalies*", ".ml-stats-*")
.privileges("read").build(),
RoleDescriptor.IndicesPrivileges.builder().indices(".ml-annotations*", ".ml-notifications*")
.privileges("read", "write").build(),
// APM agent configuration
RoleDescriptor.IndicesPrivileges.builder()
.indices(".apm-agent-configuration").privileges("all").build(),
// APM custom link index creation
RoleDescriptor.IndicesPrivileges.builder()
.indices(".apm-custom-link").privileges("all").build(),
// APM telemetry queries APM indices in kibana task runner
RoleDescriptor.IndicesPrivileges.builder()
.indices("apm-*")
.privileges("read", "read_cross_cluster").build(),
// Data telemetry reads mappings, metadata and stats of indices
RoleDescriptor.IndicesPrivileges.builder()
.indices("*")
.privileges("view_index_metadata", "monitor").build(),
// Endpoint diagnostic information. Kibana reads from these indices to send telemetry
RoleDescriptor.IndicesPrivileges.builder()
.indices(".logs-endpoint.diagnostic.collection-*")
.privileges("read").build(),
// Fleet Server indices. Kibana create this indice before Fleet Server use them.
// Fleet Server indices. Kibana read and write to this indice to manage Elastic Agents
RoleDescriptor.IndicesPrivileges.builder()
.indices(".fleet*")
.privileges("all").build(),
// Legacy "Alerts as data" index. Kibana user will create this index.
// Kibana user will read / write to these indices
RoleDescriptor.IndicesPrivileges.builder()
.indices(ReservedRolesStore.LEGACY_ALERTS_INDEX)
.privileges("all").build(),
// "Alerts as data" index. Kibana user will create this index.
// Kibana user will read / write to these indices
RoleDescriptor.IndicesPrivileges.builder()
.indices(ReservedRolesStore.ALERTS_INDEX)
.privileges("all").build(),
// Endpoint / Fleet policy responses. Kibana requires read access to send telemetry
RoleDescriptor.IndicesPrivileges.builder()
.indices("metrics-endpoint.policy-*")
.privileges("read").build(),
// Endpoint metrics. Kibana requires read access to send telemetry
RoleDescriptor.IndicesPrivileges.builder()
.indices("metrics-endpoint.metrics-*")
.privileges("read").build()
},
null,
new ConfigurableClusterPrivilege[] { new ManageApplicationPrivileges(Collections.singleton("kibana-*")) },
null, MetadataUtils.DEFAULT_RESERVED_METADATA, null))
.put(KibanaSystemUser.ROLE_NAME, kibanaSystemRoleDescriptor(KibanaSystemUser.ROLE_NAME))
.put("logstash_system", new RoleDescriptor("logstash_system", new String[] { "monitor", MonitoringBulkAction.NAME},
null, null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.put("beats_admin", new RoleDescriptor("beats_admin",
Expand Down Expand Up @@ -434,6 +363,81 @@ private static RoleDescriptor kibanaAdminUser(String name, Map<String, Object> m
null, null, metadata, null);
}

public static RoleDescriptor kibanaSystemRoleDescriptor(String name) {
return new RoleDescriptor(name,
new String[] {
"monitor", "manage_index_templates", MonitoringBulkAction.NAME, "manage_saml", "manage_token", "manage_oidc",
InvalidateApiKeyAction.NAME, "grant_api_key",
GetBuiltinPrivilegesAction.NAME, "delegate_pki", GetLifecycleAction.NAME, PutLifecycleAction.NAME,
// To facilitate ML UI functionality being controlled using Kibana security privileges
"manage_ml",
// The symbolic constant for this one is in SecurityActionMapper, so not accessible from X-Pack core
"cluster:admin/analyze",
// To facilitate using the file uploader functionality
"monitor_text_structure",
// To cancel tasks and delete async searches
"cancel_task"
},
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder()
.indices(".kibana*", ".reporting-*").privileges("all").build(),
RoleDescriptor.IndicesPrivileges.builder()
.indices(".monitoring-*").privileges("read", "read_cross_cluster").build(),
RoleDescriptor.IndicesPrivileges.builder()
.indices(".management-beats").privileges("create_index", "read", "write").build(),
// To facilitate ML UI functionality being controlled using Kibana security privileges
RoleDescriptor.IndicesPrivileges.builder()
.indices(".ml-anomalies*", ".ml-stats-*")
.privileges("read").build(),
RoleDescriptor.IndicesPrivileges.builder().indices(".ml-annotations*", ".ml-notifications*")
.privileges("read", "write").build(),
// APM agent configuration
RoleDescriptor.IndicesPrivileges.builder()
.indices(".apm-agent-configuration").privileges("all").build(),
// APM custom link index creation
RoleDescriptor.IndicesPrivileges.builder()
.indices(".apm-custom-link").privileges("all").build(),
// APM telemetry queries APM indices in kibana task runner
RoleDescriptor.IndicesPrivileges.builder()
.indices("apm-*")
.privileges("read", "read_cross_cluster").build(),
// Data telemetry reads mappings, metadata and stats of indices
RoleDescriptor.IndicesPrivileges.builder()
.indices("*")
.privileges("view_index_metadata", "monitor").build(),
// Endpoint diagnostic information. Kibana reads from these indices to send telemetry
RoleDescriptor.IndicesPrivileges.builder()
.indices(".logs-endpoint.diagnostic.collection-*")
.privileges("read").build(),
// Fleet Server indices. Kibana create this indice before Fleet Server use them.
// Fleet Server indices. Kibana read and write to this indice to manage Elastic Agents
RoleDescriptor.IndicesPrivileges.builder()
.indices(".fleet*")
.privileges("all").build(),
// Legacy "Alerts as data" index. Kibana user will create this index.
// Kibana user will read / write to these indices
RoleDescriptor.IndicesPrivileges.builder()
.indices(ReservedRolesStore.LEGACY_ALERTS_INDEX)
.privileges("all").build(),
// "Alerts as data" index. Kibana user will create this index.
// Kibana user will read / write to these indices
RoleDescriptor.IndicesPrivileges.builder()
.indices(ReservedRolesStore.ALERTS_INDEX)
.privileges("all").build(),
// Endpoint / Fleet policy responses. Kibana requires read access to send telemetry
RoleDescriptor.IndicesPrivileges.builder()
.indices("metrics-endpoint.policy-*")
.privileges("read").build(),
// Endpoint metrics. Kibana requires read access to send telemetry
RoleDescriptor.IndicesPrivileges.builder()
.indices("metrics-endpoint.metrics-*")
.privileges("read").build()
},
null,
new ConfigurableClusterPrivilege[] { new ManageApplicationPrivileges(Collections.singleton("kibana-*")) },
null, MetadataUtils.DEFAULT_RESERVED_METADATA, null);
Copy link
Member

Choose a reason for hiding this comment

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

Reserved metadata is not really needed for service account role descriptor. But it should not cause any issue either.

}

public static boolean isReserved(String role) {
return RESERVED_ROLES.containsKey(role) || UsernamesField.SYSTEM_ROLE.equals(role) ||
UsernamesField.XPACK_ROLE.equals(role) || UsernamesField.ASYNC_SEARCH_ROLE.equals(role);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,20 @@
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.core.PathUtils;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.xpack.core.security.authz.store.ReservedRolesStore;
import org.elasticsearch.xpack.core.security.user.KibanaSystemUser;
import org.junit.BeforeClass;

import java.io.FileNotFoundException;
Expand Down Expand Up @@ -165,6 +171,18 @@ public void testGetServiceAccount() throws IOException {
assertServiceAccountRoleDescriptor(getServiceAccountResponse3,
"elastic/fleet-server", ELASTIC_FLEET_SERVER_ROLE_DESCRIPTOR);

final Request getServiceAccountRequestKibana = new Request("GET", "_security/service/elastic/kibana");
final Response getServiceAccountResponseKibana = client().performRequest(getServiceAccountRequestKibana);
assertOK(getServiceAccountResponseKibana);
assertServiceAccountRoleDescriptor(
getServiceAccountResponseKibana,
"elastic/kibana",
Strings.toString(
ReservedRolesStore.kibanaSystemRoleDescriptor(KibanaSystemUser.ROLE_NAME)
.toXContent(JsonXContent.contentBuilder(), ToXContent.EMPTY_PARAMS)
)
);

final String requestPath = "_security/service/" + randomFrom("foo", "elastic/foo", "foo/bar");
final Request getServiceAccountRequest4 = new Request("GET", requestPath);
final Response getServiceAccountResponse4 = client().performRequest(getServiceAccountRequest4);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import org.elasticsearch.common.Strings;
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.core.security.authz.store.ReservedRolesStore;
import org.elasticsearch.xpack.core.security.user.User;

import java.util.List;
Expand Down Expand Up @@ -43,8 +44,10 @@ final class ElasticServiceAccounts {
null,
null
));
private static final ServiceAccount KIBANA_SYSTEM_ACCOUNT =
new ElasticServiceAccount("kibana", ReservedRolesStore.kibanaSystemRoleDescriptor(NAMESPACE + "/kibana"));

static final Map<String, ServiceAccount> ACCOUNTS = List.of(FLEET_ACCOUNT).stream()
static final Map<String, ServiceAccount> ACCOUNTS = List.of(FLEET_ACCOUNT, KIBANA_SYSTEM_ACCOUNT).stream()
.collect(Collectors.toMap(a -> a.id().asPrincipal(), Function.identity()));;

private ElasticServiceAccounts() {}
Expand Down
Loading