This is a guest post written by Drew Varner. It originally appeared on the NineFX blog, and has been republished here with his permission. We hope you enjoy!.
NineFX, a HUBZone/SDVOSB-certified, value-added reseller for CircleCI, supports both commercial and federal government customers. The software that we ship to our federal customers must meet specific regulatory requirements from the National Institute of Standards & Technology (NIST). NIST’s Federal Information Processing Standard (FIPS) 140-2 is the standard that governs cryptographic modules in federal software.
Because we service both commercial and federal customers, in this post I will describe how we use CircleCI workflows to provide timely feedback on our software’s support of FIPS 140-2 cryptography, enabling us to monitor a project’s FIPS compatibility.
We are currently developing Shuttlebus, a TAXII/STIX 2 Cyber Threat Intelligence server targeting federal and commercial clients. For federal environments, Shuttlebus has to support Erlang’s crypto module with FIPS 140-2 enabled. For commercial environments, where FIPS 140-2 is not available, it has to support the module with FIPS 140-2 disabled. CircleCI’s workflow functionality allows us to evaluate Shuttlebus’ FIPS-mode compatibility on every GitHub push, concurrently with other steps in our build process.
The following snippet from our
.circleci/config.yml shows the three default configurations we use in our workflows, defined with YAML anchors (
defaults: &defaults working_directory: /home/circleci/shuttlebus docker: - image: elixir environment: MIX_ENV: test test_defaults: &test_defaults working_directory: /home/circleci/shuttlebus docker: - image: elixir environment: MIX_ENV: test - image: circleci/postgres:10.1-alpine environment: POSTGRES_USER: someuser POSTGRES_PASSWORD: somepassword POSTGRES_DB: shuttlebus fips_defaults: &fips_defaults working_directory: /home/circleci/shuttlebus_fips docker: - image: us.gcr.io/ninefx/elixir-fips environment: MIX_ENV: fips - image: circleci/postgres:10.1-alpine environment: POSTGRES_USER: user POSTGRES_PASSWORD: somepassword POSTGRES_DB: shuttlebus
We use the standard Elixir container compilation, static code analysis, and other jobs. For our FIPS-enabled cryptography job, we use our own custom Elixir Docker image built with a FIPS-enabled OpenSSL library. We host the image in a private registry on Google Container Registry (GCR). We build these images according to the OpenSSL FIPS 140-2 Security Policy. We run our FIPS build in a separate directory to avoid collisions with persisted data after attaching a workspace from an upstream container.
Our workflow executes the standard tasks of compilation, testing, and code coverage analysis. It includes multiple forms of static code checks including linting, success typing, format verification and cross-reference analysis. It also checks dependencies to see if updated versions are available in the package manager.
fips task combines compilation and testing. We specify the FIPS defaults in the CircleCI
config.yaml using YAML’s extend (
fips: <<: *fips_defaults steps: - checkout - run: mix local.hex --force - run: mix local.rebar --force - run: name: Deps command: mix deps.get - run: name: Migrate DB command: mix ecto.migrate -r ShuttlebusEcto.Repo - run: name: Seed DB command: mix run priv/repo/test_seeds.exs - run: name: FIPS Test command: mix test
fips job, we can verify that the underlying
crypto module is operating in FIPS mode by examining captured log output in the CircleCI console:
mix test 15:44:56.272 [warn] FIPS mode :enabled 15:44:56.282 [info] starting shuttlebus with options [port: 8443, certfile: "/home/circleci/shuttlebus_fips/_build/fips/lib/shuttlebus/priv/cert.pem", keyfile: "/home/circleci/shuttlebus_fips/_build/fips/lib/shuttlebus/priv/key.pem", connections: 1000] 15:44:56.317 [info] Serving securely using HTTP/1 and HTTP/2 on port 8443 ...
It’s clear from the output in our normal test job that FIPS is not enabled when running on a container where OpenSSL is not compiled with FIPS support:
15:44:02.201 [warn] FIPS mode :not_supported 15:44:02.214 [info] starting shuttlebus with options [port: 8443, certfile: "/home/circleci/shuttlebus/_build/test/lib/shuttlebus/priv/cert.pem", keyfile: "/home/circleci/shuttlebus/_build/test/lib/shuttlebus/priv/key.pem", connections: 1000] 15:44:02.259 [info] Serving securely using HTTP/1 and HTTP/2 on port 8443 ...
For more information about how we created our custom container, we provide examples of how to configure OpenSSL, Erlang, and Elixir for FIPS 140-2 operation in Docker Hub. They are an excellent introduction to configuring your containers with OpenSSL in FIPS mode. These can be used by those who wish to check for FIPS 140-2 compatibility, however, the images built by our Docker Hub examples are not FIPS 140-2 compliant because they are not built according to the Security Officer instructions for OpenSSL, which specifies:
Any deviation from specified verification, protection, installation and initialization procedures will result in a non-FIPS 140-2 compliant module.
Automating FIPS testing as a workflow job means it can run concurrently with other build tasks. This concurrency provides faster feedback to developers on their code changes. It provides developers with confidence that their changes will work if FIPS or non-FIPS cryptography is used. The best part is that it provides assurances throughout the development process, as opposed to manual compliance checks just before a product or patch release.
NineFX is a HUBZone/SDVOSB-certified, value-added reseller for CircleCI. If you would like CircleCI consulting specific to US Federal markets or FIPS 140-2, contact us.
A software developer with over 15 years of experience, Drew Varner founded NineFX, a HUBZone/SDVOSB firm delivering innovative software solutions to commercial and Federal customers. He’s a veteran of the US Army and addicted to functional programming.