mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-04-24 23:27:25 -04:00
Ensure CI is run in FIPS 140 approved only mode (#64024)
We were depending on the BouncyCastle FIPS own mechanics to set itself in approved only mode since we run with the Security Manager enabled. The check during startup seems to happen before we set our restrictive SecurityManager though in org.elasticsearch.bootstrap.Elasticsearch , and this means that BCFIPS would not be in approved only mode, unless explicitly configured so. This commit sets the appropriate JVM property to explicitly set BCFIPS in approved only mode in CI and adds tests to ensure that we will be running with BCFIPS in approved only mode when we expect to. It also sets xpack.security.fips_mode.enabled to true for all test clusters used in fips mode and sets the distribution to the default one. It adds a password to the elasticsearch keystore for all test clusters that run in fips mode. Moreover, it changes a few unit tests where we would use bcrypt even in FIPS 140 mode. These would still pass since we are bundling our own bcrypt implementation, but are now changed to use FIPS 140 approved algorithms instead for better coverage. It also addresses a number of tests that would fail in approved only mode Mainly: Tests that use PBKDF2 with a password less than 112 bits (14char). We elected to change the passwords used everywhere to be at least 14 characters long instead of mandating the use of pbkdf2_stretch because both pbkdf2 and pbkdf2_stretch are supported and allowed in fips mode and it makes sense to test with both. We could possibly figure out the password algorithm used for each test and adjust password length accordingly only for pbkdf2 but there is little value in that. It's good practice to use strong passwords so if our docs and tests use longer passwords, then it's for the best. The approach is brittle as there is no guarantee that the next test that will be added won't use a short password, so we add some testing documentation too. This leaves us with a possible coverage gap since we do support passwords as short as 6 characters but we only test with > 14 chars but the validation itself was not tested even before. Tests can be added in a followup, outside of fips related context. Tests that use a PKCS12 keystore and were not already muted. Tests that depend on running test clusters with a basic license or using the OSS distribution as FIPS 140 support is not available in neither of these. Finally, it adds some information around FIPS 140 testing in our testing documentation reference so that developers can hopefully keep in mind fips 140 related intricacies when writing/changing docs.
This commit is contained in:
parent
6493e6575e
commit
bd873698bc
177 changed files with 1075 additions and 584 deletions
|
@ -204,13 +204,17 @@ def createAndSetWritable(Object... locations) {
|
|||
}
|
||||
}
|
||||
|
||||
tasks.register("copyKeystore", Sync) {
|
||||
tasks.register("copyNodeKeyMaterial", Sync) {
|
||||
from project(':x-pack:plugin:core')
|
||||
.file('src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks')
|
||||
.files(
|
||||
'src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem',
|
||||
'src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt'
|
||||
)
|
||||
into "${buildDir}/certs"
|
||||
doLast {
|
||||
file("${buildDir}/certs").setReadable(true, false)
|
||||
file("${buildDir}/certs/testnode.jks").setReadable(true, false)
|
||||
file("${buildDir}/certs/testnode.pem").setReadable(true, false)
|
||||
file("${buildDir}/certs/testnode.crt").setReadable(true, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,7 +234,7 @@ elasticsearch_distributions {
|
|||
|
||||
tasks.named("preProcessFixture").configure {
|
||||
dependsOn elasticsearch_distributions.docker_default, elasticsearch_distributions.docker_oss
|
||||
dependsOn "copyKeystore"
|
||||
dependsOn "copyNodeKeyMaterial"
|
||||
doLast {
|
||||
// tests expect to have an empty repo
|
||||
project.delete(
|
||||
|
@ -250,7 +254,10 @@ tasks.named("preProcessFixture").configure {
|
|||
|
||||
tasks.named("processTestResources").configure {
|
||||
from project(':x-pack:plugin:core')
|
||||
.file('src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks')
|
||||
.files(
|
||||
'src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem',
|
||||
'src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt'
|
||||
)
|
||||
}
|
||||
|
||||
tasks.register("integTest", Test) {
|
||||
|
|
|
@ -23,14 +23,17 @@ services:
|
|||
- xpack.security.audit.enabled=true
|
||||
- xpack.security.authc.realms.file.file1.order=0
|
||||
- xpack.security.authc.realms.native.native1.order=1
|
||||
- xpack.security.transport.ssl.keystore.path=/usr/share/elasticsearch/config/testnode.jks
|
||||
- xpack.security.http.ssl.keystore.path=/usr/share/elasticsearch/config/testnode.jks
|
||||
- xpack.security.transport.ssl.key=/usr/share/elasticsearch/config/testnode.pem
|
||||
- xpack.security.transport.ssl.certificate=/usr/share/elasticsearch/config/testnode.crt
|
||||
- xpack.security.http.ssl.key=/usr/share/elasticsearch/config/testnode.pem
|
||||
- xpack.security.http.ssl.certificate=/usr/share/elasticsearch/config/testnode.crt
|
||||
- xpack.http.ssl.verification_mode=certificate
|
||||
- xpack.security.transport.ssl.verification_mode=certificate
|
||||
- xpack.license.self_generated.type=trial
|
||||
volumes:
|
||||
- ./build/repo:/tmp/es-repo
|
||||
- ./build/certs/testnode.jks:/usr/share/elasticsearch/config/testnode.jks
|
||||
- ./build/certs/testnode.pem:/usr/share/elasticsearch/config/testnode.pem
|
||||
- ./build/certs/testnode.crt:/usr/share/elasticsearch/config/testnode.crt
|
||||
- ./build/logs/default-1:/usr/share/elasticsearch/logs
|
||||
- ./docker-test-entrypoint.sh:/docker-test-entrypoint.sh
|
||||
ports:
|
||||
|
@ -71,14 +74,17 @@ services:
|
|||
- xpack.security.audit.enabled=true
|
||||
- xpack.security.authc.realms.file.file1.order=0
|
||||
- xpack.security.authc.realms.native.native1.order=1
|
||||
- xpack.security.transport.ssl.keystore.path=/usr/share/elasticsearch/config/testnode.jks
|
||||
- xpack.security.http.ssl.keystore.path=/usr/share/elasticsearch/config/testnode.jks
|
||||
- xpack.security.transport.ssl.key=/usr/share/elasticsearch/config/testnode.pem
|
||||
- xpack.security.transport.ssl.certificate=/usr/share/elasticsearch/config/testnode.crt
|
||||
- xpack.security.http.ssl.key=/usr/share/elasticsearch/config/testnode.pem
|
||||
- xpack.security.http.ssl.certificate=/usr/share/elasticsearch/config/testnode.crt
|
||||
- xpack.http.ssl.verification_mode=certificate
|
||||
- xpack.security.transport.ssl.verification_mode=certificate
|
||||
- xpack.license.self_generated.type=trial
|
||||
volumes:
|
||||
- ./build/repo:/tmp/es-repo
|
||||
- ./build/certs/testnode.jks:/usr/share/elasticsearch/config/testnode.jks
|
||||
- ./build/certs/testnode.pem:/usr/share/elasticsearch/config/testnode.pem
|
||||
- ./build/certs/testnode.crt:/usr/share/elasticsearch/config/testnode.crt
|
||||
- ./build/logs/default-2:/usr/share/elasticsearch/logs
|
||||
- ./docker-test-entrypoint.sh:/docker-test-entrypoint.sh
|
||||
ports:
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
cd /usr/share/elasticsearch/bin/
|
||||
./elasticsearch-users useradd x_pack_rest_user -p x-pack-test-password -r superuser || true
|
||||
echo "testnode" > /tmp/password
|
||||
cat /tmp/password | ./elasticsearch-keystore add -x -f -v 'xpack.security.transport.ssl.keystore.secure_password'
|
||||
cat /tmp/password | ./elasticsearch-keystore add -x -f -v 'xpack.security.http.ssl.keystore.secure_password'
|
||||
cat /tmp/password | ./elasticsearch-keystore add -x -f -v 'xpack.security.transport.ssl.secure_key_passphrase'
|
||||
cat /tmp/password | ./elasticsearch-keystore add -x -f -v 'xpack.security.http.ssl.secure_key_passphrase'
|
||||
/usr/local/bin/docker-entrypoint.sh | tee /usr/share/elasticsearch/logs/console.log
|
||||
|
|
|
@ -45,7 +45,6 @@ public class DockerYmlTestSuiteIT extends ESClientYamlSuiteTestCase {
|
|||
|
||||
private static final String USER = "x_pack_rest_user";
|
||||
private static final String PASS = "x-pack-test-password";
|
||||
private static final String KEYSTORE_PASS = "testnode";
|
||||
|
||||
public DockerYmlTestSuiteIT(ClientYamlTestCandidate testCandidate) {
|
||||
super(testCandidate);
|
||||
|
@ -103,23 +102,24 @@ public class DockerYmlTestSuiteIT extends ESClientYamlSuiteTestCase {
|
|||
client().performRequest(health);
|
||||
}
|
||||
|
||||
static Path keyStore;
|
||||
static Path trustedCertFile;
|
||||
|
||||
@BeforeClass
|
||||
public static void getKeyStore() {
|
||||
public static void getTrustedCert() {
|
||||
try {
|
||||
keyStore = PathUtils.get(DockerYmlTestSuiteIT.class.getResource("/testnode.jks").toURI());
|
||||
trustedCertFile = PathUtils.get(DockerYmlTestSuiteIT.class.getResource("/testnode.crt").toURI());
|
||||
} catch (URISyntaxException e) {
|
||||
throw new ElasticsearchException("exception while reading the store", e);
|
||||
throw new ElasticsearchException("exception while reading the certificate", e);
|
||||
}
|
||||
if (Files.exists(keyStore) == false) {
|
||||
throw new IllegalStateException("Keystore file [" + keyStore + "] does not exist.");
|
||||
|
||||
if (Files.exists(trustedCertFile) == false) {
|
||||
throw new IllegalStateException("Certificate file [" + trustedCertFile + "] does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void clearKeyStore() {
|
||||
keyStore = null;
|
||||
public static void clearTrustedCert() {
|
||||
trustedCertFile = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -130,8 +130,7 @@ public class DockerYmlTestSuiteIT extends ESClientYamlSuiteTestCase {
|
|||
String token = basicAuthHeaderValue(USER, new SecureString(PASS.toCharArray()));
|
||||
return Settings.builder()
|
||||
.put(ThreadContext.PREFIX + ".Authorization", token)
|
||||
.put(ESRestTestCase.TRUSTSTORE_PATH, keyStore)
|
||||
.put(ESRestTestCase.TRUSTSTORE_PASSWORD, KEYSTORE_PASS)
|
||||
.put(ESRestTestCase.CERTIFICATE_AUTHORITIES, trustedCertFile)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -55,13 +55,13 @@ public class HasPasswordKeyStoreCommandTests extends KeyStoreCommandTestCase {
|
|||
}
|
||||
|
||||
public void testSucceedsWhenKeystoreHasPassword() throws Exception {
|
||||
createKeystore("password");
|
||||
createKeystore("keystore-password");
|
||||
String output = execute();
|
||||
assertThat(output, containsString("Keystore is password-protected"));
|
||||
}
|
||||
|
||||
public void testSilentSucceedsWhenKeystoreHasPassword() throws Exception {
|
||||
createKeystore("password");
|
||||
createKeystore("keystre-password");
|
||||
String output = execute("--silent");
|
||||
assertThat(output, is(emptyString()));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue