草庐IT

你应该知道的数仓安全:都是同名Schema惹的祸

华为云开发者社区 2023-03-28 原文
摘要:我是管理员账号,怎么还没有权限?当小伙伴询问的时候,我第一时间就会想到都是用户同名Schema惹的祸

本文分享自华为云社区《你应该知道的数仓安全——都是同名Schema惹的祸》,作者: zhangkunhn 。

典型场景

经常遇到小伙伴问到:

  • 我是管理员账号,怎么还没有权限?
  • 管理员给我赋权了啊,怎么还没有权限?

当小伙伴询问的时候,我第一时间就会想到都是用户同名Schema惹的祸。

同名Schema是私有Schema

我们知道,CREATE USER语法在创建用户的同时会在当前数据库中创建一个与用户同名的SCHEMA。这个Schema很特殊,只有两种用户能在这个Schema下面创建表、视图、函数等对象:

  1. 用户自己
  2. 管理员

然而,不管谁创建的,对象的所有者(Owner)都是用户自己。基于这个事实,我们可以称用户同名Schema为私有Schema。私有表明了当前Schema的特殊性,在这个Schema下面的所有对象都是这个用户自己的,不管是谁创建的。

我们来看一个例子。数据库中有三个用户,如表所示。

使用管理员dbadmin执行以下SQL:

 gaussdb=# create table ua.ta (c1 int);
 CREATE TABLE
 gaussdb =# select relname, relowner, rolname from pg_class c, pg_authid a where relname = 'ta' and c.relowner= a.oid;
 relname | relowner | rolname 
 ---------+----------+---------
  t1      | 16546 | ua(不是dbadmin)
 (1 row)

可以看到:系统管理员在普通用户同名schema下创建的对象,所有者为schema的同名用户

让我们来总结第一点:同名Schema是私有Schema,这个Schema下面的所有对象的所有者都是用户自己,不管是谁创建的。管理员在私有Schema下创建的表等对象会发生Owner切换。

视图规则:按照view的owner做权限检查

再来谈视图和视图封装的基表的权限。视图对基表的权限检查是按照视图的Owner做权限检查。例如

create view v1 as select * from t1;

用户执行select * from v1时做权限检查分为两步:

  1. 首先检查当前用户对视图v1的SELECT权限;
  2. 然后检查视图v1的owner对基表t1的SELECT权限。

而不是直接检查当前用户对基表t1的SELECT权限。

总结第二点:视图会按照视图的Owner对基表做权限检查。

私有Schema与视图规则导致莫名其妙的权限报错

由于私有Schema会造成Owner切换,而视图规则要求对基表按照视图Owner做权限检查。那么在私有Schema下面创建视图就会导致莫名其妙的现象:

私有Schema + view规则 --> 管理员无权限访问自己创建的视图。

 gaussdb =# set role dbadmin password ‘*******’; -- 切换到管理员用户
 SET
 gaussdb => create table ua.ta (c1 int); -- 表ta的owner是???
 CREATE TABLE
 gaussdb => create view ub.vb as select * from ua.ta; -- 视图vb的owner是???
 CREATE VIEW
 gaussdb => select * from ub.vb; -- 管理员创建的view,他竟然无权限!!!
 ERROR: SELECT permission denied to user “ub” for relation “ua.ta“ 

我们以管理员用户在用户ua的私有schema下创建表ta, 之后在用户ub的schema下创建了视图vb, 视图vb的基表是ua.ta。管理员执行对视图vb的查询,报错无权限。

对于这个莫名其妙的现象,我们仔细捋一捋其中的来龙去脉。

  1. 根据私有Schema切换Owner的法则,尽管是管理员创建的,ta的owner切换到ua, 同样vb的owner应该是u2.
  2. 结合view规则,对基表按照视图Owner做权限检查,视图vb的owner对基表ua.ta是否具有select权限。视图vb的owner是ub,而ub对ua.ta无select权限,因此查询报错。

权限报错消除

如何解决这种权限报错呢?从上述梳理中,其实已经明白了如何赋权来消除这种报错。那就是给视图的owner用户ub赋予基表ua.ta的SELCT权限:管理员或者用户ua执行下面的赋权语句即可。

 GRANT SELECT on ua.ta to ub; 

有小伙伴 问了,我每次都这么仔细捋一捋,感觉很浪费时间,有没有简单的方法。答案是有的,只需从查询的权限报错着手,不需要每次都捋一捋。

我们当前的权限报错有着非常完备的提醒,会给用户显示如下提示:

SELECT permission denied to user “user_name” for relation “ schema_name.table_name

可以看到,权限报错包括哪个权限、哪个用户、哪个schema的哪个对象。那么看到这个之后,可以直接找管理员或者Owner来执行授予操作就可以了。

对于上述报错,直接就对应到赋权语句:

grant SELECT on schema_name.table_name to user_name;

当然这个赋权跟我们前面的分析是殊途同归的。

