diff --git a/pkg/ccl/BUILD.bazel b/pkg/ccl/BUILD.bazel index c3588e9a3227..494a6fd5eef6 100644 --- a/pkg/ccl/BUILD.bazel +++ b/pkg/ccl/BUILD.bazel @@ -22,6 +22,7 @@ go_library( "//pkg/ccl/partitionccl", "//pkg/ccl/pgcryptoccl", "//pkg/ccl/plpgsqlccl", + "//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 0a35c16ba47e..fc315a0a087f 100644 --- a/pkg/ccl/ccl_init.go +++ b/pkg/ccl/ccl_init.go @@ -28,6 +28,7 @@ import ( _ "github.com/cockroachdb/cockroach/pkg/ccl/partitionccl" _ "github.com/cockroachdb/cockroach/pkg/ccl/pgcryptoccl" _ "github.com/cockroachdb/cockroach/pkg/ccl/plpgsqlccl" + _ "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 ad77a7d68d5e..bdeee99fc27b 100644 --- a/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go +++ b/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go @@ -2564,6 +2564,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 79dea2a5ba2b..8cd444649cd6 100644 --- a/pkg/ccl/logictestccl/tests/fakedist-disk/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/fakedist-disk/BUILD.bazel @@ -13,7 +13,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 14, + shard_count = 15, 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 be728a4581c4..c590d613629d 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 1a8f71c8367b..9fa50c2f327b 100644 --- a/pkg/ccl/logictestccl/tests/fakedist-vec-off/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/fakedist-vec-off/BUILD.bazel @@ -13,7 +13,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 14, + shard_count = 15, 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 685944ae63a4..0119d51a7a33 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 dc7145ec9069..70124a288de9 100644 --- a/pkg/ccl/logictestccl/tests/fakedist/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/fakedist/BUILD.bazel @@ -13,7 +13,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 15, + shard_count = 16, 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 c6b81197ee7c..afeb65534e3b 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 a92620762452..98c684b098f1 100644 --- a/pkg/ccl/logictestccl/tests/local-legacy-schema-changer/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/local-legacy-schema-changer/BUILD.bazel @@ -13,7 +13,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 14, + shard_count = 15, 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 8bba6304a8a7..0b2043469886 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 4b784f37a166..6b231b7b6fe3 100644 --- a/pkg/ccl/logictestccl/tests/local-mixed-23.1/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/local-mixed-23.1/BUILD.bazel @@ -13,7 +13,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 8, + shard_count = 9, 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 c221cd332571..90eeebd019e0 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-vec-off/BUILD.bazel b/pkg/ccl/logictestccl/tests/local-vec-off/BUILD.bazel index 7b8c1c305010..b1d932f579d0 100644 --- a/pkg/ccl/logictestccl/tests/local-vec-off/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/local-vec-off/BUILD.bazel @@ -13,7 +13,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 14, + shard_count = 15, 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 4a072c34ae09..187eb874dfd3 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 c2b46467aedf..892361db5668 100644 --- a/pkg/ccl/logictestccl/tests/local/BUILD.bazel +++ b/pkg/ccl/logictestccl/tests/local/BUILD.bazel @@ -13,7 +13,7 @@ go_test( "//pkg/ccl/logictestccl:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 28, + shard_count = 29, 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 7c04d17a1221..8cc20579db04 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 665ec8f710ed..2caadd857117 100644 --- a/pkg/sql/sem/builtins/fixed_oids.go +++ b/pkg/sql/sem/builtins/fixed_oids.go @@ -2506,6 +2506,7 @@ var builtinOidsArray = []string{ 2535: `last_value(val: refcursor) -> refcursor`, 2536: `percentile_disc_impl(arg1: float, arg2: refcursor) -> refcursor`, 2537: `percentile_disc_impl(arg1: float[], arg2: refcursor) -> refcursor[]`, + 2543: `crdb_internal.fips_ready() -> bool`, } var builtinOidsBySignature map[string]oid.Oid