mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-16 18:04:52 +00:00
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.
This commit is contained in:
parent
862799956c
commit
7a8a66d9ae
@ -408,6 +408,14 @@ class Run extends DefaultTask {
|
|||||||
public void setDataDir(String dataDirStr) {
|
public void setDataDir(String dataDirStr) {
|
||||||
project.project(':distribution').run.dataDir = 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) {
|
task run(type: Run) {
|
||||||
|
@ -174,6 +174,11 @@ public class ElasticsearchCluster implements TestClusterConfiguration, Named {
|
|||||||
nodes.all(each -> each.keystore(key, valueSupplier));
|
nodes.all(each -> each.keystore(key, valueSupplier));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keystorePassword(String password) {
|
||||||
|
nodes.all(each -> each.keystorePassword(password));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cliSetup(String binTool, CharSequence... args) {
|
public void cliSetup(String binTool, CharSequence... args) {
|
||||||
nodes.all(each -> each.cliSetup(binTool, args));
|
nodes.all(each -> each.cliSetup(binTool, args));
|
||||||
|
@ -143,6 +143,7 @@ public class ElasticsearchNode implements TestClusterConfiguration {
|
|||||||
private final Path httpPortsFile;
|
private final Path httpPortsFile;
|
||||||
private final Path esStdoutFile;
|
private final Path esStdoutFile;
|
||||||
private final Path esStderrFile;
|
private final Path esStderrFile;
|
||||||
|
private final Path esStdinFile;
|
||||||
private final Path tmpDir;
|
private final Path tmpDir;
|
||||||
|
|
||||||
private int currentDistro = 0;
|
private int currentDistro = 0;
|
||||||
@ -154,6 +155,7 @@ public class ElasticsearchNode implements TestClusterConfiguration {
|
|||||||
private String httpPort = "0";
|
private String httpPort = "0";
|
||||||
private String transportPort = "0";
|
private String transportPort = "0";
|
||||||
private Path confPathData;
|
private Path confPathData;
|
||||||
|
private String keystorePassword = "";
|
||||||
|
|
||||||
ElasticsearchNode(String name, Project project, ReaperService reaper, File workingDirBase, Jdk bwcJdk) {
|
ElasticsearchNode(String name, Project project, ReaperService reaper, File workingDirBase, Jdk bwcJdk) {
|
||||||
this.path = project.getPath();
|
this.path = project.getPath();
|
||||||
@ -170,6 +172,7 @@ public class ElasticsearchNode implements TestClusterConfiguration {
|
|||||||
httpPortsFile = confPathLogs.resolve("http.ports");
|
httpPortsFile = confPathLogs.resolve("http.ports");
|
||||||
esStdoutFile = confPathLogs.resolve("es.stdout.log");
|
esStdoutFile = confPathLogs.resolve("es.stdout.log");
|
||||||
esStderrFile = confPathLogs.resolve("es.stderr.log");
|
esStderrFile = confPathLogs.resolve("es.stderr.log");
|
||||||
|
esStdinFile = workingDir.resolve("es.stdin");
|
||||||
tmpDir = workingDir.resolve("tmp");
|
tmpDir = workingDir.resolve("tmp");
|
||||||
waitConditions.put("ports files", this::checkPortsFilesExistWithDelay);
|
waitConditions.put("ports files", this::checkPortsFilesExistWithDelay);
|
||||||
|
|
||||||
@ -305,6 +308,11 @@ public class ElasticsearchNode implements TestClusterConfiguration {
|
|||||||
keystoreFiles.put(key, valueSupplier);
|
keystoreFiles.put(key, valueSupplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keystorePassword(String password) {
|
||||||
|
keystorePassword = password;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cliSetup(String binTool, CharSequence... args) {
|
public void cliSetup(String binTool, CharSequence... args) {
|
||||||
cliSetup.add(new CliEntry(binTool, 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) {
|
if (keystoreSettings.isEmpty() == false || keystoreFiles.isEmpty() == false) {
|
||||||
logToProcessStdout("Adding " + keystoreSettings.size() + " keystore settings and " + keystoreFiles.size() + " keystore files");
|
logToProcessStdout("Adding " + keystoreSettings.size() + " keystore settings and " + keystoreFiles.size() + " keystore files");
|
||||||
runElasticsearchBinScript("elasticsearch-keystore", "create");
|
|
||||||
|
|
||||||
keystoreSettings.forEach(
|
keystoreSettings.forEach((key, value) -> runKeystoreCommandWithPassword(keystorePassword, value.toString(), "add", "-x", key));
|
||||||
(key, value) -> runElasticsearchBinScriptWithInput(value.toString(), "elasticsearch-keystore", "add", "-x", key)
|
|
||||||
);
|
|
||||||
|
|
||||||
for (Map.Entry<String, File> entry : keystoreFiles.entrySet()) {
|
for (Map.Entry<String, File> entry : keystoreFiles.entrySet()) {
|
||||||
File file = entry.getValue();
|
File file = entry.getValue();
|
||||||
@ -453,7 +465,7 @@ public class ElasticsearchNode implements TestClusterConfiguration {
|
|||||||
if (file.exists() == false) {
|
if (file.exists() == false) {
|
||||||
throw new TestClustersException("supplied keystore file " + file + " does not exist, require for " + this);
|
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) {
|
private void runElasticsearchBinScript(String tool, CharSequence... args) {
|
||||||
runElasticsearchBinScriptWithInput("", tool, args);
|
runElasticsearchBinScriptWithInput("", tool, args);
|
||||||
}
|
}
|
||||||
@ -746,6 +763,14 @@ public class ElasticsearchNode implements TestClusterConfiguration {
|
|||||||
processBuilder.redirectError(ProcessBuilder.Redirect.appendTo(esStderrFile.toFile()));
|
processBuilder.redirectError(ProcessBuilder.Redirect.appendTo(esStderrFile.toFile()));
|
||||||
processBuilder.redirectOutput(ProcessBuilder.Redirect.appendTo(esStdoutFile.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);
|
LOGGER.info("Running `{}` in `{}` for {} env: {}", command, workingDir, this, environment);
|
||||||
try {
|
try {
|
||||||
esProcess = processBuilder.start();
|
esProcess = processBuilder.start();
|
||||||
|
@ -28,6 +28,8 @@ public class RunTask extends DefaultTestClustersTask {
|
|||||||
|
|
||||||
private Path dataDir = null;
|
private Path dataDir = null;
|
||||||
|
|
||||||
|
private String keystorePassword = "";
|
||||||
|
|
||||||
@Option(option = "debug-jvm", description = "Enable debugging configuration, to allow attaching a debugger to elasticsearch.")
|
@Option(option = "debug-jvm", description = "Enable debugging configuration, to allow attaching a debugger to elasticsearch.")
|
||||||
public void setDebug(boolean enabled) {
|
public void setDebug(boolean enabled) {
|
||||||
this.debug = enabled;
|
this.debug = enabled;
|
||||||
@ -43,6 +45,17 @@ public class RunTask extends DefaultTestClustersTask {
|
|||||||
dataDir = Paths.get(dataDirStr).toAbsolutePath();
|
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
|
@Input
|
||||||
@Optional
|
@Optional
|
||||||
public String getDataDir() {
|
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);
|
node.jvmArgs("-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=" + debugPort);
|
||||||
debugPort += 1;
|
debugPort += 1;
|
||||||
}
|
}
|
||||||
|
if (keystorePassword.length() > 0) {
|
||||||
|
node.keystorePassword(keystorePassword);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,8 @@ public interface TestClusterConfiguration {
|
|||||||
|
|
||||||
void keystore(String key, FileSupplier valueSupplier);
|
void keystore(String key, FileSupplier valueSupplier);
|
||||||
|
|
||||||
|
void keystorePassword(String password);
|
||||||
|
|
||||||
void cliSetup(String binTool, CharSequence... args);
|
void cliSetup(String binTool, CharSequence... args);
|
||||||
|
|
||||||
void setting(String key, String value);
|
void setting(String key, String value);
|
||||||
|
@ -58,6 +58,7 @@ testClusters.integTest {
|
|||||||
}
|
}
|
||||||
setting 'xpack.autoscaling.enabled', 'true'
|
setting 'xpack.autoscaling.enabled', 'true'
|
||||||
setting 'xpack.eql.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
|
// enable regexes in painless so our tests don't complain about example snippets that use them
|
||||||
|
@ -36,7 +36,7 @@ the node-specific {es} keystore password.
|
|||||||
(Optional, string) The names of particular nodes in the cluster to target.
|
(Optional, string) The names of particular nodes in the cluster to target.
|
||||||
For example, `nodeId1,nodeId2`. For node selection options, see
|
For example, `nodeId1,nodeId2`. For node selection options, see
|
||||||
<<cluster-nodes>>.
|
<<cluster-nodes>>.
|
||||||
|
|
||||||
NOTE: {es} requires consistent secure settings across the cluster nodes, but
|
NOTE: {es} requires consistent secure settings across the cluster nodes, but
|
||||||
this consistency is not enforced. Hence, reloading specific nodes is not
|
this consistency is not enforced. Hence, reloading specific nodes is not
|
||||||
standard. It is justifiable only when retrying failed reload operations.
|
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]]
|
[[cluster-nodes-reload-secure-settings-api-request-body]]
|
||||||
==== {api-request-body-title}
|
==== {api-request-body-title}
|
||||||
|
|
||||||
`reload_secure_settings`::
|
`secure_settings_password`::
|
||||||
(Optional, string) The password for the {es} keystore.
|
(Optional, string) The password for the {es} keystore.
|
||||||
|
|
||||||
[[cluster-nodes-reload-secure-settings-api-example]]
|
[[cluster-nodes-reload-secure-settings-api-example]]
|
||||||
==== {api-examples-title}
|
==== {api-examples-title}
|
||||||
|
|
||||||
|
The following examples assume a common password for the {es} keystore on every
|
||||||
|
node of the cluster:
|
||||||
|
|
||||||
[source,console]
|
[source,console]
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
POST _nodes/reload_secure_settings
|
POST _nodes/reload_secure_settings
|
||||||
|
{
|
||||||
|
"secure_settings_password":"s3cr3t"
|
||||||
|
}
|
||||||
POST _nodes/nodeId1,nodeId2/reload_secure_settings
|
POST _nodes/nodeId1,nodeId2/reload_secure_settings
|
||||||
|
{
|
||||||
|
"secure_settings_password":"s3cr3t"
|
||||||
|
}
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
// TEST[setup:node]
|
// TEST[setup:node]
|
||||||
// TEST[s/nodeId1,nodeId2/*/]
|
// 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/"my_cluster"/$body.cluster_name/]
|
||||||
// TESTRESPONSE[s/"pQHNt5rXTTWNvUgOrdynKg"/\$node_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
|
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ using the `bin/elasticsearch-keystore add` command, call:
|
|||||||
----
|
----
|
||||||
POST _nodes/reload_secure_settings
|
POST _nodes/reload_secure_settings
|
||||||
{
|
{
|
||||||
"reload_secure_settings": "s3cr3t" <1>
|
"secure_settings_password": "s3cr3t" <1>
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
// NOTCONSOLE
|
// NOTCONSOLE
|
||||||
|
@ -27,11 +27,15 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"params":{
|
"params": {
|
||||||
"timeout":{
|
"timeout": {
|
||||||
"type":"time",
|
"type": "time",
|
||||||
"description":"Explicit operation timeout"
|
"description": "Explicit operation timeout"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"description": "An object containing the password for the elasticsearch keystore",
|
||||||
|
"required": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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:
|
- do:
|
||||||
nodes.reload_secure_settings: {}
|
nodes.reload_secure_settings: {}
|
||||||
|
|
||||||
|
- set:
|
||||||
|
nodes._arbitrary_key_: node_id
|
||||||
|
|
||||||
- is_true: nodes
|
- is_true: nodes
|
||||||
- is_true: cluster_name
|
- is_true: cluster_name
|
||||||
|
- is_false: nodes.$node_id.reload_exception
|
||||||
|
@ -75,7 +75,7 @@ public final class RestReloadSecureSettingsAction extends BaseRestHandler {
|
|||||||
.setNodesIds(nodesIds);
|
.setNodesIds(nodesIds);
|
||||||
request.withContentOrSourceParamParserOrNull(parser -> {
|
request.withContentOrSourceParamParserOrNull(parser -> {
|
||||||
if (parser != null) {
|
if (parser != null) {
|
||||||
final NodesReloadSecureSettingsRequest nodesRequest = nodesRequestBuilder.request();
|
final NodesReloadSecureSettingsRequest nodesRequest = PARSER.parse(parser, null);
|
||||||
nodesRequestBuilder.setSecureStorePassword(nodesRequest.getSecureSettingsPassword());
|
nodesRequestBuilder.setSecureStorePassword(nodesRequest.getSecureSettingsPassword());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
52
x-pack/qa/password-protected-keystore/build.gradle
Normal file
52
x-pack/qa/password-protected-keystore/build.gradle
Normal file
@ -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'
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
# user needs to call cluster:admin/nodes/reload_secure_settings
|
||||||
|
user_role:
|
||||||
|
cluster: [ALL]
|
||||||
|
indices: []
|
@ -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
|
||||||
|
-----------------------------------------------------------------------------------------------------------
|
||||||
|
|
Binary file not shown.
@ -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-----
|
Binary file not shown.
@ -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-----
|
Loading…
x
Reference in New Issue
Block a user