From 70e675f42ca60b909e09f89996a37a6eb8db046a Mon Sep 17 00:00:00 2001 From: Nuno Diegues Date: Tue, 9 Nov 2021 11:37:51 +0000 Subject: [PATCH] TUN-5551: Reintroduce FIPS compliance for linux amd64 now as separate binaries This is a cherry-pick of 157f5d141215ec8a77a06a93ee2f9f1376b31811 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. --- Makefile | 59 +++++++------ build-packages-fips.sh | 25 ++++++ build-packages.sh | 15 ++-- cfsetup.yaml | 85 ++++++++++++------- check-fips.sh | 15 ++++ cmd/cloudflared/generic_service.go | 1 + cmd/cloudflared/linux_service.go | 1 + cmd/cloudflared/macos_service.go | 1 + cmd/cloudflared/tunnel/configuration_test.go | 2 + cmd/cloudflared/tunnel/signal_test.go | 1 + .../updater/workers_service_test.go | 1 + cmd/cloudflared/windows_service.go | 1 + h2mux/h2_compressor_brotli.go | 1 + h2mux/h2_compressor_none.go | 1 + origin/proxy_posix_test.go | 1 + sshgen/sshgen_test.go | 1 + token/launch_browser_darwin.go | 3 +- token/launch_browser_other.go | 3 +- token/launch_browser_unix.go | 3 +- token/launch_browser_windows.go | 3 +- token/token_test.go | 1 + watcher/file_test.go | 1 + 22 files changed, 160 insertions(+), 65 deletions(-) create mode 100755 build-packages-fips.sh create mode 100755 check-fips.sh diff --git a/Makefile b/Makefile index 9bce8cbc..e6ee3c3e 100644 --- a/Makefile +++ b/Makefile @@ -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. ifeq ($(FIPS), true) - GO_BUILD_TAGS := $(GO_BUILD_TAGS) fips -endif - -ifneq ($(GO_BUILD_TAGS),) - GO_BUILD_TAGS := -tags $(GO_BUILD_TAGS) + BINARY_NAME := cloudflared-fips +else + BINARY_NAME := cloudflared endif ifeq ($(NIGHTLY), true) + # We do not release FIPS in NIGHTLY, so no need to consider that case here. DEB_PACKAGE_NAME := cloudflared-nightly NIGHTLY_FLAGS := --conflicts cloudflared --replaces cloudflared else - DEB_PACKAGE_NAME := cloudflared + DEB_PACKAGE_NAME := $(BINARY_NAME) endif 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 PACKAGE_DIR := $(CURDIR)/packaging @@ -61,9 +72,9 @@ else endif ifeq ($(TARGET_OS), windows) - EXECUTABLE_PATH=./cloudflared.exe + EXECUTABLE_PATH=./$(BINARY_NAME).exe else - EXECUTABLE_PATH=./cloudflared + EXECUTABLE_PATH=./$(BINARY_NAME) endif ifeq ($(FLAVOR), centos-7) @@ -80,17 +91,15 @@ clean: go clean .PHONY: cloudflared -cloudflared: +cloudflared: ifeq ($(FIPS), true) $(info Building cloudflared with go-fips) - -test -f fips/fips.go && mv fips/fips.go fips/fips.go.linux-amd64 - mv fips/fips.go.linux-amd64 fips/fips.go + cp -f fips/fips.go.linux-amd64 cmd/cloudflared/fips.go endif - - GOOS=$(TARGET_OS) GOARCH=$(TARGET_ARCH) go build -v -mod=vendor $(GO_BUILD_TAGS) $(VERSION_FLAGS) $(IMPORT_PATH)/cmd/cloudflared - + GOOS=$(TARGET_OS) GOARCH=$(TARGET_ARCH) go build -v -mod=vendor $(GO_BUILD_TAGS) $(LDFLAGS) $(IMPORT_PATH)/cmd/cloudflared ifeq ($(FIPS), true) - mv fips/fips.go fips/fips.go.linux-amd64 + rm -f cmd/cloudflared/fips.go + ./check-fips.sh cloudflared endif .PHONY: container @@ -100,10 +109,10 @@ container: .PHONY: test test: vet ifndef CI - go test -v -mod=vendor -race $(VERSION_FLAGS) ./... + go test -v -mod=vendor -race $(LDFLAGS) ./... else @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 endif @@ -112,10 +121,10 @@ test-ssh-server: docker-compose -f ssh_server_tests/docker-compose.yml up define publish_package - chmod 664 cloudflared*.$(1); \ + chmod 664 $(BINARY_NAME)*.$(1); \ for HOST in $(CF_PKG_HOSTS); do \ 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 endef @@ -127,6 +136,8 @@ publish-deb: cloudflared-deb publish-rpm: cloudflared-rpm $(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 mkdir -p $(PACKAGE_DIR) cp cloudflared $(PACKAGE_DIR)/cloudflared @@ -247,8 +258,8 @@ tunnelrpc-deps: capnp compile -ogo tunnelrpc/tunnelrpc.capnp .PHONY: quic-deps -quic-deps: - which capnp +quic-deps: + which capnp which capnpc-go 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) # 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. - which go-sumtype + which go-sumtype go-sumtype $$(go list -mod=vendor ./...) .PHONY: 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 \ No newline at end of file diff --git a/build-packages-fips.sh b/build-packages-fips.sh new file mode 100755 index 00000000..6daec235 --- /dev/null +++ b/build-packages-fips.sh @@ -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 \ No newline at end of file diff --git a/build-packages.sh b/build-packages.sh index 7b4ece82..2c01bf9b 100755 --- a/build-packages.sh +++ b/build-packages.sh @@ -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 + +# Avoid depending on C code since we don't need it. export CGO_ENABLED=0 + # This controls the directory the built artifacts go into export ARTIFACT_DIR=built_artifacts/ mkdir -p $ARTIFACT_DIR windowsArchs=("amd64" "386") export TARGET_OS=windows -for arch in ${windowsArchs[@]}; do +for arch in ${windowsArchs[@]}; do export TARGET_ARCH=$arch make cloudflared-msi mv ./cloudflared.exe $ARTIFACT_DIR/cloudflared-windows-$arch.exe @@ -14,15 +17,14 @@ for arch in ${windowsArchs[@]}; do done -export FIPS=true -linuxArchs=("amd64" "386" "arm" "arm64") +linuxArchs=("386" "amd64" "arm" "arm64") export TARGET_OS=linux -for arch in ${linuxArchs[@]}; do +for arch in ${linuxArchs[@]}; do export TARGET_ARCH=$arch make cloudflared-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') RPMARCH=$arch if [ $arch == "amd64" ];then @@ -37,4 +39,3 @@ for arch in ${linuxArchs[@]}; do # finally move the linux binary as well. mv ./cloudflared $ARTIFACT_DIR/cloudflared-linux-$arch done - diff --git a/cfsetup.yaml b/cfsetup.yaml index 383fab86..6380d459 100644 --- a/cfsetup.yaml +++ b/cfsetup.yaml @@ -1,20 +1,10 @@ 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 default-flavor: buster stretch: &stretch 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 builddeps: - *pinned_go @@ -23,11 +13,22 @@ stretch: &stretch - export GOOS=linux - export GOARCH=amd64 - make cloudflared - build-all-packages: #except osxpkg + build-fips: build_dir: *build_dir builddeps: - *pinned_go_fips - 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 - rubygem-fpm - rpm @@ -35,15 +36,21 @@ stretch: &stretch # libmsi and libgcab are libraries the wixl binary depends on. - libmsi-dev - libgcab-dev - pre-cache: - # TODO: https://jira.cfops.it/browse/TUN-4792 Replace this wixl with the official one once msitools supports - # environment. + - python3-dev + - libffi-dev + - 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 - chmod a+x /usr/local/bin/wixl + - pip3 install pygithub post-cache: - - export FIPS=true + # build all packages (except macos and FIPS) and move them to /cfsetup/built_artifacts - ./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 builddeps: - *pinned_go_fips @@ -59,18 +66,25 @@ stretch: &stretch - libffi-dev - python3-setuptools - python3-pip - 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 + pre-cache: *github_release_pkgs_pre_cache post-cache: - # build all packages and move them to /cfsetup/built_artifacts - - ./build-packages.sh - # release the packages built and moved to /cfsetup/built_artifacts + # same logic as above, but for FIPS packages only + - ./build-packages-fips.sh - make github-release-built-pkgs build-deb: build_dir: *build_dir 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 - build-essential - fakeroot @@ -86,7 +100,6 @@ stretch: &stretch post-cache: - export GOOS=linux - export GOARCH=amd64 - - export FIPS=true - export NIGHTLY=true - make cloudflared-deb build-deb-arm64: @@ -99,7 +112,7 @@ stretch: &stretch publish-deb: build_dir: *build_dir builddeps: - - *pinned_go_fips + - *pinned_go - build-essential - fakeroot - rubygem-fpm @@ -107,7 +120,6 @@ stretch: &stretch post-cache: - export GOOS=linux - export GOARCH=amd64 - - export FIPS=true - make publish-deb github-release-macos-amd64: build_dir: *build_dir @@ -123,14 +135,27 @@ stretch: &stretch post-cache: - make github-mac-upload 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 builddeps: - *pinned_go_fips - build-essential - gotest-to-teamcity - pre-cache: - - go get golang.org/x/tools/cmd/goimports - - go get github.com/sudarshan-reddy/go-sumtype@v0.0.0-20210827105221-82eca7e5abb1 + pre-cache: *test_pre_cache post-cache: - export GOOS=linux - export GOARCH=amd64 diff --git a/check-fips.sh b/check-fips.sh new file mode 100755 index 00000000..98c05af1 --- /dev/null +++ b/check-fips.sh @@ -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" diff --git a/cmd/cloudflared/generic_service.go b/cmd/cloudflared/generic_service.go index 1b237593..25872bbf 100644 --- a/cmd/cloudflared/generic_service.go +++ b/cmd/cloudflared/generic_service.go @@ -1,3 +1,4 @@ +//go:build !windows && !darwin && !linux // +build !windows,!darwin,!linux package main diff --git a/cmd/cloudflared/linux_service.go b/cmd/cloudflared/linux_service.go index 32314092..85d195fa 100644 --- a/cmd/cloudflared/linux_service.go +++ b/cmd/cloudflared/linux_service.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package main diff --git a/cmd/cloudflared/macos_service.go b/cmd/cloudflared/macos_service.go index 31bfb3bd..e987df87 100644 --- a/cmd/cloudflared/macos_service.go +++ b/cmd/cloudflared/macos_service.go @@ -1,3 +1,4 @@ +//go:build darwin // +build darwin package main diff --git a/cmd/cloudflared/tunnel/configuration_test.go b/cmd/cloudflared/tunnel/configuration_test.go index c18c6c09..b4edf636 100644 --- a/cmd/cloudflared/tunnel/configuration_test.go +++ b/cmd/cloudflared/tunnel/configuration_test.go @@ -1,4 +1,6 @@ +//go:build ignore // +build ignore + // TODO: Remove the above build tag and include this test when we start compiling with Golang 1.10.0+ package tunnel diff --git a/cmd/cloudflared/tunnel/signal_test.go b/cmd/cloudflared/tunnel/signal_test.go index 43921c6f..294ed713 100644 --- a/cmd/cloudflared/tunnel/signal_test.go +++ b/cmd/cloudflared/tunnel/signal_test.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package tunnel diff --git a/cmd/cloudflared/updater/workers_service_test.go b/cmd/cloudflared/updater/workers_service_test.go index 94cf8a7e..72a51c9c 100644 --- a/cmd/cloudflared/updater/workers_service_test.go +++ b/cmd/cloudflared/updater/workers_service_test.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package updater diff --git a/cmd/cloudflared/windows_service.go b/cmd/cloudflared/windows_service.go index 87602c42..2eba4780 100644 --- a/cmd/cloudflared/windows_service.go +++ b/cmd/cloudflared/windows_service.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package main diff --git a/h2mux/h2_compressor_brotli.go b/h2mux/h2_compressor_brotli.go index ed0b85b7..6ff99514 100644 --- a/h2mux/h2_compressor_brotli.go +++ b/h2mux/h2_compressor_brotli.go @@ -1,3 +1,4 @@ +//go:build cgo // +build cgo package h2mux diff --git a/h2mux/h2_compressor_none.go b/h2mux/h2_compressor_none.go index 1ca4d284..bfd6bafe 100644 --- a/h2mux/h2_compressor_none.go +++ b/h2mux/h2_compressor_none.go @@ -1,3 +1,4 @@ +//go:build !cgo // +build !cgo package h2mux diff --git a/origin/proxy_posix_test.go b/origin/proxy_posix_test.go index 24b1f278..1b649a43 100644 --- a/origin/proxy_posix_test.go +++ b/origin/proxy_posix_test.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package origin diff --git a/sshgen/sshgen_test.go b/sshgen/sshgen_test.go index a42345ba..99ac8021 100644 --- a/sshgen/sshgen_test.go +++ b/sshgen/sshgen_test.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package sshgen diff --git a/token/launch_browser_darwin.go b/token/launch_browser_darwin.go index b5b2ff53..a9cb9e82 100644 --- a/token/launch_browser_darwin.go +++ b/token/launch_browser_darwin.go @@ -1,4 +1,5 @@ -//+build darwin +//go:build darwin +// +build darwin package token diff --git a/token/launch_browser_other.go b/token/launch_browser_other.go index ac4cc319..fb0c558c 100644 --- a/token/launch_browser_other.go +++ b/token/launch_browser_other.go @@ -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 diff --git a/token/launch_browser_unix.go b/token/launch_browser_unix.go index 2b15a0ff..0a6adc4d 100644 --- a/token/launch_browser_unix.go +++ b/token/launch_browser_unix.go @@ -1,4 +1,5 @@ -//+build linux freebsd openbsd netbsd +//go:build linux || freebsd || openbsd || netbsd +// +build linux freebsd openbsd netbsd package token diff --git a/token/launch_browser_windows.go b/token/launch_browser_windows.go index a49b99f3..da0edd91 100644 --- a/token/launch_browser_windows.go +++ b/token/launch_browser_windows.go @@ -1,4 +1,5 @@ -//+build windows +//go:build windows +// +build windows package token diff --git a/token/token_test.go b/token/token_test.go index 65d9a751..18bcf448 100644 --- a/token/token_test.go +++ b/token/token_test.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package token diff --git a/watcher/file_test.go b/watcher/file_test.go index 1e99fe30..1c20e4b1 100644 --- a/watcher/file_test.go +++ b/watcher/file_test.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package watcher