Skip to content

Conversation

@beanuwave
Copy link
Contributor

@beanuwave beanuwave commented Jun 11, 2025

Description

Makes the required changes to build and test under FIPS-140-3 compliance support. FIPS mode can be activated by adding the -Pcrypto.standard=FIPS-140-3 Gradle parameter.

NOTE:

  • This PR includes all remaining changes from the original PR#14912
  • Due to the netty FIPS reflection bug in v4.1.125.Final and v4.1.126.Final, the :plugins:transport-reactor-netty4:test task will fail. To run properly, netty needs to be updated to a newer version, such as v4.1.127.Final. Not relevant after update to netty 4.2.7

Related Issues

Resolves RFC

Check List

  • Functionality includes testing.
  • API changes companion pull request created, if applicable.
  • Public documentation issue/PR created, if applicable.

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.

@github-actions
Copy link
Contributor

❌ Gradle check result for 9b5da5c: 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?

@github-actions
Copy link
Contributor

github-actions bot commented Jul 7, 2025

❌ Gradle check result for 986dce7: 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?

@terryquigleysas
Copy link
Contributor

I'd like to raise a general point here to keep in mind with this development, especially as instructions will be required for Java setups other than the bundled version. The Red Hat JDK 21, for example, has a default of fips.keystore.type: PKCS12 - see https://docs.redhat.com/en/documentation/red_hat_build_of_openjdk/21/html/configuring_red_hat_build_of_openjdk_21_on_rhel_with_fips/fips_settings#fips_settings .

We'd like to ensure that code checks aren't so stringent as to prevent this setup from working.

@github-actions
Copy link
Contributor

❌ Gradle check result for 939e6b5: 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?

@github-actions
Copy link
Contributor

❌ Gradle check result for 11da667: 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?

@github-actions
Copy link
Contributor

❌ Gradle check result for 9a387a4: 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?

@github-actions
Copy link
Contributor

❌ Gradle check result for 4e0af75: 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?

@github-actions
Copy link
Contributor

❌ Gradle check result for 9efd838: 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?

@github-actions
Copy link
Contributor

❌ Gradle check result for 4fc6b40: 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?

@github-actions
Copy link
Contributor

❌ Gradle check result for 0139eaa: 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?

@github-actions
Copy link
Contributor

❌ Gradle check result for f52e720: null

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?

@beanuwave
Copy link
Contributor Author

beanuwave commented Jul 16, 2025

The Red Hat JDK 21, for example, has a default of fips.keystore.type: PKCS12

@terryquigleysas Thank you for pointing out those limitations.

We'd like to ensure that code checks aren't so stringent as to prevent this setup from working.

We rely on SunPKCS12 provider to load the JVM's default truststore. In case of OpenJKD the default type is the same as RHEL's - so nothing changes for us.

@terryquigleysas
Copy link
Contributor

terryquigleysas commented Jul 16, 2025

The Red Hat JDK 21, for example, has a default of fips.keystore.type: PKCS12

@terryquigleysas Thank you for pointing out those limitations.

We'd like to ensure that code checks aren't so stringent as to prevent this setup from working.

We rely on SunPKCS12 provider to load the JVM's default truststore. In case of OpenJKD the default type is the same as RHEL's - so nothing changes for us.

Good news. Thank you for the reply. Much appreciated!

@github-actions
Copy link
Contributor

github-actions bot commented Aug 1, 2025

❌ Gradle check result for cb7949d: null

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?

@beanuwave beanuwave changed the title remaining changes from 14912 Make test-suite runnable under FIPS JVM Aug 4, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Aug 4, 2025

❌ Gradle check result for 0680de8: 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?

@github-actions
Copy link
Contributor

github-actions bot commented Aug 4, 2025

❌ Gradle check result for 732e412: 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?

