FIPS Enabling the FOSS Puppet Server
Intro
This is primarily a running log for anyone that needs to FIPS-enable the FOSS version of Puppet. Pull Requests are most welcome if things change over time.
This article targets RHEL systems but should generally be suitable on any platform.
Initial Setup
-
FIPS enable your system
- Do NOT try to do this after you have installed and configured your system. Things tend to go poorly over time unless this is the first step.
- If you are running in a
podman
hosted container on an already FIPS’d RHEL system, you just need to runfips-mode-setup --enable
- Install the puppet server
- Run:
/opt/puppetlabs/bin/puppetserver ca setup
The Problem
At this point, if you run /opt/puppetlabs/bin/puppetserver foreground
, you
will be presented with the following error:
Execution error (NoSuchAlgorithmException) at java.security.KeyPairGenerator/getInstance (KeyPairGenerator.java:218).
RSA KeyPairGenerator not available
Full stacktrace
ERROR [async-dispatch-2] [p.t.internal] Error during service init!!!
java.security.NoSuchAlgorithmException: RSA KeyPairGenerator not available
at java.security.KeyPairGenerator.getInstance(KeyPairGenerator.java:218)
at com.puppetlabs.ssl_utils.SSLUtils.generateKeyPair(SSLUtils.java:154)
at puppetlabs.ssl_utils.core$fn__21552$generate_key_pair__21561$fn__21564.invoke(core.clj:522)
at puppetlabs.ssl_utils.core$fn__21552$generate_key_pair__21561.invoke(core.clj:517)
at puppetlabs.puppetserver.certificate_authority$fn__37524$generate_ssl_files_BANG___37529$fn__37530.invoke(certificate_authority.clj:708)
at puppetlabs.puppetserver.certificate_authority$fn__37524$generate_ssl_files_BANG___37529.invoke(certificate_authority.clj:695)
at puppetlabs.puppetserver.certificate_authority$fn__38749$initialize_BANG___38754$fn__38755.invoke(certificate_authority.clj:1565)
at puppetlabs.puppetserver.certificate_authority$fn__38749$initialize_BANG___38754.invoke(certificate_authority.clj:1544)
at puppetlabs.services.ca.certificate_authority_service$reify__43837$service_fnk__5324__auto___positional$reify__43852.init(certificate_authority_service.clj:36)
at puppetlabs.trapperkeeper.services$fn__5148$G__5140__5151.invoke(services.clj:9)
at puppetlabs.trapperkeeper.services$fn__5148$G__5139__5155.invoke(services.clj:9)
at puppetlabs.trapperkeeper.internal$fn__14387$run_lifecycle_fn_BANG___14394$fn__14395.invoke(internal.clj:196)
at puppetlabs.trapperkeeper.internal$fn__14387$run_lifecycle_fn_BANG___14394.invoke(internal.clj:179)
at puppetlabs.trapperkeeper.internal$fn__14416$run_lifecycle_fns__14421$fn__14422.invoke(internal.clj:229)
at puppetlabs.trapperkeeper.internal$fn__14416$run_lifecycle_fns__14421.invoke(internal.clj:206)
at puppetlabs.trapperkeeper.internal$fn__15041$build_app_STAR___15050$fn$reify__15062.init(internal.clj:614)
at puppetlabs.trapperkeeper.internal$fn__15091$boot_services_for_app_STAR__STAR___15098$fn__15099$fn__15101.invoke(internal.clj:648)
at puppetlabs.trapperkeeper.internal$fn__15091$boot_services_for_app_STAR__STAR___15098$fn__15099.invoke(internal.clj:647)
at puppetlabs.trapperkeeper.internal$fn__15091$boot_services_for_app_STAR__STAR___15098.invoke(internal.clj:641)
at clojure.core$partial$fn__5910.invoke(core.clj:2647)
at puppetlabs.trapperkeeper.internal$fn__14461$initialize_lifecycle_worker__14472$fn__14473$fn__14636$state_machine__11695__auto____14661$fn__14664.invoke(internal.clj:249)
at puppetlabs.trapperkeeper.internal$fn__14461$initialize_lifecycle_worker__14472$fn__14473$fn__14636$state_machine__11695__auto____14661.invoke(internal.clj:249)
at clojure.core.async.impl.ioc_macros$run_state_machine.invokeStatic(ioc_macros.clj:978)
at clojure.core.async.impl.ioc_macros$run_state_machine.invoke(ioc_macros.clj:977)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invokeStatic(ioc_macros.clj:982)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invoke(ioc_macros.clj:980)
at clojure.core.async$ioc_alts_BANG_$fn__11924.invoke(async.clj:421)
at clojure.core.async$do_alts$fn__11863$fn__11866.invoke(async.clj:288)
at clojure.core.async.impl.channels.ManyToManyChannel$fn__6536$fn__6537.invoke(channels.clj:99)
at clojure.lang.AFn.run(AFn.java:22)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at clojure.core.async.impl.concurrent$counted_thread_factory$reify__6439$fn__6440.invoke(concurrent.clj:29)
at clojure.lang.AFn.run(AFn.java:22)
at java.lang.Thread.run(Thread.java:750)
This is due to the fact that the puppetserver
has been compiled against the
BouncyCastle
libraries whereas the system is attempting to force the use of the RHEL-native
FIPS libraries.
The Solution
To remedy the issue, we need to ensure that the puppetserver
has access to the
BouncyCastle FIPS
libraries and is properly configured to use them.
Download the BouncyCastle FIPS Libraries
Grab the latest versions available at the time and please
donate to
the BouncyCastle project if you can!
FOSS is expensive and time consuming to support!
cd /opt/puppetlabs/server/data/puppetserver/jars
curl -LO https://downloads.bouncycastle.org/fips-java/bc-fips-1.0.2.4.jar
curl -LO https://downloads.bouncycastle.org/fips-java/bcpkix-fips-1.0.7.jar
curl -LO https://downloads.bouncycastle.org/fips-java/bctls-fips-1.0.18.jar
- Verify the checksums
At this point, the BouncyCastle FIPS libraries are loaded into the server’s classpath but you’ll hit another issue when you try to start the server:
Execution error (SecurityException) at java.net.URLClassLoader/getAndVerifyPackage (URLClassLoader.java:412).
sealing violation: can't seal package org.bouncycastle.crypto: already loaded
This means that there is a baked-in version of the BouncyCastle libraries in the
puppetserver
uber-jar that we need to replace.
Surgery
Now to get our hands dirty and mod the puppetserver
JAR itself.
You’ll need the
jar
command for this so you may want to do it on a different system withjava-devel
installed.
cd /opt/puppetlabs/server/apps/puppetserver
mkdir tmp
cd tmp
jar -xvf ../puppet-server-release.jar
find . -name bouncycastle -exec rm -rf {} \;
jar -cf ../puppet-server-release.jar *
cd ..
rm -rf tmp
If you’ve done everything properly, now when you run
/opt/puppetlabs/bin/puppetserver foreground
, you will get the following error:
Execution error (NoSuchAlgorithmException) at sun.security.jca.GetInstance/getInstance (GetInstance.java:159).
BCFKS KeyStore not available
Set Up a New Security Policy
Our issue is now that the puppetserver
is still using the system
java.security
policy without any overrides that tell it to use the
BouncyCastle FIPS library.
mkdir /etc/sysconfig/puppetserver-properties
-
Add the following to
/etc/sysconfig/puppetserver-properties/java.security
security.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider security.provider.2=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider BCFIPS security.provider.3=com.sun.net.ssl.internal.ssl.Provider BCFIPS security.provider.4=sun.security.provider.Sun security.provider.5=sun.security.ec.SunEC security.provider.6= fips.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider fips.provider.2=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider BCFIPS fips.provider.3=com.sun.net.ssl.internal.ssl.Provider BCFIPS fips.provider.4=sun.security.provider.Sun fips.provider.5=sun.security.ec.SunEC fips.provider.6=
You may now see a warning that says
invalid entry for security.provider.6
.
Everything is fine
We’re using this to ensure that no other providers are loaded afterwards. - Add the following to the
JAVA_ARGS
line (inside the double quotes) in-
-Djava.security.properties=/etc/sysconfig/puppetserver-properties/java.security
- Points to the new
java.security
file
- Points to the new
-
-Dorg.bouncycastle.fips.approved_only=true
- Ensures that we limit BouncyCastle FIPS to only using approved algorithms
-
Regenerate All Certificates
You’ll need to regenerate all certificates to ensure that everything is generated using the FIPS libraries.
rm -rf /etc/puppetlabs/puppetserver/ca
rm -rf /etc/puppetlabs/puppet/ssl/*
/opt/puppetlabs/bin/puppetserver ca setup
And You’re Off
Simply run systemctl restart puppetserver
and you should be good to go!