Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions buildSrc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ if (project != rootProject) {
exclude '**/*.p12'
// the file that actually defines nocommit
exclude '**/ForbiddenPatternsTask.java'
exclude '**/*.bcfks'
}

testingConventions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,12 @@ import groovy.transform.CompileStatic
import org.apache.commons.io.IOUtils
import org.elasticsearch.gradle.info.BuildParams
import org.elasticsearch.gradle.info.GlobalBuildInfoPlugin
import org.elasticsearch.gradle.info.GlobalInfoExtension
import org.elasticsearch.gradle.info.JavaHome
import org.elasticsearch.gradle.precommit.DependencyLicensesTask
import org.elasticsearch.gradle.precommit.PrecommitTasks
import org.elasticsearch.gradle.test.ErrorReportingTestListener
import org.elasticsearch.gradle.testclusters.ElasticsearchCluster
import org.elasticsearch.gradle.testclusters.TestClustersPlugin
import org.elasticsearch.gradle.tool.Boilerplate
import org.gradle.api.Action
import org.gradle.api.GradleException
import org.gradle.api.InvalidUserDataException
Expand Down Expand Up @@ -138,31 +137,50 @@ class BuildPlugin implements Plugin<Project> {
configureTestTasks(project)
configurePrecommit(project)
configureDependenciesInfo(project)

configureFips140(project)
}

