Skip to content

Commit b257da1

Browse files
Auto configure TLS for new nodes of new clusters (#77231)
This commit introduces TLS auto-configuration for elasticsearch nodes, during the first startup. A number of heuristics are performed in order to determine if the node should get TLS auto-configuration which can also be explicitly disallowed with the use of xpack.security.autoconfiguration.enabled setting. This affects archive installations and docker. Packaged installations are handled in #75144 and #75704 . Co-authored-by: Ioannis Kakavas <ioannis@elastic.co>
1 parent 62d2df4 commit b257da1

31 files changed

Lines changed: 1394 additions & 592 deletions

distribution/src/bin/elasticsearch

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616
source "`dirname "$0"`"/elasticsearch-env
1717

1818
CHECK_KEYSTORE=true
19+
ATTEMPT_SECURITY_AUTO_CONFIG=true
1920
DAEMONIZE=false
2021
for option in "$@"; do
2122
case "$option" in
2223
-h|--help|-V|--version)
2324
CHECK_KEYSTORE=false
25+
ATTEMPT_SECURITY_AUTO_CONFIG=false
2426
;;
2527
-d|--daemonize)
2628
DAEMONIZE=true
@@ -45,6 +47,27 @@ then
4547
fi
4648
fi
4749

50+
if [[ $ATTEMPT_SECURITY_AUTO_CONFIG = true ]]; then
51+
# It is possible that an auto-conf failure prevents the node from starting, but this is only the exceptional case (exit code 1).
52+
# Most likely an auto-conf failure will leave the configuration untouched (exit codes 73, 78 and 80), optionally printing a message
53+
# if the error is uncommon or unexpected, but it should otherwise let the node to start as usual.
54+
# It is passed in all the command line options in order to read the node settings ones (-E), while the other parameters are ignored
55+
# (a small caveat is that it also inspects the -v option in order to provide more information on how auto config went)
56+
if ES_MAIN_CLASS=org.elasticsearch.xpack.security.cli.ConfigInitialNode \
57+
ES_ADDITIONAL_SOURCES="x-pack-env;x-pack-security-env" \
58+
ES_ADDITIONAL_CLASSPATH_DIRECTORIES=lib/tools/security-cli \
59+
"`dirname "$0"`"/elasticsearch-cli "$@" <<<"$KEYSTORE_PASSWORD"; then
60+
:
61+
else
62+
retval=$?
63+
# these exit codes cover the cases where auto-conf cannot run but the node should NOT be prevented from starting as usual
64+
# eg the node is restarted, is already configured in an incompatible way, or the file system permissions do not allow it
65+
if [[ $retval -ne 80 ]] && [[ $retval -ne 73 ]] && [[ $retval -ne 78 ]]; then
66+
exit $retval
67+
fi
68+
fi
69+
fi
70+
4871
# The JVM options parser produces the final JVM options to start Elasticsearch.
4972
# It does this by incorporating JVM options in the following way:
5073
# - first, system JVM options are applied (these are hardcoded options in the

distribution/src/bin/elasticsearch-env

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,22 +119,35 @@ if [[ "$ES_DISTRIBUTION_TYPE" == "docker" ]]; then
119119

120120
declare -a es_arg_array
121121

122+
containsElement () {
123+
local e match="$1"
124+
shift
125+
for e; do [[ "$e" == "$match" ]] && return 0; done
126+
return 1
127+
}
128+
122129
# Elasticsearch settings need to either:
123130
# a. have at least two dot separated lower case words, e.g. `cluster.name`, or
124131
while IFS='=' read -r envvar_key envvar_value; do
132+
es_opt=""
125133
if [[ -n "$envvar_value" ]]; then
126134
es_opt="-E${envvar_key}=${envvar_value}"
135+
fi
136+
if [[ ! -z "${es_opt}" ]] && ! containsElement "${es_opt}" "$@" ; then
127137
es_arg_array+=("${es_opt}")
128138
fi
129139
done <<< "$(env | grep -E '^[-a-z0-9_]+(\.[-a-z0-9_]+)+=')"
130140

131141
# b. be upper cased with underscore separators and prefixed with `ES_SETTING_`, e.g. `ES_SETTING_CLUSTER_NAME`.
132142
# Underscores in setting names are escaped by writing them as a double-underscore e.g. "__"
133143
while IFS='=' read -r envvar_key envvar_value; do
144+
es_opt=""
134145
if [[ -n "$envvar_value" ]]; then
135146
# The long-hand sed `y` command works in any sed variant.
136147
envvar_key="$(echo "$envvar_key" | sed -e 's/^ES_SETTING_//; s/_/./g ; s/\.\./_/g; y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' )"
137148
es_opt="-E${envvar_key}=${envvar_value}"
149+
fi
150+
if [[ ! -z "${es_opt}" ]] && ! containsElement "${es_opt}" "$@" ; then
138151
es_arg_array+=("${es_opt}")
139152
fi
140153
done <<< "$(env | grep -E '^ES_SETTING(_{1,2}[A-Z]+)+=')"

distribution/src/bin/elasticsearch.bat

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ setlocal enableextensions
55

66
SET params='%*'
77
SET checkpassword=Y
8+
SET attemptautoconfig=Y
89

