From 67e32e5c823f984098f81ae3c96037ef46200d7b Mon Sep 17 00:00:00 2001 From: Patrick Doyle <810052+prdoyle@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:12:27 -0400 Subject: [PATCH 1/6] Initial trivial hello-world entitlements agent (#113112) * Initial hello-world entitlements agent * Respond to Ryan's comments * License header * Fix forbidden APIs setup * Rename EntitlementAgent * Automated refactor missed one * Automated rename really let me down here * Very serious test name * README files for the new modules * Use "tasks.named('jar')" Co-authored-by: Rene Groeschke * Use 'tasks.named('test')' Co-authored-by: Rene Groeschke * More deferral of gradle tasks Co-authored-by: Rene Groeschke * Even more deferral Co-authored-by: Rene Groeschke * FIx gradle syntax for javaagent arg --------- Co-authored-by: Rene Groeschke --- .../tools/entitlement-agent/README.md | 10 +++++ .../tools/entitlement-agent/build.gradle | 39 +++++++++++++++++++ .../src/main/java/module-info.java | 13 +++++++ .../entitlement/agent/EntitlementAgent.java | 21 ++++++++++ .../agent/EntitlementAgentTests.java | 29 ++++++++++++++ libs/entitlement-runtime/README.md | 14 +++++++ libs/entitlement-runtime/build.gradle | 24 ++++++++++++ .../src/main/java/module-info.java | 14 +++++++ .../runtime/api/EntitlementChecks.java | 22 +++++++++++ settings.gradle | 1 + 10 files changed, 187 insertions(+) create mode 100644 distribution/tools/entitlement-agent/README.md create mode 100644 distribution/tools/entitlement-agent/build.gradle create mode 100644 distribution/tools/entitlement-agent/src/main/java/module-info.java create mode 100644 distribution/tools/entitlement-agent/src/main/java/org/elasticsearch/entitlement/agent/EntitlementAgent.java create mode 100644 distribution/tools/entitlement-agent/src/test/java/org/elasticsearch/entitlement/agent/EntitlementAgentTests.java create mode 100644 libs/entitlement-runtime/README.md create mode 100644 libs/entitlement-runtime/build.gradle create mode 100644 libs/entitlement-runtime/src/main/java/module-info.java create mode 100644 libs/entitlement-runtime/src/main/java/org/elasticsearch/entitlement/runtime/api/EntitlementChecks.java diff --git a/distribution/tools/entitlement-agent/README.md b/distribution/tools/entitlement-agent/README.md new file mode 100644 index 0000000000000..ff40651706a7f --- /dev/null +++ b/distribution/tools/entitlement-agent/README.md @@ -0,0 +1,10 @@ +### Entitlement Agent + +This is a java agent that instruments sensitive class library methods with calls into the `entitlement-runtime` module to check for permissions granted under the _entitlements_ system. + +The entitlements system provides an alternative to the legacy `SecurityManager` system, which is deprecated for removal. +With this agent, the Elasticsearch server can retain some control over which class library methods can be invoked by which callers. + +This module is responsible for inserting the appropriate bytecode to achieve enforcement of the rules governed by the `entitlement-runtime` module. + +It is not responsible for permission granting or checking logic. That responsibility lies with `entitlement-runtime`. diff --git a/distribution/tools/entitlement-agent/build.gradle b/distribution/tools/entitlement-agent/build.gradle new file mode 100644 index 0000000000000..56e2ffac53fd7 --- /dev/null +++ b/distribution/tools/entitlement-agent/build.gradle @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +apply plugin: 'elasticsearch.build' + +configurations { + entitlementRuntime +} + +dependencies { + entitlementRuntime project(":libs:elasticsearch-entitlement-runtime") + implementation project(":libs:elasticsearch-entitlement-runtime") + testImplementation project(":test:framework") +} + +tasks.named('test').configure { + dependsOn('jar') + jvmArgs "-javaagent:${ tasks.named('jar').flatMap{ it.archiveFile }.get()}" +} + +tasks.named('jar').configure { + manifest { + attributes( + 'Premain-Class': 'org.elasticsearch.entitlement.agent.EntitlementAgent' + , 'Can-Retransform-Classes': 'true' + ) + } +} + +tasks.named('forbiddenApisMain').configure { + replaceSignatureFiles 'jdk-signatures' +} + diff --git a/distribution/tools/entitlement-agent/src/main/java/module-info.java b/distribution/tools/entitlement-agent/src/main/java/module-info.java new file mode 100644 index 0000000000000..df6fc154fc67f --- /dev/null +++ b/distribution/tools/entitlement-agent/src/main/java/module-info.java @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +module org.elasticsearch.entitlement.agent { + requires java.instrument; + requires org.elasticsearch.entitlement.runtime; +} diff --git a/distribution/tools/entitlement-agent/src/main/java/org/elasticsearch/entitlement/agent/EntitlementAgent.java b/distribution/tools/entitlement-agent/src/main/java/org/elasticsearch/entitlement/agent/EntitlementAgent.java new file mode 100644 index 0000000000000..b843e42f4a03e --- /dev/null +++ b/distribution/tools/entitlement-agent/src/main/java/org/elasticsearch/entitlement/agent/EntitlementAgent.java @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.entitlement.agent; + +import org.elasticsearch.entitlement.runtime.api.EntitlementChecks; + +import java.lang.instrument.Instrumentation; + +public class EntitlementAgent { + + public static void premain(String agentArgs, Instrumentation inst) throws Exception { + EntitlementChecks.setAgentBooted(); + } +} diff --git a/distribution/tools/entitlement-agent/src/test/java/org/elasticsearch/entitlement/agent/EntitlementAgentTests.java b/distribution/tools/entitlement-agent/src/test/java/org/elasticsearch/entitlement/agent/EntitlementAgentTests.java new file mode 100644 index 0000000000000..3927465570c98 --- /dev/null +++ b/distribution/tools/entitlement-agent/src/test/java/org/elasticsearch/entitlement/agent/EntitlementAgentTests.java @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.entitlement.agent; + +import org.elasticsearch.entitlement.runtime.api.EntitlementChecks; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.ESTestCase.WithoutSecurityManager; + +/** + * This is an end-to-end test that runs with the javaagent installed. + * It should exhaustively test every instrumented method to make sure it passes with the entitlement + * and fails without it. + * See {@code build.gradle} for how we set the command line arguments for this test. + */ +@WithoutSecurityManager +public class EntitlementAgentTests extends ESTestCase { + + public void testAgentBooted() { + assertTrue(EntitlementChecks.isAgentBooted()); + } + +} diff --git a/libs/entitlement-runtime/README.md b/libs/entitlement-runtime/README.md new file mode 100644 index 0000000000000..49cbc873c9de5 --- /dev/null +++ b/libs/entitlement-runtime/README.md @@ -0,0 +1,14 @@ +### Entitlement runtime + +This module implements mechanisms to grant and check permissions under the _entitlements_ system. + +The entitlements system provides an alternative to the legacy `SecurityManager` system, which is deprecated for removal. +The `entitlement-agent` tool instruments sensitive class library methods with calls to this module, in order to enforce the controls. + +This module is responsible for: +- Defining which class library methods are sensitive +- Defining what permissions should be checked for each sensitive method +- Implementing the permission checks +- Offering a "grant" API to grant permissions + +It is not responsible for anything to do with bytecode instrumentation; that responsibility lies with `entitlement-agent`. diff --git a/libs/entitlement-runtime/build.gradle b/libs/entitlement-runtime/build.gradle new file mode 100644 index 0000000000000..a552dd7d5ba47 --- /dev/null +++ b/libs/entitlement-runtime/build.gradle @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ +apply plugin: 'elasticsearch.build' +apply plugin: 'elasticsearch.publish' + +dependencies { + compileOnly project(':libs:elasticsearch-core') + + testImplementation project(":test:framework") +} + +tasks.named('forbiddenApisMain').configure { + replaceSignatureFiles 'jdk-signatures' +} + +tasks.named('forbiddenApisMain').configure { + replaceSignatureFiles 'jdk-signatures' +} diff --git a/libs/entitlement-runtime/src/main/java/module-info.java b/libs/entitlement-runtime/src/main/java/module-info.java new file mode 100644 index 0000000000000..13849f0658d72 --- /dev/null +++ b/libs/entitlement-runtime/src/main/java/module-info.java @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +module org.elasticsearch.entitlement.runtime { + requires org.elasticsearch.base; + + exports org.elasticsearch.entitlement.runtime.api to org.elasticsearch.entitlement.agent; +} diff --git a/libs/entitlement-runtime/src/main/java/org/elasticsearch/entitlement/runtime/api/EntitlementChecks.java b/libs/entitlement-runtime/src/main/java/org/elasticsearch/entitlement/runtime/api/EntitlementChecks.java new file mode 100644 index 0000000000000..c06e1e5b1f858 --- /dev/null +++ b/libs/entitlement-runtime/src/main/java/org/elasticsearch/entitlement/runtime/api/EntitlementChecks.java @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.entitlement.runtime.api; + +public class EntitlementChecks { + static boolean isAgentBooted = false; + + public static void setAgentBooted() { + isAgentBooted = true; + } + + public static boolean isAgentBooted() { + return isAgentBooted; + } +} diff --git a/settings.gradle b/settings.gradle index ab87861105156..2926a9a303375 100644 --- a/settings.gradle +++ b/settings.gradle @@ -91,6 +91,7 @@ List projects = [ 'distribution:tools:keystore-cli', 'distribution:tools:geoip-cli', 'distribution:tools:ansi-console', + 'distribution:tools:entitlement-agent', 'server', 'test:framework', 'test:fixtures:azure-fixture', From af896313df79032dfccd3b363f34cf4914bc2917 Mon Sep 17 00:00:00 2001 From: elasticsearchmachine <58790826+elasticsearchmachine@users.noreply.github.com> Date: Sat, 21 Sep 2024 03:12:33 +1000 Subject: [PATCH 2/6] Mute org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT test {date.EvalDateFormatString SYNC} #113293 --- muted-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/muted-tests.yml b/muted-tests.yml index a350c8209ae5a..9bb1f22fde215 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -274,6 +274,9 @@ tests: - class: org.elasticsearch.xpack.security.authz.SecurityScrollTests method: testSearchAndClearScroll issue: https://github.com/elastic/elasticsearch/issues/113285 +- class: org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT + method: test {date.EvalDateFormatString SYNC} + issue: https://github.com/elastic/elasticsearch/issues/113293 # Examples: # From 36874b0da6605fa8ed43c25f88dc471590df7303 Mon Sep 17 00:00:00 2001 From: elasticsearchmachine <58790826+elasticsearchmachine@users.noreply.github.com> Date: Sat, 21 Sep 2024 03:12:46 +1000 Subject: [PATCH 3/6] Mute org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT test {date.EvalDateFormat} #113294 --- muted-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/muted-tests.yml b/muted-tests.yml index 9bb1f22fde215..c5d434e36c8fc 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -277,6 +277,9 @@ tests: - class: org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT method: test {date.EvalDateFormatString SYNC} issue: https://github.com/elastic/elasticsearch/issues/113293 +- class: org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT + method: test {date.EvalDateFormat} + issue: https://github.com/elastic/elasticsearch/issues/113294 # Examples: # From d34ec20463b1c1f16f61ee8179ac4ea75ff5bdd2 Mon Sep 17 00:00:00 2001 From: elasticsearchmachine <58790826+elasticsearchmachine@users.noreply.github.com> Date: Sat, 21 Sep 2024 03:12:57 +1000 Subject: [PATCH 4/6] Mute org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT test {date.DocsDateFormat} #113295 --- muted-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/muted-tests.yml b/muted-tests.yml index c5d434e36c8fc..f6110d0bf8825 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -280,6 +280,9 @@ tests: - class: org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT method: test {date.EvalDateFormat} issue: https://github.com/elastic/elasticsearch/issues/113294 +- class: org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT + method: test {date.DocsDateFormat} + issue: https://github.com/elastic/elasticsearch/issues/113295 # Examples: # From 417f308528e17c2f4a4a2ee2aa26b15b31f9d895 Mon Sep 17 00:00:00 2001 From: elasticsearchmachine <58790826+elasticsearchmachine@users.noreply.github.com> Date: Sat, 21 Sep 2024 03:13:07 +1000 Subject: [PATCH 5/6] Mute org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT test {stats.DocsStatsGroupByMultipleValues} #113296 --- muted-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/muted-tests.yml b/muted-tests.yml index f6110d0bf8825..2fbff4abd5c06 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -283,6 +283,9 @@ tests: - class: org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT method: test {date.DocsDateFormat} issue: https://github.com/elastic/elasticsearch/issues/113295 +- class: org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT + method: test {stats.DocsStatsGroupByMultipleValues} + issue: https://github.com/elastic/elasticsearch/issues/113296 # Examples: # From 079b4c355dab2c7acf8f8118efc30f4314897a32 Mon Sep 17 00:00:00 2001 From: elasticsearchmachine <58790826+elasticsearchmachine@users.noreply.github.com> Date: Sat, 21 Sep 2024 04:06:27 +1000 Subject: [PATCH 6/6] Mute org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT #113298 --- muted-tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/muted-tests.yml b/muted-tests.yml index 2fbff4abd5c06..6b7e30bb9c0e3 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -286,6 +286,8 @@ tests: - class: org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT method: test {stats.DocsStatsGroupByMultipleValues} issue: https://github.com/elastic/elasticsearch/issues/113296 +- class: org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT + issue: https://github.com/elastic/elasticsearch/issues/113298 # Examples: #