Skip to content

Commit

Permalink
Provision automatic test runs for ruby/java unit tests and integratio…
Browse files Browse the repository at this point in the history
…n tests with fips mode (#17029)

* Run ruby unit tests under FIPS mode

This commit shows a proposed pattern for running automated tests for logstash in
FIPS mode. It uses a new identifier in gradle for conditionally setting
properties to configure fips mode. The tests are run in a container
representative of the base image the final artifacts will be built from.

* Move everything from qa/fips -> x-pack

This commit moves test setup/config under x-pack dir.

* Extend test pipelines for fips mode to java unit tests and integration

* Add git to container for gradle

* move fips-mode gradle hooks to x-pack

* Skip license check for now

---------

Co-authored-by: Ry Biesemeyer <ry.biesemeyer@elastic.co>
  • Loading branch information
donoghuc and yaauie committed Feb 28, 2025
1 parent 18772dd commit bedc706
Show file tree
Hide file tree
Showing 7 changed files with 313 additions and 0 deletions.
64 changes: 64 additions & 0 deletions .buildkite/pull_request_pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ steps:
export JRUBY_OPTS="-J-Xmx1g"
export GRADLE_OPTS="-Xmx2g -Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info"
ci/license_check.sh -m 4G
# SKIP LICENCE CHECK FOR NOW WHILE WE FIGURE OUT DEPENDENCY VENDORING/PACKAGING
skip: "Skipping license check: TODO unskip once packaging is sorted out"

- label: ":rspec: Ruby unit tests"
key: "ruby-unit-tests"
Expand All @@ -37,6 +39,26 @@ steps:
artifact_paths:
- "coverage/coverage.json"

- label: ":rspec: Ruby unit tests - FIPS mode"
key: "ruby-unit-tests-fips"
agents:
provider: gcp
imageProject: elastic-images-prod
image: family/platform-ingest-logstash-ubuntu-2204
machineType: "n2-standard-4"
diskSizeGb: 64
retry:
automatic:
# dont retry on failure while they are expected
- limit: 0
command: |
set -euo pipefail
docker build -t test-runner-image -f x-pack/distributions/internal/observabilitySRE/docker/Dockerfile .
docker run test-runner-image ./gradlew --info --stacktrace -PrunTestsInFIPSMode=true rubyTests
artifact_paths:
- "coverage/coverage.json"

- label: ":java: Java unit tests"
key: "java-unit-tests"
agents:
Expand All @@ -58,6 +80,30 @@ steps:
- "**/jacocoTestReport.xml"
- "**/build/classes/**/*.*"

- label: ":java: Java unit tests - FIPS mode"
key: "java-unit-tests-fips"
agents:
provider: gcp
imageProject: elastic-images-prod
image: family/platform-ingest-logstash-ubuntu-2204
machineType: "n2-standard-4"
diskSizeGb: 64
retry:
automatic:
# dont retry on failure while they are expected
- limit: 0
env:
ENABLE_SONARQUBE: true
command: |
set -euo pipefail
docker build -t test-runner-image -f x-pack/distributions/internal/observabilitySRE/docker/Dockerfile .
docker run test-runner-image ./gradlew --info --stacktrace -PrunTestsInFIPSMode=true javaTests
artifact_paths:
- "**/build/test-results/javaTests/TEST-*.xml"
- "**/jacocoTestReport.xml"
- "**/build/classes/**/*.*"

- label: ":sonarqube: Continuous Code Inspection"
if: |
build.pull_request.id != null ||
Expand All @@ -79,6 +125,24 @@ steps:
manual:
allowed: true

- label: ":lab_coat: Integration Tests - FIPS mode"
key: "integration-tests-fips"
agents:
provider: gcp
imageProject: elastic-images-prod
image: family/platform-ingest-logstash-ubuntu-2204
machineType: "n2-standard-4"
diskSizeGb: 64
retry:
automatic:
# dont retry on failure while they are expected
- limit: 0
command: |
set -euo pipefail
docker build -t test-runner-image -f x-pack/distributions/internal/observabilitySRE/docker/Dockerfile .
docker run test-runner-image ./gradlew --info --stacktrace -PrunTestsInFIPSMode=true runIntegrationTests
- label: ":lab_coat: Integration Tests / part 1"
key: "integration-tests-part-1"
agents:
Expand Down
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ plugins {
id "com.dorongold.task-tree" version "2.1.0"
}

apply from: "${projectDir}/x-pack/distributions/internal/observabilitySRE/build-ext.gradle"

apply plugin: 'de.undercouch.download'
apply from: "rubyUtils.gradle"

Expand Down
5 changes: 5 additions & 0 deletions logstash-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,11 @@ dependencies {
runtimeOnly 'commons-logging:commons-logging:1.3.1'
// also handle libraries relying on log4j 1.x to redirect their logs
runtimeOnly "org.apache.logging.log4j:log4j-1.2-api:${log4jVersion}"
// FIPS deps. TODO: figure out how to actually manage these
runtimeOnly("org.bouncycastle:bc-fips:2.0.0")
runtimeOnly("org.bouncycastle:bcpkix-fips:2.0.7")
runtimeOnly("org.bouncycastle:bctls-fips:2.0.19")
runtimeOnly("org.bouncycastle:bcutil-fips:2.0.3")
implementation('org.reflections:reflections:0.10.2') {
exclude group: 'com.google.guava', module: 'guava'
}
Expand Down
31 changes: 31 additions & 0 deletions x-pack/distributions/internal/observabilitySRE/build-ext.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
ext {
runTestsInFIPSMode = project.hasProperty('runTestsInFIPSMode') ? project.property('runTestsInFIPSMode').toBoolean() : false
}

subprojects {
ext {
runTestsInFIPSMode = rootProject.runTestsInFIPSMode
}
}

allprojects {
afterEvaluate {
tasks.withType(Test) {
if (runTestsInFIPSMode) {
logger.debug("configuring ${it} to run in FIPSMode ")
systemProperty "java.security.properties", System.getenv("JAVA_SECURITY_PROPERTIES")
systemProperty "javax.net.ssl.keyStore", "/etc/java/security/keystore.bcfks"
systemProperty "javax.net.ssl.keyStoreType", "BCFKS"
systemProperty "javax.net.ssl.keyStoreProvider", "BCFIPS"
systemProperty "javax.net.ssl.keyStorePassword", "changeit"
systemProperty "javax.net.ssl.trustStore", "/etc/java/security/cacerts.bcfks"
systemProperty "javax.net.ssl.trustStoreType", "BCFKS"
systemProperty "javax.net.ssl.trustStoreProvider", "BCFIPS"
systemProperty "javax.net.ssl.trustStorePassword", "changeit"
systemProperty "ssl.KeyManagerFactory.algorithm", "PKIX"
systemProperty "ssl.TrustManagerFactory.algorithm", "PKIX"
systemProperty "org.bouncycastle.fips.approved_only", "true"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
grant {
// Your existing permissions
permission java.lang.PropertyPermission "java.runtime.name", "read";
permission java.lang.RuntimePermission "accessClassInPackage.sun.security.internal.spec";
permission java.lang.RuntimePermission "getProtectionDomain";
permission java.lang.RuntimePermission "accessDeclaredMembers";
permission org.bouncycastle.crypto.CryptoServicesPermission "tlsAlgorithmsEnabled";
permission org.bouncycastle.crypto.CryptoServicesPermission "exportKeys";

// Add provider permissions
permission java.security.SecurityPermission "putProviderProperty.BCFIPS";
permission java.security.SecurityPermission "insertProvider.BCFIPS";
permission java.security.SecurityPermission "putProviderProperty.BCJSSE";
permission java.security.SecurityPermission "insertProvider.BCJSSE";
};

deny {
permission java.security.SecurityPermission "putProviderProperty.BC";
permission java.security.SecurityPermission "insertProvider.BC";
permission java.security.SecurityPermission "removeProvider.BC";
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
security.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider
security.provider.2=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider fips:BCFIPS
security.provider.3=SUN
security.provider.11=-BC

securerandom.source=file:/dev/random
securerandom.strongAlgorithms=NativePRNGBlocking:SUN,DRBG:SUN
securerandom.drbg.config=

login.configuration.provider=sun.security.provider.ConfigFile

policy.provider=sun.security.provider.PolicyFile
policy.url.1=file:/etc/java/security/java.policy
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

sun.security.krb5.disableReferrals=false
sun.security.krb5.maxReferrals=5

jdk.disabled.namedCurves = secp112r1, secp112r2, secp128r1, secp128r2, \
secp160k1, secp160r1, secp160r2, secp192k1, secp192r1, secp224k1, \
secp224r1, secp256k1, sect113r1, sect113r2, sect131r1, sect131r2, \
sect163k1, sect163r1, sect163r2, sect193r1, sect193r2, sect233k1, \
sect233r1, sect239k1, sect283k1, sect283r1, sect409k1, sect409r1, \
sect571k1, sect571r1, X9.62 c2tnb191v1, X9.62 c2tnb191v2, \
X9.62 c2tnb191v3, X9.62 c2tnb239v1, X9.62 c2tnb239v2, X9.62 c2tnb239v3, \
X9.62 c2tnb359v1, X9.62 c2tnb431r1, X9.62 prime192v2, X9.62 prime192v3, \
X9.62 prime239v1, X9.62 prime239v2, X9.62 prime239v3, brainpoolP256r1, \
brainpoolP320r1, brainpoolP384r1, brainpoolP512r1

jdk.certpath.disabledAlgorithms=MD2, MD5, \
RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224, \
SHA1, \
secp112r1, secp112r2, secp128r1, secp128r2, \
secp160k1, secp160r1, secp160r2, secp192k1, secp192r1, secp224k1, \
secp224r1, secp256k1, sect113r1, sect113r2, sect131r1, sect131r2, \
sect163k1, sect163r1, sect163r2, sect193r1, sect193r2, sect233k1, \
sect233r1, sect239k1, sect283k1, sect283r1, sect409k1, sect409r1, \
sect571k1, sect571r1, \
brainpoolP256r1, brainpoolP320r1, brainpoolP384r1, brainpoolP512r1

jdk.security.legacyAlgorithms=SHA1, \
RSA keySize < 2048, DSA keySize < 2048

jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
DSA keySize < 1024, SHA1, \
secp112r1, secp112r2, secp128r1, secp128r2, \
secp160k1, secp160r1, secp160r2, secp192k1, secp192r1, secp224k1, \
secp224r1, secp256k1, sect113r1, sect113r2, sect131r1, sect131r2, \
sect163k1, sect163r1, sect163r2, sect193r1, sect193r2, sect233k1, \
sect233r1, sect239k1, sect283k1, sect283r1, sect409k1, sect409r1, \
sect571k1, sect571r1, X9.62 c2tnb191v1, X9.62 c2tnb191v2, \
X9.62 c2tnb191v3, X9.62 c2tnb239v1, X9.62 c2tnb239v2, X9.62 c2tnb239v3, \
X9.62 c2tnb359v1, X9.62 c2tnb431r1, X9.62 prime192v2, X9.62 prime192v3, \
X9.62 prime239v1, X9.62 prime239v2, X9.62 prime239v3, brainpoolP256r1, \
brainpoolP320r1, brainpoolP384r1, brainpoolP512r1

jdk.tls.disabledAlgorithms=MD5, SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \
DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \
secp112r1, secp112r2, secp128r1, secp128r2, \
secp160k1, secp160r1, secp160r2, secp192k1, secp192r1, secp224k1, \
secp224r1, secp256k1, sect113r1, sect113r2, sect131r1, sect131r2, \
sect163k1, sect163r1, sect163r2, sect193r1, sect193r2, sect233k1, \
sect233r1, sect239k1, sect283k1, sect283r1, sect409k1, sect409r1, \
sect571k1, sect571r1, brainpoolP256r1, \
brainpoolP320r1, brainpoolP384r1, brainpoolP512r1
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, \
ChaCha20-Poly1305 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;!*

jdk.sasl.disabledMechanisms=CRAM-MD5, DIGEST-MD5
jdk.security.caDistrustPolicies=SYMANTEC_TLS
jdk.io.permissionsUseCanonicalPath=false

jdk.tls.alpnCharset=ISO_8859_1

org.bouncycastle.fips.approved_only=true
72 changes: 72 additions & 0 deletions x-pack/distributions/internal/observabilitySRE/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Start from the FIPS-compliant base image
FROM docker.elastic.co/wolfi/chainguard-base-fips:latest

# Install OpenJDK 21
RUN apk add --no-cache \
openjdk-21 \
bash \
git

# Create directory for security configuration
RUN mkdir -p /etc/java/security
RUN mkdir -p /root/.gradle

# Copy configuration files
COPY x-pack/distributions/internal/observabilitySRE/config/security/java.security /etc/java/security/
COPY x-pack/distributions/internal/observabilitySRE/config/security/java.policy /etc/java/security/

# Set environment variables
ENV JAVA_HOME=/usr/lib/jvm/java-21-openjdk
ENV PATH="${JAVA_HOME}/bin:${PATH}"

# Create working directory
WORKDIR /logstash

# Copy the local Logstash source
COPY . .

# Initial build using JKS truststore
RUN ./gradlew clean bootstrap assemble installDefaultGems

# Convert JKS to BCFKS for truststore and keystore
RUN keytool -importkeystore \
-srckeystore $JAVA_HOME/lib/security/cacerts \
-destkeystore /etc/java/security/cacerts.bcfks \
-srcstoretype jks \
-deststoretype bcfks \
-providerpath /logstash/logstash-core/lib/jars/bc-fips-2.0.0.jar \
-provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider \
-deststorepass changeit \
-srcstorepass changeit \
-noprompt

RUN keytool -importkeystore \
-srckeystore $JAVA_HOME/lib/security/cacerts \
-destkeystore /etc/java/security/keystore.bcfks \
-srcstoretype jks \
-deststoretype bcfks \
-providerpath /logstash/logstash-core/lib/jars/bc-fips-2.0.0.jar \
-provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider \
-deststorepass changeit \
-srcstorepass changeit \
-noprompt

ENV JAVA_SECURITY_PROPERTIES=/etc/java/security/java.security
ENV LS_JAVA_OPTS="\
-Dio.netty.ssl.provider=JDK \
-Djava.security.debug=ssl,provider,certpath \
-Djava.security.properties=${JAVA_SECURITY_PROPERTIES} \
-Djavax.net.ssl.keyStore=/etc/java/security/keystore.bcfks \
-Djavax.net.ssl.keyStoreType=BCFKS \
-Djavax.net.ssl.keyStoreProvider=BCFIPS \
-Djavax.net.ssl.keyStorePassword=changeit \
-Djavax.net.ssl.trustStore=/etc/java/security/cacerts.bcfks \
-Djavax.net.ssl.trustStoreType=BCFKS \
-Djavax.net.ssl.trustStoreProvider=BCFIPS \
-Djavax.net.ssl.trustStorePassword=changeit \
-Dssl.KeyManagerFactory.algorithm=PKIX \
-Dssl.TrustManagerFactory.algorithm=PKIX \
-Dorg.bouncycastle.fips.approved_only=true"

# Example test run, most use cases will override this
CMD ["./gradlew", "--info", "--stacktrace", "-PrunTestsInFIPSMode=true", "runIntegrationTests"]

0 comments on commit bedc706

Please sign in to comment.