910
:loop
1011
FOR /F "usebackq tokens=1* delims= " %%A IN (!params!) DO (
@@ -21,16 +22,20 @@ FOR /F "usebackq tokens=1* delims= " %%A IN (!params!) DO (
2122

2223
IF "!current!" == "-h" (
2324
SET checkpassword=N
25+
SET attemptautoconfig=N
2426
)
2527
IF "!current!" == "--help" (
2628
SET checkpassword=N
29+
SET attemptautoconfig=N
2730
)
2831

2932
IF "!current!" == "-V" (
3033
SET checkpassword=N
34+
SET attemptautoconfig=N
3135
)
3236
IF "!current!" == "--version" (
3337
SET checkpassword=N
38+
SET attemptautoconfig=N
3439
)
3540

3641
IF "!silent!" == "Y" (
@@ -68,6 +73,23 @@ IF "%checkpassword%"=="Y" (
6873
)
6974
)
7075

76+
IF "%attemptautoconfig%"=="Y" (
77+
ECHO.!KEYSTORE_PASSWORD!| %JAVA% %ES_JAVA_OPTS% ^
78+
-Des.path.home="%ES_HOME%" ^
79+
-Des.path.conf="%ES_PATH_CONF%" ^
80+
-Des.distribution.flavor="%ES_DISTRIBUTION_FLAVOR%" ^
81+
-Des.distribution.type="%ES_DISTRIBUTION_TYPE%" ^
82+
-cp "!ES_CLASSPATH!;!ES_HOME!/lib/tools/security-cli/*;!ES_HOME!/modules/x-pack-core/*;!ES_HOME!/modules/x-pack-security/*" "org.elasticsearch.xpack.security.cli.ConfigInitialNode" !newparams!
83+
SET SHOULDEXIT=Y
84+
IF !ERRORLEVEL! EQU 0 SET SHOULDEXIT=N
85+
IF !ERRORLEVEL! EQU 73 SET SHOULDEXIT=N
86+
IF !ERRORLEVEL! EQU 78 SET SHOULDEXIT=N
87+
IF !ERRORLEVEL! EQU 80 SET SHOULDEXIT=N
88+
IF "!SHOULDEXIT!"=="Y" (
89+
exit /b !ERRORLEVEL!
90+
)
91+
)
92+
7193
if not defined ES_TMPDIR (
7294
for /f "tokens=* usebackq" %%a in (`CALL %JAVA% -cp "!ES_CLASSPATH!" "org.elasticsearch.tools.launchers.TempDirectory"`) do set ES_TMPDIR=%%a
7395
)

docs/changelog/77231.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
pr: 77231
2+
summary: Auto configure TLS for new nodes of new clusters
3+
area: Security
4+
type: feature
5+
issues:
6+
- 75144
7+
- 75704

libs/cli/src/main/java/org/elasticsearch/cli/ExitCodes.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
* POSIX exit codes.
1313
*/
1414
public class ExitCodes {
15+
// please be extra careful when changing these as the values might be used in scripts,
16+
// usages of which are not tracked by the IDE
1517
public static final int OK = 0;
16-
public static final int NOOP = 63; // nothing to do
1718
public static final int USAGE = 64; // command line usage error
1819
public static final int DATA_ERROR = 65; // data format error
1920
public static final int NO_INPUT = 66; // cannot open input
@@ -27,6 +28,7 @@ public class ExitCodes {
2728
public static final int PROTOCOL = 76; // remote error in protocol
2829
public static final int NOPERM = 77; // permission denied
2930
public static final int CONFIG = 78; // configuration error
31+
public static final int NOOP = 80; // nothing to do
3032

3133
private ExitCodes() { /* no instance, just constants */ }
3234
}

qa/os/src/test/java/org/elasticsearch/packaging/test/ArchiveGenerateInitialCredentialsTests.java

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
package org.elasticsearch.packaging.test;
1010

11-
import org.apache.http.client.fluent.Request;
1211
import org.elasticsearch.packaging.util.Distribution;
1312
import org.elasticsearch.packaging.util.FileUtils;
1413
import org.elasticsearch.packaging.util.ServerUtils;
@@ -45,15 +44,10 @@ public static void filterDistros() {
4544
}
4645

4746
public void test10Install() throws Exception {
48-
// security config tool would run as administrator and change the owner of the config file, which is elasticsearch
49-
// We can re-enable this when #77231 is merged, but the rest of the tests in class are also currently muted on windows
50-
assumeTrue("Don't run on windows", distribution.platform != Distribution.Platform.WINDOWS);
5147
installation = installArchive(sh, distribution());
5248
// Enable security for these tests only where it is necessary, until we can enable it for all
53-
// TODO: Remove this when https://github.com/elastic/elasticsearch/pull/77231 is merged
5449
ServerUtils.enableSecurityFeatures(installation);
5550
verifyArchiveInstallation(installation, distribution());
56-
installation.executables().securityConfigTool.run("");
5751
}
5852

5953
public void test20NoAutoGenerationWhenAutoConfigurationDisabled() throws Exception {
@@ -88,12 +82,7 @@ public void test40VerifyAutogeneratedCredentials() throws Exception {
8882
assertThat(parseElasticPassword(result.stdout), notNullValue());
8983
assertThat(parseKibanaToken(result.stdout), notNullValue());
9084
assertThat(parseFingerprint(result.stdout), notNullValue());
91-
String response = ServerUtils.makeRequest(
92-
Request.Get("https://localhost:9200"),
93-
"elastic",
94-
parseElasticPassword(result.stdout),
95-
ServerUtils.getCaCert(installation.config)
96-
);
85+
String response = makeRequestAsElastic("https://localhost:9200", parseElasticPassword(result.stdout));
9786
assertThat(response, containsString("You Know, for Search"));
9887
}
9988

0 commit comments

Comments
 (0)