Skip to content

Commit a2dbd83

Browse files
authored
Allow Integ Tests to run in a FIPS-140 JVM (#31989)
* Complete changes for running IT in a fips JVM - Mute :x-pack:qa:sql:security:ssl:integTest as it cannot run in FIPS 140 JVM until the SQL CLI supports key/cert. - Set default JVM keystore/truststore password in top level build script for all integTest tasks in a FIPS 140 JVM - Changed top level x-pack build script to use keys and certificates for trust/key material when spinning up clusters for IT
1 parent 1777507 commit a2dbd83

File tree

20 files changed

+223
-402
lines changed

20 files changed

+223
-402
lines changed

buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ class BuildPlugin implements Plugin<Project> {
131131
runtimeJavaVersionEnum = JavaVersion.toVersion(findJavaSpecificationVersion(project, runtimeJavaHome))
132132
}
133133

134+
String inFipsJvmScript = 'print(java.security.Security.getProviders()[0].name.toLowerCase().contains("fips"));'
135+
boolean inFipsJvm = Boolean.parseBoolean(runJavascript(project, runtimeJavaHome, inFipsJvmScript))
136+
134137
// Build debugging info
135138
println '======================================='
136139
println 'Elasticsearch Build Hamster says Hello!'
@@ -202,6 +205,7 @@ class BuildPlugin implements Plugin<Project> {
202205
project.rootProject.ext.buildChecksDone = true
203206
project.rootProject.ext.minimumCompilerVersion = minimumCompilerVersion
204207
project.rootProject.ext.minimumRuntimeVersion = minimumRuntimeVersion
208+
project.rootProject.ext.inFipsJvm = inFipsJvm
205209
}
206210

207211
project.targetCompatibility = project.rootProject.ext.minimumRuntimeVersion
@@ -213,6 +217,7 @@ class BuildPlugin implements Plugin<Project> {
213217
project.ext.compilerJavaVersion = project.rootProject.ext.compilerJavaVersion
214218
project.ext.runtimeJavaVersion = project.rootProject.ext.runtimeJavaVersion
215219
project.ext.javaVersions = project.rootProject.ext.javaVersions
220+
project.ext.inFipsJvm = project.rootProject.ext.inFipsJvm
216221
}
217222

218223
private static String findCompilerJavaHome() {
@@ -770,7 +775,11 @@ class BuildPlugin implements Plugin<Project> {
770775
systemProperty property.getKey(), property.getValue()
771776
}
772777
}
773-
778+
// Set the system keystore/truststore password if we're running tests in a FIPS-140 JVM
779+
if (project.inFipsJvm) {
780+
systemProperty 'javax.net.ssl.trustStorePassword', 'password'
781+
systemProperty 'javax.net.ssl.keyStorePassword', 'password'
782+
}
774783
boolean assertionsEnabled = Boolean.parseBoolean(System.getProperty('tests.asserts', 'true'))
775784
enableSystemAssertions assertionsEnabled
776785
enableAssertions assertionsEnabled

plugins/discovery-gce/build.gradle

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -22,36 +22,6 @@ dependencies {
2222
compile "commons-codec:commons-codec:${versions.commonscodec}"
2323
}
2424

25-
26-
// needed to be consistent with ssl host checking
27-
String host = InetAddress.getLoopbackAddress().getHostAddress();
28-
29-
// location of keystore and files to generate it
30-
File keystore = new File(project.buildDir, 'keystore/test-node.jks')
31-
32-
// generate the keystore
33-
task createKey(type: LoggedExec) {
34-
doFirst {
35-
project.delete(keystore.parentFile)
36-
keystore.parentFile.mkdirs()
37-
}
38-
executable = new File(project.runtimeJavaHome, 'bin/keytool')
39-
standardInput = new ByteArrayInputStream('FirstName LastName\nUnit\nOrganization\nCity\nState\nNL\nyes\n\n'.getBytes('UTF-8'))
40-
args '-genkey',
41-
'-alias', 'test-node',
42-
'-keystore', keystore,
43-
'-keyalg', 'RSA',
44-
'-keysize', '2048',
45-
'-validity', '712',
46-
'-dname', 'CN=' + host,
47-
'-keypass', 'keypass',
48-
'-storepass', 'keypass'
49-
}
50-
51-
// add keystore to test classpath: it expects it there
52-
sourceSets.test.resources.srcDir(keystore.parentFile)
53-
processTestResources.dependsOn(createKey)
54-
5525
dependencyLicenses {
5626
mapping from: /google-.*/, to: 'google'
5727
}

server/src/test/java/org/elasticsearch/action/admin/ReloadSecureSettingsIT.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,14 @@ public void onResponse(NodesReloadSecureSettingsResponse nodesReloadResponse) {
205205
assertThat(nodesMap.size(), equalTo(cluster().size()));
206206
for (final NodesReloadSecureSettingsResponse.NodeResponse nodeResponse : nodesReloadResponse.getNodes()) {
207207
assertThat(nodeResponse.reloadException(), notNullValue());
208-
assertThat(nodeResponse.reloadException(), instanceOf(IOException.class));
208+
// Running in a JVM with a BouncyCastle FIPS Security Provider, decrypting the Keystore with the wrong
209+
// password returns a SecurityException if the DataInputStream can't be fully consumed
210+
if (inFipsJvm()) {
211+
assertThat(nodeResponse.reloadException(), instanceOf(SecurityException.class));
212+
} else {
213+
assertThat(nodeResponse.reloadException(), instanceOf(IOException.class));
214+
}
215+
209216
}
210217
} catch (final AssertionError e) {
211218
reloadSettingsError.set(e);

test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@
176176
import java.net.URL;
177177
import java.nio.file.Files;
178178
import java.nio.file.Path;
179+
import java.security.Security;
179180
import java.util.ArrayList;
180181
import java.util.Arrays;
181182
import java.util.Collection;
@@ -2364,4 +2365,7 @@ protected void assertSeqNos() throws Exception {
23642365
});
23652366
}
23662367