(PrivilegedAction<Version>) () -> Version.parse(System.getProperty("java.version"))
);
if (full.compareTo(Version.parse("12.0.1")) < 0) {
if (!inFipsJvm()) {
Copy link
Contributor

@reta reta Nov 7, 2025

Choose a reason for hiding this comment

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

Not related, but our baseline is JDK-21, we could clean up this code

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've reverted my changes to this plugin. Azure classic is generally not worth trying to make it FIPS-compliant. We should keep it as is - unsupported.

if (Security.getProvider("BCFIPS") != null) {
certTrustStore = KeyStore.getInstance("BCFKS");
InputStream keyStoreStream = getClass().getResourceAsStream("/google.bcfks");
SecurityUtils.loadKeyStore(certTrustStore, keyStoreStream, "notasecret");
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe we definitely should not hardcode password here, please have a setting for it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let's make a setting for SSL trust as well as it's passphrase w/o a fallback and use this google.bcfks store only for tests.

@reta
Copy link
Contributor

reta commented Nov 7, 2025

@cwperks @reta I believe this PR is ready for review - can you take a look please?

Thanks @beanuwave , sorry haven't looked yet but will do this week, thank you

Thanks @beanuwave , did a first pass, a few minor comments but I have two major concerns:

  • Incredible amount of "if" logic related to FIPS mode checks (and its variations like assumeFalse). I would like to suggest to split test cases in XxxBaseTest and XxxNoFipsTest extends XxxBaseTest (the naming is not very important). With this setup, we could easily exclude *NoFipsTest* from test runs that use FIPS mode (and XxxBaseTest would be run in any mode)
  • We now have to run all test suites in 2 modes - w/o FIPS. AFAICT this is not done yet, what is your plan here?

Thank you.

@beanuwave
Copy link
Contributor Author

We now have to run all test suites in 2 modes - w/o FIPS. AFAICT this is not done yet, what is your plan here?

I believe @cwperks suggested creating a new GitHub workflow that supports both scheduled runs and PR comments.

iigonin and others added 2 commits November 13, 2025 10:45
…or TYPE_TO_EXTENSION_MAP; revert changes to SecureSettingsHelpers.getSecureSettingsProvider; revert changes to AzureClassic

Signed-off-by: Igonin <[email protected]>
Co-authored-by: Benny Goerzig <[email protected]>
Co-authored-by: Karsten Schnitter <[email protected]>
Co-authored-by: Kai Sternad <[email protected]>
Signed-off-by: Igonin <[email protected]>
Co-authored-by: Benny Goerzig <[email protected]>
Co-authored-by: Karsten Schnitter <[email protected]>
Co-authored-by: Kai Sternad <[email protected]>
@reta
Copy link
Contributor

reta commented Nov 14, 2025

I believe @cwperks suggested creating a new GitHub workflow that supports both scheduled runs and PR comments.

Sorry, a bit late here, I think this is in general viable option, but:

  • we need to make sure out build scripts are adapted (we build on Jenkins, not GA)
  • we need to run the these checks in parallel

iigonin and others added 3 commits November 14, 2025 17:32
Signed-off-by: Igonin <[email protected]>
Co-authored-by: Benny Goerzig <[email protected]>
Co-authored-by: Karsten Schnitter <[email protected]>
Co-authored-by: Kai Sternad <[email protected]>
… google.p12 in non-FIPS mode and an exception in FIPS mode when no truststore is set up.

Signed-off-by: Igonin <[email protected]>
Co-authored-by: Benny Goerzig <[email protected]>
Co-authored-by: Karsten Schnitter <[email protected]>
Co-authored-by: Kai Sternad <[email protected]>
@github-actions
Copy link
Contributor

❌ Gradle check result for 07c6358: 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?

@cwperks
Copy link
Member

cwperks commented Nov 17, 2025

We now have to run all test suites in 2 modes - w/o FIPS. AFAICT this is not done yet, what is your plan here?

I believe @cwperks suggested creating a new GitHub workflow that supports both scheduled runs and PR comments.

What I was thinking was something similar to benchmark-pull-request where the benchmarks are run ad hoc

  1. To trigger the run requires leaving a comment on a PR. Example: Allow collectors take advantage of preaggregated data using collectRange API #20009 (comment)
  2. This would then open an issue where a maintainer can approve to run the workflow. Example: Request to approve/deny benchmark run for PR #19573 #19969

@peterzhuamazon @rishabh6788 Would you be able to help us with setup for such a workflow?

Signed-off-by: Igonin <[email protected]>
Co-authored-by: Benny Goerzig <[email protected]>
Co-authored-by: Karsten Schnitter <[email protected]>
Co-authored-by: Kai Sternad <[email protected]>
@github-actions
Copy link
Contributor

✅ Gradle check result for 826d92f: SUCCESS

iigonin and others added 3 commits November 19, 2025 14:49
Signed-off-by: Igonin <[email protected]>
Co-authored-by: Benny Goerzig <[email protected]>
Co-authored-by: Karsten Schnitter <[email protected]>
Co-authored-by: Kai Sternad <[email protected]>
Signed-off-by: Igonin <[email protected]>
Co-authored-by: Benny Goerzig <[email protected]>
Co-authored-by: Karsten Schnitter <[email protected]>
Co-authored-by: Kai Sternad <[email protected]>
…oreUtils

Signed-off-by: Igonin <[email protected]>
Co-authored-by: Benny Goerzig <[email protected]>
Co-authored-by: Karsten Schnitter <[email protected]>
Co-authored-by: Kai Sternad <[email protected]>
@github-actions
Copy link
Contributor

✅ Gradle check result for f3f0880: SUCCESS

@beanuwave
Copy link
Contributor Author

@reta @cwperks The earlier comments have been resolved. Whenever it’s convenient, a second review would be appreciated.

Copy link
Member

@cwperks cwperks left a comment

Choose a reason for hiding this comment

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

Thank you for the diligence on this PR @beanuwave! With these changes it greatly expands the test coverage when running in FIPS approved mode.

@peterzhuamazon what would be required to add another gradle check to run with the FIPS approved setting? i.e. ./gradlew check -Pcrypto.standard=FIPS-140-3

final KeyStore keyStore = KeyStore.getInstance(keyStoreType, jcaProvider);

keyStore.load(
SecureNetty4HttpServerTransportTests.class.getResourceAsStream("/netty4-server-keystore" + fileExtension),
Copy link
Contributor

Choose a reason for hiding this comment

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

try (InputStream in = SecureNetty4HttpServerTransportTests.class.getResourceAsStream("/netty4-server-keystore" + fileExtension) {
    keyStore.load(in, PASSWORD);
}


// Cached factory to avoid repeated keystore loading (especially slow in FIPS mode with BCFKS).
// TODO: Replace with @BeforeAll when migrating to JUnit 5.
private static volatile KeyManagerFactory cachedKeyManagerFactory;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why we cannot use @BeforeClass (JUnit 4) here?


// Cached factories to avoid repeated keystore loading (especially slow in FIPS mode)
// TODO: Replace with @BeforeAll when migrating to JUnit 5.
private static volatile KeyManagerFactory cachedServerKeyManagerFactory;
Copy link
Contributor

Choose a reason for hiding this comment

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

Same question please, @BeforeClass should be sufficient


SSLEngine engine = SslContextBuilder.forServer(keyManagerFactory)
return Optional.of(
SslContextBuilder.forServer(getServerKeyManagerFactory())
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't we need to provide trustManager here as well?

import static org.opensearch.repositories.gcs.GoogleCloudStorageClientSettings.TRUSTSTORE_PATH_SETTING;
import static org.opensearch.repositories.gcs.GoogleCloudStorageClientSettings.TRUSTSTORE_TYPE_SETTING;

@SuppressForbidden(reason = "use a http server")
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, why do we need @SuppressForbidden here?


// Cached keystore to avoid expensive cert generation on every test (especially slow in FIPS mode)
// TODO: Replace with @BeforeAll when migrating to JUnit 5.
private static volatile KeyStore cachedServerKeyStore;
Copy link
Contributor

Choose a reason for hiding this comment

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

Please use @BeforeClass

testTask.systemProperty 'javax.net.ssl.trustStoreProvider', 'BCFIPS'
testTask.systemProperty 'javax.net.ssl.trustStorePassword', 'changeit'

// Exclude base test classes that have corresponding FipsTests or FipsIT
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we just rename these tests to:

XxxNoFipsTests.java
XxxNoFipsIT.java

?

*/
final class KeyStoreUtil {

public static final Supplier<Boolean> inFipsMode = () -> {
Copy link
Contributor

@reta reta Nov 22, 2025

Choose a reason for hiding this comment

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

Why do need Supplier here? The value of the FIPS mode will not change, we need to capture it only once:

      public static final boolean IN_FIPS_MODE = isInFipsMode();

      private static boolean isInFipsMode() {
        try {
            // Equivalent to: boolean approvedOnly = CryptoServicesRegistrar.isInApprovedOnlyMode()
            var registrarClass = Class.forName("org.bouncycastle.crypto.CryptoServicesRegistrar");
            var isApprovedOnlyMethod = registrarClass.getMethod("isInApprovedOnlyMode");
            return (Boolean) isApprovedOnlyMethod.invoke(null);
        } catch (ReflectiveOperationException e) {
            return false;
        }
    }

}
try {
KeyStore keyStore = KeyStore.getInstance(type);
if (CryptoServicesRegistrar.isInApprovedOnlyMode() && !FIPS_COMPLIANT_KEYSTORE_TYPES.contains(type)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

So why we are calling CryptoServicesRegistrar directly here but using reflection above (inFipsMode)? If we do not require CryptoServicesRegistrar to be present on the classpath, we should use IN_FIPS_MODE , otherwise we should just use CryptoServicesRegistrar.isInApprovedOnlyMode()

@reta
Copy link
Contributor

reta commented Nov 22, 2025

@reta @cwperks The earlier comments have been resolved. Whenever it’s convenient, a second review would be appreciated.

Thanks a lot @beanuwave , it looks great, few quite minor comments but awesome work by all means! Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stalled Issues that have stalled

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[RFC] FIPS-140 Compliance Roadmap for OpenSearch

5 participants