Skip to content

Commit

Permalink
Add FIPS builds (#2165)
Browse files Browse the repository at this point in the history
* Add FIPS builds for linux amd64

* add version check

* fix CI labels and add local dev commands

* fix ci version tagging

* switch to ubuntu 20.04

* add CLI version tag

* add gcompat for alpine glibc cgo compatibility

* remove FIPS version check from connect-init

* address comments
  • Loading branch information
skpratt authored and absolutelightning committed Aug 4, 2023
1 parent bc4af33 commit 1ed3306
Show file tree
Hide file tree
Showing 12 changed files with 210 additions and 37 deletions.
92 changes: 66 additions & 26 deletions .github/workflows/build.yml

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ control-plane-dev-docker-multi-arch: check-remote-dev-image-env ## Build consul-
--push \
-f $(CURDIR)/control-plane/Dockerfile $(CURDIR)/control-plane

control-plane-fips-dev-docker: ## Build consul-k8s-control-plane FIPS dev Docker image.
@$(SHELL) $(CURDIR)/control-plane/build-support/scripts/build-local.sh -o linux -a $(GOARCH) --fips
@docker build -t '$(DEV_IMAGE)' \
--target=dev \
--build-arg 'TARGETARCH=$(GOARCH)' \
--build-arg 'GIT_COMMIT=$(GIT_COMMIT)' \
--build-arg 'GIT_DIRTY=$(GIT_DIRTY)' \
--build-arg 'GIT_DESCRIBE=$(GIT_DESCRIBE)' \
--push \
-f $(CURDIR)/control-plane/Dockerfile $(CURDIR)/control-plane

control-plane-test: ## Run go test for the control plane.
cd control-plane; go test ./...

Expand Down Expand Up @@ -98,6 +109,10 @@ cli-dev:
@echo "==> Installing consul-k8s CLI tool for ${GOOS}/${GOARCH}"
@cd cli; go build -o ./bin/consul-k8s; cp ./bin/consul-k8s ${GOPATH}/bin/

cli-fips-dev:
@echo "==> Installing consul-k8s CLI tool for ${GOOS}/${GOARCH}"
@cd cli; CGO_ENABLED=1 GOEXPERIMENT=boringcrypto go build -o ./bin/consul-k8s -tags "fips"; cp ./bin/consul-k8s ${GOPATH}/bin/


cli-lint: ## Run linter in the control-plane directory.
cd cli; golangci-lint run -c ../.golangci.yml
Expand Down
27 changes: 27 additions & 0 deletions cli/version/fips_build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//go:build fips

package version

// This validates during compilation that we are being built with a FIPS enabled go toolchain
import (
_ "crypto/tls/fipsonly"
"runtime"
"strings"
)

// IsFIPS returns true if consul-k8s is operating in FIPS-140-2 mode.
func IsFIPS() bool {
return true
}

func GetFIPSInfo() string {
str := "Enabled"
// Try to get the crypto module name
gover := strings.Split(runtime.Version(), "X:")
if len(gover) >= 2 {
gover_last := gover[len(gover)-1]
// Able to find crypto module name; add that to status string.
str = "FIPS 140-2 Enabled, crypto module " + gover_last
}
return str
}
12 changes: 12 additions & 0 deletions cli/version/non_fips_build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//go:build !fips

package version

// IsFIPS returns true if consul-k8s is operating in FIPS-140-2 mode.
func IsFIPS() bool {
return false
}

func GetFIPSInfo() string {
return ""
}
6 changes: 5 additions & 1 deletion cli/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@ func GetHumanVersion() string {
release = "dev"
}

if IsFIPS() {
version += ".fips1402"
}

if release != "" {
if !strings.HasSuffix(version, "-"+release) {
if !strings.Contains(version, "-"+release) {
// if we tagged a prerelease version then the release is in the version already
version += fmt.Sprintf("-%s", release)
}
Expand Down
6 changes: 5 additions & 1 deletion control-plane/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,11 @@ LABEL name=${BIN_NAME} \
ENV BIN_NAME=${BIN_NAME}
ENV VERSION=${PRODUCT_VERSION}

RUN apk add --no-cache ca-certificates libcap openssl su-exec iputils libc6-compat iptables
RUN apk add --no-cache ca-certificates libcap openssl su-exec iputils gcompat libc6-compat libstdc++ iptables

# for FIPS CGO glibc compatibility in alpine
# see https://github.com/golang/go/issues/59305
RUN ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2

# TARGETOS and TARGETARCH are set automatically when --platform is provided.
ARG TARGETOS
Expand Down
14 changes: 11 additions & 3 deletions control-plane/build-support/functions/20-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,22 @@ function build_consul_local {
# * - error
#
# Note:
# The GOLDFLAGS and GOTAGS environment variables will be used if set
# The GOLDFLAGS, GOEXPERIMENT, and GOTAGS environment variables will be used if set
# If the CONSUL_DEV environment var is truthy only the local platform/architecture is built.
# If the XC_OS or the XC_ARCH environment vars are present then only those platforms/architectures
# will be built. Otherwise all supported platform/architectures are built
# The NOGOX environment variable will be used if present. This will prevent using gox and instead
# build with go install.
# The GOXPARALLEL environment variable is used if set

if [ $GOTAGS == "fips" ]; then
CGO_ENABLED=1
else
CGO_ENABLED=0
fi

echo "GOEXPERIMENT: $GOEXPERIMENT, GOTAGS: $GOTAGS CGO_ENABLED: $CGO_ENABLED" >> ~/debug.txt

if ! test -d "$1"
then
err "ERROR: '$1' is not a directory. build_consul must be called with the path to the top level source as the first argument'"
Expand Down Expand Up @@ -242,7 +250,7 @@ function build_consul_local {
then
status "Using gox for concurrent compilation"

CGO_ENABLED=0 gox \
CGO_ENABLED=${CGO_ENABLED} GOEXPERIMENT=${GOEXPERIMENT} gox \
-os="${build_os}" \
-arch="${build_arch}" \
-ldflags="${GOLDFLAGS}" \
Expand Down Expand Up @@ -290,7 +298,7 @@ function build_consul_local {
else
OS_BIN_EXTENSION=""
fi
CGO_ENABLED=0 GOOS=${os} GOARCH=${arch} go build -ldflags "${GOLDFLAGS}" -tags "${GOTAGS}" -o "${outdir}/${bin_name}"
CGO_ENABLED=${CGO_ENABLED} GOEXPERIMENT=${GOEXPERIMENT} GOOS=${os} GOARCH=${arch} go build -ldflags "${GOLDFLAGS}" -tags "${GOTAGS}" -o "${outdir}/${bin_name}"
if test $? -ne 0
then
err "ERROR: Failed to build Consul for ${osarch}"
Expand Down
7 changes: 7 additions & 0 deletions control-plane/build-support/scripts/build-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ Options:
-a | --arch ARCH Space separated string of
architectures to build.
--fips FIPS Whether to use FIPS cryptography.
-h | --help Print this help text.
EOF
}
Expand Down Expand Up @@ -94,6 +96,11 @@ function main {
build_arch="$2"
shift 2
;;
--fips )
GOTAGS="fips"
GOEXPERIMENT="boringcrypto"
shift 1
;;
* )
err_usage "ERROR: Unknown argument: '$1'"
return 1
Expand Down
23 changes: 18 additions & 5 deletions control-plane/subcommand/connect-init/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,19 @@ import (
"time"

"github.com/cenkalti/backoff"
"github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants"
"github.com/hashicorp/consul-k8s/control-plane/consul"
"github.com/hashicorp/consul-k8s/control-plane/namespaces"
"github.com/hashicorp/consul-k8s/control-plane/subcommand/common"
"github.com/hashicorp/consul-k8s/control-plane/subcommand/flags"
"github.com/hashicorp/consul-server-connection-manager/discovery"
"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/sdk/iptables"
"github.com/hashicorp/go-hclog"
"github.com/mitchellh/cli"
"github.com/mitchellh/mapstructure"

"github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants"
"github.com/hashicorp/consul-k8s/control-plane/consul"
"github.com/hashicorp/consul-k8s/control-plane/namespaces"
"github.com/hashicorp/consul-k8s/control-plane/subcommand/common"
"github.com/hashicorp/consul-k8s/control-plane/subcommand/flags"
"github.com/hashicorp/consul-k8s/control-plane/version"
)

const (
Expand Down Expand Up @@ -163,6 +165,17 @@ func (c *Command) Run(args []string) int {
c.logger.Error("Unable to get client connection", "error", err)
return 1
}
if version.IsFIPS() {
// make sure we are also using FIPS Consul
var versionInfo map[string]interface{}
_, err := consulClient.Raw().Query("/v1/agent/version", versionInfo, nil)
if err != nil {
c.logger.Warn("This is a FIPS build of consul-k8s, which should be used with FIPS Consul. Unable to verify FIPS Consul while setting up Consul API client.")
}
if val, ok := versionInfo["FIPS"]; !ok || val == "" {
c.logger.Warn("This is a FIPS build of consul-k8s, which should be used with FIPS Consul. A non-FIPS version of Consul was detected.")
}
}
proxyService := &api.AgentService{}
if c.flagGatewayKind != "" {
err = backoff.Retry(c.getGatewayRegistration(consulClient), backoff.WithMaxRetries(backoff.NewConstantBackOff(1*time.Second), c.serviceRegistrationPollingAttempts))
Expand Down
27 changes: 27 additions & 0 deletions control-plane/version/fips_build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//go:build fips

package version

// This validates during compilation that we are being built with a FIPS enabled go toolchain
import (
_ "crypto/tls/fipsonly"
"runtime"
"strings"
)

// IsFIPS returns true if consul-k8s is operating in FIPS-140-2 mode.
func IsFIPS() bool {
return true
}

func GetFIPSInfo() string {
str := "Enabled"
// Try to get the crypto module name
gover := strings.Split(runtime.Version(), "X:")
if len(gover) >= 2 {
gover_last := gover[len(gover)-1]
// Able to find crypto module name; add that to status string.
str = "FIPS 140-2 Enabled, crypto module " + gover_last
}
return str
}
12 changes: 12 additions & 0 deletions control-plane/version/non_fips_build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//go:build !fips

package version

// IsFIPS returns true if consul-k8s is operating in FIPS-140-2 mode.
func IsFIPS() bool {
return false
}

func GetFIPSInfo() string {
return ""
}
6 changes: 5 additions & 1 deletion control-plane/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@ func GetHumanVersion() string {
release = "dev"
}

if IsFIPS() {
version += ".fips1402"
}

if release != "" {
if !strings.HasSuffix(version, "-"+release) {
if !strings.Contains(version, "-"+release) {
// if we tagged a prerelease version then the release is in the version already
version += fmt.Sprintf("-%s", release)
}
Expand Down

0 comments on commit 1ed3306

Please sign in to comment.