Skip to content

Commit

Permalink
cliccl: Add debug enterprise-check-fips command
Browse files Browse the repository at this point in the history
This command reports on the status of certain prerequisites for our fips-ready
builds.

Updates #114344

Release note (cli change): New command `cockroach debug
enterprise-check-fips` diagnoses errors in FIPS deployments
  • Loading branch information
bdarnell committed Nov 27, 2023
1 parent 8023b29 commit cd9077c
Show file tree
Hide file tree
Showing 9 changed files with 229 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@
/pkg/scheduledjobs/ @cockroachdb/jobs-prs @cockroachdb/disaster-recovery
/pkg/security/ @cockroachdb/prodsec @cockroachdb/server-prs
/pkg/security/clientsecopts/ @cockroachdb/sql-foundations @cockroachdb/prodsec
/pkg/ccl/securityccl/ @cockroachdb/prodsec
#!/pkg/settings/ @cockroachdb/unowned
/pkg/spanconfig/ @cockroachdb/kv-prs @cockroachdb/sql-foundations
/pkg/spanconfig/spanconfigbounds/ @cockroachdb/sql-foundations
Expand Down
1 change: 1 addition & 0 deletions pkg/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,7 @@ GO_TARGETS = [
"//pkg/ccl/pgcryptoccl:pgcryptoccl_test",
"//pkg/ccl/schemachangerccl:schemachangerccl",
"//pkg/ccl/schemachangerccl:schemachangerccl_test",
"//pkg/ccl/securityccl/fipsccl:fipsccl",
"//pkg/ccl/serverccl/adminccl:adminccl_test",
"//pkg/ccl/serverccl/diagnosticsccl:diagnosticsccl_test",
"//pkg/ccl/serverccl/statusccl:statusccl_test",
Expand Down
2 changes: 2 additions & 0 deletions pkg/ccl/cliccl/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ go_library(
"//pkg/base",
"//pkg/ccl/baseccl",
"//pkg/ccl/cliccl/cliflagsccl",
"//pkg/ccl/securityccl/fipsccl",
"//pkg/ccl/sqlproxyccl",
"//pkg/ccl/sqlproxyccl/tenantdirsvr",
"//pkg/ccl/storageccl/engineccl/enginepbccl",
Expand All @@ -41,6 +42,7 @@ go_library(
"@com_github_cockroachdb_errors//oserror",
"@com_github_cockroachdb_pebble//vfs",
"@com_github_cockroachdb_redact//:redact",
"@com_github_olekukonko_tablewriter//:tablewriter",
"@com_github_spf13_cobra//:cobra",
],
)
Expand Down
56 changes: 56 additions & 0 deletions pkg/ccl/cliccl/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"sort"
"time"

"github.com/cockroachdb/cockroach/pkg/base"
"github.com/cockroachdb/cockroach/pkg/ccl/baseccl"
"github.com/cockroachdb/cockroach/pkg/ccl/cliccl/cliflagsccl"
"github.com/cockroachdb/cockroach/pkg/ccl/securityccl/fipsccl"
"github.com/cockroachdb/cockroach/pkg/ccl/storageccl/engineccl/enginepbccl"
"github.com/cockroachdb/cockroach/pkg/cli"
"github.com/cockroachdb/cockroach/pkg/cli/clierrorplus"
Expand All @@ -31,6 +33,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/util/timeutil"
"github.com/cockroachdb/errors"
"github.com/cockroachdb/errors/oserror"
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -102,12 +105,24 @@ with their env type and encryption settings (if applicable).
RunE: clierrorplus.MaybeDecorateError(runList),
}

checkFipsCmd := &cobra.Command{
Use: "enterprise-check-fips",
Short: "print diagnostics for FIPS-ready configuration",
Long: `
Performs various tests of this binary's ability to operate in FIPS-ready
mode in the current environment.
`,

RunE: clierrorplus.MaybeDecorateError(runCheckFips),
}

// Add commands to the root debug command.
// We can't add them to the lists of commands (eg: DebugCmdsForPebble) as cli init() is called before us.
cli.DebugCmd.AddCommand(encryptionStatusCmd)
cli.DebugCmd.AddCommand(encryptionActiveKeyCmd)
cli.DebugCmd.AddCommand(encryptionDecryptCmd)
cli.DebugCmd.AddCommand(encryptionRegistryList)
cli.DebugCmd.AddCommand(checkFipsCmd)

// Add the encryption flag to commands that need it.
// For the encryption-status command.
Expand Down Expand Up @@ -376,3 +391,44 @@ func getActiveEncryptionkey(dir string) (string, string, error) {

return setting.EncryptionType.String(), setting.KeyId, nil
}

func runCheckFips(cmd *cobra.Command, args []string) error {
if runtime.GOOS != "linux" {
return errors.New("FIPS-ready mode is only supported on linux")
}
// Our FIPS-ready deployments have three major requirements:
// 1. This binary is built with the golang-fips toolchain and running on linux
// 2. FIPS mode is enabled in the kernel.
// 3. We can dynamically load the OpenSSL library (which must be the same major version that was present at
// build time). Verifying that the OpenSSL library is FIPS-compliant is outside the scope of this command.
table := tablewriter.NewWriter(os.Stdout)
table.SetBorder(false)
table.SetAlignment(tablewriter.ALIGN_LEFT)
emit := func(label string, status bool, detail string) {
statusSymbol := "❌"
if status {
statusSymbol = "✅"
}
table.Append([]string{label, statusSymbol, detail})
}

emit("FIPS-ready build", fipsccl.IsCompileTimeFIPSReady(), "")
buildOpenSSLVersion, soname, err := fipsccl.BuildOpenSSLVersion()
if err == nil {
table.Append([]string{"Build-time OpenSSL Version", "", buildOpenSSLVersion})
table.Append([]string{"OpenSSL library filename", "", soname})
}

isKernelEnabled, err := fipsccl.IsKernelEnabled()
detail := ""
if err != nil {
detail = err.Error()
}
emit("Kernel FIPS mode enabled", isKernelEnabled, detail)

emit("OpenSSL loaded", fipsccl.IsOpenSSLLoaded(), "")
emit("FIPS ready", fipsccl.IsFIPSReady(), "")

table.Render()
return nil
}
17 changes: 17 additions & 0 deletions pkg/ccl/securityccl/fipsccl/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")