现在来回想下,是不是一切都清晰了。那么我们再来看一遍示例。以管理员dbadmin执行以下SQL语句。

 gaussdb => create table ua.ta (c1 int); -- ta的owner是ua
 CREATE TABLE
 gaussdb => create view ub.vb as select * from ua.ta; -- vb的owner是ub
 CREATE VIEW
 postgres=# select * from ub.vb; -- 按照报错的指引来
 ERROR: SELECT permission denied to user “ub” for relation “ua.ta“ 
 gaussdb =# grant usage on schema ua to ub; -- 将schema ua和基表ta的权限给ub
 GRANT
 gaussdb =# grant select on ua.ta to ub;
 GRANT
 postgres=# select * from ub.vb; -- 权限检查通过,可以正常查询
  c1 
 ----
 (0 rows)

补充知识:

  1. CREATE USER语法在创建用户的同时会在当前数据库中,为该用户创建一个同名的SCHEMA;其他数据库中,则不会创建同名的SCHEMA;如果需要,可使用create schema authorization user_name语法,该语法会根据用户名来创建同名schema。
  2. 为什么用户同名Schema这么特殊,别的Schema没有这些特点?因为:a) 在创建用户时同时创建了与用户同名的Schema,并将Schema的owner设置为同名用户;b) 在创建对象时,如果创建对象的schema是用户同名Schema,就会将对象的Owner切换为同名用户,而不是执行SQL语句的当前用户。

总结

遇到权限报错第一时间想到是否涉及同名schema。同名Schema是用户的私有Schema。私有Schema中所有的对象Owner都是用户自己,不管是谁创建的。在私有Schema中创建对象,对象Owner会切换到同名用户。视图规则是按照视图Owner来检查对基表的权限。由于私有Schema的Owner切换机制和视图规则导致了同名Schema的权限报错。根据报错的提示,授予用户相应的权限就可以解决权限报错问题。

 

点击关注,第一时间了解华为云新鲜技术~

有关你应该知道的数仓安全:都是同名Schema惹的祸的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  3. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  4. ruby - 如何安全地删除文件? - 2

    在Ruby中是否有Gem或安全删除文件的方法?我想避免系统上可能不存在的外部程序。“安全删除”指的是覆盖文件内容。 最佳答案 如果您使用的是*nix,一个很好的方法是使用exec/open3/open4调用shred:`shred-fxuz#{filename}`http://www.gnu.org/s/coreutils/manual/html_node/shred-invocation.html检查这个类似的帖子:Writingafileshredderinpythonorruby?

  5. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  6. ruby - 用 YAML.load 解析 json 安全吗? - 2

    我正在使用ruby2.1.0我有一个json文件。例如:test.json{"item":[{"apple":1},{"banana":2}]}用YAML.load加载这个文件安全吗?YAML.load(File.read('test.json'))我正在尝试加载一个json或yaml格式的文件。 最佳答案 YAML可以加载JSONYAML.load('{"something":"test","other":4}')=>{"something"=>"test","other"=>4}JSON将无法加载YAML。JSON.load("

  7. ruby-on-rails - 带有 Zeus 的 RSpec 3.1,我应该在 spec_helper 中要求 'rspec/rails' 吗? - 2

    使用rspec-rails3.0+,测试设置分为spec_helper和rails_helper我注意到生成的spec_helper不需要'rspec/rails'。这会导致zeus崩溃:spec_helper.rb:5:in`':undefinedmethod`configure'forRSpec:Module(NoMethodError)对thisissue最常见的回应是需要'rspec/rails'。但这是否会破坏仅使用spec_helper拆分rails规范和PORO规范的全部目的?或者这无关紧要,因为Zeus无论如何都会预加载Rails?我应该在我的spec_helper中做

  8. ruby - EventMachine - 你怎么知道你是否落后了? - 2

    我正在研究使用EventMachine支持的twitter-streamruby​​gem来跟踪和捕获推文。我对整个事件编程有点陌生。我如何判断我在事件循环中所做的任何处理是否导致我落后?有没有简单的检查方法? 最佳答案 您可以通过使用周期性计时器并打印出耗时来确定延迟。如果您使用的是1秒的计时器,您应该已经过了大约1秒,如果它更长,您就知道您正在减慢react器的速度。@last=Time.now.to_fEM.add_periodic_timer(1)doputs"LATENCY:#{Time.now.to_f-@last}"@

  9. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  10. ruby-on-rails - 具有同名的模块和类 - 2

    我有一个模块stat存在于目录结构中:lib/stat_creator/stat/在lib/stat_creator/stat.rb中,我在lib/stat_creator/stat/目录中有我需要的文件,以及:moduleStatCreatormoduleStatendend当我使用该模块时,我将这些类称为StatCreator::Stat::Foo.new现在我想要一个存在于应用程序中的根Stat类。我在app/models中制作了我的Stat类,并在routes.rb中进行了设置。但是,如果我转到Rails控制台并尝试在应用程序/模型中使用Stat类,例如:Stat.by_use

随机推荐