-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for FIPS compliance mode #14912
base: main
Are you sure you want to change the base?
Support for FIPS compliance mode #14912
Conversation
❌ Gradle check result for 6016d5d: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
8e8ed47
to
6016d5d
Compare
❌ Gradle check result for 8e8ed47: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
❌ Gradle check result for 6016d5d: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
.../identity-shiro/src/main/java/org/opensearch/identity/shiro/realm/BCryptPasswordMatcher.java
Outdated
Show resolved
Hide resolved
Could use some help maybe from @cwperks or @peternied reviewing this, please. |
buildSrc/src/main/java/org/opensearch/gradle/testclusters/OpenSearchNode.java
Outdated
Show resolved
Hide resolved
…ional tests. Signed-off-by: Iwan Igonin <[email protected]>
Signed-off-by: Iwan Igonin <[email protected]>
Signed-off-by: Iwan Igonin <[email protected]>
Signed-off-by: Iwan Igonin <[email protected]>
Signed-off-by: Iwan Igonin <[email protected]>
Signed-off-by: Iwan Igonin <[email protected]>
…Pattern Signed-off-by: Iwan Igonin <[email protected]>
Summery: - replace unsecure kerberos crypto algorithms - add 'java.security.KeyStore' to forbidden-apis - instantiate and use SecureRandom from BCFIPS library - exclude SunJCE from security providers list at runtime, when running in FIPS JVM - exclude Azure tests when running in FIPS JVM Signed-off-by: Iwan Igonin <[email protected]>
f4856e4
to
5698702
Compare
❌ Gradle check result for 5698702: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
5698702
to
e98bfce
Compare
❌ Gradle check result for e98bfce: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
e98bfce
to
f775677
Compare
❕ Gradle check result for f775677: UNSTABLE Please review all flaky tests that succeeded after retry and create an issue if one does not already exist to track the flaky failure. |
Thanks everyone for taking the time to review this PR. The last commit includes following changes:
Next I will focus on the two unresolved comments from above. |
// test with FIPS-140-3 enabled | ||
plugins.withType(JavaPlugin).configureEach { | ||
tasks.withType(Test).configureEach { testTask -> | ||
if (System.getenv('OPENSEARCH_CRYPTO_STANDARD') == 'FIPS-140-3') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use BuildParams
consistently please:
if (System.getenv('OPENSEARCH_CRYPTO_STANDARD') == 'FIPS-140-3') { | |
if (BuildParams.inFipsJvm == true) { |
@@ -239,12 +240,17 @@ private KeyStore buildTrustStoreFromCA() throws GeneralSecurityException, IOExce | |||
return store; | |||
} | |||
|
|||
@SuppressForbiddenApi("runs exclusively in test-context without KeyStoreFactory on classpath.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SuppressForbiddenApi("runs exclusively in test-context without KeyStoreFactory on classpath.") | |
@SuppressForbidden |
import org.gradle.api.logging.Logger; | ||
import org.gradle.api.logging.Logging; | ||
import org.gradle.internal.impldep.com.jcraft.jsch.annotations.SuppressForbiddenApi; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import org.gradle.internal.impldep.com.jcraft.jsch.annotations.SuppressForbiddenApi; | |
import de.thetaphi.forbiddenapis.SuppressForbidden; |
@@ -123,6 +123,8 @@ dependencies { | |||
api 'org.jruby.joni:joni:2.2.1' | |||
api "com.fasterxml.jackson.core:jackson-databind:${props.getProperty('jackson_databind')}" | |||
api "org.ajoberstar.grgit:grgit-core:5.2.1" | |||
api "org.bouncycastle:bc-fips:${props.getProperty('bouncycastle_jce')}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is optional dependency and should not be included by default (this is build tooling which mostly every single plugin will depend upon:
api "org.bouncycastle:bc-fips:${props.getProperty('bouncycastle_jce')}" | |
if (System.getenv('OPENSEARCH_CRYPTO_STANDARD') == 'FIPS-140-3') { | |
api "org.bouncycastle:bc-fips:${props.getProperty('bouncycastle_jce')}" | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(we sadly cannot use BuildParams
here)
@@ -112,6 +113,8 @@ public void apply(Project project) { | |||
BuildParams.init(params -> { | |||
// Initialize global build parameters | |||
boolean isInternal = GlobalBuildInfoPlugin.class.getResource("/buildSrc.marker") != null; | |||
var cryptoStandard = System.getenv(OPENSEARCH_CRYPTO_STANDARD); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be useful to extract this into FipsBuild
helper class (or similar), so we could consolidate OPENSEARCH_CRYPTO_STANDARD
usage in 1 place:
public final class FipsBuildParams {
private static final String fipsMode = System.getenv("OPENSEARCH_CRYPTO_STANDARD");
private FipsBuildParams() {
}
public static boolean isInFipsMode() {
return "FIPS-140-3".equals(fipsMode);
}
public static String getFipsMode() {
return fipsMode;
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(we could use it here and https://github.com/opensearch-project/OpenSearch/pull/14912/files#r1913283753)
private SSLContext createSslContext(KeyStore trustStore) throws GeneralSecurityException { | ||
checkForTrustEntry(trustStore); | ||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); | ||
tmf.init(trustStore); | ||
SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); | ||
sslContext.init(new KeyManager[0], tmf.getTrustManagers(), new SecureRandom()); | ||
sslContext.init(new KeyManager[0], tmf.getTrustManagers(), CryptoServicesRegistrar.getSecureRandom()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since FIPS dependency has to be optional, we need to make its usage so as well:
sslContext.init(new KeyManager[0], tmf.getTrustManagers(), CryptoServicesRegistrar.getSecureRandom()); | |
private static final class SecureRandomProvider { | |
private final static MethodHandle MH_BC_SECURE_RANDOM; | |
static { | |
MethodHandle mh = null; | |
if (FipsBuildParams.isInFipsMode()) { | |
try { | |
final Class<?> cryptoServicesRegistrarClass = Class.forName("org.bouncycastle.crypto.CryptoServicesRegistrar"); | |
mh = MethodHandles.publicLookup() | |
.findStatic(cryptoServicesRegistrarClass, "getSecureRandom", MethodType.methodType(SecureRandom.class)); | |
} catch (final Throwable ex) { | |
throw new SecurityException("Unable to find org.bouncycastle.crypto.CryptoServicesRegistrar class", ex); | |
} | |
} | |
MH_BC_SECURE_RANDOM = mh; | |
} | |
public static SecureRandom getSecureRandom() throws GeneralSecurityException { | |
if (MH_BC_SECURE_RANDOM == null) { | |
return new SecureRandom(); | |
} else try { | |
return (SecureRandom) MH_BC_SECURE_RANDOM.invoke(); | |
} catch (final Throwable ex) { | |
throw new GeneralSecurityException(ex); | |
} | |
} | |
} | |
... | |
sslContext.init(new KeyManager[0], tmf.getTrustManagers(), SecureRandomProvider.getSecureRandom()); |
@@ -43,6 +43,12 @@ dependencies { | |||
api "com.carrotsearch.randomizedtesting:randomizedtesting-runner:${versions.randomizedrunner}" | |||
api "junit:junit:${versions.junit}" | |||
api "org.hamcrest:hamcrest:${versions.hamcrest}" | |||
api "org.bouncycastle:bc-fips:${versions.bouncycastle_jce}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These dependencies should be conditional on FIPS mode:
import org.opensearch.gradle.info.BuildParams
if (BuildParams.inFipsJvm == true) {
api "org.bouncycastle:bc-fips:${versions.bouncycastle_jce}"
api "org.bouncycastle:bcutil-fips:${versions.bouncycastle_util}"
}
api "org.bouncycastle:bcutil-fips:${versions.bouncycastle_util}" | ||
} | ||
|
||
tasks.named("dependencyLicenses").configure { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (BuildParams.inFipsJvm == true) {
tasks.named("dependencyLicenses").configure {
mapping from: /bc.*/, to: 'bouncycastle'
}
}
@@ -51,12 +51,15 @@ dependencies { | |||
api "commons-codec:commons-codec:${versions.commonscodec}" | |||
api "commons-logging:commons-logging:${versions.commonslogging}" | |||
api "org.slf4j:slf4j-api:${versions.slf4j}" | |||
api "org.bouncycastle:bctls-fips:${versions.bouncycastle_tls}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
api "org.bouncycastle:bctls-fips:${versions.bouncycastle_tls}" | |
import org.opensearch.gradle.info.BuildParams | |
... | |
if (BuildParams.inFipsJvm == true) { | |
api "org.bouncycastle:bctls-fips:${versions.bouncycastle_tls}" | |
} |
@@ -34,8 +34,8 @@ apply plugin: 'opensearch.build' | |||
apply plugin: 'opensearch.publish' | |||
|
|||
java { | |||
targetCompatibility = JavaVersion.VERSION_1_8 | |||
sourceCompatibility = JavaVersion.VERSION_1_8 | |||
targetCompatibility = JavaVersion.VERSION_11 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please revert this, Rest Client must use JDK 8 baseline
@beanuwave thanks for working on this, I went through the large chunk of changes and there is one major issue that bothers me (or I do not understand something). The FIPS mode compliance is optional (at least at the moment) but its leaks everywhere as a mandatory prerequisite now:
We have to make it truly optional, otherwise it is becoming a major breaking change (in my opinion). |
Description
This PR makes FIPS mode available through the
OPENSEARCH_CRYPTO_STANDARD=FIPS-140-3
environmental parameter instead of thetests.fips.enabled
setting. It provides FIPS 140-3 support by replacing all BC dependencies with BCFIPS dependencies and making FIPS approved-only mode configurable at launch. Running this mode restricts the BCFIPS provider to rely solely on FIPS-certified ciphers.fips.gradle
build script is removed in order to support a single-build solution.java.security
file is added to the build to distinguish between FIPS and non-FIPS environments.fips_java.security
file is altered due to evolving security standards.security.policy
file is altered to grant necessary security permissions.Runtime limitations (known so far) that come with enabling FIPS mode:
Admins can continue to manage their systems without being impacted by this change. However, for those keen on FIPS compliance, the most common obstacle will likely be the requirement to set a stronger password for the internal keystore and also convert key and truststores to *.bcfks format.
ssl.verification_mode=NONE
setting is not permitted.Reasons for refactoring
PemUtils
, which is used by the Reindex API in cases of migrating data from a remote cluster that is TLS protected:Related Issues
opensearch-project/security#3420
Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.