public static void configureFips140(Project project) {
// Need to do it here to support external plugins
GlobalInfoExtension globalInfo = project.rootProject.extensions.getByType(GlobalInfoExtension)
// wait until global info is populated because we don't know if we are running in a fips jvm until execution time
globalInfo.ready {
// Common config when running with a FIPS-140 runtime JVM
if (BuildParams.inFipsJvm) {
project.tasks.withType(Test).configureEach { Test task ->
task.systemProperty 'javax.net.ssl.trustStorePassword', 'password'
task.systemProperty 'javax.net.ssl.keyStorePassword', 'password'
}
project.pluginManager.withPlugin("elasticsearch.testclusters") {
NamedDomainObjectContainer<ElasticsearchCluster> testClusters = project.extensions.findByName(TestClustersPlugin.EXTENSION_NAME) as NamedDomainObjectContainer<ElasticsearchCluster>
if (testClusters != null) {
testClusters.all { ElasticsearchCluster cluster ->
cluster.systemProperty 'javax.net.ssl.trustStorePassword', 'password'
cluster.systemProperty 'javax.net.ssl.keyStorePassword', 'password'
}
}
static void configureFips140(Project project) {
// Common config when running with a FIPS-140 runtime JVM
if (inFipsJvm()) {
ExportElasticsearchBuildResourcesTask buildResources = project.tasks.getByName('buildResources') as ExportElasticsearchBuildResourcesTask
File securityProperties = buildResources.copy("fips_java.security")
File securityPolicy = buildResources.copy("fips_java.policy")
File bcfksKeystore = buildResources.copy("cacerts.bcfks")
// This configuration can be removed once system modules are available
Boilerplate.maybeCreate(project.configurations, 'extraJars') {
project.dependencies.add('extraJars', "org.bouncycastle:bc-fips:1.0.1")
project.dependencies.add('extraJars', "org.bouncycastle:bctls-fips:1.0.9")
}
project.pluginManager.withPlugin("elasticsearch.testclusters") {
NamedDomainObjectContainer<ElasticsearchCluster> testClusters = project.extensions.findByName(TestClustersPlugin.EXTENSION_NAME) as NamedDomainObjectContainer<ElasticsearchCluster>
testClusters.all { ElasticsearchCluster cluster ->
for (File dep : project.getConfigurations().getByName("extraJars").getFiles()){
cluster.extraJarFile(dep)
}
cluster.extraConfigFile("fips_java.security", securityProperties)
cluster.extraConfigFile("fips_java.policy", securityPolicy)
cluster.extraConfigFile("cacerts.bcfks", bcfksKeystore)
cluster.systemProperty('java.security.properties', '=${ES_PATH_CONF}/fips_java.security')
cluster.systemProperty('java.security.policy', '=${ES_PATH_CONF}/fips_java.policy')
cluster.systemProperty('javax.net.ssl.trustStore', '${ES_PATH_CONF}/cacerts.bcfks')
cluster.systemProperty('javax.net.ssl.trustStorePassword', 'password')
cluster.systemProperty('javax.net.ssl.keyStorePassword', 'password')
cluster.systemProperty('javax.net.ssl.keyStoreType', 'BCFKS')
}
}
project.tasks.withType(Test).configureEach { Test task ->
task.dependsOn(buildResources)
task.systemProperty('javax.net.ssl.trustStorePassword', 'password')
task.systemProperty('javax.net.ssl.keyStorePassword', 'password')
task.systemProperty('javax.net.ssl.trustStoreType', 'BCFKS')
// Using the key==value format to override default JVM security settings and policy
// see also: https://docs.oracle.com/javase/8/docs/technotes/guides/security/PolicyFiles.html
task.systemProperty('java.security.properties', String.format(Locale.ROOT, "=%s", securityProperties.toString()))
task.systemProperty('java.security.policy', String.format(Locale.ROOT, "=%s", securityPolicy.toString()))
task.systemProperty('javax.net.ssl.trustStore', bcfksKeystore.toString())
}

}
}

Expand Down Expand Up @@ -623,15 +641,13 @@ class BuildPlugin implements Plugin<Project> {
project.mkdir(heapdumpDir)
project.mkdir(test.workingDir)

if (BuildParams.inFipsJvm) {
nonInputProperties.systemProperty('runtime.java', "${-> BuildParams.runtimeJavaVersion.majorVersion}FIPS")
} else {
nonInputProperties.systemProperty('runtime.java', "${-> BuildParams.runtimeJavaVersion.majorVersion}")
}
//TODO remove once jvm.options are added to test system properties
test.systemProperty ('java.locale.providers','SPI,COMPAT')
}

if (inFipsJvm()) {
project.dependencies.add('testRuntimeOnly', "org.bouncycastle:bc-fips:1.0.1")
project.dependencies.add('testRuntimeOnly', "org.bouncycastle:bctls-fips:1.0.9")
}
test.jvmArgumentProviders.add(nonInputProperties)
test.extensions.add('nonInputProperties', nonInputProperties)

Expand Down Expand Up @@ -775,4 +791,8 @@ class BuildPlugin implements Plugin<Project> {
})
}
}

private static inFipsJvm(){
return Boolean.parseBoolean(System.getProperty("tests.fips.enabled"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,7 @@ public void generate() {
runtimeJavaVersionDetails = findJavaVersionDetails(runtimeJavaHome);
runtimeJavaVersionEnum = JavaVersion.toVersion(findJavaSpecificationVersion(runtimeJavaHome));

// We don't expect Gradle to be running in a FIPS JVM
String inFipsJvmScript = "print(java.security.Security.getProviders()[0].name.toLowerCase().contains(\"fips\"));";
inFipsJvm = Boolean.parseBoolean(runJavaAsScript(runtimeJavaHome, inFipsJvmScript));
inFipsJvm = Boolean.parseBoolean(System.getProperty("tests.fips.enabled"));
} else {
throw new RuntimeException("Runtime Java home path of '" + compilerJavaHome + "' does not exist");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,11 @@ public void extraConfigFile(String destination, File from, PropertyNormalization
nodes.all(node -> node.extraConfigFile(destination, from, normalization));
}

@Override
public void extraJarFile(File from) {
nodes.all(node -> node.extraJarFile(from));
}

@Override
public void user(Map<String, String> userSpec) {
nodes.all(node -> node.user(userSpec));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ public class ElasticsearchNode implements TestClusterConfiguration {
private final LazyPropertyMap<String, CharSequence> environment = new LazyPropertyMap<>("Environment", this);
private final LazyPropertyList<CharSequence> jvmArgs = new LazyPropertyList<>("JVM arguments", this);
private final LazyPropertyMap<String, File> extraConfigFiles = new LazyPropertyMap<>("Extra config files", this, FileEntry::new);
private final LazyPropertyList<File> extraJarFiles = new LazyPropertyList<>("Extra jar files", this);
private final List<Map<String, String>> credentials = new ArrayList<>();
final LinkedHashMap<String, String> defaultConfig = new LinkedHashMap<>();

Expand Down Expand Up @@ -454,6 +455,8 @@ public synchronized void start() {

copyExtraConfigFiles();

copyExtraJars();

if (isSettingTrue("xpack.security.enabled")) {
if (credentials.isEmpty()) {
user(Collections.emptyMap());
Expand Down Expand Up @@ -530,6 +533,25 @@ private void copyExtraConfigFiles() {
});
}

/**
* Copies extra jars to the `/lib` directory.
* //TODO: Remove this when system modules are available
*/
private void copyExtraJars() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We prefer not to couple testclusters with random project configuration like an extraJars configuration.
Would be better to have extra jars work exactly as extra config files so these jars could be passed in externally.

A more generic way would be to add the possibility to add hooks right before the task starts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved this outside as suggested, similar to how extraConfigurationFiles work

if (extraJarFiles.isEmpty() == false){
logToProcessStdout("Setting up " + extraJarFiles.size() + " additional jar dependencies");
}
extraJarFiles.forEach(from -> {
Path destination = getDistroDir().resolve("lib").resolve(from.getName());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will leave trash behind. @atorok don't we setup a link for the lib dir? This would copy into the lib dir and be left behind after the test is run?

Copy link
Contributor

@alpar-t alpar-t Oct 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't set up links for directories, so this will be fine.
We create a matching directory structure, and create hard links for the files.

That does bring up a slightly different problem, if we were to replace one of the jars with this mechanism, that will be reflected for all invocations across all projects because the initial file could have changed. That would be really hard to spot and debug. We originally had code to set the links to read only so this would error out, maybe we should get that back ? It would work across the board, as opposed to just checking that the libs don't replace other libs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this something that should be taken into consideration in the context of this PR @atorok or are we ok to merge this and address it in a follow up ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's ok as a follow-up

try {
Files.copy(from.toPath(), destination, StandardCopyOption.REPLACE_EXISTING);
LOGGER.info("Added extra jar {} to {}", from.getName(), destination);
} catch (IOException e) {
throw new UncheckedIOException("Can't copy extra jar dependency " + from.getName() + " to " + destination.toString(), e);
}
});
}

private void installModules() {
if (testDistribution == TestDistribution.INTEG_TEST) {
logToProcessStdout("Installing " + modules.size() + "modules");
Expand Down Expand Up @@ -576,6 +598,14 @@ public void extraConfigFile(String destination, File from, PropertyNormalization
extraConfigFiles.put(destination, from, normalization);
}

@Override
public void extraJarFile(File from) {
if (from.toString().endsWith(".jar") == false) {
throw new IllegalArgumentException("extra jar file " + from.toString() + " doesn't appear to be a JAR");
}
extraJarFiles.add(from);
}

@Override
public void user(Map<String, String> userSpec) {
Set<String> keys = new HashSet<>(userSpec.keySet());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ public interface TestClusterConfiguration {

void extraConfigFile(String destination, File from, PropertyNormalization normalization);

void extraJarFile(File from);

void user(Map<String, String> userSpec);

String getHttpSocketURI();
Expand Down
Binary file added buildSrc/src/main/resources/cacerts.bcfks
Binary file not shown.
16 changes: 16 additions & 0 deletions buildSrc/src/main/resources/fips_java.policy
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
grant {
permission java.security.SecurityPermission "putProviderProperty.BCFIPS";
permission java.security.SecurityPermission "putProviderProperty.BCJSSE";
permission java.lang.RuntimePermission "getProtectionDomain";
permission java.util.PropertyPermission "java.runtime.name", "read";
permission org.bouncycastle.crypto.CryptoServicesPermission "tlsAlgorithmsEnabled";
//io.netty.handler.codec.DecoderException
permission java.lang.RuntimePermission "accessClassInPackage.sun.security.internal.spec";
//java.security.InvalidAlgorithmParameterException: Cannot process GCMParameterSpec
permission java.lang.RuntimePermission "accessDeclaredMembers";
permission java.util.PropertyPermission "intellij.debug.agent", "read";
permission java.util.PropertyPermission "intellij.debug.agent", "write";
permission org.bouncycastle.crypto.CryptoServicesPermission "exportSecretKey";
permission org.bouncycastle.crypto.CryptoServicesPermission "exportPrivateKey";
permission java.io.FilePermission "${javax.net.ssl.trustStore}", "read";
};
50 changes: 50 additions & 0 deletions buildSrc/src/main/resources/fips_java.security
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
security.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider
security.provider.2=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider fips:BCFIPS
security.provider.3=SUN
securerandom.source=file:/dev/urandom
securerandom.strongAlgorithms=NativePRNGBlocking:SUN,DRBG:SUN
securerandom.drbg.config=
login.configuration.provider=sun.security.provider.ConfigFile
policy.provider=sun.security.provider.PolicyFile
policy.expandProperties=true
policy.allowSystemProperty=true
policy.ignoreIdentityScope=false
keystore.type=BCFKS
keystore.type.compat=true
package.access=sun.misc.,\
sun.reflect.
package.definition=sun.misc.,\
sun.reflect.
security.overridePropertiesFile=true
ssl.KeyManagerFactory.algorithm=PKIX
ssl.TrustManagerFactory.algorithm=PKIX
networkaddress.cache.negative.ttl=10
krb5.kdc.bad.policy = tryLast
jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \
RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224
jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
DSA keySize < 1024
jdk.tls.disabledAlgorithms=SSLv3, RC4, MD5withRSA, DH keySize < 1024, \
EC keySize < 224, DES40_CBC, RC4_40, 3DES_EDE_CBC
jdk.tls.legacyAlgorithms= \
K_NULL, C_NULL, M_NULL, \
DH_anon, ECDH_anon, \
RC4_128, RC4_40, DES_CBC, DES40_CBC, \
3DES_EDE_CBC
jdk.tls.keyLimits=AES/GCM/NoPadding KeyUpdate 2^37
crypto.policy=unlimited
jdk.xml.dsig.secureValidationPolicy=\
disallowAlg http://www.w3.org/TR/1999/REC-xslt-19991116,\
disallowAlg http://www.w3.org/2001/04/xmldsig-more#rsa-md5,\
disallowAlg http://www.w3.org/2001/04/xmldsig-more#hmac-md5,\
disallowAlg http://www.w3.org/2001/04/xmldsig-more#md5,\
maxTransforms 5,\
maxReferences 30,\
disallowReferenceUriSchemes file http https,\
minKeySize RSA 1024,\
minKeySize DSA 1024,\
minKeySize EC 224,\
noDuplicateIds,\
noRetrievalMethodLoops
jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep;\
java.base/java.security.KeyRep$Type;java.base/javax.crypto.spec.SecretKeySpec;!*
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
Expand Down Expand Up @@ -87,8 +89,13 @@ public void accept(final int lineNumber, final String line) {
.filter(Predicate.not(String::isBlank))
.collect(Collectors.toUnmodifiableList()));
}
final Map<String, String> substitutions = new HashMap<>();
substitutions.put("ES_TMPDIR", System.getenv("ES_TMPDIR"));
if (null != System.getenv("ES_PATH_CONF")){
substitutions.put("ES_PATH_CONF", System.getenv("ES_PATH_CONF"));
}
final List<String> substitutedJvmOptions =
substitutePlaceholders(jvmOptions, Map.of("ES_TMPDIR", System.getenv("ES_TMPDIR")));
substitutePlaceholders(jvmOptions, Collections.unmodifiableMap(substitutions));
final List<String> ergonomicJvmOptions = JvmErgonomics.choose(substitutedJvmOptions);
final List<String> systemJvmOptions = SystemJvmOptions.systemJvmOptions();
final List<String> finalJvmOptions =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import javax.net.ssl.X509ExtendedTrustManager;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
Expand Down Expand Up @@ -51,7 +52,12 @@ public class SslConfiguration {
static final Map<String, String> ORDERED_PROTOCOL_ALGORITHM_MAP;
static {
LinkedHashMap<String, String> protocolAlgorithmMap = new LinkedHashMap<>();
protocolAlgorithmMap.put("TLSv1.3", "TLSv1.3");
try {
SSLContext.getInstance("TLSv1.3");
protocolAlgorithmMap.put("TLSv1.3", "TLSv1.3");
} catch (NoSuchAlgorithmException e) {
// ignore since we support JVMs using BCJSSE in FIPS mode which doesn't support TLSv1.3
}
protocolAlgorithmMap.put("TLSv1.2", "TLSv1.2");
protocolAlgorithmMap.put("TLSv1.1", "TLSv1.1");
protocolAlgorithmMap.put("TLSv1", "TLSv1");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.elasticsearch.common.ssl.KeyStoreUtil.inferKeyStoreType;
import static org.elasticsearch.common.ssl.SslConfiguration.ORDERED_PROTOCOL_ALGORITHM_MAP;
import static org.elasticsearch.common.ssl.SslConfigurationKeys.CERTIFICATE;
import static org.elasticsearch.common.ssl.SslConfigurationKeys.CERTIFICATE_AUTHORITIES;
import static org.elasticsearch.common.ssl.SslConfigurationKeys.CIPHERS;
Expand Down Expand Up @@ -66,7 +69,9 @@
*/
public abstract class SslConfigurationLoader {

static final List<String> DEFAULT_PROTOCOLS = List.of("TLSv1.3", "TLSv1.2", "TLSv1.1");
static final List<String> DEFAULT_PROTOCOLS = Collections.unmodifiableList(
ORDERED_PROTOCOL_ALGORITHM_MAP.containsKey("TLSv1.3") ?
Arrays.asList("TLSv1.3", "TLSv1.2", "TLSv1.1") : Arrays.asList("TLSv1.2", "TLSv1.1"));

private static final List<String> JDK11_CIPHERS = List.of(
// TLSv1.3 cipher has PFS, AEAD, hardware support
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.Security;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
Expand Down Expand Up @@ -2086,6 +2085,6 @@ public static Index resolveIndex(String index) {
}

public static boolean inFipsJvm() {
return Security.getProviders()[0].getName().toLowerCase(Locale.ROOT).contains("fips");
return Boolean.parseBoolean(System.getProperty(FIPS_SYSPROP));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.security.Security;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -192,6 +191,8 @@ public static void resetPortCounter() {

public static final String DEFAULT_TEST_WORKER_ID = "--not-gradle--";

public static final String FIPS_SYSPROP = "tests.fips.enabled";

static {
TEST_WORKER_VM_ID = System.getProperty(TEST_WORKER_SYS_PROPERTY, DEFAULT_TEST_WORKER_ID);
setTestSysProps();
Expand Down Expand Up @@ -1341,7 +1342,7 @@ private static boolean isUnusableLocale() {
}

public static boolean inFipsJvm() {
return Security.getProviders()[0].getName().toLowerCase(Locale.ROOT).contains("fips");
return Boolean.parseBoolean(System.getProperty(FIPS_SYSPROP));
}

/**
Expand Down
Loading