From 5b626231d99e686b3a3797aaf7fd46a1cf60f578 Mon Sep 17 00:00:00 2001 From: rmartinc Date: Thu, 9 Feb 2023 10:14:20 +0100 Subject: [PATCH] Doublecheck if real FIPS host available in GH actions Closes https://github.com/keycloak/keycloak/issues/15069 --- .github/fake_fips/Makefile | 6 ++ .github/fake_fips/fake_fips.c | 72 +++++++++++++++++++ .github/scripts/run-fips-it.sh | 17 +++++ .github/scripts/run-fips-ut.sh | 15 ++++ .github/workflows/ci.yml | 31 ++++---- .../java/org/keycloak/common/ProfileTest.java | 16 ++++- 6 files changed, 142 insertions(+), 15 deletions(-) create mode 100644 .github/fake_fips/Makefile create mode 100644 .github/fake_fips/fake_fips.c create mode 100755 .github/scripts/run-fips-it.sh create mode 100755 .github/scripts/run-fips-ut.sh diff --git a/.github/fake_fips/Makefile b/.github/fake_fips/Makefile new file mode 100644 index 0000000000..7d08538330 --- /dev/null +++ b/.github/fake_fips/Makefile @@ -0,0 +1,6 @@ +obj-m = fake_fips.o +KVERSION = $(shell uname -r) +all: + make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules +clean: + make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean diff --git a/.github/fake_fips/fake_fips.c b/.github/fake_fips/fake_fips.c new file mode 100644 index 0000000000..207a4a5c7d --- /dev/null +++ b/.github/fake_fips/fake_fips.c @@ -0,0 +1,72 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * https://github.com/torvalds/linux/blob/master/crypto/fips.c + * https://pointer-overloading.blogspot.com/2013/09/linux-creating-entry-in-proc-file.html + */ + +#include +#include + +int fips_enabled = 1; + +static struct ctl_table crypto_sysctl_table[] = { + { + .procname = "fips_enabled", + .data = &fips_enabled, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = proc_dointvec + }, + {} +}; +static struct ctl_table crypto_dir_table[] = { + { + .procname = "crypto", + .mode = 0555, + .child = crypto_sysctl_table + }, + {} +}; + +static struct ctl_table_header *crypto_sysctls; + +static void crypto_proc_fips_init(void) +{ + crypto_sysctls = register_sysctl_table(crypto_dir_table); +} + +static void crypto_proc_fips_exit(void) +{ + unregister_sysctl_table(crypto_sysctls); +} + +static int __init fips_init(void) +{ + crypto_proc_fips_init(); + return 0; +} + +static void __exit fips_exit(void) +{ + crypto_proc_fips_exit(); +} + +MODULE_LICENSE("GPL"); +subsys_initcall(fips_init); +module_exit(fips_exit); diff --git a/.github/scripts/run-fips-it.sh b/.github/scripts/run-fips-it.sh new file mode 100755 index 0000000000..462ebf4bef --- /dev/null +++ b/.github/scripts/run-fips-it.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +dnf install -y java-17-openjdk-devel crypto-policies-scripts +fips-mode-setup --enable --no-bootcfg +fips-mode-setup --is-enabled +if [ $? -ne 0 ]; then + exit 1 +fi +STRICT_OPTIONS="" +if [ "$1" = "strict" ]; then + STRICT_OPTIONS="-Dauth.server.fips.mode=strict -Dauth.server.supported.keystore.types=BCFKS -Dauth.server.keystore.type=bcfks -Dauth.server.supported.rsa.key.sizes=2048,4096" +fi +echo "STRICT_OPTIONS: $STRICT_OPTIONS" +TESTS=`testsuite/integration-arquillian/tests/base/testsuites/suite.sh fips` +echo "Tests: $TESTS" +export JAVA_HOME=/etc/alternatives/java_sdk_17 +./mvnw test -Dsurefire.rerunFailingTestsCount=$SUREFIRE_RERUN_FAILING_COUNT -nsu -B -Pauth-server-quarkus,auth-server-fips140-2 -Dcom.redhat.fips=false $STRICT_OPTIONS -Dtest=$TESTS -pl testsuite/integration-arquillian/tests/base | misc/log/trimmer.sh diff --git a/.github/scripts/run-fips-ut.sh b/.github/scripts/run-fips-ut.sh new file mode 100755 index 0000000000..d5ed8b0487 --- /dev/null +++ b/.github/scripts/run-fips-ut.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +dnf install -y java-17-openjdk-devel crypto-policies-scripts +fips-mode-setup --enable --no-bootcfg +fips-mode-setup --is-enabled +if [ $? -ne 0 ]; then + exit 1 +fi +echo "fips.provider.7=XMLDSig" >>/etc/alternatives/java_sdk_17/conf/security/java.security +export JAVA_HOME=/etc/alternatives/java_sdk_17 +./mvnw test -nsu -B -am -pl crypto/default,crypto/fips1402 -Dcom.redhat.fips=true +if [ $? -ne 0 ]; then + exit 1 +fi +./mvnw test -nsu -B -am -pl crypto/default,crypto/fips1402 -Dcom.redhat.fips=true -Dorg.bouncycastle.fips.approved_only=true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36acb88a44..f88b6ab4eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -390,15 +390,20 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Fake fips + run: | + cd .github/fake_fips + make + sudo insmod fake_fips.ko + - id: unit-test-setup name: Unit test setup uses: ./.github/actions/unit-test-setup + with: + jdk-version: 17 - - name: Run crypto tests (BCFIPS non-approved mode) - run: ./mvnw test -nsu -B -am -pl crypto/default,crypto/fips1402,crypto/elytron -Dcom.redhat.fips=true - - - name: Run crypto tests (BCFIPS approved mode) - run: ./mvnw test -nsu -B -am -pl crypto/default,crypto/fips1402,crypto/elytron -Dcom.redhat.fips=true -Dorg.bouncycastle.fips.approved_only=true + - name: Run crypto tests + run: docker run --rm --workdir /github/workspace -v "${{ github.workspace }}":"/github/workspace" -v "$HOME/.m2":"/root/.m2" registry.access.redhat.com/ubi8/ubi:latest .github/scripts/run-fips-ut.sh - name: Upload JVM Heapdumps if: always() @@ -424,21 +429,23 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Fake fips + run: | + cd .github/fake_fips + make + sudo insmod fake_fips.ko + - id: integration-test-setup name: Integration test setup uses: ./.github/actions/integration-test-setup + with: + jdk-version: 17 - name: Prepare Quarkus distribution with BCFIPS run: ./mvnw install -nsu -B -e -pl testsuite/integration-arquillian/servers/auth-server/quarkus -Pauth-server-quarkus,auth-server-fips140-2 - name: Run base tests - run: | - declare -A PARAMS - PARAMS["non-strict"]="" - PARAMS["strict"]="-Dauth.server.fips.mode=strict -Dauth.server.supported.keystore.types=BCFKS -Dauth.server.keystore.type=bcfks -Dauth.server.supported.rsa.key.sizes=2048,4096" - TESTS=`testsuite/integration-arquillian/tests/base/testsuites/suite.sh fips` - echo "Tests: $TESTS" - ./mvnw test -Dsurefire.rerunFailingTestsCount=${{ env.SUREFIRE_RERUN_FAILING_COUNT }} -nsu -B -Pauth-server-quarkus,auth-server-fips140-2 ${PARAMS["${{ matrix.mode }}"]} -Dtest=$TESTS -pl testsuite/integration-arquillian/tests/base | misc/log/trimmer.sh + run: docker run --rm --workdir /github/workspace -e "SUREFIRE_RERUN_FAILING_COUNT" -v "${{ github.workspace }}":"/github/workspace" -v "$HOME/.m2":"/root/.m2" registry.access.redhat.com/ubi8/ubi:latest .github/scripts/run-fips-it.sh ${{ matrix.mode }} - name: Upload JVM Heapdumps if: always() diff --git a/common/src/test/java/org/keycloak/common/ProfileTest.java b/common/src/test/java/org/keycloak/common/ProfileTest.java index cb8f64cc9b..0aeb196a8f 100644 --- a/common/src/test/java/org/keycloak/common/ProfileTest.java +++ b/common/src/test/java/org/keycloak/common/ProfileTest.java @@ -11,13 +11,14 @@ import org.keycloak.common.profile.ProfileException; import org.keycloak.common.profile.PropertiesFileProfileConfigResolver; import org.keycloak.common.profile.PropertiesProfileConfigResolver; -import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; +import java.util.Collection; import java.util.Comparator; +import java.util.HashSet; import java.util.Properties; import java.util.Set; @@ -69,7 +70,12 @@ public class ProfileTest { } Assert.assertEquals(Profile.ProfileName.DEFAULT, profile.getName()); - assertEquals(profile.getDisabledFeatures(), Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.DYNAMIC_SCOPES, Profile.Feature.DOCKER, Profile.Feature.RECOVERY_CODES, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.OPENSHIFT_INTEGRATION, Profile.Feature.MAP_STORAGE, Profile.Feature.DECLARATIVE_USER_PROFILE, Profile.Feature.CLIENT_SECRET_ROTATION, Profile.Feature.UPDATE_EMAIL); + Set disabledFeatutes = new HashSet<>(Arrays.asList(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.DYNAMIC_SCOPES, Profile.Feature.DOCKER, Profile.Feature.RECOVERY_CODES, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.OPENSHIFT_INTEGRATION, Profile.Feature.MAP_STORAGE, Profile.Feature.DECLARATIVE_USER_PROFILE, Profile.Feature.CLIENT_SECRET_ROTATION, Profile.Feature.UPDATE_EMAIL)); + // KERBEROS can be disabled (i.e. FIPS mode disables SunJGSS provider) + if (Profile.Feature.KERBEROS.getType() == Profile.Feature.Type.DISABLED_BY_DEFAULT) { + disabledFeatutes.add(Profile.Feature.KERBEROS); + } + assertEquals(profile.getDisabledFeatures(), disabledFeatutes); assertEquals(profile.getPreviewFeatures(), Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.RECOVERY_CODES, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.OPENSHIFT_INTEGRATION, Profile.Feature.DECLARATIVE_USER_PROFILE, Profile.Feature.CLIENT_SECRET_ROTATION, Profile.Feature.UPDATE_EMAIL); } @@ -226,8 +232,12 @@ public class ProfileTest { Assert.assertTrue(Profile.isFeatureEnabled(PREVIEW_FEATURE)); } + public static void assertEquals(Set actual, Collection expected) { + assertEquals(actual, expected.toArray(new Profile.Feature[0])); + } + public static void assertEquals(Set actual, Profile.Feature... expected) { - Profile.Feature[] a = actual.toArray(new Profile.Feature[actual.size()]); + Profile.Feature[] a = actual.toArray(new Profile.Feature[0]); Arrays.sort(a, new FeatureComparator()); Arrays.sort(expected, new FeatureComparator()); Assert.assertArrayEquals(a, expected);