如何授予工程师过滤数据库访问权限
你好,布雷泽
进入 Hypershield
总结
完毕!
许多公司(包括 DEV)经常面临的一个问题是,应该赋予工程师多少数据访问权限。允许工程师访问生产数据有很多好处。这可以帮助他们在项目过程中做出更明智的决策,因为他们对将要处理的数据有清晰的了解。当生产代码出现故障,工程师需要找出原因时,这在调试过程中也非常有用。
另一方面,允许工程师访问生产数据也存在风险。你肯定不希望工程师意外更改数据库中不该更改的内容。你的数据库中可能还包含一些你不想让工程师看到的敏感客户数据。我们在 DEV 就遇到过类似的问题,并找到了一个非常满意的解决方案,我想与大家分享。
你好,布雷泽
首先,我们解决了数据库访问问题。我们如何授权工程师访问数据库及其所有信息?有些公司允许工程师访问生产控制台。但这对我们来说不可行,因为我们使用 Heroku,只有几位高级工程师拥有启动控制台所需的 Heroku 完整访问权限。
既然控制台访问已经无法实现,我们开始寻找其他方法。这时,我们发现了Andrew Kane 编写的Blazer 插件。安装后,Blazer 允许用户通过如下所示的 Web UI 查询数据库。
除了允许用户查询数据库之外,Blazer 还有许多其他不错的功能,例如:
这正是我们所寻找的,因此我们继续按照 gem 主页上概述的步骤将Blazer 添加到 DEV 。
有几点需要注意。首先,我们只开放了super_admins
Blazer 的访问权限,因为我们还需要解决数据隐私和只读访问的问题。
authenticate :user, ->(user) { user.has_role?(:super_admin) } do
mount Blazer::Engine, at: "blazer"
end
开发设置
请注意,Blazer 使用 ENV 变量BLAZER_DATABASE_URL
来指定指向数据库的位置。在开发过程中,我发现如果BLAZER_DATABASE_URL
该变量为 nil,Blazer 将使用 ActiveRecord 连接与数据库通信。这使得 Blazer 的设置和开发工作变得非常容易。
生产设置
您还可以BLAZER_DATABASE_URL
设置 Blazer,使用单独的用户与数据库通信。使用 Blazer 时,我们最想避免的一件事就是工程师意外更改生产数据。根据 Blazer 的 README 文件:
Blazer 尝试防止修改数据的查询(通过在事务中运行每个查询并将其回滚),但更安全的方法是使用只读用户。
尽管 Blazer 使用了事务,但我们还是想格外小心,通过只读用户来使用它。使用与默认 ActiveRecord 连接不同的 URL,我们可以在 URL 中使用只读用户的凭据,以确保数据不会被更改。
ENV["BLAZER_DATABASE_URL"] = "postgres://read-only-user:read-only-user-password@hostname:5432/database-name"
设置只读用户
Blazer 甚至提供了关于如何为指定数据库设置只读用户的文档。由于我们使用 Postgres 和 Heroku,我根据 Heroku Postgres指南 中概述的步骤,通过 Heroku Postgres 插件创建了只读用户。
一旦您有了新用户,您就需要获取该用户的名称和密码以及您的数据库名称并创建您的BLAZER_DATABASE_URL
。
有了这套BLAZER_DATABASE_URL
设置,我们现在有了查询生产数据库的 UI,并且数据库受到了保护,不会被任何方式更改。剩下唯一要做的就是过滤数据。
进入 Hypershield
不,不是那种盾牌!我们想要的盾牌是能够隐藏敏感用户数据的盾牌。为了实现这一点,我们再次使用了 Andrew Kane 的另一款杰作——Hypershield。它的工作原理如下:
Hypershield 创建屏蔽视图(默认在 hypershield 模式中),用于隐藏敏感表和列。与列级权限相比,这种方法的优势在于您可以使用 SELECT *。
要使其正常工作,第一步是安装 gem,并创建我们想要屏蔽的列列表。我们将 gem 安装在生产组中,因为我们只想在生产环境中运行它。
group :production do
gem "hypershield", "~> 0.2.0" # Allow admins to query data via internal
gem "nakayoshi_fork", "~> 0.0.4" # solves CoW friendly problem on MRI 2.2 and later
gem "rack-host-redirect", "~> 1.3" # Lean and simple host redirection via Rack middleware
end
接下来,我们在初始化文件中创建了我们想要屏蔽的列的列表hypershield.rb
。
if Rails.env.production?
Hypershield.enabled = ENV["ENABLE_HYPERSHIELD"].present?
# Validate that hypershield schema exists before trying to use it
begin
if ActiveRecord::Base.connection.schema_exists?("hypershield")
# Specify the schema to use and columns to show and hide
Hypershield.schemas = {
hypershield: {
# columns to hide
# matches table.column
hide: %w[
auth_data_dump
email
encrypted
encrypted_password
message_html
message_markdown
password
previous_refresh_token
refresh_token
secret
token
current_sign_in_ip
last_sign_in_ip
reset_password_token
remember_token
unconfirmed_email
]
}
}
# Log SQL statements
Hypershield.log_sql = false
end
rescue ActiveRecord::NoDatabaseError
Rails.logger.error("Hypershield initializer failed to check schema due to NoDatabaseError")
end
end
你会注意到,在配置 Hypershield 之前,我们额外加了几行代码来做不同的检查。首先,我们有:
Hypershield.enabled = ENV["ENABLE_HYPERSHIELD"].present?
如果不存在ENV 变量,此行将禁用在运行迁移时发生的Hypershield 模式refresh
任务。ENABLE_HYPERSHIELD
接下来我们有:
if ActiveRecord::Base.connection.schema_exists?("hypershield")
这确保了如果 HyperShield 架构不存在,我们不会尝试设置它并报错。这两行代码非常重要,因为其他社区正在使用 DEV 应用程序源代码,我们不希望由于我们添加到应用程序中的缺失(完全可选)功能而导致其他社区无法使用。
创建架构
一旦 gem 和初始化程序准备就绪,接下来我们需要创建 hypershield 模式。由于我们使用的是 Postgres,因此以下是设置步骤。这些设置步骤以及其他数据库类型的设置步骤均记录在gem 的 README 文件中。
在数据库中创建新的架构
CREATE SCHEMA hypershield;
向您已使用 Blazer 设置的用户授予权限。在本例中,我们希望将所有这些权限授予我们通过 Heroku 设置的只读 Blazer 用户。
GRANT USAGE ON SCHEMA hypershield TO readonly-blazer-username;
-- replace migrations with the user who manages your schema
ALTER DEFAULT PRIVILEGES FOR ROLE heroku-default-user IN SCHEMA hypershield
GRANT SELECT ON TABLES TO readonly-blazer-username;
-- keep public in search path for functions
ALTER ROLE readonly-blazer-username SET search_path TO hypershield, public;
如果您正在使用 Heroku,则可以通过 Rails 控制台运行这些命令。
sql = <<-SQL
CREATE SCHEMA hypershield;
SQL
ActiveRecord::Base.connection.execute(sql)
或者您可以使用之前设置的 Blazer 用户凭据通过 Heroku CLI 直接连接到 Postgres。
heroku pg:psql postgres-app-name --credential readonly-blazer-username --app your-app-name
我发现最后一条ALTER ROLE
语句需要由我们的只读 Blazer 用户运行,因此您可能需要使用 Heroku CLI 并结合该用户的凭据来执行该语句。另一个 Heroku 小问题是,当您设置只读 Blazer 用户时,它会被授予对公共架构的完全访问权限。您需要使用以下命令撤销此权限。这可确保您的 Blazer 用户只能查看由 Hypershield Gem 设置的屏蔽视图。
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM readonly-blazer-username;
总结
在您为 Blazer 只读用户设置好屏蔽模式后,就可以在 Blazer 上进行测试,以确保一切正常。一个简单的方法是SELECT *
在您希望过滤的表之一上运行查询。在我们的例子中,我使用消息进行了测试。
正如预期的那样,没有任何消息文本或正文字段存在。另一种测试方法是从表中请求您屏蔽的字段之一。在本例中,我尝试message_html
从消息中显式请求,但如您所见,我收到了错误。
当你对所有测试都满意后,最后要做的就是将 Blazer 开放给你希望使用它的人。在 DEV,我们选择允许所有技术管理员(主要是工程师)访问 Blazer 控制台。
authenticate :user, ->(user) { user.has_role?(:tech_admin) } do
mount Blazer::Engine, at: "blazer"
end
完毕!
这样就大功告成了!现在,就坐下来,静待同事们的赞叹吧,因为他们终于可以访问他们急需的数据了。
