diff --git a/Dockerfile b/Dockerfile index bb5f202e..c42f2de5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,11 @@ RUN \ --mount=type=cache,target=/cache/gocache \ --mount=type=cache,target=/cache/gomodcache \ mkdir out && \ - export GOCACHE=/cache/gocache GOMODCACHE=/cache/gomodcache CGO_ENABLED=0 GOOS=linux GOARCH=amd64 && \ + export GOCACHE=/cache/gocache && \ + export GOMODCACHE=/cache/gomodcache && \ + export CGO_ENABLED=0 && \ + export GOOS=linux && \ + export GOARCH=amd64 && \ go build -v -trimpath -ldflags "$(hack/get-ldflags.sh) -w -s" -o /usr/local/bin/pinniped-concierge-kube-cert-agent ./cmd/pinniped-concierge-kube-cert-agent/... && \ go build -v -trimpath -ldflags "$(hack/get-ldflags.sh) -w -s" -o /usr/local/bin/pinniped-server ./cmd/pinniped-server/... && \ ln -s /usr/local/bin/pinniped-server /usr/local/bin/pinniped-concierge && \ diff --git a/cmd/pinniped-concierge-kube-cert-agent/main.go b/cmd/pinniped-concierge-kube-cert-agent/main.go index af96c5f8..78b0fb7f 100644 --- a/cmd/pinniped-concierge-kube-cert-agent/main.go +++ b/cmd/pinniped-concierge-kube-cert-agent/main.go @@ -13,7 +13,7 @@ import ( "os" "time" - // This side effect import ensures that we use fipsonly crypto during TLS in fips_strict mode. + // This side effect import ensures that we use fipsonly crypto in boringcrypto mode. // // Commenting this out because it causes the runtime memory consumption of this binary to increase // from ~1 MB to ~8 MB (as measured when running the sleep subcommand). This binary does not use TLS, @@ -25,11 +25,8 @@ import ( //nolint:godot // This is not sentence, it is a commented out line of import code. // _ "go.pinniped.dev/internal/crypto/ptls" - // This side effect imports cgo so that runtime/cgo gets linked, when in fips_strict mode. - // Without this line, the binary will exit 133 upon startup in fips_strict mode. - // It also enables fipsonly tls mode, just to be absolutely sure that the fips code is enabled, - // even though it shouldn't be used currently by this binary. - _ "go.pinniped.dev/internal/crypto/fips" + // This side effect ensures building with at least go1.19. + _ "go.pinniped.dev/internal/build" ) //nolint:gochecknoglobals // these are swapped during unit tests. diff --git a/cmd/pinniped-server/main.go b/cmd/pinniped-server/main.go index df2917fb..3dd17233 100644 --- a/cmd/pinniped-server/main.go +++ b/cmd/pinniped-server/main.go @@ -15,11 +15,15 @@ import ( "k8s.io/apimachinery/pkg/util/sets" concierge "go.pinniped.dev/internal/concierge/server" - // this side effect import ensures that we use fipsonly crypto in fips_strict mode. - _ "go.pinniped.dev/internal/crypto/ptls" lua "go.pinniped.dev/internal/localuserauthenticator" "go.pinniped.dev/internal/plog" supervisor "go.pinniped.dev/internal/supervisor/server" + + // this side effect import ensures that we use fipsonly crypto in boringcrypto mode. + _ "go.pinniped.dev/internal/crypto/ptls" + + // This side effect ensures building with at least go1.19. + _ "go.pinniped.dev/internal/build" ) //nolint:gochecknoglobals // these are swapped during unit tests. diff --git a/cmd/pinniped/main.go b/cmd/pinniped/main.go index b4825b1e..63ef7c5f 100644 --- a/cmd/pinniped/main.go +++ b/cmd/pinniped/main.go @@ -1,4 +1,4 @@ -// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package main @@ -9,8 +9,11 @@ import ( "github.com/pkg/browser" "go.pinniped.dev/cmd/pinniped/cmd" - // this side effect import ensures that we use fipsonly crypto in fips_strict mode. + // this side effect import ensures that we use fipsonly crypto in boringcrypto mode. _ "go.pinniped.dev/internal/crypto/ptls" + + // This side effect ensures building with at least go1.19. + _ "go.pinniped.dev/internal/build" ) //nolint:gochecknoinits diff --git a/hack/Dockerfile_fips b/hack/Dockerfile_fips index bf883a6a..447b1f7d 100644 --- a/hack/Dockerfile_fips +++ b/hack/Dockerfile_fips @@ -3,13 +3,13 @@ # Copyright 2022-2023 the Pinniped contributors. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -# this dockerfile is used to produce a binary of Pinniped that uses -# only fips-allowable ciphers. Note that this is provided only as -# an example. Pinniped has no official support for fips and using +# This dockerfile is used to produce a binary of Pinniped that uses +# only FIPS-allowable ciphers. Note that this is provided only as +# an example. Pinniped has no official support for FIPS and using # a version built from this dockerfile may have unforseen consquences. # Please do not create issues in regards to problems encountered by # using this dockerfile. Using this dockerfile does not convey -# any type of fips certification. +# any type of FIPS certification. # Starting in 1.19, go-boringcrypto has been added to the main Go toolchain, # hidden behind a `GOEXPERIMENT=boringcrypto` env var. @@ -21,37 +21,15 @@ WORKDIR /work COPY . . ARG GOPROXY -# Build the executable binary (CGO_ENABLED=1 is required for go boring). -# Even though we need cgo to call the boring crypto C functions, these -# functions are statically linked into the binary. We also want to statically -# link any libc bits hence we pass "-linkmode=external -extldflags -static" -# to the ldflags directive. We do not pass "-s" to ldflags because we do -# not want to strip symbols - those are used to verify if we compiled correctly. -# We do not pass in GOCACHE (build cache) and GOMODCACHE (module cache) -# because there have been bugs in the Go compiler caching when using cgo -# (it will sometimes use cached artifiacts when it should not). Since we -# use gcc as the C compiler, the following warning is emitted: -# /boring/boringssl/build/../crypto/bio/socket_helper.c:55: warning: -# Using 'getaddrinfo' in statically linked applications requires at -# runtime the shared libraries from the glibc version used for linking -# This is referring to the code in -# https://github.com/google/boringssl/blob/af34f6460f0bf99dc267818f02b2936f60a30de7/crypto/bio/socket_helper.c#L55 -# which calls the getaddrinfo function. This function, even when statically linked, -# uses dlopen to dynamically fetch networking config. It is safe for us to ignore -# this warning because the go boring cypto code does not create netowrking connections: -# https://github.com/golang/go/blob/9d6ab825f6fe125f7ce630e103b887e580403802/src/crypto/internal/boring/goboringcrypto.h -# The osusergo and netgo tags are used to make sure that the Go implementations of these -# standard library packages are used instead of the libc based versions. -# We want to have no reliance on any C code other than the boring crypto bits. -# Setting GOOS=linux GOARCH=amd64 is a hard requirment for boring crypto: -# https://github.com/golang/go/blob/9d6ab825f6fe125f7ce630e103b887e580403802/misc/boring/README.md?plain=1#L95 -# Thus trying to compile the pinniped CLI with boring crypto is meaningless -# since we would not be able to ship windows and macOS binaries. +# GOEXPERIMENT=boringcrypto will tell both Pinniped source code and Golang to use boringcrypto RUN \ mkdir out && \ - export CGO_ENABLED=1 GOOS=linux GOARCH=amd64 GOEXPERIMENT=boringcrypto && \ - go build -tags fips_strict,osusergo,netgo -v -trimpath -ldflags "$(hack/get-ldflags.sh) -w -linkmode=external -extldflags -static" -o /usr/local/bin/pinniped-concierge-kube-cert-agent ./cmd/pinniped-concierge-kube-cert-agent/... && \ - go build -tags fips_strict,osusergo,netgo -v -trimpath -ldflags "$(hack/get-ldflags.sh) -w -linkmode=external -extldflags -static" -o /usr/local/bin/pinniped-server ./cmd/pinniped-server/... && \ + export CGO_ENABLED=1 && \ + export GOOS=linux && \ + export GOARCH=amd64 && \ + export GOEXPERIMENT=boringcrypto && \ + go build -tags osusergo,netgo -v -trimpath -ldflags "$(hack/get-ldflags.sh) -w -linkmode=external -extldflags -static" -o /usr/local/bin/pinniped-concierge-kube-cert-agent ./cmd/pinniped-concierge-kube-cert-agent/... && \ + go build -tags osusergo,netgo -v -trimpath -ldflags "$(hack/get-ldflags.sh) -w -linkmode=external -extldflags -static" -o /usr/local/bin/pinniped-server ./cmd/pinniped-server/... && \ ln -s /usr/local/bin/pinniped-server /usr/local/bin/pinniped-concierge && \ ln -s /usr/local/bin/pinniped-server /usr/local/bin/pinniped-supervisor && \ ln -s /usr/local/bin/pinniped-server /usr/local/bin/local-user-authenticator diff --git a/hack/check-copyright-year.sh b/hack/check-copyright-year.sh index 0870da68..4341f19c 100755 --- a/hack/check-copyright-year.sh +++ b/hack/check-copyright-year.sh @@ -24,6 +24,6 @@ if [[ "${#missing_copyright_files[@]}" -gt "0" ]]; then for f in "${missing_copyright_files[@]}"; do echo " $f" done - echo "Try using hack/update-copyright-year.sh to update the copyright automatically in staged files." + echo "Try using ./hack/update-copyright-year.sh to update the copyright automatically in staged files." exit 1 fi diff --git a/internal/build/package.go b/internal/build/package.go new file mode 100644 index 00000000..335c1e27 --- /dev/null +++ b/internal/build/package.go @@ -0,0 +1,4 @@ +// Copyright 2023 the Pinniped contributors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package build diff --git a/internal/build/requires_1.19.go b/internal/build/requires_1.19.go new file mode 100644 index 00000000..9772e131 --- /dev/null +++ b/internal/build/requires_1.19.go @@ -0,0 +1,11 @@ +// Copyright 2023 the Pinniped contributors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +//go:build !go1.19 + +package build + +func init() { + // fail unless compiling with 1.19+ + "requires go1.19 or greater" +} diff --git a/internal/crypto/fips/doc.go b/internal/crypto/fips/doc.go deleted file mode 100644 index e265bb85..00000000 --- a/internal/crypto/fips/doc.go +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2023 the Pinniped contributors. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -// Package fips can be imported to enable fipsonly tls mode when compiling with fips_strict. -// It will also cause cgo to be explicitly imported when compiling with fips_strict. -package fips diff --git a/internal/crypto/fips/fips_strict.go b/internal/crypto/fips/fips_strict.go deleted file mode 100644 index f9459b62..00000000 --- a/internal/crypto/fips/fips_strict.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2023 the Pinniped contributors. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -//go:build fips_strict - -package fips - -import ( - "C" // explicitly import cgo so that runtime/cgo gets linked into the kube-cert-agent - _ "crypto/tls/fipsonly" // restricts all TLS configuration to FIPS-approved settings. -) diff --git a/internal/crypto/ptls/boringcrypto.go b/internal/crypto/ptls/boringcrypto.go new file mode 100644 index 00000000..b6d27dc5 --- /dev/null +++ b/internal/crypto/ptls/boringcrypto.go @@ -0,0 +1,28 @@ +// Copyright 2022-2023 the Pinniped contributors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +//go:build boringcrypto + +package ptls + +import ( + "C" // explicitly import cgo + _ "crypto/tls/fipsonly" // restricts all TLS configuration to FIPS-approved settings. + "os" + "path/filepath" + "runtime" + + "go.pinniped.dev/internal/plog" +) + +func init() { + switch filepath.Base(os.Args[0]) { + case "pinniped-server", "pinniped-supervisor", "pinniped-concierge", "pinniped-concierge-kube-cert-agent": + default: + return // do not print FIPS logs if we cannot confirm that we are running a server binary + } + + // this init runs before we have parsed our config to determine our log level + // thus we must use a log statement that will always print instead of conditionally print + plog.Always("using boring crypto in fips only mode", "go version", runtime.Version()) +} diff --git a/internal/crypto/ptls/default.go b/internal/crypto/ptls/default.go index 98a70015..a1aa006a 100644 --- a/internal/crypto/ptls/default.go +++ b/internal/crypto/ptls/default.go @@ -1,7 +1,7 @@ // Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -//go:build !fips_strict +//go:build !boringcrypto package ptls diff --git a/internal/crypto/ptls/fips_strict.go b/internal/crypto/ptls/default_boringcrypto.go similarity index 71% rename from internal/crypto/ptls/fips_strict.go rename to internal/crypto/ptls/default_boringcrypto.go index d5039854..feb53929 100644 --- a/internal/crypto/ptls/fips_strict.go +++ b/internal/crypto/ptls/default_boringcrypto.go @@ -1,10 +1,7 @@ // Copyright 2022-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -// The configurations here override the usual ptls.Secure, ptls.Default, and ptls.DefaultLDAP -// configs when Pinniped is built in fips-only mode. -// All of these are the same because FIPs is already so limited. -//go:build fips_strict +//go:build boringcrypto package ptls @@ -15,17 +12,9 @@ import ( "path/filepath" "runtime" - "k8s.io/apiserver/pkg/server/options" - - // Cause fipsonly tls mode with this side effect import. - _ "go.pinniped.dev/internal/crypto/fips" "go.pinniped.dev/internal/plog" ) -// Always use TLS 1.2 for FIPs -const secureServingOptionsMinTLSVersion = "VersionTLS12" -const SecureTLSConfigMinTLSVersion = tls.VersionTLS12 - func init() { switch filepath.Base(os.Args[0]) { case "pinniped-server", "pinniped-supervisor", "pinniped-concierge", "pinniped-concierge-kube-cert-agent": @@ -52,7 +41,7 @@ func Default(rootCAs *x509.CertPool) *tls.Config { // optional root CAs, nil means use the host's root CA set RootCAs: rootCAs, - // This is all of the fips-approved ciphers. + // This is all the fips-approved ciphers. // The list is hard-coded for convenience of testing. // This is kept in sync with the boring crypto compiler via TestFIPSCipherSuites. CipherSuites: []uint16{ @@ -66,14 +55,6 @@ func Default(rootCAs *x509.CertPool) *tls.Config { } } -func Secure(rootCAs *x509.CertPool) *tls.Config { - return Default(rootCAs) -} - func DefaultLDAP(rootCAs *x509.CertPool) *tls.Config { return Default(rootCAs) } - -func secureServing(opts *options.SecureServingOptionsWithLoopback) { - defaultServing(opts) -} diff --git a/internal/crypto/ptls/old.go b/internal/crypto/ptls/old.go deleted file mode 100644 index 0848df7d..00000000 --- a/internal/crypto/ptls/old.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -//go:build !go1.19 - -package ptls - -func init() { - // cause compile time failure if an older version of Go is used - `Pinniped's TLS configuration makes assumptions about how the Go standard library implementation of TLS works. -It particular, we rely on the server controlling cipher suite selection. For these assumptions to hold, Pinniped -must be compiled with Go 1.19+. If you are seeing this error message, your attempt to compile Pinniped with an -older Go compiler was explicitly failed to prevent an unsafe configuration.` -} diff --git a/internal/crypto/ptls/secure.go b/internal/crypto/ptls/secure.go index 68e65b0e..84d3ea17 100644 --- a/internal/crypto/ptls/secure.go +++ b/internal/crypto/ptls/secure.go @@ -1,7 +1,7 @@ // Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -//go:build !fips_strict +//go:build !boringcrypto package ptls diff --git a/internal/crypto/ptls/secure_boringcrypto.go b/internal/crypto/ptls/secure_boringcrypto.go new file mode 100644 index 00000000..82ee0a06 --- /dev/null +++ b/internal/crypto/ptls/secure_boringcrypto.go @@ -0,0 +1,32 @@ +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +//go:build boringcrypto + +package ptls + +import ( + "crypto/tls" + "crypto/x509" + + "k8s.io/apiserver/pkg/server/options" +) + +// secureServingOptionsMinTLSVersion is the minimum tls version in the format +// expected by SecureServingOptions.MinTLSVersion from +// k8s.io/apiserver/pkg/server/options. +// +// Always use TLS 1.2 for FIPs. +const secureServingOptionsMinTLSVersion = "VersionTLS12" + +// SecureTLSConfigMinTLSVersion is the minimum tls version in the format expected +// by tls.Config. +const SecureTLSConfigMinTLSVersion = tls.VersionTLS12 + +func Secure(rootCAs *x509.CertPool) *tls.Config { + return Default(rootCAs) +} + +func secureServing(opts *options.SecureServingOptionsWithLoopback) { + defaultServing(opts) +} diff --git a/site/content/docs/reference/fips.md b/site/content/docs/reference/fips.md index e3391b18..6f603b3e 100644 --- a/site/content/docs/reference/fips.md +++ b/site/content/docs/reference/fips.md @@ -12,8 +12,7 @@ menu: By default, the Pinniped supervisor and concierge use ciphers that are not supported by FIPS 140-2. If you are deploying Pinniped in an environment with FIPS compliance requirements, you will have to build -the binaries yourself using the `fips_strict` build tag and Golang's -`go-boringcrypto` fork. +the binaries yourself using Golang 1.19 and the `GOEXPERIMENT=boringcrypto` build tag. The Pinniped team provides an [example Dockerfile](https://github.com/vmware-tanzu/pinniped/blob/main/hack/Dockerfile_fips) demonstrating how you can build Pinniped images in a FIPS compatible way. diff --git a/test/integration/securetls_fips_test.go b/test/integration/securetls_fips_test.go index 5a35ab5e..521784c5 100644 --- a/test/integration/securetls_fips_test.go +++ b/test/integration/securetls_fips_test.go @@ -1,7 +1,7 @@ // Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -//go:build fips_strict +//go:build boringcrypto package integration diff --git a/test/testlib/securetls_preference_fips.go b/test/testlib/securetls_preference_fips.go index 3d76932e..303eb435 100644 --- a/test/testlib/securetls_preference_fips.go +++ b/test/testlib/securetls_preference_fips.go @@ -1,7 +1,7 @@ // Copyright 2022-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -//go:build fips_strict +//go:build boringcrypto package testlib diff --git a/test/testlib/securetls_preference_nonfips.go b/test/testlib/securetls_preference_nonfips.go index 3306a9c1..d1f74400 100644 --- a/test/testlib/securetls_preference_nonfips.go +++ b/test/testlib/securetls_preference_nonfips.go @@ -1,7 +1,7 @@ // Copyright 2022-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -//go:build !fips_strict +//go:build !boringcrypto package testlib