From 62af449104d1352fd216f0943102be637dace5c1 Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Sun, 19 Nov 2023 19:11:14 +0000 Subject: [PATCH] fipsccl: Add a SQL function to check fips status This function provides a way to verify FIPS readiness without modifying the deployment to add the --enterprise-require-fips-ready flag. Updates #114344 Release note (enterprise change): New SQL function fips_ready can be used to verify the FIPS readiness of the gateway node. --- pkg/ccl/BUILD.bazel | 1 + pkg/ccl/ccl_init.go | 1 + .../testdata/logic_test/fips_ready | 14 ++++ .../tests/3node-tenant/generated_test.go | 7 ++ .../tests/fakedist-disk/BUILD.bazel | 2 +- .../tests/fakedist-disk/generated_test.go | 7 ++ .../tests/fakedist-vec-off/BUILD.bazel | 2 +- .../tests/fakedist-vec-off/generated_test.go | 7 ++ .../logictestccl/tests/fakedist/BUILD.bazel | 2 +- .../tests/fakedist/generated_test.go | 7 ++ .../local-legacy-schema-changer/BUILD.bazel | 2 +- .../generated_test.go | 7 ++ .../tests/local-mixed-23.1/BUILD.bazel | 2 +- .../tests/local-mixed-23.1/generated_test.go | 7 ++ .../tests/local-mixed-23.2/BUILD.bazel | 2 +- .../tests/local-mixed-23.2/generated_test.go | 7 ++ .../tests/local-vec-off/BUILD.bazel | 2 +- .../tests/local-vec-off/generated_test.go | 7 ++ pkg/ccl/logictestccl/tests/local/BUILD.bazel | 2 +- .../tests/local/generated_test.go | 7 ++ pkg/ccl/securityccl/fipsccl/BUILD.bazel | 9 +++ pkg/ccl/securityccl/fipsccl/sql.go | 64 +++++++++++++++++++ pkg/sql/sem/builtins/fixed_oids.go | 1 + 23 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 pkg/ccl/logictestccl/testdata/logic_test/fips_ready create mode 100644 pkg/ccl/securityccl/fipsccl/sql.go diff --git a/pkg/ccl/BUILD.bazel b/pkg/ccl/BUILD.bazel index b86474e903d9..a324ae2bb115 100644 --- a/pkg/ccl/BUILD.bazel +++ b/pkg/ccl/BUILD.bazel @@ -21,6 +21,7 @@ go_library( "//pkg/ccl/oidcccl", "//pkg/ccl/partitionccl", "//pkg/ccl/pgcryptoccl", + "//pkg/ccl/securityccl/fipsccl", "//pkg/ccl/storageccl", "//pkg/ccl/storageccl/engineccl", "//pkg/ccl/streamingccl/streamingest", diff --git a/pkg/ccl/ccl_init.go b/pkg/ccl/ccl_init.go index 4a224d5cd10c..ca925de44dd5 100644 --- a/pkg/ccl/ccl_init.go +++ b/pkg/ccl/ccl_init.go @@ -27,6 +27,7 @@ import ( _ "github.com/cockroachdb/cockroach/pkg/ccl/oidcccl" _ "github.com/cockroachdb/cockroach/pkg/ccl/partitionccl" _ "github.com/cockroachdb/cockroach/pkg/ccl/pgcryptoccl" + _ "github.com/cockroachdb/cockroach/pkg/ccl/securityccl/fipsccl" _ "github.com/cockroachdb/cockroach/pkg/ccl/storageccl" _ "github.com/cockroachdb/cockroach/pkg/ccl/storageccl/engineccl" _ "github.com/cockroachdb/cockroach/pkg/ccl/streamingccl/streamingest" diff --git a/pkg/ccl/logictestccl/testdata/logic_test/fips_ready b/pkg/ccl/logictestccl/testdata/logic_test/fips_ready new file mode 100644 index 000000000000..be6f4294bfa9 --- /dev/null +++ b/pkg/ccl/logictestccl/testdata/logic_test/fips_ready @@ -0,0 +1,14 @@ +subtest fips_ready + +# We do not have the plumbing that would let test cases know whether they are +# running in a fips environment or not so this is just a very basic test to +# make sure that all the registration, oids, etc work properly. +query _ +SELECT crdb_internal.fips_ready() +---- +_ + +user testuser + +statement error pq: crdb_internal\.fips_ready\(\): user testuser does not have VIEWCLUSTERSETTING system privilege +SELECT crdb_internal.fips_ready() diff --git a/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go b/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go index dba1b80d43e3..0a799ad3904d 100644 --- a/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go +++ b/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go @@ -2606,6 +2606,13 @@ func TestTenantLogicCCL_crdb_internal_tenant( runCCLLogicTest(t, "crdb_internal_tenant") } +func TestTenantLogicCCL_fips_ready( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runCCLLogicTest(t, "fips_ready") +} + func TestTenantLogicCCL_new_schema_changer( t *testing.T, ) { diff --git a/pkg/ccl/logictestccl/tests/fakedist-disk/BUILD.bazel b/pkg/ccl/logictestccl/tests/fakedist-disk/BUILD.bazel index 2fef49525e31..00ba9ff29601 100644 --- a/pkg/ccl/logictestccl/tests/fakedist-disk/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/fakedist-disk/BUILD.bazel @@ -9,7 +9,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 6, + shard_count = 7, tags = [ "ccl_test", "cpu:2", diff --git a/pkg/ccl/logictestccl/tests/fakedist-disk/generated_test.go b/pkg/ccl/logictestccl/tests/fakedist-disk/generated_test.go index ed15a067a5b3..c901c45d24e8 100644 --- a/pkg/ccl/logictestccl/tests/fakedist-disk/generated_test.go +++ b/pkg/ccl/logictestccl/tests/fakedist-disk/generated_test.go @@ -78,6 +78,13 @@ func TestLogic_tmp(t *testing.T) { logictest.RunLogicTests(t, logictest.TestServerArgs{}, configIdx, glob) } +func TestCCLLogic_fips_ready( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runCCLLogicTest(t, "fips_ready") +} + func TestCCLLogic_new_schema_changer( t *testing.T, ) { diff --git a/pkg/ccl/logictestccl/tests/fakedist-vec-off/BUILD.bazel b/pkg/ccl/logictestccl/tests/fakedist-vec-off/BUILD.bazel index 731a6dba7e27..92498312b1e4 100644 --- a/pkg/ccl/logictestccl/tests/fakedist-vec-off/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/fakedist-vec-off/BUILD.bazel @@ -9,7 +9,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 6, + shard_count = 7, tags = [ "ccl_test", "cpu:2", diff --git a/pkg/ccl/logictestccl/tests/fakedist-vec-off/generated_test.go b/pkg/ccl/logictestccl/tests/fakedist-vec-off/generated_test.go index 662396114099..eeda3c15e837 100644 --- a/pkg/ccl/logictestccl/tests/fakedist-vec-off/generated_test.go +++ b/pkg/ccl/logictestccl/tests/fakedist-vec-off/generated_test.go @@ -78,6 +78,13 @@ func TestLogic_tmp(t *testing.T) { logictest.RunLogicTests(t, logictest.TestServerArgs{}, configIdx, glob) } +func TestCCLLogic_fips_ready( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runCCLLogicTest(t, "fips_ready") +} + func TestCCLLogic_new_schema_changer( t *testing.T, ) { diff --git a/pkg/ccl/logictestccl/tests/fakedist/BUILD.bazel b/pkg/ccl/logictestccl/tests/fakedist/BUILD.bazel index 6240d6f37d3b..63b47e74f0f6 100644 --- a/pkg/ccl/logictestccl/tests/fakedist/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/fakedist/BUILD.bazel @@ -9,7 +9,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 7, + shard_count = 8, tags = [ "ccl_test", "cpu:2", diff --git a/pkg/ccl/logictestccl/tests/fakedist/generated_test.go b/pkg/ccl/logictestccl/tests/fakedist/generated_test.go index 4781d36ae881..740b8da2992f 100644 --- a/pkg/ccl/logictestccl/tests/fakedist/generated_test.go +++ b/pkg/ccl/logictestccl/tests/fakedist/generated_test.go @@ -78,6 +78,13 @@ func TestLogic_tmp(t *testing.T) { logictest.RunLogicTests(t, logictest.TestServerArgs{}, configIdx, glob) } +func TestCCLLogic_fips_ready( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runCCLLogicTest(t, "fips_ready") +} + func TestCCLLogic_new_schema_changer( t *testing.T, ) { diff --git a/pkg/ccl/logictestccl/tests/local-legacy-schema-changer/BUILD.bazel b/pkg/ccl/logictestccl/tests/local-legacy-schema-changer/BUILD.bazel index 779fa2337028..902f07d858a8 100644 --- a/pkg/ccl/logictestccl/tests/local-legacy-schema-changer/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/local-legacy-schema-changer/BUILD.bazel @@ -9,7 +9,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 6, + shard_count = 7, tags = [ "ccl_test", "cpu:1", diff --git a/pkg/ccl/logictestccl/tests/local-legacy-schema-changer/generated_test.go b/pkg/ccl/logictestccl/tests/local-legacy-schema-changer/generated_test.go index 74fb8bc7ccb8..78c74e88e1d2 100644 --- a/pkg/ccl/logictestccl/tests/local-legacy-schema-changer/generated_test.go +++ b/pkg/ccl/logictestccl/tests/local-legacy-schema-changer/generated_test.go @@ -78,6 +78,13 @@ func TestLogic_tmp(t *testing.T) { logictest.RunLogicTests(t, logictest.TestServerArgs{}, configIdx, glob) } +func TestCCLLogic_fips_ready( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runCCLLogicTest(t, "fips_ready") +} + func TestCCLLogic_new_schema_changer( t *testing.T, ) { diff --git a/pkg/ccl/logictestccl/tests/local-mixed-23.1/BUILD.bazel b/pkg/ccl/logictestccl/tests/local-mixed-23.1/BUILD.bazel index 322c935e4c17..76267f75c810 100644 --- a/pkg/ccl/logictestccl/tests/local-mixed-23.1/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/local-mixed-23.1/BUILD.bazel @@ -9,7 +9,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 7, + shard_count = 8, tags = [ "ccl_test", "cpu:1", diff --git a/pkg/ccl/logictestccl/tests/local-mixed-23.1/generated_test.go b/pkg/ccl/logictestccl/tests/local-mixed-23.1/generated_test.go index d6082e807060..5edb77cdcb07 100644 --- a/pkg/ccl/logictestccl/tests/local-mixed-23.1/generated_test.go +++ b/pkg/ccl/logictestccl/tests/local-mixed-23.1/generated_test.go @@ -85,6 +85,13 @@ func TestCCLLogic_changefeed( runCCLLogicTest(t, "changefeed") } +func TestCCLLogic_fips_ready( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runCCLLogicTest(t, "fips_ready") +} + func TestCCLLogic_new_schema_changer( t *testing.T, ) { diff --git a/pkg/ccl/logictestccl/tests/local-mixed-23.2/BUILD.bazel b/pkg/ccl/logictestccl/tests/local-mixed-23.2/BUILD.bazel index f962607f0235..a8c7ebea2699 100644 --- a/pkg/ccl/logictestccl/tests/local-mixed-23.2/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/local-mixed-23.2/BUILD.bazel @@ -9,7 +9,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 6, + shard_count = 7, tags = [ "ccl_test", "cpu:1", diff --git a/pkg/ccl/logictestccl/tests/local-mixed-23.2/generated_test.go b/pkg/ccl/logictestccl/tests/local-mixed-23.2/generated_test.go index 83d04f190498..571b77d39762 100644 --- a/pkg/ccl/logictestccl/tests/local-mixed-23.2/generated_test.go +++ b/pkg/ccl/logictestccl/tests/local-mixed-23.2/generated_test.go @@ -78,6 +78,13 @@ func TestLogic_tmp(t *testing.T) { logictest.RunLogicTests(t, logictest.TestServerArgs{}, configIdx, glob) } +func TestCCLLogic_fips_ready( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runCCLLogicTest(t, "fips_ready") +} + func TestCCLLogic_new_schema_changer( t *testing.T, ) { diff --git a/pkg/ccl/logictestccl/tests/local-vec-off/BUILD.bazel b/pkg/ccl/logictestccl/tests/local-vec-off/BUILD.bazel index 97bcb27684b8..62f452f8d75d 100644 --- a/pkg/ccl/logictestccl/tests/local-vec-off/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/local-vec-off/BUILD.bazel @@ -9,7 +9,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 6, + shard_count = 7, tags = [ "ccl_test", "cpu:1", diff --git a/pkg/ccl/logictestccl/tests/local-vec-off/generated_test.go b/pkg/ccl/logictestccl/tests/local-vec-off/generated_test.go index eae4fccbd6fb..d4243389a683 100644 --- a/pkg/ccl/logictestccl/tests/local-vec-off/generated_test.go +++ b/pkg/ccl/logictestccl/tests/local-vec-off/generated_test.go @@ -78,6 +78,13 @@ func TestLogic_tmp(t *testing.T) { logictest.RunLogicTests(t, logictest.TestServerArgs{}, configIdx, glob) } +func TestCCLLogic_fips_ready( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runCCLLogicTest(t, "fips_ready") +} + func TestCCLLogic_new_schema_changer( t *testing.T, ) { diff --git a/pkg/ccl/logictestccl/tests/local/BUILD.bazel b/pkg/ccl/logictestccl/tests/local/BUILD.bazel index 70300c42c6f5..4956870d306f 100644 --- a/pkg/ccl/logictestccl/tests/local/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/local/BUILD.bazel @@ -9,7 +9,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 20, + shard_count = 21, tags = [ "ccl_test", "cpu:1", diff --git a/pkg/ccl/logictestccl/tests/local/generated_test.go b/pkg/ccl/logictestccl/tests/local/generated_test.go index dd66a1be3062..096c7c496613 100644 --- a/pkg/ccl/logictestccl/tests/local/generated_test.go +++ b/pkg/ccl/logictestccl/tests/local/generated_test.go @@ -120,6 +120,13 @@ func TestCCLLogic_explain_redact( runCCLLogicTest(t, "explain_redact") } +func TestCCLLogic_fips_ready( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runCCLLogicTest(t, "fips_ready") +} + func TestCCLLogic_new_schema_changer( t *testing.T, ) { diff --git a/pkg/ccl/securityccl/fipsccl/BUILD.bazel b/pkg/ccl/securityccl/fipsccl/BUILD.bazel index ed17d4a9ccec..c71c275b068e 100644 --- a/pkg/ccl/securityccl/fipsccl/BUILD.bazel +++ b/pkg/ccl/securityccl/fipsccl/BUILD.bazel @@ -7,11 +7,20 @@ go_library( "build_noboring.go", "fips_linux.go", "fips_nolinux.go", + "sql.go", ], cgo = True, importpath = "github.com/cockroachdb/cockroach/pkg/ccl/securityccl/fipsccl", visibility = ["//visibility:public"], deps = [ + "//pkg/ccl/utilccl", + "//pkg/sql/privilege", + "//pkg/sql/roleoption", + "//pkg/sql/sem/eval", + "//pkg/sql/sem/tree", + "//pkg/sql/sem/volatility", + "//pkg/sql/syntheticprivilege", + "//pkg/sql/types", "@com_github_cockroachdb_errors//:errors", ], ) diff --git a/pkg/ccl/securityccl/fipsccl/sql.go b/pkg/ccl/securityccl/fipsccl/sql.go new file mode 100644 index 000000000000..5b76ca4c53ad --- /dev/null +++ b/pkg/ccl/securityccl/fipsccl/sql.go @@ -0,0 +1,64 @@ +// 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 ( + "context" + + "github.com/cockroachdb/cockroach/pkg/ccl/utilccl" + "github.com/cockroachdb/cockroach/pkg/sql/privilege" + "github.com/cockroachdb/cockroach/pkg/sql/roleoption" + "github.com/cockroachdb/cockroach/pkg/sql/sem/eval" + "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" + "github.com/cockroachdb/cockroach/pkg/sql/sem/volatility" + "github.com/cockroachdb/cockroach/pkg/sql/syntheticprivilege" + "github.com/cockroachdb/cockroach/pkg/sql/types" +) + +func init() { + overload := tree.Overload{ + Types: tree.ParamTypes{}, + ReturnType: tree.FixedReturnType(types.Bool), + Fn: func(ctx context.Context, evalCtx *eval.Context, args tree.Datums) (tree.Datum, error) { + if err := utilccl.CheckEnterpriseEnabled( + evalCtx.Settings, evalCtx.ClusterID, "fips_ready", + ); err != nil { + return nil, err + } + // It's debatable whether we need a permission check here at all. + // It's not very sensitive and is (currently) a very cheap function + // call. However, it's something that regular users should have no + // reason to look at so in the interest of least privilege we put it + // behind the VIEWCLUSTERSETTING privilige. + session := evalCtx.SessionAccessor + isAdmin, err := session.HasAdminRole(ctx) + if err != nil { + return nil, err + } + if !isAdmin { + hasView, err := session.HasRoleOption(ctx, roleoption.VIEWCLUSTERSETTING) + if err != nil { + return nil, err + } + if !hasView { + if err := session.CheckPrivilege(ctx, syntheticprivilege.GlobalPrivilegeObject, privilege.VIEWCLUSTERSETTING); err != nil { + return nil, err + } + } + } + return tree.MakeDBool(tree.DBool(IsFIPSReady())), nil + }, + Class: tree.NormalClass, + Volatility: volatility.Stable, + } + + utilccl.RegisterCCLBuiltin("crdb_internal.fips_ready", + `Returns true if all FIPS readiness checks pass.`, + overload) +} diff --git a/pkg/sql/sem/builtins/fixed_oids.go b/pkg/sql/sem/builtins/fixed_oids.go index a9cb1ae51e4e..a416bbec92c8 100644 --- a/pkg/sql/sem/builtins/fixed_oids.go +++ b/pkg/sql/sem/builtins/fixed_oids.go @@ -2509,6 +2509,7 @@ var builtinOidsArray = []string{ 2540: `information_schema._pg_datetime_precision(typid: oid, typmod: int4) -> int`, 2541: `information_schema._pg_interval_type(typid: oid, typmod: int4) -> string`, 2542: `crdb_internal.release_series(version: string) -> string`, + 2543: `crdb_internal.fips_ready() -> bool`, } var builtinOidsBySignature map[string]oid.Oid