2368+
public static boolean inFipsJvm() {
2369+
return Security.getProviders()[0].getName().toLowerCase(Locale.ROOT).contains("fips");
2370+
}
23672371
}

x-pack/plugin/build.gradle

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -104,39 +104,28 @@ integTestRunner {
104104
systemProperty 'tests.rest.blacklist', blacklist.join(',')
105105
}
106106

107-
// location of generated keystores and certificates
107+
// location for keys and certificates
108108
File keystoreDir = new File(project.buildDir, 'keystore')
109-
110-
// Generate the node's keystore
111-
File nodeKeystore = new File(keystoreDir, 'test-node.jks')
112-
task createNodeKeyStore(type: LoggedExec) {
113-
doFirst {
114-
if (nodeKeystore.parentFile.exists() == false) {
115-
nodeKeystore.parentFile.mkdirs()
116-
}
117-
if (nodeKeystore.exists()) {
118-
delete nodeKeystore
109+
File nodeKey = file("$keystoreDir/testnode.pem")
110+
File nodeCert = file("$keystoreDir/testnode.crt")
111+
112+
// Add key and certs to test classpath: it expects them there
113+
// User cert and key PEM files instead of a JKS Keystore for the cluster's trust material so that
114+
// it can run in a FIPS 140 JVM
115+
// TODO: Remove all existing uses of cross project file references when the new approach for referencing static files is available
116+
// https://github.com/elastic/elasticsearch/pull/32201
117+
task copyKeyCerts(type: Copy) {
118+
from(project(':x-pack:plugin:core').file('src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/')) {
119+
include 'testnode.crt', 'testnode.pem'
119120
}
120-
}
121-
executable = new File(project.runtimeJavaHome, 'bin/keytool')
122-
standardInput = new ByteArrayInputStream('FirstName LastName\nUnit\nOrganization\nCity\nState\nNL\nyes\n\n'.getBytes('UTF-8'))
123-
args '-genkey',
124-
'-alias', 'test-node',
125-
'-keystore', nodeKeystore,
126-
'-keyalg', 'RSA',
127-
'-keysize', '2048',
128-
'-validity', '712',
129-
'-dname', 'CN=smoke-test-plugins-ssl',
130-
'-keypass', 'keypass',
131-
'-storepass', 'keypass'
121+
into keystoreDir
132122
}
133-
134123
// Add keystores to test classpath: it expects it there
135124
sourceSets.test.resources.srcDir(keystoreDir)
136-
processTestResources.dependsOn(createNodeKeyStore)
125+
processTestResources.dependsOn(copyKeyCerts)
137126

138127
integTestCluster {
139-
dependsOn createNodeKeyStore
128+
dependsOn copyKeyCerts
140129
setting 'xpack.ml.enabled', 'true'
141130
setting 'xpack.security.enabled', 'true'
142131
setting 'logger.org.elasticsearch.xpack.ml.datafeed', 'TRACE'
@@ -145,17 +134,19 @@ integTestCluster {
145134
setting 'xpack.monitoring.exporters._local.enabled', 'false'
146135
setting 'xpack.security.authc.token.enabled', 'true'
147136
setting 'xpack.security.transport.ssl.enabled', 'true'
148-
setting 'xpack.security.transport.ssl.keystore.path', nodeKeystore.name
137+
setting 'xpack.security.transport.ssl.key', nodeKey.name
138+
setting 'xpack.security.transport.ssl.certificate', nodeCert.name
149139
setting 'xpack.security.transport.ssl.verification_mode', 'certificate'
150140
setting 'xpack.security.audit.enabled', 'true'
151141
setting 'xpack.license.self_generated.type', 'trial'
152142
keystoreSetting 'bootstrap.password', 'x-pack-test-password'
153-
keystoreSetting 'xpack.security.transport.ssl.keystore.secure_password', 'keypass'
143+
keystoreSetting 'xpack.security.transport.ssl.secure_key_passphrase', 'testnode'
154144
distribution = 'zip' // this is important since we use the reindex module in ML
155145

156146
setupCommand 'setupTestUser', 'bin/elasticsearch-users', 'useradd', 'x_pack_rest_user', '-p', 'x-pack-test-password', '-r', 'superuser'
157147

158-
extraConfigFile nodeKeystore.name, nodeKeystore
148+
extraConfigFile nodeKey.name, nodeKey
149+
extraConfigFile nodeCert.name, nodeCert
159150

160151
waitCondition = { NodeInfo node, AntBuilder ant ->
161152
File tmpFile = new File(node.cwd, 'wait.success')

x-pack/plugin/src/test/resources/rest-api-spec/test/ssl/10_basic.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
xpack.ssl.certificates: {}
55

66
- length: { $body: 1 }
7-
- match: { $body.0.path: "test-node.jks" }
8-
- match: { $body.0.format: "jks" }
9-
- match: { $body.0.alias: "test-node" }
7+
- match: { $body.0.path: "testnode.crt" }
8+
- match: { $body.0.format: "PEM" }
109
- match: { $body.0.has_private_key: true }

x-pack/qa/full-cluster-restart/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ subprojects {
125125

126126
String output = "${buildDir}/generated-resources/${project.name}"
127127
task copyTestNodeKeystore(type: Copy) {
128-
from project(xpackModule('core'))
129-
.file('src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks')
128+
from project(':x-pack:plugin:core')
129+
.file('src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks')
130130
into outputDir
131131
}
132132

x-pack/qa/ml-native-multi-node-tests/build.gradle

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,59 +18,45 @@ integTestRunner {
1818
systemProperty 'es.set.netty.runtime.available.processors', 'false'
1919
}
2020

21-
// location of generated keystores and certificates
21+
// location for keys and certificates
2222
File keystoreDir = new File(project.buildDir, 'keystore')
23-
24-
// Generate the node's keystore
25-
File nodeKeystore = new File(keystoreDir, 'test-node.jks')
26-
task createNodeKeyStore(type: LoggedExec) {
27-
doFirst {
28-
if (nodeKeystore.parentFile.exists() == false) {
29-
nodeKeystore.parentFile.mkdirs()
30-
}
31-
if (nodeKeystore.exists()) {
32-
delete nodeKeystore
33-
}
23+
File nodeKey = file("$keystoreDir/testnode.pem")
24+
File nodeCert = file("$keystoreDir/testnode.crt")
25+
// Add key and certs to test classpath: it expects it there
26+
task copyKeyCerts(type: Copy) {
27+
from(project(':x-pack:plugin:core').file('src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/')) {
28+
include 'testnode.crt', 'testnode.pem'
3429
}
35-
executable = new File(project.runtimeJavaHome, 'bin/keytool')
36-
standardInput = new ByteArrayInputStream('FirstName LastName\nUnit\nOrganization\nCity\nState\nNL\nyes\n\n'.getBytes('UTF-8'))
37-
args '-genkey',
38-
'-alias', 'test-node',
39-
'-keystore', nodeKeystore,
40-
'-keyalg', 'RSA',
41-
'-keysize', '2048',
42-
'-validity', '712',
43-
'-dname', 'CN=smoke-test-plugins-ssl',
44-
'-keypass', 'keypass',
45-
'-storepass', 'keypass'
30+
into keystoreDir
4631
}
47-
48-
// Add keystores to test classpath: it expects it there
32+
// Add keys and cets to test classpath: it expects it there
4933
sourceSets.test.resources.srcDir(keystoreDir)
50-
processTestResources.dependsOn(createNodeKeyStore)
34+
processTestResources.dependsOn(copyKeyCerts)
5135

5236
integTestCluster {
53-
dependsOn createNodeKeyStore
37+
dependsOn copyKeyCerts
5438
setting 'xpack.security.enabled', 'true'
5539
setting 'xpack.ml.enabled', 'true'
5640
setting 'logger.org.elasticsearch.xpack.ml.datafeed', 'TRACE'
5741
setting 'xpack.monitoring.enabled', 'false'
5842
setting 'xpack.security.authc.token.enabled', 'true'
5943
setting 'xpack.security.transport.ssl.enabled', 'true'
60-
setting 'xpack.security.transport.ssl.keystore.path', nodeKeystore.name
44+
setting 'xpack.security.transport.ssl.key', nodeKey.name
45+
setting 'xpack.security.transport.ssl.certificate', nodeCert.name
6146
setting 'xpack.security.transport.ssl.verification_mode', 'certificate'
6247
setting 'xpack.security.audit.enabled', 'true'
6348
setting 'xpack.license.self_generated.type', 'trial'
6449

6550
keystoreSetting 'bootstrap.password', 'x-pack-test-password'
66-
keystoreSetting 'xpack.security.transport.ssl.keystore.secure_password', 'keypass'
51+
keystoreSetting 'xpack.security.transport.ssl.secure_key_passphrase', 'testnode'
6752

6853
numNodes = 3
6954

7055
setupCommand 'setupDummyUser',
7156
'bin/elasticsearch-users', 'useradd', 'x_pack_rest_user', '-p', 'x-pack-test-password', '-r', 'superuser'
7257

73-
extraConfigFile nodeKeystore.name, nodeKeystore
58+
extraConfigFile nodeKey.name, nodeKey
59+
extraConfigFile nodeCert.name, nodeCert
7460

7561
waitCondition = { node, ant ->
7662
File tmpFile = new File(node.cwd, 'wait.success')

x-pack/qa/ml-native-multi-node-tests/src/test/java/org/elasticsearch/xpack/ml/integration/MlNativeAutodetectIntegTestCase.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,11 @@ protected Collection<Class<? extends Plugin>> transportClientPlugins() {
124124

125125
@Override
126126
protected Settings externalClusterClientSettings() {
127-
Path keyStore;
127+
Path key;
128+
Path certificate;
128129
try {
129-
keyStore = PathUtils.get(getClass().getResource("/test-node.jks").toURI());
130+
key = PathUtils.get(getClass().getResource("/testnode.pem").toURI());
131+
certificate = PathUtils.get(getClass().getResource("/testnode.crt").toURI());
130132
} catch (URISyntaxException e) {
131133
throw new IllegalStateException("error trying to get keystore path", e);
132134
}
@@ -135,8 +137,9 @@ protected Settings externalClusterClientSettings() {
135137
builder.put(SecurityField.USER_SETTING.getKey(), "x_pack_rest_user:" + SecuritySettingsSourceField.TEST_PASSWORD_SECURE_STRING);
136138
builder.put(XPackSettings.MACHINE_LEARNING_ENABLED.getKey(), true);
137139
builder.put("xpack.security.transport.ssl.enabled", true);
138-
builder.put("xpack.security.transport.ssl.keystore.path", keyStore.toAbsolutePath().toString());
139-
builder.put("xpack.security.transport.ssl.keystore.password", "keypass");
140+
builder.put("xpack.security.transport.ssl.key", key.toAbsolutePath().toString());
141+
builder.put("xpack.security.transport.ssl.certificate", certificate.toAbsolutePath().toString());
142+
builder.put("xpack.security.transport.ssl.key_passphrase", "testnode");
140143
builder.put("xpack.security.transport.ssl.verification_mode", "certificate");
141144
return builder.build();
142145
}

x-pack/qa/rolling-upgrade/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ subprojects {
107107

108108
String output = "${buildDir}/generated-resources/${project.name}"
109109
task copyTestNodeKeystore(type: Copy) {
110-
from project(xpackModule('core'))
110+
from project(':x-pack:plugin:core')
111111
.file('src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks')
112112
into outputDir
113113
}

0 commit comments

Comments
 (0)