go_library(
name = "fipsccl",
srcs = [
"build_boring.go", # keep
"build_noboring.go",
"fips_linux.go",
"fips_nolinux.go",
],
cgo = True,
importpath = "github.com/cockroachdb/cockroach/pkg/ccl/securityccl/fipsccl",
visibility = ["//visibility:public"],
deps = [
"@com_github_cockroachdb_errors//:errors",
],
)
72 changes: 72 additions & 0 deletions pkg/ccl/securityccl/fipsccl/build_boring.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2023 The Cockroach Authors.
//
// Licensed as a CockroachDB Enterprise file under the Cockroach Community
// License (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt
//
//go:build boringcrypto

package fipsccl

/*
#include <openssl/ossl_typ.h>
static unsigned long _fipsccl_openssl_version_number() {
return OPENSSL_VERSION_NUMBER;
}
*/
import "C"

import (
"crypto/boring"
"fmt"
)

// IsCompileTimeFIPSReady returns true if this binary was built with correct
// toolchain and options, which is a prerequisite for FIPS-ready mode.
// Note that we only support the golang-fips toolchain even though the
// build tag we test for is "boringcrypto". The two are not actually
// compatible because crypto/boring.Enabled is a bool in one and a function
// in the other.
func IsCompileTimeFIPSReady() bool {
return true
}

// IsOpenSSLLoaded returns true if the OpenSSL library has been found and
// loaded.
func IsOpenSSLLoaded() bool {
return boring.Enabled()
}

// IsFIPSReady returns true if all of our FIPS readiness checks succeed.
func IsFIPSReady() bool {
// The golang-fips toolchain only attempts to load OpenSSL if the kernel
// fips mode is enabled. Therefore we only need this single check for our
// overall fips-readiness status. We could redundantly call IsBoringBuild
// and IsKernelEnabled, but doing so would risk some divergence between our
// implementation and the toolchain itself so it's better at this time to
// use the single check.
return IsOpenSSLLoaded()
}

// BuildOpenSSLVersion returns the version number of OpenSSL that was used at
// build time. The first return value is the hex value of the
// OPENSSL_VERSION_NUMBER constant (for example, 10100000 for OpenSSL 1.1 and
// 30000000 for OpenSSL 3.0), and the second is the versioned name of the
// libcrypto.so file.
func BuildOpenSSLVersion() (string, string, error) {
buildVersion := uint64(C._fipsccl_openssl_version_number())
var soname string
// Reference:
// https://github.com/golang-fips/go/blob/7f64529ab80e5d394bb2496e982d6f6e11023902/patches/001-initial-openssl-for-fips.patch#L3476-L3482
if buildVersion < 0x10100000 {
soname = "libcrypto.so.10"
} else if buildVersion < 0x30000000 {
soname = "libcrypto.so.1.1"
} else {
soname = "libcrypto.so.3"
}
return fmt.Sprintf("%x", buildVersion), soname, nil
}
29 changes: 29 additions & 0 deletions pkg/ccl/securityccl/fipsccl/build_noboring.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2023 The Cockroach Authors.
//
// Licensed as a CockroachDB Enterprise file under the Cockroach Community
// License (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt
//
//go:build !boringcrypto

package fipsccl

import "github.com/cockroachdb/errors"

func IsCompileTimeFIPSReady() bool {
return false
}

func IsOpenSSLLoaded() bool {
return false
}

func IsFIPSReady() bool {
return false
}

func BuildOpenSSLVersion() (string, string, error) {
return "", "", errors.New("openssl support not present")
}
34 changes: 34 additions & 0 deletions pkg/ccl/securityccl/fipsccl/fips_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2023 The Cockroach Authors.
//
// Licensed as a CockroachDB Enterprise file under the Cockroach Community
// License (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt

package fipsccl

import (
"fmt"
"os"

"github.com/cockroachdb/errors"
)

const fipsSysctlFilename = "/proc/sys/crypto/fips_enabled"

// IsKernelEnabled returns true if FIPS mode is enabled in the kernel
// (by reading the crypto.fips_enabled sysctl).
func IsKernelEnabled() (bool, error) {
data, err := os.ReadFile(fipsSysctlFilename)
if err != nil {
return false, err
}
if len(data) == 0 {
return false, errors.New("sysctl file empty")
}
if data[0] == '1' {
return true, nil
}
return false, fmt.Errorf("sysctl value: %q", data)
}
17 changes: 17 additions & 0 deletions pkg/ccl/securityccl/fipsccl/fips_nolinux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2023 The Cockroach Authors.
//
// Licensed as a CockroachDB Enterprise file under the Cockroach Community
// License (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt
//
//go:build !linux

package fipsccl

import "github.com/cockroachdb/errors"

func IsKernelEnabled() (bool, error) {
return false, errors.New("only supported on linux")
}

0 comments on commit cd9077c

Please sign in to comment.