TUN-5551: Show whether the binary was built for FIPS compliance

This is shown in 3 ways:
 - the version output with `cloudflared version` and alike commands
 - the build_info prometheus metric
 - a logging message
This commit is contained in:
Nuno Diegues 2021-12-27 19:05:14 +00:00
parent 01ad2785ee
commit a39d95d5f7
8 changed files with 46 additions and 29 deletions

View File

@ -25,6 +25,7 @@ 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
VERSION_FLAGS := $(VERSION_FLAGS) -X "main.BuildType=FIPS"
endif
LDFLAGS := -ldflags='$(VERSION_FLAGS) $(LINK_FLAGS)'

View File

@ -1,4 +1,4 @@
package buildinfo
package cliutil
import (
"fmt"
@ -11,23 +11,39 @@ type BuildInfo struct {
GoOS string `json:"go_os"`
GoVersion string `json:"go_version"`
GoArch string `json:"go_arch"`
BuildType string `json:"build_type"`
CloudflaredVersion string `json:"cloudflared_version"`
}
func GetBuildInfo(cloudflaredVersion string) *BuildInfo {
func GetBuildInfo(buildType, version string) *BuildInfo {
return &BuildInfo{
GoOS: runtime.GOOS,
GoVersion: runtime.Version(),
GoArch: runtime.GOARCH,
CloudflaredVersion: cloudflaredVersion,
BuildType: buildType,
CloudflaredVersion: version,
}
}
func (bi *BuildInfo) Log(log *zerolog.Logger) {
log.Info().Msgf("Version %s", bi.CloudflaredVersion)
if bi.BuildType != "" {
log.Info().Msgf("Built%s", bi.GetBuildTypeMsg())
}
log.Info().Msgf("GOOS: %s, GOVersion: %s, GoArch: %s", bi.GoOS, bi.GoVersion, bi.GoArch)
}
func (bi *BuildInfo) OSArch() string {
return fmt.Sprintf("%s_%s", bi.GoOS, bi.GoArch)
}
func (bi *BuildInfo) Version() string {
return bi.CloudflaredVersion
}
func (bi *BuildInfo) GetBuildTypeMsg() string {
if bi.BuildType == "" {
return ""
}
return fmt.Sprintf(" with %s", bi.BuildType)
}

View File

@ -31,6 +31,7 @@ const (
var (
Version = "DEV"
BuildTime = "unknown"
BuildType = ""
// Mostly network errors that we don't want reported back to Sentry, this is done by substring match.
ignoredErrors = []string{
"connection reset by peer",
@ -46,9 +47,10 @@ var (
func main() {
rand.Seed(time.Now().UnixNano())
metrics.RegisterBuildInfo(BuildTime, Version)
metrics.RegisterBuildInfo(BuildType, BuildTime, Version)
raven.SetRelease(Version)
maxprocs.Set()
bInfo := cliutil.GetBuildInfo(BuildType, Version)
// Graceful shutdown channel used by the app. When closed, app must terminate gracefully.
// Windows service manager closes this channel when it receives stop command.
@ -71,7 +73,7 @@ func main() {
Terms (https://www.cloudflare.com/terms/) and Privacy Policy (https://www.cloudflare.com/privacypolicy/).`,
time.Now().Year(),
)
app.Version = fmt.Sprintf("%s (built %s)", Version, BuildTime)
app.Version = fmt.Sprintf("%s (built %s%s)", Version, BuildTime, bInfo.GetBuildTypeMsg())
app.Description = `cloudflared connects your machine or user identity to Cloudflare's global network.
You can use it to authenticate a session to reach an API behind Access, route web traffic to this machine,
and configure access control.
@ -81,7 +83,7 @@ func main() {
app.Action = action(graceShutdownC)
app.Commands = commands(cli.ShowVersion)
tunnel.Init(Version, graceShutdownC) // we need this to support the tunnel sub command...
tunnel.Init(bInfo, graceShutdownC) // we need this to support the tunnel sub command...
access.Init(graceShutdownC)
updater.Init(Version)
runApp(app, graceShutdownC)

View File

@ -22,7 +22,6 @@ import (
"github.com/urfave/cli/v2/altsrc"
"github.com/cloudflare/cloudflared/cfapi"
"github.com/cloudflare/cloudflared/cmd/cloudflared/buildinfo"
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
"github.com/cloudflare/cloudflared/cmd/cloudflared/proxydns"
"github.com/cloudflare/cloudflared/cmd/cloudflared/ui"
@ -86,7 +85,7 @@ const (
var (
graceShutdownC chan struct{}
version string
buildInfo *cliutil.BuildInfo
routeFailMsg = fmt.Sprintf("failed to provision routing, please create it manually via Cloudflare dashboard or UI; "+
"most likely you already have a conflicting record there. You can also rerun this command with --%s to overwrite "+
@ -175,8 +174,8 @@ func TunnelCommand(c *cli.Context) error {
return runClassicTunnel(sc)
}
func Init(ver string, gracefulShutdown chan struct{}) {
version, graceShutdownC = ver, gracefulShutdown
func Init(info *cliutil.BuildInfo, gracefulShutdown chan struct{}) {
buildInfo, graceShutdownC = info, gracefulShutdown
}
// runAdhocNamedTunnel create, route and run a named tunnel in one command
@ -209,7 +208,7 @@ func runAdhocNamedTunnel(sc *subcommandContext, name, credentialsOutputPath stri
// runClassicTunnel creates a "classic" non-named tunnel
func runClassicTunnel(sc *subcommandContext) error {
return StartServer(sc.c, version, nil, sc.log, sc.isUIEnabled)
return StartServer(sc.c, buildInfo, nil, sc.log, sc.isUIEnabled)
}
func routeFromFlag(c *cli.Context) (route cfapi.HostnameRoute, ok bool) {
@ -224,7 +223,7 @@ func routeFromFlag(c *cli.Context) (route cfapi.HostnameRoute, ok bool) {
func StartServer(
c *cli.Context,
version string,
info *cliutil.BuildInfo,
namedTunnel *connection.NamedTunnelConfig,
log *zerolog.Logger,
isUIEnabled bool,
@ -271,8 +270,7 @@ func StartServer(
defer trace.Stop()
}
buildInfo := buildinfo.GetBuildInfo(version)
buildInfo.Log(log)
info.Log(log)
logClientOptions(c, log)
// this context drives the server, when it's cancelled tunnel and all other components (origins, dns, etc...) should stop
@ -336,7 +334,7 @@ func StartServer(
observer.SendURL(quickTunnelURL)
}
tunnelConfig, ingressRules, err := prepareTunnelConfig(c, buildInfo, version, log, logTransport, observer, namedTunnel)
tunnelConfig, ingressRules, err := prepareTunnelConfig(c, info, log, logTransport, observer, namedTunnel)
if err != nil {
log.Err(err).Msg("Couldn't start tunnel")
return err
@ -377,7 +375,7 @@ func StartServer(
if isUIEnabled {
tunnelUI := ui.NewUIModel(
version,
info.Version(),
hostname,
metricsListener.Addr().String(),
&ingressRules,

View File

@ -16,7 +16,8 @@ import (
"github.com/urfave/cli/v2"
"golang.org/x/crypto/ssh/terminal"
"github.com/cloudflare/cloudflared/cmd/cloudflared/buildinfo"
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
"github.com/cloudflare/cloudflared/config"
"github.com/cloudflare/cloudflared/connection"
"github.com/cloudflare/cloudflared/edgediscovery"
@ -148,8 +149,7 @@ func getOriginCert(originCertPath string, log *zerolog.Logger) ([]byte, error) {
func prepareTunnelConfig(
c *cli.Context,
buildInfo *buildinfo.BuildInfo,
version string,
info *cliutil.BuildInfo,
log, logTransport *zerolog.Logger,
observer *connection.Observer,
namedTunnel *connection.NamedTunnelConfig,
@ -193,8 +193,8 @@ func prepareTunnelConfig(
namedTunnel.Client = tunnelpogs.ClientInfo{
ClientID: clientUUID[:],
Features: dedup(features),
Version: version,
Arch: buildInfo.OSArch(),
Version: info.Version(),
Arch: info.OSArch(),
}
ingressRules, err = ingress.ParseIngress(cfg)
if err != nil && err != ingress.ErrNoIngressRules {
@ -281,7 +281,7 @@ func prepareTunnelConfig(
return &origin.TunnelConfig{
ConnectionConfig: connectionConfig,
OSArch: buildInfo.OSArch(),
OSArch: info.OSArch(),
ClientID: clientID,
EdgeAddrs: c.StringSlice("edge"),
Region: c.String("region"),
@ -293,7 +293,7 @@ func prepareTunnelConfig(
Log: log,
LogTransport: logTransport,
Observer: observer,
ReportedVersion: version,
ReportedVersion: info.Version(),
// Note TUN-3758 , we use Int because UInt is not supported with altsrc
Retries: uint(c.Int("retries")),
RunFromTerminal: isRunningFromTerminal(),

View File

@ -76,7 +76,7 @@ func RunQuickTunnel(sc *subcommandContext) error {
return StartServer(
sc.c,
version,
buildInfo,
&connection.NamedTunnelConfig{Credentials: credentials, QuickTunnelUrl: data.Result.Hostname},
sc.log,
sc.isUIEnabled,

View File

@ -76,7 +76,7 @@ func (sc *subcommandContext) client() (cfapi.Client, error) {
if err != nil {
return nil, err
}
userAgent := fmt.Sprintf("cloudflared/%s", version)
userAgent := fmt.Sprintf("cloudflared/%s", buildInfo.Version())
client, err := cfapi.NewRESTClient(
sc.c.String("api-url"),
credential.cert.AccountID,
@ -303,7 +303,7 @@ func (sc *subcommandContext) run(tunnelID uuid.UUID) error {
return StartServer(
sc.c,
version,
buildInfo,
&connection.NamedTunnelConfig{Credentials: credentials},
sc.log,
sc.isUIEnabled,

View File

@ -83,15 +83,15 @@ func ServeMetrics(
return err
}
func RegisterBuildInfo(buildTime string, version string) {
func RegisterBuildInfo(buildType, buildTime, version string) {
buildInfo := prometheus.NewGaugeVec(
prometheus.GaugeOpts{
// Don't namespace build_info, since we want it to be consistent across all Cloudflare services
Name: "build_info",
Help: "Build and version information",
},
[]string{"goversion", "revision", "version"},
[]string{"goversion", "type", "revision", "version"},
)
prometheus.MustRegister(buildInfo)
buildInfo.WithLabelValues(runtime.Version(), buildTime, version).Set(1)
buildInfo.WithLabelValues(runtime.Version(), buildType, buildTime, version).Set(1)
}