From 7a8a66d9ae49161271d24ddaf512c51c2423faae Mon Sep 17 00:00:00 2001 From: Ioannis Kakavas Date: Mon, 13 Apr 2020 09:50:55 +0300 Subject: [PATCH] [7.x] Fix ReloadSecureSettings API to consume password (#54771) (#55059) The secure_settings_password was never taken into consideration in the ReloadSecureSettings API. This commit fixes that and adds necessary REST layer testing. Doing so, it also: - Allows TestClusters to have a password protected keystore so that it can be set for tests. - Adds a parameter to the run task so that elastisearch can be run with a password protected keystore from source. --- build.gradle | 8 ++ .../testclusters/ElasticsearchCluster.java | 5 + .../testclusters/ElasticsearchNode.java | 35 ++++++- .../gradle/testclusters/RunTask.java | 16 +++ .../TestClusterConfiguration.java | 2 + docs/build.gradle | 1 + .../nodes-reload-secure-settings.asciidoc | 37 +++---- docs/reference/setup/secure-settings.asciidoc | 2 +- .../api/nodes.reload_secure_settings.json | 12 ++- .../nodes.reload_secure_settings/10_basic.yml | 25 ++++- .../RestReloadSecureSettingsAction.java | 2 +- .../password-protected-keystore/build.gradle | 52 ++++++++++ ...gsWithPasswordProtectedKeystoreRestIT.java | 97 +++++++++++++++++++ .../src/test/resources/roles.yml | 4 + .../src/test/resources/ssl/README.asciidoc | 31 ++++++ .../src/test/resources/ssl/ca.crt | 20 ++++ .../src/test/resources/ssl/ca.key | 30 ++++++ .../src/test/resources/ssl/transport.crt | 22 +++++ .../src/test/resources/ssl/transport.key | 30 ++++++ 19 files changed, 393 insertions(+), 38 deletions(-) create mode 100644 x-pack/qa/password-protected-keystore/build.gradle create mode 100644 x-pack/qa/password-protected-keystore/src/test/java/org/elasticsearch/password_protected_keystore/ReloadSecureSettingsWithPasswordProtectedKeystoreRestIT.java create mode 100644 x-pack/qa/password-protected-keystore/src/test/resources/roles.yml create mode 100644 x-pack/qa/password-protected-keystore/src/test/resources/ssl/README.asciidoc create mode 100644 x-pack/qa/password-protected-keystore/src/test/resources/ssl/ca.crt create mode 100644 x-pack/qa/password-protected-keystore/src/test/resources/ssl/ca.key create mode 100644 x-pack/qa/password-protected-keystore/src/test/resources/ssl/transport.crt create mode 100644 x-pack/qa/password-protected-keystore/src/test/resources/ssl/transport.key diff --git a/build.gradle b/build.gradle index 4af128c6222..568204eb398 100644 --- a/build.gradle +++ b/build.gradle @@ -408,6 +408,14 @@ class Run extends DefaultTask { public void setDataDir(String dataDirStr) { project.project(':distribution').run.dataDir = dataDirStr } + + @Option( + option = "keystore-password", + description = "Set the elasticsearch keystore password" + ) + public void setKeystorePassword(String password) { + project.project(':distribution').run.keystorePassword = password + } } task run(type: Run) { diff --git a/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchCluster.java b/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchCluster.java index 9343447c6c0..71c9aa0b627 100644 --- a/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchCluster.java +++ b/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchCluster.java @@ -174,6 +174,11 @@ public class ElasticsearchCluster implements TestClusterConfiguration, Named { nodes.all(each -> each.keystore(key, valueSupplier)); } + @Override + public void keystorePassword(String password) { + nodes.all(each -> each.keystorePassword(password)); + } + @Override public void cliSetup(String binTool, CharSequence... args) { nodes.all(each -> each.cliSetup(binTool, args)); diff --git a/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java b/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java index bff6cc3fea7..049fe7797e2 100644 --- a/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java +++ b/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java @@ -143,6 +143,7 @@ public class ElasticsearchNode implements TestClusterConfiguration { private final Path httpPortsFile; private final Path esStdoutFile; private final Path esStderrFile; + private final Path esStdinFile; private final Path tmpDir; private int currentDistro = 0; @@ -154,6 +155,7 @@ public class ElasticsearchNode implements TestClusterConfiguration { private String httpPort = "0"; private String transportPort = "0"; private Path confPathData; + private String keystorePassword = ""; ElasticsearchNode(String name, Project project, ReaperService reaper, File workingDirBase, Jdk bwcJdk) { this.path = project.getPath(); @@ -170,6 +172,7 @@ public class ElasticsearchNode implements TestClusterConfiguration { httpPortsFile = confPathLogs.resolve("http.ports"); esStdoutFile = confPathLogs.resolve("es.stdout.log"); esStderrFile = confPathLogs.resolve("es.stderr.log"); + esStdinFile = workingDir.resolve("es.stdin"); tmpDir = workingDir.resolve("tmp"); waitConditions.put("ports files", this::checkPortsFilesExistWithDelay); @@ -305,6 +308,11 @@ public class ElasticsearchNode implements TestClusterConfiguration { keystoreFiles.put(key, valueSupplier); } + @Override + public void keystorePassword(String password) { + keystorePassword = password; + } + @Override public void cliSetup(String binTool, CharSequence... args) { cliSetup.add(new CliEntry(binTool, args)); @@ -439,13 +447,17 @@ public class ElasticsearchNode implements TestClusterConfiguration { } } + logToProcessStdout("Creating elasticsearch keystore with password set to [" + keystorePassword + "]"); + if (keystorePassword.length() > 0) { + runElasticsearchBinScriptWithInput(keystorePassword + "\n" + keystorePassword, "elasticsearch-keystore", "create", "-p"); + } else { + runElasticsearchBinScript("elasticsearch-keystore", "create"); + } + if (keystoreSettings.isEmpty() == false || keystoreFiles.isEmpty() == false) { logToProcessStdout("Adding " + keystoreSettings.size() + " keystore settings and " + keystoreFiles.size() + " keystore files"); - runElasticsearchBinScript("elasticsearch-keystore", "create"); - keystoreSettings.forEach( - (key, value) -> runElasticsearchBinScriptWithInput(value.toString(), "elasticsearch-keystore", "add", "-x", key) - ); + keystoreSettings.forEach((key, value) -> runKeystoreCommandWithPassword(keystorePassword, value.toString(), "add", "-x", key)); for (Map.Entry entry : keystoreFiles.entrySet()) { File file = entry.getValue(); @@ -453,7 +465,7 @@ public class ElasticsearchNode implements TestClusterConfiguration { if (file.exists() == false) { throw new TestClustersException("supplied keystore file " + file + " does not exist, require for " + this); } - runElasticsearchBinScript("elasticsearch-keystore", "add-file", entry.getKey(), file.getAbsolutePath()); + runKeystoreCommandWithPassword(keystorePassword, "", "add-file", entry.getKey(), file.getAbsolutePath()); } } @@ -657,6 +669,11 @@ public class ElasticsearchNode implements TestClusterConfiguration { } } + private void runKeystoreCommandWithPassword(String keystorePassword, String input, CharSequence... args) { + final String actualInput = keystorePassword.length() > 0 ? keystorePassword + "\n" + input : input; + runElasticsearchBinScriptWithInput(actualInput, "elasticsearch-keystore", args); + } + private void runElasticsearchBinScript(String tool, CharSequence... args) { runElasticsearchBinScriptWithInput("", tool, args); } @@ -746,6 +763,14 @@ public class ElasticsearchNode implements TestClusterConfiguration { processBuilder.redirectError(ProcessBuilder.Redirect.appendTo(esStderrFile.toFile())); processBuilder.redirectOutput(ProcessBuilder.Redirect.appendTo(esStdoutFile.toFile())); + if (keystorePassword != null && keystorePassword.length() > 0) { + try { + Files.write(esStdinFile, (keystorePassword + "\n").getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE); + processBuilder.redirectInput(esStdinFile.toFile()); + } catch (IOException e) { + throw new TestClustersException("Failed to set the keystore password for " + this, e); + } + } LOGGER.info("Running `{}` in `{}` for {} env: {}", command, workingDir, this, environment); try { esProcess = processBuilder.start(); diff --git a/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/RunTask.java b/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/RunTask.java index 99114ed15ec..4f6b2459515 100644 --- a/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/RunTask.java +++ b/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/RunTask.java @@ -28,6 +28,8 @@ public class RunTask extends DefaultTestClustersTask { private Path dataDir = null; + private String keystorePassword = ""; + @Option(option = "debug-jvm", description = "Enable debugging configuration, to allow attaching a debugger to elasticsearch.") public void setDebug(boolean enabled) { this.debug = enabled; @@ -43,6 +45,17 @@ public class RunTask extends DefaultTestClustersTask { dataDir = Paths.get(dataDirStr).toAbsolutePath(); } + @Option(option = "keystore-password", description = "Set the elasticsearch keystore password") + public void setKeystorePassword(String password) { + keystorePassword = password; + } + + @Input + @Optional + public String getKeystorePassword() { + return keystorePassword; + } + @Input @Optional public String getDataDir() { @@ -90,6 +103,9 @@ public class RunTask extends DefaultTestClustersTask { node.jvmArgs("-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=" + debugPort); debugPort += 1; } + if (keystorePassword.length() > 0) { + node.keystorePassword(keystorePassword); + } } } } diff --git a/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/TestClusterConfiguration.java b/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/TestClusterConfiguration.java index 3b431c2b6c8..01acae2c050 100644 --- a/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/TestClusterConfiguration.java +++ b/buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/TestClusterConfiguration.java @@ -57,6 +57,8 @@ public interface TestClusterConfiguration { void keystore(String key, FileSupplier valueSupplier); + void keystorePassword(String password); + void cliSetup(String binTool, CharSequence... args); void setting(String key, String value); diff --git a/docs/build.gradle b/docs/build.gradle index d476ceda711..917f0ea66a3 100644 --- a/docs/build.gradle +++ b/docs/build.gradle @@ -58,6 +58,7 @@ testClusters.integTest { } setting 'xpack.autoscaling.enabled', 'true' setting 'xpack.eql.enabled', 'true' + keystorePassword 's3cr3t' } // enable regexes in painless so our tests don't complain about example snippets that use them diff --git a/docs/reference/cluster/nodes-reload-secure-settings.asciidoc b/docs/reference/cluster/nodes-reload-secure-settings.asciidoc index 3ee6ee0a38f..deba27c6a09 100644 --- a/docs/reference/cluster/nodes-reload-secure-settings.asciidoc +++ b/docs/reference/cluster/nodes-reload-secure-settings.asciidoc @@ -36,7 +36,7 @@ the node-specific {es} keystore password. (Optional, string) The names of particular nodes in the cluster to target. For example, `nodeId1,nodeId2`. For node selection options, see <>. - + NOTE: {es} requires consistent secure settings across the cluster nodes, but this consistency is not enforced. Hence, reloading specific nodes is not standard. It is justifiable only when retrying failed reload operations. @@ -44,16 +44,25 @@ standard. It is justifiable only when retrying failed reload operations. [[cluster-nodes-reload-secure-settings-api-request-body]] ==== {api-request-body-title} -`reload_secure_settings`:: +`secure_settings_password`:: (Optional, string) The password for the {es} keystore. [[cluster-nodes-reload-secure-settings-api-example]] ==== {api-examples-title} +The following examples assume a common password for the {es} keystore on every +node of the cluster: + [source,console] -------------------------------------------------- POST _nodes/reload_secure_settings +{ + "secure_settings_password":"s3cr3t" +} POST _nodes/nodeId1,nodeId2/reload_secure_settings +{ + "secure_settings_password":"s3cr3t" +} -------------------------------------------------- // TEST[setup:node] // TEST[s/nodeId1,nodeId2/*/] @@ -81,27 +90,3 @@ that was thrown during the reload process, if any. -------------------------------------------------- // TESTRESPONSE[s/"my_cluster"/$body.cluster_name/] // TESTRESPONSE[s/"pQHNt5rXTTWNvUgOrdynKg"/\$node_name/] - -The following example uses a common password for the {es} keystore on every -node of the cluster: - -[source,js] --------------------------------------------------- -POST _nodes/reload_secure_settings -{ - "reload_secure_settings": "s3cr3t" -} --------------------------------------------------- -// NOTCONSOLE - -The following example uses a password for the {es} keystore on the local node: - -[source,js] --------------------------------------------------- -POST _nodes/_local/reload_secure_settings -{ - "reload_secure_settings": "s3cr3t" -} --------------------------------------------------- -// NOTCONSOLE - diff --git a/docs/reference/setup/secure-settings.asciidoc b/docs/reference/setup/secure-settings.asciidoc index 23387804123..682cbb53f16 100644 --- a/docs/reference/setup/secure-settings.asciidoc +++ b/docs/reference/setup/secure-settings.asciidoc @@ -35,7 +35,7 @@ using the `bin/elasticsearch-keystore add` command, call: ---- POST _nodes/reload_secure_settings { - "reload_secure_settings": "s3cr3t" <1> + "secure_settings_password": "s3cr3t" <1> } ---- // NOTCONSOLE diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/nodes.reload_secure_settings.json b/rest-api-spec/src/main/resources/rest-api-spec/api/nodes.reload_secure_settings.json index b1be8af3eee..fd5420d0288 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/api/nodes.reload_secure_settings.json +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/nodes.reload_secure_settings.json @@ -27,11 +27,15 @@ } ] }, - "params":{ - "timeout":{ - "type":"time", - "description":"Explicit operation timeout" + "params": { + "timeout": { + "type": "time", + "description": "Explicit operation timeout" } + }, + "body": { + "description": "An object containing the password for the elasticsearch keystore", + "required": false } } } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.reload_secure_settings/10_basic.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.reload_secure_settings/10_basic.yml index 0a4cf0d64a0..cf5ef338db6 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.reload_secure_settings/10_basic.yml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.reload_secure_settings/10_basic.yml @@ -1,8 +1,31 @@ --- -"node_reload_secure_settings test": +"node_reload_secure_settings test wrong password": + - skip: + version: " - 7.99.99" + reason: "support for reloading password protected keystores was introduced in 7.7.0" + + - do: + nodes.reload_secure_settings: + node_id: _local + body: + secure_settings_password: awrongpasswordhere + - set: + nodes._arbitrary_key_: node_id + + - is_true: nodes + - is_true: cluster_name + - match: { nodes.$node_id.reload_exception.type: "security_exception" } + - match: { nodes.$node_id.reload_exception.reason: "Provided keystore password was incorrect" } + +--- +"node_reload_secure_settings test correct(empty) password": - do: nodes.reload_secure_settings: {} + - set: + nodes._arbitrary_key_: node_id + - is_true: nodes - is_true: cluster_name + - is_false: nodes.$node_id.reload_exception diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestReloadSecureSettingsAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestReloadSecureSettingsAction.java index 209e0ef7d33..ae7e2edf7b4 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestReloadSecureSettingsAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestReloadSecureSettingsAction.java @@ -75,7 +75,7 @@ public final class RestReloadSecureSettingsAction extends BaseRestHandler { .setNodesIds(nodesIds); request.withContentOrSourceParamParserOrNull(parser -> { if (parser != null) { - final NodesReloadSecureSettingsRequest nodesRequest = nodesRequestBuilder.request(); + final NodesReloadSecureSettingsRequest nodesRequest = PARSER.parse(parser, null); nodesRequestBuilder.setSecureStorePassword(nodesRequest.getSecureSettingsPassword()); } }); diff --git a/x-pack/qa/password-protected-keystore/build.gradle b/x-pack/qa/password-protected-keystore/build.gradle new file mode 100644 index 00000000000..8accfa742bd --- /dev/null +++ b/x-pack/qa/password-protected-keystore/build.gradle @@ -0,0 +1,52 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * Tests that need to run against an Elasticsearch cluster that + * is using a password protected keystore in its nodes. + */ + +apply plugin: 'elasticsearch.testclusters' +apply plugin: 'elasticsearch.standalone-rest-test' +apply plugin: 'elasticsearch.rest-test' +dependencies { + testCompile project(path: xpackModule('core'), configuration: 'default') +} + +testClusters.integTest { + testDistribution = 'DEFAULT' + numberOfNodes = 2 + keystorePassword 's3cr3t' + + setting 'xpack.security.enabled', 'true' + setting 'xpack.security.authc.anonymous.roles', 'anonymous' + setting 'xpack.security.transport.ssl.enabled', 'true' + setting 'xpack.security.transport.ssl.certificate', 'transport.crt' + setting 'xpack.security.transport.ssl.key', 'transport.key' + setting 'xpack.security.transport.ssl.key_passphrase', 'transport-password' + setting 'xpack.security.transport.ssl.certificate_authorities', 'ca.crt' + + extraConfigFile 'transport.key', file('src/test/resources/ssl/transport.key') + extraConfigFile 'transport.crt', file('src/test/resources/ssl/transport.crt') + extraConfigFile 'ca.crt', file('src/test/resources/ssl/ca.crt') + extraConfigFile 'roles.yml', file('src/test/resources/roles.yml') + + user username: 'admin_user', password: 'admin-password' + user username:'test-user' ,password: 'test-password', role: 'user_role' +} diff --git a/x-pack/qa/password-protected-keystore/src/test/java/org/elasticsearch/password_protected_keystore/ReloadSecureSettingsWithPasswordProtectedKeystoreRestIT.java b/x-pack/qa/password-protected-keystore/src/test/java/org/elasticsearch/password_protected_keystore/ReloadSecureSettingsWithPasswordProtectedKeystoreRestIT.java new file mode 100644 index 00000000000..a145ecbe6d5 --- /dev/null +++ b/x-pack/qa/password-protected-keystore/src/test/java/org/elasticsearch/password_protected_keystore/ReloadSecureSettingsWithPasswordProtectedKeystoreRestIT.java @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.password_protected_keystore; + +import org.elasticsearch.client.Request; +import org.elasticsearch.client.Response; +import org.elasticsearch.common.settings.SecureString; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.common.xcontent.ObjectPath; +import org.elasticsearch.test.rest.ESRestTestCase; + +import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.nullValue; + +import java.util.Map; + +public class ReloadSecureSettingsWithPasswordProtectedKeystoreRestIT extends ESRestTestCase { + // From build.gradle + private final String KEYSTORE_PASSWORD = "s3cr3t"; + private final int NUM_NODES = 2; + + @SuppressWarnings("unchecked") + public void testReloadSecureSettingsWithCorrectPassword() throws Exception { + final Request request = new Request("POST", "_nodes/reload_secure_settings"); + request.setJsonEntity("{\"secure_settings_password\":\"" + KEYSTORE_PASSWORD + "\"}"); + final Response response = client().performRequest(request); + final Map map = entityAsMap(response); + assertThat(ObjectPath.eval("cluster_name", map), equalTo("integTest")); + assertThat(map.get("nodes"), instanceOf(Map.class)); + final Map nodes = (Map) map.get("nodes"); + assertThat(nodes.size(), equalTo(NUM_NODES)); + for (Map.Entry entry : nodes.entrySet()) { + assertThat(entry.getValue(), instanceOf(Map.class)); + final Map node = (Map) entry.getValue(); + assertThat(node.get("reload_exception"), nullValue()); + } + } + + @SuppressWarnings("unchecked") + public void testReloadSecureSettingsWithInCorrectPassword() throws Exception { + final Request request = new Request("POST", "_nodes/reload_secure_settings"); + request.setJsonEntity("{\"secure_settings_password\":\"" + KEYSTORE_PASSWORD + randomAlphaOfLength(7) + "\"}"); + final Response response = client().performRequest(request); + final Map map = entityAsMap(response); + assertThat(ObjectPath.eval("cluster_name", map), equalTo("integTest")); + assertThat(map.get("nodes"), instanceOf(Map.class)); + final Map nodes = (Map) map.get("nodes"); + assertThat(nodes.size(), equalTo(NUM_NODES)); + for (Map.Entry entry : nodes.entrySet()) { + assertThat(entry.getValue(), instanceOf(Map.class)); + final Map node = (Map) entry.getValue(); + assertThat(node.get("reload_exception"), instanceOf(Map.class)); + assertThat(ObjectPath.eval("reload_exception.reason", node), equalTo("Provided keystore password was incorrect")); + assertThat(ObjectPath.eval("reload_exception.type", node), equalTo("security_exception")); + } + } + + @SuppressWarnings("unchecked") + public void testReloadSecureSettingsWithEmptyPassword() throws Exception { + final Request request = new Request("POST", "_nodes/reload_secure_settings"); + final Response response = client().performRequest(request); + final Map map = entityAsMap(response); + assertThat(ObjectPath.eval("cluster_name", map), equalTo("integTest")); + assertThat(map.get("nodes"), instanceOf(Map.class)); + final Map nodes = (Map) map.get("nodes"); + assertThat(nodes.size(), equalTo(NUM_NODES)); + for (Map.Entry entry : nodes.entrySet()) { + assertThat(entry.getValue(), instanceOf(Map.class)); + final Map node = (Map) entry.getValue(); + assertThat(node.get("reload_exception"), instanceOf(Map.class)); + assertThat(ObjectPath.eval("reload_exception.reason", node), equalTo("Provided keystore password was incorrect")); + assertThat(ObjectPath.eval("reload_exception.type", node), equalTo("security_exception")); + } + } + + @Override + protected Settings restClientSettings() { + String token = basicAuthHeaderValue("test-user", new SecureString("test-password".toCharArray())); + return Settings.builder() + .put(ThreadContext.PREFIX + ".Authorization", token) + .build(); + } + + @Override + protected Settings restAdminSettings() { + String token = basicAuthHeaderValue("admin_user", new SecureString("admin-password".toCharArray())); + return Settings.builder() + .put(ThreadContext.PREFIX + ".Authorization", token) + .build(); + } +} diff --git a/x-pack/qa/password-protected-keystore/src/test/resources/roles.yml b/x-pack/qa/password-protected-keystore/src/test/resources/roles.yml new file mode 100644 index 00000000000..60dd459d0f8 --- /dev/null +++ b/x-pack/qa/password-protected-keystore/src/test/resources/roles.yml @@ -0,0 +1,4 @@ +# user needs to call cluster:admin/nodes/reload_secure_settings +user_role: + cluster: [ALL] + indices: [] diff --git a/x-pack/qa/password-protected-keystore/src/test/resources/ssl/README.asciidoc b/x-pack/qa/password-protected-keystore/src/test/resources/ssl/README.asciidoc new file mode 100644 index 00000000000..94e4c885fd0 --- /dev/null +++ b/x-pack/qa/password-protected-keystore/src/test/resources/ssl/README.asciidoc @@ -0,0 +1,31 @@ += Keystore Details + +This document details the steps used to create the certificate and keystore files in this directory. + +== Instructions on generating certificates +The certificates in this directory have been generated using elasticsearch-certutil (8.0.0 SNAPSHOT) + +[source,shell] +----------------------------------------------------------------------------------------------------------- +elasticsearch-certutil ca --pem --out=ca.zip --pass="ca-password" --days=3500 +unzip ca.zip +mv ca/ca.* ./ + +rm ca.zip +rmdir ca +----------------------------------------------------------------------------------------------------------- + +[source,shell] +----------------------------------------------------------------------------------------------------------- +elasticsearch-certutil cert --pem --name=transport --out=transport.zip --pass="transport-password" --days=3500 \ + --ca-cert=ca.crt --ca-key=ca.key --ca-pass="ca-password" \ + --dns=localhost --dns=localhost.localdomain --dns=localhost4 --dns=localhost4.localdomain4 --dns=localhost6 --dns=localhost6.localdomain6 \ + --ip=127.0.0.1 --ip=0:0:0:0:0:0:0:1 + +unzip transport.zip +mv transport/transport.* ./ + +rm transport.zip +rmdir transport +----------------------------------------------------------------------------------------------------------- + diff --git a/x-pack/qa/password-protected-keystore/src/test/resources/ssl/ca.crt b/x-pack/qa/password-protected-keystore/src/test/resources/ssl/ca.crt new file mode 100644 index 00000000000..320f00ccde5 --- /dev/null +++ b/x-pack/qa/password-protected-keystore/src/test/resources/ssl/ca.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSTCCAjGgAwIBAgIUGuBmPtwyEv7WZ1H0Yy5vyEEYVR8wDQYJKoZIhvcNAQEL +BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l +cmF0ZWQgQ0EwHhcNMjAwNDA3MTEzMDA1WhcNMjkxMTA2MTEzMDA1WjA0MTIwMAYD +VQQDEylFbGFzdGljIENlcnRpZmljYXRlIFRvb2wgQXV0b2dlbmVyYXRlZCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALeTNx0a6X+Fhf6IQj4ggN9U +1HGIzJKEHGIpATDgbfdIv88e0O0I6HN7pmLf5LuUPDGc2oLGnxqATgnFek5eJ4QW +sKgflGB4C0EgQH4JAooIG0EI6aj3IcdzBwH8bdymAdsGj0Zcvm6wjhLixgiN3yIM +8KJAtJrSCITI88gfXhXyU0XCSzgruFkdvHjFBCWpCaK3hnjoiO65186PcGbrZHB8 +Izs2soa6H1AHVDMhmJjlwJWYtibjok+sgrjkDWG7cBh6Al7yXGUBOs9SgMXUpI3Y +0r/dDdeISdI5VzwKZpX6qYcNJI+jtgZUD0alMKBxjq3+v8GlDE/QVNyDwp/7SA8C +AwEAAaNTMFEwHQYDVR0OBBYEFMdSVLWtAhqfDXRQj+5o80nK1XaQMB8GA1UdIwQY +MBaAFMdSVLWtAhqfDXRQj+5o80nK1XaQMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI +hvcNAQELBQADggEBAEiaX+JtgDb6PuPqO9NtxuPEsg6Ghj0dVYLOYE9cmKS9xeyy +sIDJbPl8vy7gomVBDYe+3qM2UElKFdApKGjOctjNlH8npkQxg72sarBUzOfuFPx5 +Z6u5TuKMfqjx2dwpTr3Yp/iUFs9e9zcDMnQYt5B6SCjKpKKodKKh+CE6wOg4nbSF +43OYO9HFHfwIlEqvof7j0r5gnPf5fYSYybYFAqy4oAfpESPq9lJuEvA46TrGpmP6 +IpMYkJJ6O+98A7RHo5kstZJdnG5paAKobdPEYxbIZvRyMJ8IxW8kSAaTKsK7W34k +IYciDd/YY3R+nhnh8F5DjVcyc79Zkv9Cjig/OxQ= +-----END CERTIFICATE----- diff --git a/x-pack/qa/password-protected-keystore/src/test/resources/ssl/ca.key b/x-pack/qa/password-protected-keystore/src/test/resources/ssl/ca.key new file mode 100644 index 00000000000..6bbdd44d274 --- /dev/null +++ b/x-pack/qa/password-protected-keystore/src/test/resources/ssl/ca.key @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,8209E02F62E3909502FECF5E5E9CF7A7 + +EdOFZ6/z/e4elfeAKs2B++/Px/IpiZdmiseZPjfwa6jgpY+8sehmze5+34vrxYJT +cMBH3QafmhdQZ4/Eo7DVFONrjJ3OmD5//ZiTIujTPwMsgGAdeq0yMC0cDkzg8SQ7 +KvTh0PY0feC6bVsY+YjDprDfpqIWf89F8ikgat9cmucV9YO3RbYnxgxRIztbHLP3 +GenAtdG+v7DzdefAdRQktBSNldkadsY6d/kVBknOHcA4pB/UtDpz77ZF40CNB95z +1Tr37nNnuRBUNHbKklXuozkvYLah66tFxA5v7Rf6F37d2QGBkgDphg/QMbJrrB+q +MsfiXeXqRaCzBN/ZuzTQAdQ/67XpQ+Ax89UOiT6SkKBKN1uNDk7Juzv5zHrq7aWS +aj1qtHDG2vMB+UM5A1MngD1LtXzs21Q0+9a2UT83x+VIP0hVq2uKmO8wAQ9gbBe9 +wkBPca4gLYlbIMWzaAe4DV0rcmux+i7Ezk8oVYW1JcoGjoZ3f9KewIQynBUlXXuO +EzSl4R3yiF/birrK9Lo6c9hOcQKCW2qAX73BKq8PjKgWT3rnqzg97q9PPK/vaien +fwSrTXDgEoy1RCwsPsxjyRf0LGFYLUFRVqrbFPhhjg4aEiuzawcpvRxjorC5UX0L +dpImNssdALDd0BbiqAbChUryFSSxFhQ2yo6hfUXZevD236b09V0jUpnZeyQjeTTk +fhhAUUpnd1YzWuYneD2JZQKvGdgWgYRyEKParFeHLjp95rXNWPSOgoAM+w0fFEjq +zkYQMaDGSnUWbc6LVv2exyRIRTrLAWamKnne7z8VxzetqXXmuX0WJb2lFiYMUw4/ +wf31RA8ZsVSgb9werSyPD9aRe/+YZM+kM3/3MC4jJGc6OJuDqEOhhB06L2Df2AWU +UQwZ7y+2yUC1kcFzc8+oT1TNgBHixouY+oqWkhbdCkbUFUe4FwXNXrMyrY9gZs1/ +PEkhVxxYgpLwifkbfQRJPeJvXxh7NxeolXyISaVENdLkMMYUhdsKTa+GOQbO2yfa +4BhOwAqJvyDFfsRxLiDlbxjzvY5qnMl0e/q8wZ60onHJOFCTCfm2BNx7sW+Sk5Kx +zm0Rxsz4rIIxA5S6zbbdsHxjTC9XiUelKaq+W0XTg76USYneORQNN/Mk9sCXvTud +HUqmSf1wREA1PdEcoJ3tMoAOZWGY43/IrdoG3bTNT96AdToD+D+Or8M2VcOZorVf +c3IRNfxGv2/SwhxW/z4tSLSToSJlt4QKxU9Xzm4UundDy1cHmS1faN6+bBnI5+/F +OKwzPCCUJ6H02CAjx2P/P6YEjoLl8B+7h4whlOfT/+IQbzOcGMpPyGu4jSf1KffA +asAQeBvYTx0QPdv2E7e216RLOlp/ERMzkUvF1G7UYKF7Ao6cUpSH6nvGABPLKNXV +fqjpWq8O4R1UEUXi6dqF1HfAHllI+vMw7LzRJK/5zVrWlJPm4c/Rng5OkK7aAGee +J0eTSlCdNpyaZzjyk2ZAQ54kZVqAS90zS1zo6lg2v9yfAfz6eYlfl2OGfFVG40Jt +oYxEVcG9LeD3XOkPOnTblHdKMor8cQt+TEJPu9eM31ay1QSilixx2yfOOFTgJZOi +-----END RSA PRIVATE KEY----- diff --git a/x-pack/qa/password-protected-keystore/src/test/resources/ssl/transport.crt b/x-pack/qa/password-protected-keystore/src/test/resources/ssl/transport.crt new file mode 100644 index 00000000000..db93ca6ac47 --- /dev/null +++ b/x-pack/qa/password-protected-keystore/src/test/resources/ssl/transport.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIVAIdpYPATbRn96E+eVTG/s0byNh/FMA0GCSqGSIb3DQEB +CwUAMDQxMjAwBgNVBAMTKUVsYXN0aWMgQ2VydGlmaWNhdGUgVG9vbCBBdXRvZ2Vu +ZXJhdGVkIENBMB4XDTIwMDQwNzExMzA1OFoXDTI5MTEwNjExMzA1OFowFDESMBAG +A1UEAxMJdHJhbnNwb3J0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +pvfY9x3F8xR2+noX0PWxsc6XrKCxTQcbSHkkEr2Qr6BqGVXwEj/d6ocqdgcC7IZy +0HEwewBbO69Pg8INQ/21stcwZzW+4ZnKYsBmaZx1yCxYcplndFm9t5Fj/jTBsoJ3 +PemvJwMrewuVSwsE4WHVkXz4KVETfUd8DZiWoVnlRgaXfvvudib1DNxtuGEra+Zh +d3JcC1Wsn51qjpHsj/6s/usT6hmlm4Bu5tjAMxXFVX6J0skfRSVhLmNWgr86WBKB +9/qTJU34FBQGh2Ok/knkiO5rae+UCPpEpCNCCV3rFcMdxP613WfemRRqhUL0V6g3 +n4ExJa0853SsfvPEyHOADQIDAQABo4HgMIHdMB0GA1UdDgQWBBSraIvkNPX2TQQg +h8Ee3mWCALYr/zAfBgNVHSMEGDAWgBTHUlS1rQIanw10UI/uaPNJytV2kDCBjwYD +VR0RBIGHMIGEgglsb2NhbGhvc3SCF2xvY2FsaG9zdDYubG9jYWxkb21haW42hwR/ +AAABhxAAAAAAAAAAAAAAAAAAAAABggpsb2NhbGhvc3Q0ggpsb2NhbGhvc3Q2ghVs +b2NhbGhvc3QubG9jYWxkb21haW6CF2xvY2FsaG9zdDQubG9jYWxkb21haW40MAkG +A1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggEBABRKISeKdMRRQAvZBan2ONUFUD3P +7Aq8JP+GttC9Y+1uI0CTIZsnih+tuZ9l2Gq9nyfBVMcDSutlnBoQZLg5lCYQPaK7 +SuFhPRHGauEGYw1TjhrMEPokxzoT/X0/Sz5Ter6/qWzPKQs9EuaVJ27XfZd+kySn +S+cXd95woi+S8JQzQbcpA0rXCnWJ3l2frwG/3Hg8f82x2c6vgOzTG0Hklp0sFkUt +UqaBHGXPLiitaB01jUX60HZbxt5HIEseLctUmQlDtAEWwA3X6cRUEjulwRx8s52T +1FT2ORbVJ7ybKARGBSs932Fv2rWGmg8pOBA4ulJTJNvT0T+ob/H/i40Qd04= +-----END CERTIFICATE----- diff --git a/x-pack/qa/password-protected-keystore/src/test/resources/ssl/transport.key b/x-pack/qa/password-protected-keystore/src/test/resources/ssl/transport.key new file mode 100644 index 00000000000..601c665a48c --- /dev/null +++ b/x-pack/qa/password-protected-keystore/src/test/resources/ssl/transport.key @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,DAC0DDB93011ABD08161118074F353A7 + +hPjzr8y4t3omv6jItFSxF/UeirrdlMhFoxxsw+E5fl4hRjD2J6LuUpOl0XBuvrCO +2NN9Simlkfo57l2O8tZ3xwKU037x9qP2O3wo0FZ4OuRcLbXZtp5kIV30/wdo0kbp +GV+18PtGfReo75rszs/VAm9Hg1URqVw0La2r7DomYQB9FJY8N8mwSdSvF194kjGO +pBxiuzzECUwXEGuMRzmc1Cddbw7NsIdg43FRd1uoC4dqj9yBonYEYe5P8WgopL4N +obTi6PzH+kqDSCaJo7Fdr9CYo37f2YsSbtHmuEZP58J/aSB9nl5wdAmas3/dohrI +5GSM9zp+UocFuV6Uf+X9TTJMt97BlRgFdPODh88pTKGLVQyKeBPQbVjgwl9mttxO +i+c/dej/jHt0gwlt8cvZw0Ss50YdNnWtck91yYpXE7iz59CTY+QI24DEvsaP4bkR +QYdIhJHOYamGW0ttCSU8bw1h9RubIvSa+BoiuB+1TaCYU+azuaAYnFlyuR31z4rD +yniPMnb0+5uOkU/srwb4MxVVw/0iYkKAGTEwdLPKhyheuDU9ixkNOQ/k12zV0R7d +gzMFQOlrB4v8Y4LrsNPnAz/uCTvKgBrOS8p076qeGkSX+JIZVNHYyzLnSy7p6hjO +eD3tDx/SA1HaiLzD1VqujnYb6wshYjQGkSPSY3COq8dQgpCqMAlkOycUQO1SbuNt +HZFv9X0w2z5HjPJXtKLLXMLeluNNRQD+IVhvbZjIM1cAUQNqL3OQPGa7W5RYoFYK +rDffzQAzukD5dt6jH+uu3cwnEeJiW8hxZ0+DHJR1X5EJWpN544yTl8jgSPT8MPAU +kxq7OyE0F/JY+UWP1hPILimDrf3Ov8KRtTDGsSvV3IcX+92QKMcvnK21QBZqZjSs +zcmjp2jN1MLwieJyZ3un0MUT9kOyG/5vGoAJe9O/KDtv6rrhKQN5JHi5yKw0Uwi9 +CwrwwkxbRLSBbWugZGXyBHkR/RGIuEEysLKRFej2q4WBZrPOzZlgyvgBbd6/4Eg5 +twngo6JTmYALwVJNW/drok1H0JelanZ6jM/JjNRFWMZnS5o+4cwQURB5O7TIKHdV +7zEkaw82Ng0Nq8dPrU8N9G3LTmIC1E4t++L+D18C2lV0ZDd0Svh3NIA65FXSRvX9 +2g9GQGfGGbgydmjv9j5lx6VdhuTgYKRL4b5bS7VnH+F9m864g/MtSQpXQPR5B54g +YHFGiKCAzruZt1MmJ5m8Jvpg84i2lIZkGImwAstV7xVkmQoC3i77awmcQP6s7rJd +Lo7RKEysVPDbzdnZnWGK0PWJwtgsqrAvVcK7ghygi+vSQkDF0L7qunchOKa00oZR +LZa08b5BWuXeqw4lXZDQDT7hk3NUyW3H7Z1uxUlt1kvcGb6zrInW6Bin0hqsODvj +0drMOZp/5NTDSwcEzkW+LgjfKZw8Szmhlt3v+luNFr3KzbnFtEvewD1OVikNGzm9 +sfZ899zNkWfvNJaXL3bvzbTn9d8T15YKCwO9RqPpYKDqXBaC4+OjbNsy4AW/JHPr +H/i3D3rhMXR/CALhp4+Knq4o3vMA+3TsUeZ3lOTogobVloWfixIIiRXfaqT4LmEC +-----END RSA PRIVATE KEY-----