Go is an open source programming language that makes it easy to build simple, reliable, and efficient software. This is a modified version of Go enabling it to call into OpenSSL for FIPS compliance.
Before exploring the container’s possibilities, let’s start by deploying the default configuration:
docker run \
--interactive \
--tty \
--rm \
--name <container-name> \
dp.apps.rancher.io/containers/go-fips:1.24.4.1
Check our authentication guide if you need to configure Application Collection OCI credentials in your Docker client.
Our container is based on the Microsoft builds of Go, which is a modified version of the Go programming language which enables it to call into OpenSSL for FIPS compliance, and adapted to include our best practices. As such, any container-related documentation provided by upstream will work out of the box with our container. You can check the official documentation.
The container image is provided in the following flavors:
curl
, find
or grep
. It is ideal
if you are looking for a minimal image to build your Go application.dev
: This flavor is based on BCI Base FIPS and includes the zypper
package manager, the rpm
packaging tool, and various
different build tools such as curl
, find
, grep
. Therefore, it is ideal for build pipelines that need extra programs to build your application.The Go FIPS container, like the official container images, does not specify any entrypoint to run the container image. It is up to the end user to run any specific programs within the container image.
Compared to standard Go container images, this container image is configured with the following additional environment variables, to enable OpenSSL calls for FIPS compliance:
GOEXPERIMENT
set to opensslcrypto
, to instruct Go to use OpenSSL as back-end for its cryptographic library.GOFLAGS
set to -tags=requirefips
, to make built programs always require FIPS mode, and panic if it is not enabled.You must not override any of the above environment variables when using Go FIPS, or it could potentially result in built programs not to be FIPS compliant.
We will describe how you can use the Go FIPS container image to generate a binary that is FIPS compliant, and how you can create a container image that runs this FIPS-compliant program.
You can use the below example to build a FIPS-compliant program, which starts a basic HTTPS server on port 8443 and uses the SSL/TLS certificate
and certificate key files at cert.pem
and key.pem
, respectively, in the same directory as the server:
package main
import (
"crypto/tls"
"fmt"
"log"
"net/http"
)
func main() {
// Minimal HTTPS handler
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello world!\n")
})
// Minimal HTTPS server configuration
server := &http.Server{
Addr: ":8443",
Handler: handler,
TLSConfig: &tls.Config{
MinVersion: tls.VersionTLS12, // FIPS minimum TLS version
},
}
// Start HTTPS server using existing TLS/SSL certificates
log.Println("Starting HTTPS server on https://localhost:8443")
certFile := "cert.pem"
keyFile := "key.pem"
err := server.ListenAndServeTLS(certFile, keyFile)
if err != nil {
log.Fatalf("Server failed: %v", err)
}
}
You can generate a self-signed SSL/TLS certificate (
cert.pem
) with a certificate key file (key.pem
) with the following command in the same directory as the previous HTTPS server program:openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 365 -subj "/CN=localhost"
To build the program, run the following command in the Go FIPS container image. In the below example, let’s assume the source code was added
to the server.go
file:
go build -o server server.go
To optimize the binary further, you can remove debug symbols:
go build -ldflags '-s -w' -o server server.go
If you remove debug symbols, it will not be possible to check if the binary contains FIPS symbols with
go tool nm
.
You can then proceed to run the program and ensure that it works as expected. To exit, press `Ctrl+C:
$ ./server
2025/07/04 15:43:24 Starting HTTPS server on https://localhost:8443
^C
There are several things you can do to verify that a binary is FIPS-enabled, if it was built with the Go FIPS toolchain.
The binary does not work without FIPS mode. A simple way to verify this is to run it with GOFIPS=0
:
$ GOFIPS=0 ./server
panic: the 'requirefips' build tag is enabled, but it conflicts with the environment variable GOFIPS=0 which would disable FIPS mode
goroutine 1 [running]:
crypto/internal/backend/fips140.init.0()
crypto/internal/backend/fips140/fips140.go:55 +0x2e0
Check that the binary contains FIPS symbols. You can use the environment variable LD_DEBUG=symbols
or the tool go tool nm
:
$ LD_DEBUG=symbols ./server 2>&1 | grep -Ei '(ssl|crypto|fips)'
157: symbol=_ITM_deregisterTMCloneTable; lookup in file=/usr/lib64/libcrypto.so.3 [0]
157: symbol=__gmon_start__; lookup in file=/usr/lib64/libcrypto.so.3 [0]
157: symbol=_ITM_registerTMCloneTable; lookup in file=/usr/lib64/libcrypto.so.3 [0]
$ go tool nm ./server | grep -i fips | head -n 10
14f38 T _cgo_7856f5258810_Cfunc_go_openssl_EVP_default_properties_enable_fips
14f90 T _cgo_7856f5258810_Cfunc_go_openssl_EVP_default_properties_is_fips_enabled
14fe8 T _cgo_7856f5258810_Cfunc_go_openssl_FIPS_mode
15038 T _cgo_7856f5258810_Cfunc_go_openssl_FIPS_mode_set
151f8 T _cgo_7856f5258810_Cfunc_go_openssl_fips_enabled
5f1910 D _g_EVP_default_properties_enable_fips
5f1918 D _g_EVP_default_properties_is_fips_enabled
5f1920 D _g_FIPS_mode
5f1928 D _g_FIPS_mode_set
399640 R crypto/ecdsa..dict.privateKeyToFIPS[*crypto/internal/fips140/nistec.P224Point]
If the symbols were removed at build time, these commands will not show any symbol.
Check compilation flags for FIPS configuration. You can run go version -m
on the binary to check that it includes the expected configuration
to enable FIPS:
$ go version -m ./server | grep -Ei '(ssl|crypto|fips)'
./server: go1.24.4 X:opensslcrypto
dep golang.org/x/crypto v0.39.0
build -tags=requirefips
build GOEXPERIMENT=opensslcrypto
The
grep
command is only available in thedev
flavor of the Go FIPS container image.
Execute the following commands in your environment:
echo 'Allowed cipher/TLS combo:'
curl --ciphers ECDHE-RSA-AES256-GCM-SHA384 --insecure https://localhost:8443
echo
echo 'Disallowed cipher/TLS combo:'
curl --ciphers ECDHE-RSA-AES128-GCM-SHA256 --tls-max 1.2 --insecure https://localhost:8443
If you execute the above commands in a FIPS-enabled environment, and in an environment where it is not enforced, you will see different results:
In a FIPS-enabled environment, the first request succeeds with the allowed cipher/TLS combination, and the latter will fail because the cipher/TLS combination is not allowed according to the FIPS 140-2 specification:
Allowed cipher/TLS combo:
Hello world!
Disallowed cipher/TLS combo:
curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to localhost:8443
In an environment which is not enforcing FIPS, both requests will succeed because there isn’t any limitation on the allowed cipher/TLS combinations:
Allowed cipher/TLS combo:
Hello world!
Disallowed cipher/TLS combo:
Hello world!
You can use the following Dockerfile to create a container image for the previous example:
FROM dp.apps.rancher.io/containers/bci-micro-fips:15.6
COPY server /
ENTRYPOINT [ "/server" ]
Execute the following command to build the container image:
docker build -t IMAGE_NAME:latest .
Then, you can use the following command to start the container, exposing the service to port 8443 and mounting the certificate key and file:
$ docker run -p 8443:8443 -v ./cert.pem:/cert.pem -v ./key.pem:/key.pem --rm -ti CONTAINER_NAME
2025/07/04 16:34:34 Starting HTTPS server on https://localhost:8443
In a separate shell session, you can verify that the server works:
curl --insecure https://localhost:8443
Finally, you can proceed to distribute the container image to your desired container image registry.
CGO_ENABLED
must never be disabled.dlopen
. Therefore, you
must run the resulting binary in an environment which contains a compatible OpenSSL image, such as the SLE BCI FIPS-140-2 container images as
suggested in the previous section.crypto
APIs and workflows are implemented in a FIPS-compliant manner.