FIPS 140 Compliance#

FIPS 140 (Federal Information Processing Standard 140) is a US and Canadian government standard for cryptographic modules. If you sell software to US federal agencies, process federal data, or operate under FedRAMP, you must use FIPS 140-validated cryptographic modules. Many regulated industries (finance, healthcare, defense) also require or strongly prefer FIPS compliance.

FIPS 140 does not tell you which algorithms to use — it validates that a specific implementation of those algorithms has been tested and certified by an accredited lab (CMVP — Cryptographic Module Validation Program).

FIPS 140-2 vs FIPS 140-3#

FIPS 140-2 was the standard from 2001 to 2022. FIPS 140-3 replaced it. Key differences:

Aspect FIPS 140-2 FIPS 140-3
Status No new validations accepted after 2022 Current standard
Basis Standalone spec Based on ISO/IEC 19790 and 24759
Security levels 1-4 1-4 (aligned with ISO)
Testing CMVP labs Same CMVP labs, updated test requirements
Transition Existing validations remain valid until sunset New submissions must target 140-3

Most existing FIPS-validated modules were certified under 140-2. These remain valid until their certificate’s sunset date. New modules must target 140-3.

For practical purposes as a developer: you need to use a cryptographic module that has an active CMVP validation certificate. Whether it is 140-2 or 140-3 depends on when it was validated.

What FIPS Compliance Means in Practice#

FIPS compliance is not about your application code directly. It is about the cryptographic library your application uses. Specifically:

  1. All cryptographic operations (encryption, hashing, signing, key generation, random number generation, TLS handshakes) must go through a FIPS-validated module.
  2. The module must operate in FIPS mode, which disables non-approved algorithms.
  3. You must be able to demonstrate that your application uses the validated module and does not bypass it.

Approved Algorithms (FIPS Mode)#

When a cryptographic module runs in FIPS mode, only approved algorithms are available:

Function Approved Not Approved in FIPS
Symmetric encryption AES-128, AES-192, AES-256 (GCM, CBC, CTR) Blowfish, DES, 3DES (deprecated), RC4, ChaCha20
Hashing SHA-256, SHA-384, SHA-512, SHA-3 MD5, SHA-1 (signing only deprecated)
Asymmetric encryption RSA (2048+), ECDSA (P-256, P-384, P-521) RSA < 2048, Ed25519, X25519
Key exchange ECDH (P-256, P-384), DH (2048+) X25519, X448
MAC HMAC-SHA-256, CMAC-AES Poly1305
RNG SP 800-90A DRBG (CTR_DRBG, Hash_DRBG, HMAC_DRBG) /dev/urandom directly (must seed DRBG)
TLS TLS 1.2, TLS 1.3 (with approved cipher suites) TLS 1.0, TLS 1.1

Important: Ed25519 and ChaCha20-Poly1305 are widely used in modern systems (WireGuard, SSH, etc.) but are not currently FIPS-approved. This is a common source of compliance failures.

FIPS TLS Cipher Suites#

In FIPS mode, only these TLS cipher suites are available:

# TLS 1.2 (FIPS-approved)
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384

# TLS 1.3 (FIPS-approved)
TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384

TLS 1.3’s TLS_CHACHA20_POLY1305_SHA256 is not FIPS-approved.

FIPS in Go#

Go’s standard crypto package is not FIPS-validated. For FIPS compliance, you have two options:

Microsoft Go (go-crypto-fips)#

Microsoft maintains a Go fork that uses BoringCrypto (Google’s FIPS-validated module) for all cryptographic operations:

# Use Microsoft's Go toolchain
go install golang.org/dl/gotip@latest
# Or use the microsoft/go fork directly

When built with the goexperiment tag for BoringCrypto, Go uses BoringSSL’s FIPS-validated module instead of the standard Go crypto:

# Build with BoringCrypto
GOEXPERIMENT=boringcrypto go build -o myapp ./cmd/myapp

Verify FIPS mode is active:

import "crypto/boring"

func init() {
    if !boring.Enabled() {
        log.Fatal("FIPS mode (BoringCrypto) is not enabled")
    }
}

When BoringCrypto is enabled, the standard Go crypto packages automatically delegate to BoringSSL. Your application code does not need to change — crypto/tls, crypto/aes, crypto/sha256 all use the FIPS-validated module transparently.

