Prechádzať zdrojové kódy

Fix ReloadSecureSettings API to consume password (#54771)

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.
Ioannis Kakavas 5 rokov pred
rodič
commit
16e9433ead
19 zmenil súbory, kde vykonal 390 pridanie a 38 odobranie
  1. 8 0
      build.gradle
  2. 5 0
      buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchCluster.java
  3. 30 5
      buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java
  4. 16 0
      buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/RunTask.java
  5. 2 0
      buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/TestClusterConfiguration.java
  6. 1 0
      docs/build.gradle
  7. 11 26
      docs/reference/cluster/nodes-reload-secure-settings.asciidoc
  8. 1 1
      docs/reference/setup/secure-settings.asciidoc
  9. 8 4
      rest-api-spec/src/main/resources/rest-api-spec/api/nodes.reload_secure_settings.json
  10. 21 1
      rest-api-spec/src/main/resources/rest-api-spec/test/nodes.reload_secure_settings/10_basic.yml
  11. 1 1
      server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestReloadSecureSettingsAction.java
  12. 52 0
      x-pack/qa/password-protected-keystore/build.gradle
  13. 97 0
      x-pack/qa/password-protected-keystore/src/test/java/org/elasticsearch/password_protected_keystore/ReloadSecureSettingsWithPasswordProtectedKeystoreRestIT.java
  14. 4 0
      x-pack/qa/password-protected-keystore/src/test/resources/roles.yml
  15. 31 0
      x-pack/qa/password-protected-keystore/src/test/resources/ssl/README.asciidoc
  16. 20 0
      x-pack/qa/password-protected-keystore/src/test/resources/ssl/ca.crt
  17. 30 0
      x-pack/qa/password-protected-keystore/src/test/resources/ssl/ca.key
  18. 22 0
      x-pack/qa/password-protected-keystore/src/test/resources/ssl/transport.crt
  19. 30 0
      x-pack/qa/password-protected-keystore/src/test/resources/ssl/transport.key

+ 8 - 0
build.gradle

@@ -405,6 +405,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) {

+ 5 - 0
buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchCluster.java

@@ -189,6 +189,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));

+ 30 - 5
buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java

@@ -145,6 +145,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;
@@ -156,6 +157,7 @@ public class ElasticsearchNode implements TestClusterConfiguration {
     private String httpPort = "0";
     private String transportPort = "0";
     private Path confPathData;
+    private String keystorePassword = "";
 
     ElasticsearchNode(String path, String name, Project project, ReaperService reaper, File workingDirBase) {
         this.path = path;
@@ -171,6 +173,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);
 
@@ -327,6 +330,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));
@@ -453,13 +461,17 @@ public class ElasticsearchNode implements TestClusterConfiguration {
             logToProcessStdout("installed plugins");
         }
 
+        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<String, File> entry : keystoreFiles.entrySet()) {
                 File file = entry.getValue();
@@ -467,7 +479,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());
             }
         }
 
@@ -670,6 +682,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();

+ 16 - 0
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);
+                }
             }
         }
     }

+ 2 - 0
buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/TestClusterConfiguration.java

@@ -67,6 +67,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);

+ 1 - 0
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

+ 11 - 26
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
     <<cluster-nodes>>.
-    
+
 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
-

+ 1 - 1
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

+ 8 - 4
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
     }
   }
 }

+ 21 - 1
rest-api-spec/src/main/resources/rest-api-spec/test/nodes.reload_secure_settings/10_basic.yml

@@ -1,8 +1,28 @@
 ---
-"node_reload_secure_settings test":
+"node_reload_secure_settings test wrong password":
+
+  - 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

+ 1 - 1
server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestReloadSecureSettingsAction.java

@@ -73,7 +73,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());
             }
         });

+ 52 - 0
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'
+}

+ 97 - 0
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<String, Object> map = entityAsMap(response);
+        assertThat(ObjectPath.eval("cluster_name", map), equalTo("integTest"));
+        assertThat(map.get("nodes"), instanceOf(Map.class));
+        final Map<String, Object> nodes = (Map<String, Object>) map.get("nodes");
+        assertThat(nodes.size(), equalTo(NUM_NODES));
+        for (Map.Entry<String, Object> entry : nodes.entrySet()) {
+            assertThat(entry.getValue(), instanceOf(Map.class));
+            final Map<String, Object> node = (Map<String, Object>) 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<String, Object> map = entityAsMap(response);
+        assertThat(ObjectPath.eval("cluster_name", map), equalTo("integTest"));
+        assertThat(map.get("nodes"), instanceOf(Map.class));
+        final Map<String, Object> nodes = (Map<String, Object>) map.get("nodes");
+        assertThat(nodes.size(), equalTo(NUM_NODES));
+        for (Map.Entry<String, Object> entry : nodes.entrySet()) {
+            assertThat(entry.getValue(), instanceOf(Map.class));
+            final Map<String, Object> node = (Map<String, Object>) 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<String, Object> map = entityAsMap(response);
+        assertThat(ObjectPath.eval("cluster_name", map), equalTo("integTest"));
+        assertThat(map.get("nodes"), instanceOf(Map.class));
+        final Map<String, Object> nodes = (Map<String, Object>) map.get("nodes");
+        assertThat(nodes.size(), equalTo(NUM_NODES));
+        for (Map.Entry<String, Object> entry : nodes.entrySet()) {
+            assertThat(entry.getValue(), instanceOf(Map.class));
+            final Map<String, Object> node = (Map<String, Object>) 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();
+    }
+}

+ 4 - 0
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: []

+ 31 - 0
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
+-----------------------------------------------------------------------------------------------------------
+

+ 20 - 0
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-----

+ 30 - 0
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-----

+ 22 - 0
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-----

+ 30 - 0
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-----