diff --git a/pkg/ccl/logictestccl/testdata/logic_test/zone b/pkg/ccl/logictestccl/testdata/logic_test/zone index 463480ce75da..f0aef991f7bc 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/zone +++ b/pkg/ccl/logictestccl/testdata/logic_test/zone @@ -692,3 +692,68 @@ t40417 CREATE TABLE t40417 ( ); ALTER PARTITION p1 OF INDEX "my database".public.t40417@primary CONFIGURE ZONE USING num_replicas = 1 + +subtest authorization + +statement ok +CREATE DATABASE auth; +CREATE TABLE auth.t (x INT PRIMARY KEY) PARTITION BY LIST (x) ( + PARTITION p VALUES IN (1) +); +CREATE INDEX x ON auth.t (x) PARTITION BY LIST (x) ( + PARTITION p VALUES IN (1) +) + +user testuser + +# User should have no CONFIGURE ZONE abilities by default. +statement error only users with the admin role are allowed to alter system ranges +ALTER RANGE default CONFIGURE ZONE USING num_replicas = 3 + +statement error pq: user testuser does not have CREATE privilege on database auth +ALTER DATABASE auth CONFIGURE ZONE USING num_replicas = 3 + +statement error pq: only users with the admin role are allowed to alter system tables +ALTER TABLE system.jobs CONFIGURE ZONE USING num_replicas = 3 + +statement error user testuser does not have CREATE privilege on relation t +ALTER TABLE auth.t CONFIGURE ZONE USING num_replicas = 3 + +statement error user testuser does not have CREATE privilege on relation t +ALTER PARTITION p OF TABLE auth.t CONFIGURE ZONE USING num_replicas = 3 + +statement error user testuser does not have CREATE privilege on relation t +ALTER PARTITION p OF INDEX auth.t@x CONFIGURE ZONE USING num_replicas = 3 + +# Granting CREATE on databases and tables should allow CONFIGURE ZONE on those +# objects. +user root + +statement ok +GRANT CREATE ON DATABASE auth TO testuser + +statement ok +GRANT CREATE ON TABLE auth.t TO testuser + +user testuser + +statement ok +ALTER DATABASE auth CONFIGURE ZONE USING num_replicas = 3 + +statement ok +ALTER TABLE auth.t CONFIGURE ZONE USING num_replicas = 3 + +# Granting the admin role should allow configuring zones on system tables and +# ranges. +user root + +statement ok +GRANT admin TO testuser + +user testuser + +statement ok +ALTER RANGE default CONFIGURE ZONE USING num_replicas = 3 + +statement ok +ALTER TABLE system.jobs CONFIGURE ZONE USING num_replicas = 3 diff --git a/pkg/sql/set_zone_config.go b/pkg/sql/set_zone_config.go index 67431c8d60a8..21018418ab7d 100644 --- a/pkg/sql/set_zone_config.go +++ b/pkg/sql/set_zone_config.go @@ -22,6 +22,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/server/serverpb" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" + "github.com/cockroachdb/cockroach/pkg/sql/privilege" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" "github.com/cockroachdb/cockroach/pkg/sql/types" @@ -93,6 +94,10 @@ func loadYAML(dst interface{}, yamlString string) { } func (p *planner) SetZoneConfig(ctx context.Context, n *tree.SetZoneConfig) (planNode, error) { + if err := checkPrivilegeForSetZoneConfig(ctx, p, n.ZoneSpecifier); err != nil { + return nil, err + } + var yamlConfig tree.TypedExpr if n.YAMLConfig != nil { @@ -158,6 +163,36 @@ func (p *planner) SetZoneConfig(ctx context.Context, n *tree.SetZoneConfig) (pla }, nil } +func checkPrivilegeForSetZoneConfig(ctx context.Context, p *planner, zs tree.ZoneSpecifier) error { + // For system ranges, the system database, or system tables, the user must be + // an admin. Otherwise we require CREATE privileges on the database or table + // in question. + if zs.NamedZone != "" { + return p.RequireAdminRole(ctx, "alter system ranges") + } + if zs.Database != "" { + if zs.Database == "system" { + return p.RequireAdminRole(ctx, "alter the system database") + } + dbDesc, err := p.ResolveUncachedDatabaseByName(ctx, string(zs.Database), true) + if err != nil { + return err + } + return p.CheckPrivilege(ctx, dbDesc, privilege.CREATE) + } + tableDesc, err := p.resolveTableForZone(ctx, &zs) + if err != nil { + if zs.TargetsIndex() && zs.TableOrIndex.Table.TableName == "" { + err = errors.WithHint(err, "try specifying the index as @") + } + return err + } + if tableDesc.ParentID == keys.SystemDatabaseID { + return p.RequireAdminRole(ctx, "alter system tables") + } + return p.CheckPrivilege(ctx, tableDesc, privilege.CREATE) +} + // setZoneConfigRun contains the run-time state of setZoneConfigNode during local execution. type setZoneConfigRun struct { numAffected int @@ -240,9 +275,6 @@ func (n *setZoneConfigNode) startExec(params runParams) error { // descriptor. table, err := params.p.resolveTableForZone(params.ctx, &n.zoneSpecifier) if err != nil { - if n.zoneSpecifier.TargetsIndex() && n.zoneSpecifier.TableOrIndex.Table.TableName == "" { - return errors.WithHint(err, "try specifying the index as @") - } return err }