Red Hat Go Toolset#

Red Hat provides a Go toolchain with OpenSSL FIPS integration:

FROM registry.access.redhat.com/ubi9/go-toolset:latest AS builder
COPY . .
RUN go build -tags strictfipsruntime -o /app ./cmd/myapp

This links against the FIPS-validated OpenSSL module on the RHEL/UBI base image.

FIPS in Python#

Python’s standard hashlib and ssl modules use OpenSSL under the hood. FIPS compliance depends on the underlying OpenSSL library being FIPS-validated and running in FIPS mode.

Using OpenSSL FIPS Provider (OpenSSL 3.x)#

OpenSSL 3.x has a modular architecture with a FIPS provider:

import ssl
import hashlib

# Verify OpenSSL version and FIPS support
print(ssl.OPENSSL_VERSION)

# On a FIPS-enabled system, non-approved algorithms raise errors:
try:
    hashlib.md5(b"test")  # Will raise if FIPS mode enforced at OS level
except ValueError as e:
    print(f"FIPS mode active: {e}")

RHEL/UBI with FIPS Mode#

The simplest path is running Python on a FIPS-enabled RHEL or UBI system:

FROM registry.access.redhat.com/ubi9/python-311:latest

# FIPS mode is controlled at the OS level
# When the host runs in FIPS mode, OpenSSL inside the container uses FIPS
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]

Enable FIPS on the host:

# RHEL 9
sudo fips-mode-setup --enable
sudo reboot
# Verify
fips-mode-setup --check

Python Libraries to Audit#

Some Python packages bundle their own crypto instead of using OpenSSL:

Library FIPS Concern
cryptography Uses OpenSSL by default — FIPS-compatible on FIPS-enabled systems
pynacl / libnacl Uses libsodium (Ed25519, ChaCha20) — NOT FIPS-approved algorithms
pycryptodome Standalone crypto implementation — NOT FIPS-validated
paramiko Uses cryptography — check that it does not negotiate non-FIPS ciphers
bcrypt bcrypt is not a FIPS-approved algorithm

Audit all dependencies that perform cryptographic operations. A single non-FIPS library in your dependency tree breaks compliance.

FIPS in Node.js#

Node.js uses OpenSSL for its crypto module. Enable FIPS mode:

// Enable FIPS at startup
const crypto = require('crypto');
crypto.setFips(1);

// Or via environment variable
// NODE_OPTIONS=--enable-fips node app.js

// Verify
console.log('FIPS mode:', crypto.getFips() === 1);

When FIPS is enabled, Node.js rejects non-approved algorithms:

// This will throw in FIPS mode
try {
    crypto.createHash('md5').update('test').digest('hex');
} catch (e) {
    console.error('MD5 blocked in FIPS mode:', e.message);
}

// This works
crypto.createHash('sha256').update('test').digest('hex');

Node.js must be built against a FIPS-validated OpenSSL. The standard Node.js binary from nodejs.org uses OpenSSL but is not FIPS-validated. Use Red Hat’s Node.js distribution or build Node.js against a FIPS-validated OpenSSL library.

FIPS Container Images#

Red Hat Universal Base Image (UBI)#

UBI images include FIPS-validated OpenSSL:

FROM registry.access.redhat.com/ubi9/ubi-minimal:latest

# OpenSSL on UBI 9 is FIPS-validated (certificate #4282 or newer)
# FIPS mode is inherited from the host kernel

RUN microdnf install -y openssl && microdnf clean all

# Verify FIPS-validated OpenSSL
RUN openssl version && openssl list -providers

Alpine Is Not FIPS-Compatible#

Alpine Linux uses musl libc and links against LibreSSL or OpenSSL builds that are not FIPS-validated. Do not use Alpine base images for FIPS workloads.

Ubuntu FIPS#

Ubuntu Pro includes FIPS-validated packages:

FROM ubuntu:22.04

# Ubuntu FIPS requires Ubuntu Pro subscription
# Packages: libssl3-fips, openssl-fips-provider
RUN apt-get update && apt-get install -y libssl3 openssl

Verifying FIPS in a Container#

# Check if FIPS mode is active
cat /proc/sys/crypto/fips_enabled
# Returns 1 if FIPS mode is on, 0 if off

# Check OpenSSL FIPS provider
openssl list -providers
# Should show "fips" provider

