TUN-5551: Reintroduce FIPS compliance for linux amd64 now as separate binaries

This is a cherry-pick of 157f5d1412
followed by build/CI changes so that amd64/linux FIPS compliance is
provided by new/separate binaries/artifacts/packages.

The reasoning being that FIPS compliance places excessive requirements
in the encryption algorithms used for regular users that do not care
about that. This can cause cloudflared to reject HTTPS origins that
would otherwise be accepted without FIPS checks.

This way, by having separate binaries, existing ones remain as they
were, and only FIPS-needy users will opt-in to the new FIPS binaries.
This commit is contained in:
Nuno Diegues 2021-11-09 11:37:51 +00:00
parent 8f46065ab5
commit 70e675f42c
22 changed files with 160 additions and 65 deletions

View File

@ -4,22 +4,33 @@ MSI_VERSION := $(shell git tag -l --sort=v:refname | grep "w" | tail -1 | cut
#e.g. w3.0.1 or w4.2.10. It trims off the w character when creating the MSI. #e.g. w3.0.1 or w4.2.10. It trims off the w character when creating the MSI.
ifeq ($(FIPS), true) ifeq ($(FIPS), true)
GO_BUILD_TAGS := $(GO_BUILD_TAGS) fips BINARY_NAME := cloudflared-fips
endif else
BINARY_NAME := cloudflared
ifneq ($(GO_BUILD_TAGS),)
GO_BUILD_TAGS := -tags $(GO_BUILD_TAGS)
endif endif
ifeq ($(NIGHTLY), true) ifeq ($(NIGHTLY), true)
# We do not release FIPS in NIGHTLY, so no need to consider that case here.
DEB_PACKAGE_NAME := cloudflared-nightly DEB_PACKAGE_NAME := cloudflared-nightly
NIGHTLY_FLAGS := --conflicts cloudflared --replaces cloudflared NIGHTLY_FLAGS := --conflicts cloudflared --replaces cloudflared
else else
DEB_PACKAGE_NAME := cloudflared DEB_PACKAGE_NAME := $(BINARY_NAME)
endif endif
DATE := $(shell date -u '+%Y-%m-%d-%H%M UTC') DATE := $(shell date -u '+%Y-%m-%d-%H%M UTC')
VERSION_FLAGS := -ldflags='-X "main.Version=$(VERSION)" -X "main.BuildTime=$(DATE)"' VERSION_FLAGS := -X "main.Version=$(VERSION)" -X "main.BuildTime=$(DATE)"
LINK_FLAGS :=
ifeq ($(FIPS), true)
LINK_FLAGS := -linkmode=external -extldflags=-static $(LINK_FLAGS)
# Prevent linking with libc regardless of CGO enabled or not.
GO_BUILD_TAGS := $(GO_BUILD_TAGS) osusergo netgo fips
endif
LDFLAGS := -ldflags='$(VERSION_FLAGS) $(LINK_FLAGS)'
ifneq ($(GO_BUILD_TAGS),)
GO_BUILD_TAGS := -tags "$(GO_BUILD_TAGS)"
endif
IMPORT_PATH := github.com/cloudflare/cloudflared IMPORT_PATH := github.com/cloudflare/cloudflared
PACKAGE_DIR := $(CURDIR)/packaging PACKAGE_DIR := $(CURDIR)/packaging
@ -61,9 +72,9 @@ else
endif endif
ifeq ($(TARGET_OS), windows) ifeq ($(TARGET_OS), windows)
EXECUTABLE_PATH=./cloudflared.exe EXECUTABLE_PATH=./$(BINARY_NAME).exe
else else
EXECUTABLE_PATH=./cloudflared EXECUTABLE_PATH=./$(BINARY_NAME)
endif endif
ifeq ($(FLAVOR), centos-7) ifeq ($(FLAVOR), centos-7)
@ -80,17 +91,15 @@ clean:
go clean go clean
.PHONY: cloudflared .PHONY: cloudflared
cloudflared: cloudflared:
ifeq ($(FIPS), true) ifeq ($(FIPS), true)
$(info Building cloudflared with go-fips) $(info Building cloudflared with go-fips)
-test -f fips/fips.go && mv fips/fips.go fips/fips.go.linux-amd64 cp -f fips/fips.go.linux-amd64 cmd/cloudflared/fips.go
mv fips/fips.go.linux-amd64 fips/fips.go
endif endif
GOOS=$(TARGET_OS) GOARCH=$(TARGET_ARCH) go build -v -mod=vendor $(GO_BUILD_TAGS) $(LDFLAGS) $(IMPORT_PATH)/cmd/cloudflared
GOOS=$(TARGET_OS) GOARCH=$(TARGET_ARCH) go build -v -mod=vendor $(GO_BUILD_TAGS) $(VERSION_FLAGS) $(IMPORT_PATH)/cmd/cloudflared
ifeq ($(FIPS), true) ifeq ($(FIPS), true)
mv fips/fips.go fips/fips.go.linux-amd64 rm -f cmd/cloudflared/fips.go
./check-fips.sh cloudflared
endif endif
.PHONY: container .PHONY: container
@ -100,10 +109,10 @@ container:
.PHONY: test .PHONY: test
test: vet test: vet
ifndef CI ifndef CI
go test -v -mod=vendor -race $(VERSION_FLAGS) ./... go test -v -mod=vendor -race $(LDFLAGS) ./...
else else
@mkdir -p .cover @mkdir -p .cover
go test -v -mod=vendor -race $(VERSION_FLAGS) -coverprofile=".cover/c.out" ./... go test -v -mod=vendor -race $(LDFLAGS) -coverprofile=".cover/c.out" ./...
go tool cover -html ".cover/c.out" -o .cover/all.html go tool cover -html ".cover/c.out" -o .cover/all.html
endif endif
@ -112,10 +121,10 @@ test-ssh-server:
docker-compose -f ssh_server_tests/docker-compose.yml up docker-compose -f ssh_server_tests/docker-compose.yml up
define publish_package define publish_package
chmod 664 cloudflared*.$(1); \ chmod 664 $(BINARY_NAME)*.$(1); \
for HOST in $(CF_PKG_HOSTS); do \ for HOST in $(CF_PKG_HOSTS); do \
ssh-keyscan -t ecdsa $$HOST >> ~/.ssh/known_hosts; \ ssh-keyscan -t ecdsa $$HOST >> ~/.ssh/known_hosts; \
scp -p -4 cloudflared*.$(1) cfsync@$$HOST:/state/cf-pkg/staging/$(2)/$(TARGET_PUBLIC_REPO)/cloudflared/; \ scp -p -4 $(BINARY_NAME)*.$(1) cfsync@$$HOST:/state/cf-pkg/staging/$(2)/$(TARGET_PUBLIC_REPO)/$(BINARY_NAME)/; \
done done
endef endef
@ -127,6 +136,8 @@ publish-deb: cloudflared-deb
publish-rpm: cloudflared-rpm publish-rpm: cloudflared-rpm
$(call publish_package,rpm,yum) $(call publish_package,rpm,yum)
# When we build packages, the package name will be FIPS-aware.
# But we keep the binary installed by it to be named "cloudflared" regardless.
define build_package define build_package
mkdir -p $(PACKAGE_DIR) mkdir -p $(PACKAGE_DIR)
cp cloudflared $(PACKAGE_DIR)/cloudflared cp cloudflared $(PACKAGE_DIR)/cloudflared
@ -247,8 +258,8 @@ tunnelrpc-deps:
capnp compile -ogo tunnelrpc/tunnelrpc.capnp capnp compile -ogo tunnelrpc/tunnelrpc.capnp
.PHONY: quic-deps .PHONY: quic-deps
quic-deps: quic-deps:
which capnp which capnp
which capnpc-go which capnpc-go
capnp compile -ogo quic/schema/quic_metadata_protocol.capnp capnp compile -ogo quic/schema/quic_metadata_protocol.capnp
@ -258,9 +269,9 @@ vet:
# go get github.com/sudarshan-reddy/go-sumtype (don't do this in build directory or this will cause vendor issues) # go get github.com/sudarshan-reddy/go-sumtype (don't do this in build directory or this will cause vendor issues)
# Note: If you have github.com/BurntSushi/go-sumtype then you might have to use the repo above instead # Note: If you have github.com/BurntSushi/go-sumtype then you might have to use the repo above instead
# for now because it uses an older version of golang.org/x/tools. # for now because it uses an older version of golang.org/x/tools.
which go-sumtype which go-sumtype
go-sumtype $$(go list -mod=vendor ./...) go-sumtype $$(go list -mod=vendor ./...)
.PHONY: goimports .PHONY: goimports
goimports: goimports:
for d in $$(go list -mod=readonly -f '{{.Dir}}' -a ./... | fgrep -v tunnelrpc) ; do goimports -format-only -local github.com/cloudflare/cloudflared -w $$d ; done for d in $$(go list -mod=readonly -f '{{.Dir}}' -a ./... | fgrep -v tunnelrpc) ; do goimports -format-only -local github.com/cloudflare/cloudflared -w $$d ; done

25
build-packages-fips.sh Executable file
View File

@ -0,0 +1,25 @@
VERSION=$(git describe --tags --always --match "[0-9][0-9][0-9][0-9].*.*")
echo $VERSION
# This controls the directory the built artifacts go into
export ARTIFACT_DIR=built_artifacts/
mkdir -p $ARTIFACT_DIR
arch=("amd64")
export TARGET_ARCH=$arch
export TARGET_OS=linux
export FIPS=true
# For BoringCrypto to link, we need CGO enabled. Otherwise compilation fails.
export CGO_ENABLED=1
make cloudflared-deb
mv cloudflared-fips\_$VERSION\_$arch.deb $ARTIFACT_DIR/cloudflared-fips-linux-$arch.deb
# rpm packages invert the - and _ and use x86_64 instead of amd64.
RPMVERSION=$(echo $VERSION|sed -r 's/-/_/g')
RPMARCH="x86_64"
make cloudflared-rpm
mv cloudflared-fips-$RPMVERSION-1.$RPMARCH.rpm $ARTIFACT_DIR/cloudflared-fips-linux-$RPMARCH.rpm
# finally move the linux binary as well.
mv ./cloudflared $ARTIFACT_DIR/cloudflared-fips-linux-$arch

View File

@ -1,12 +1,15 @@
VERSION=$(git describe --tags --always --dirty="-dev" --match "[0-9][0-9][0-9][0-9].*.*") VERSION=$(git describe --tags --always --match "[0-9][0-9][0-9][0-9].*.*")
echo $VERSION echo $VERSION
# Avoid depending on C code since we don't need it.
export CGO_ENABLED=0 export CGO_ENABLED=0
# This controls the directory the built artifacts go into # This controls the directory the built artifacts go into
export ARTIFACT_DIR=built_artifacts/ export ARTIFACT_DIR=built_artifacts/
mkdir -p $ARTIFACT_DIR mkdir -p $ARTIFACT_DIR
windowsArchs=("amd64" "386") windowsArchs=("amd64" "386")
export TARGET_OS=windows export TARGET_OS=windows
for arch in ${windowsArchs[@]}; do for arch in ${windowsArchs[@]}; do
export TARGET_ARCH=$arch export TARGET_ARCH=$arch
make cloudflared-msi make cloudflared-msi
mv ./cloudflared.exe $ARTIFACT_DIR/cloudflared-windows-$arch.exe mv ./cloudflared.exe $ARTIFACT_DIR/cloudflared-windows-$arch.exe
@ -14,15 +17,14 @@ for arch in ${windowsArchs[@]}; do
done done
export FIPS=true linuxArchs=("386" "amd64" "arm" "arm64")
linuxArchs=("amd64" "386" "arm" "arm64")
export TARGET_OS=linux export TARGET_OS=linux
for arch in ${linuxArchs[@]}; do for arch in ${linuxArchs[@]}; do
export TARGET_ARCH=$arch export TARGET_ARCH=$arch
make cloudflared-deb make cloudflared-deb
mv cloudflared\_$VERSION\_$arch.deb $ARTIFACT_DIR/cloudflared-linux-$arch.deb mv cloudflared\_$VERSION\_$arch.deb $ARTIFACT_DIR/cloudflared-linux-$arch.deb
# rpm packages invert the - and _ and use x86_64 instead of amd64. # rpm packages invert the - and _ and use x86_64 instead of amd64.
RPMVERSION=$(echo $VERSION|sed -r 's/-/_/g') RPMVERSION=$(echo $VERSION|sed -r 's/-/_/g')
RPMARCH=$arch RPMARCH=$arch
if [ $arch == "amd64" ];then if [ $arch == "amd64" ];then
@ -37,4 +39,3 @@ for arch in ${linuxArchs[@]}; do
# finally move the linux binary as well. # finally move the linux binary as well.
mv ./cloudflared $ARTIFACT_DIR/cloudflared-linux-$arch mv ./cloudflared $ARTIFACT_DIR/cloudflared-linux-$arch
done done

View File

@ -1,20 +1,10 @@
pinned_go: &pinned_go go=1.17-1 pinned_go: &pinned_go go=1.17-1
pinned_go_fips: &pinned_go_fips go-boring=1.16.6-6 pinned_go_fips: &pinned_go_fips go-boring=1.16.6-7
build_dir: &build_dir /cfsetup_build build_dir: &build_dir /cfsetup_build
default-flavor: buster default-flavor: buster
stretch: &stretch stretch: &stretch
build: build:
build_dir: *build_dir
builddeps:
- *pinned_go_fips
- build-essential
post-cache:
- export GOOS=linux
- export GOARCH=amd64
- export FIPS=true
- make cloudflared
build-non-fips: # helpful to catch problems with non-fips (only used for releasing non-linux artifacts) before releases
build_dir: *build_dir build_dir: *build_dir
builddeps: builddeps:
- *pinned_go - *pinned_go
@ -23,11 +13,22 @@ stretch: &stretch
- export GOOS=linux - export GOOS=linux
- export GOARCH=amd64 - export GOARCH=amd64
- make cloudflared - make cloudflared
build-all-packages: #except osxpkg build-fips:
build_dir: *build_dir build_dir: *build_dir
builddeps: builddeps:
- *pinned_go_fips - *pinned_go_fips
- build-essential - build-essential
post-cache:
- export GOOS=linux
- export GOARCH=amd64
- export FIPS=true
- make cloudflared
# except FIPS (handled in github-fips-release-pkgs) and macos (handled in github-release-macos-amd64)
github-release-pkgs:
build_dir: *build_dir
builddeps:
- *pinned_go
- build-essential
- fakeroot - fakeroot
- rubygem-fpm - rubygem-fpm
- rpm - rpm
@ -35,15 +36,21 @@ stretch: &stretch
# libmsi and libgcab are libraries the wixl binary depends on. # libmsi and libgcab are libraries the wixl binary depends on.
- libmsi-dev - libmsi-dev
- libgcab-dev - libgcab-dev
pre-cache: - python3-dev
# TODO: https://jira.cfops.it/browse/TUN-4792 Replace this wixl with the official one once msitools supports - libffi-dev
# environment. - python3-setuptools
- python3-pip
pre-cache: &github_release_pkgs_pre_cache
- wget https://github.com/sudarshan-reddy/msitools/releases/download/v0.101b/wixl -P /usr/local/bin - wget https://github.com/sudarshan-reddy/msitools/releases/download/v0.101b/wixl -P /usr/local/bin
- chmod a+x /usr/local/bin/wixl - chmod a+x /usr/local/bin/wixl
- pip3 install pygithub
post-cache: post-cache:
- export FIPS=true # build all packages (except macos and FIPS) and move them to /cfsetup/built_artifacts
- ./build-packages.sh - ./build-packages.sh
github-release-pkgs: # release the packages built and moved to /cfsetup/built_artifacts
- make github-release-built-pkgs
# handle FIPS separately so that we built with gofips compiler
github-fips-release-pkgs:
build_dir: *build_dir build_dir: *build_dir
builddeps: builddeps:
- *pinned_go_fips - *pinned_go_fips
@ -59,18 +66,25 @@ stretch: &stretch
- libffi-dev - libffi-dev
- python3-setuptools - python3-setuptools
- python3-pip - python3-pip
pre-cache: pre-cache: *github_release_pkgs_pre_cache
- wget https://github.com/sudarshan-reddy/msitools/releases/download/v0.101b/wixl -P /usr/local/bin
- chmod a+x /usr/local/bin/wixl
- pip3 install pygithub
post-cache: post-cache:
# build all packages and move them to /cfsetup/built_artifacts # same logic as above, but for FIPS packages only
- ./build-packages.sh - ./build-packages-fips.sh
# release the packages built and moved to /cfsetup/built_artifacts
- make github-release-built-pkgs - make github-release-built-pkgs
build-deb: build-deb:
build_dir: *build_dir build_dir: *build_dir
builddeps: &build_deb_deps builddeps: &build_deb_deps
- *pinned_go
- build-essential
- fakeroot
- rubygem-fpm
post-cache:
- export GOOS=linux
- export GOARCH=amd64
- make cloudflared-deb
build-fips-deb:
build_dir: *build_dir
builddeps:
- *pinned_go_fips - *pinned_go_fips
- build-essential - build-essential
- fakeroot - fakeroot
@ -86,7 +100,6 @@ stretch: &stretch
post-cache: post-cache:
- export GOOS=linux - export GOOS=linux
- export GOARCH=amd64 - export GOARCH=amd64
- export FIPS=true
- export NIGHTLY=true - export NIGHTLY=true
- make cloudflared-deb - make cloudflared-deb
build-deb-arm64: build-deb-arm64:
@ -99,7 +112,7 @@ stretch: &stretch
publish-deb: publish-deb:
build_dir: *build_dir build_dir: *build_dir
builddeps: builddeps:
- *pinned_go_fips - *pinned_go
- build-essential - build-essential
- fakeroot - fakeroot
- rubygem-fpm - rubygem-fpm
@ -107,7 +120,6 @@ stretch: &stretch
post-cache: post-cache:
- export GOOS=linux - export GOOS=linux
- export GOARCH=amd64 - export GOARCH=amd64
- export FIPS=true
- make publish-deb - make publish-deb
github-release-macos-amd64: github-release-macos-amd64:
build_dir: *build_dir build_dir: *build_dir
@ -123,14 +135,27 @@ stretch: &stretch
post-cache: post-cache:
- make github-mac-upload - make github-mac-upload
test: test:
build_dir: *build_dir
builddeps:
- *pinned_go
- build-essential
- gotest-to-teamcity
pre-cache: &test_pre_cache
- go get golang.org/x/tools/cmd/goimports
- go get github.com/sudarshan-reddy/go-sumtype@v0.0.0-20210827105221-82eca7e5abb1
post-cache:
- export GOOS=linux
- export GOARCH=amd64
- export PATH="$HOME/go/bin:$PATH"
- ./fmt-check.sh
- make test | gotest-to-teamcity
test-fips:
build_dir: *build_dir build_dir: *build_dir
builddeps: builddeps:
- *pinned_go_fips - *pinned_go_fips
- build-essential - build-essential
- gotest-to-teamcity - gotest-to-teamcity
pre-cache: pre-cache: *test_pre_cache
- go get golang.org/x/tools/cmd/goimports
- go get github.com/sudarshan-reddy/go-sumtype@v0.0.0-20210827105221-82eca7e5abb1
post-cache: post-cache:
- export GOOS=linux - export GOOS=linux
- export GOARCH=amd64 - export GOARCH=amd64

15
check-fips.sh Executable file
View File

@ -0,0 +1,15 @@
# Pass the path to the executable to check for FIPS compliance
exe=$1
if [ "$(go tool nm "${exe}" | grep -c '_Cfunc__goboringcrypto_')" -eq 0 ]; then
# Asserts that executable is using FIPS-compliant boringcrypto
echo "${exe}: missing goboring symbols" >&2
exit 1
fi
if [ "$(go tool nm "${exe}" | grep -c 'crypto/internal/boring/sig.FIPSOnly')" -eq 0 ]; then
# Asserts that executable is using FIPS-only schemes
echo "${exe}: missing fipsonly symbols" >&2
exit 1
fi
echo "${exe} is FIPS-compliant"

View File

@ -1,3 +1,4 @@
//go:build !windows && !darwin && !linux
// +build !windows,!darwin,!linux // +build !windows,!darwin,!linux
package main package main

View File

@ -1,3 +1,4 @@
//go:build linux
// +build linux // +build linux
package main package main

View File

@ -1,3 +1,4 @@
//go:build darwin
// +build darwin // +build darwin
package main package main

View File

@ -1,4 +1,6 @@
//go:build ignore
// +build ignore // +build ignore
// TODO: Remove the above build tag and include this test when we start compiling with Golang 1.10.0+ // TODO: Remove the above build tag and include this test when we start compiling with Golang 1.10.0+
package tunnel package tunnel

View File

@ -1,3 +1,4 @@
//go:build !windows
// +build !windows // +build !windows
package tunnel package tunnel

View File

@ -1,3 +1,4 @@
//go:build !windows
// +build !windows // +build !windows
package updater package updater

View File

@ -1,3 +1,4 @@
//go:build windows
// +build windows // +build windows
package main package main

View File

@ -1,3 +1,4 @@
//go:build cgo
// +build cgo // +build cgo
package h2mux package h2mux

View File

@ -1,3 +1,4 @@
//go:build !cgo
// +build !cgo // +build !cgo
package h2mux package h2mux

View File

@ -1,3 +1,4 @@
//go:build !windows
// +build !windows // +build !windows
package origin package origin

View File

@ -1,3 +1,4 @@
//go:build !windows
// +build !windows // +build !windows
package sshgen package sshgen

View File

@ -1,4 +1,5 @@
//+build darwin //go:build darwin
// +build darwin
package token package token

View File

@ -1,4 +1,5 @@
//+build !windows,!darwin,!linux,!netbsd,!freebsd,!openbsd //go:build !windows && !darwin && !linux && !netbsd && !freebsd && !openbsd
// +build !windows,!darwin,!linux,!netbsd,!freebsd,!openbsd
package token package token

View File

@ -1,4 +1,5 @@
//+build linux freebsd openbsd netbsd //go:build linux || freebsd || openbsd || netbsd
// +build linux freebsd openbsd netbsd
package token package token

View File

@ -1,4 +1,5 @@
//+build windows //go:build windows
// +build windows
package token package token

View File

@ -1,3 +1,4 @@
//go:build linux
// +build linux // +build linux
package token package token

View File

@ -1,3 +1,4 @@
//go:build !windows
// +build !windows // +build !windows
package watcher package watcher