# Test that non-approved algorithms are blocked
openssl md5 /dev/null 2>&1 || echo "MD5 blocked (FIPS active)"

FIPS-Compliant Kubernetes#

Node-Level FIPS#

FIPS starts at the OS level. Kubernetes nodes must run a FIPS-enabled operating system:

  • RHEL 9 with FIPS modefips-mode-setup --enable
  • Ubuntu Pro FIPS — FIPS-certified kernel and crypto modules
  • Amazon Linux 2023 — FIPS mode available via configuration

When the host kernel has FIPS enabled (/proc/sys/crypto/fips_enabled = 1), containers inherit FIPS mode. The kernel blocks non-approved crypto operations system-wide.

Managed Kubernetes with FIPS#

Provider FIPS Support
EKS Use Amazon Linux 2023 AMI with FIPS; or Bottlerocket FIPS variant
AKS FIPS-enabled node pools available (--enable-fips-image)
GKE Use Container-Optimized OS with FIPS boot option; or Ubuntu FIPS nodes
OpenShift FIPS mode enabled at install time; all components use FIPS-validated crypto
# AKS: create a FIPS node pool
az aks nodepool add \
  --resource-group mygroup \
  --cluster-name mycluster \
  --name fipspool \
  --enable-fips-image \
  --node-count 3

etcd Encryption#

etcd stores all Kubernetes state. FIPS requires that encryption at rest uses approved algorithms:

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
      - configmaps
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: <base64-encoded-32-byte-key>  # AES-256
      - identity: {}

Use aescbc (AES-CBC) or aesgcm (AES-GCM). Do not use secretbox — it uses XSalsa20-Poly1305, which is not FIPS-approved.

Service Mesh TLS#

If using Istio or Linkerd for mTLS, verify the sidecar proxy uses FIPS-approved cipher suites:

# Istio: restrict to FIPS cipher suites
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: fips-tls
spec:
  host: "*.my-app.svc.cluster.local"
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL
      # Envoy uses BoringSSL which is FIPS-validated
      # Configure cipher suites if needed

Istio’s Envoy proxy uses BoringSSL, which has FIPS-validated builds. Use Istio’s FIPS-enabled images for strict compliance.

FIPS Validation vs FIPS Compliance#

These are different things:

  • FIPS validation means a cryptographic module has been tested and certified by a CMVP-accredited lab. The module has a validation certificate number. Only the exact version tested is validated.
  • FIPS compliance means your application uses FIPS-validated modules in FIPS mode and does not bypass them. Your application itself is not “FIPS-validated” — the crypto library it uses is.

You do not validate your application with CMVP. You demonstrate that your application uses validated modules and that those modules operate in FIPS mode.

How to Document FIPS Compliance#

For auditors and procurement reviews, document:

  1. Which FIPS-validated module your application uses (name, version, CMVP certificate number).
  2. How FIPS mode is enforced (OS-level, application-level, build flags).
  3. Which cryptographic operations your application performs and that they all use approved algorithms.
  4. Dependency audit showing no non-FIPS crypto libraries in the dependency tree.
  5. Test evidence showing non-approved algorithms are rejected (MD5 fails, ChaCha20 fails, etc.).

CMVP certificates are searchable at https://csrc.nist.gov/projects/cryptographic-module-validation-program/validated-modules.

Common Mistakes#

  1. Assuming OpenSSL means FIPS. OpenSSL has a FIPS provider, but it must be explicitly enabled and the specific build must be validated. Stock OpenSSL from most Linux distributions is not FIPS-validated without additional configuration.
  2. Using Alpine base images for FIPS workloads. Alpine does not include FIPS-validated crypto libraries. Use UBI, RHEL, or Ubuntu FIPS images.
  3. Forgetting Ed25519 is not FIPS-approved. Ed25519 is excellent cryptography but is not on the approved algorithms list. SSH keys, WireGuard, and many modern tools default to Ed25519. Switch to ECDSA P-256 or RSA 2048+ for FIPS environments.
  4. Not auditing transitive dependencies. Your application may use a FIPS OpenSSL, but a dependency deep in your tree might bundle its own crypto. Audit the full dependency graph.
  5. Enabling FIPS mode only in production. If development and CI environments are not in FIPS mode, you will discover FIPS-incompatible code at deployment time. Enable FIPS mode in all environments.