我希望将AWS RDS IAM database authentication与Ruby on Rails一起使用,因为它为AWS用户提供了一种方便的方式来管理数据库权限并避免在其代码库中存储数据库密码。
在较高的层次上,它的工作原理是根据您的AWS凭据生成密码,以连接到仅有效15分钟的数据库。如果您想在15分钟后再次连接,则需要生成新密码。
此密码可以轻松地使用AWS Ruby SDK生成,因此理论上可以像config/database.yml
一样嵌入到production:
adapter: mysql2
host: db_host
database: db_name
username: db_user
password: <%=
Aws::RDS::AuthTokenGenerator
.new(credentials: Aws::InstanceProfileCredentials.new)
.auth_token(
region: 'us-east-1',
endpoint: 'db_host:3306',
user_name: 'db_user'
)
%>
中;
config/database.yml
但是,据我所知,---------
|letter|
|a |
|b |
|c |
--------
在启动时只评估一次,并且在Rails的生命周期内仍然在该状态下缓存。
因此,通过使用这种方法,Rails服务器最初会成功连接到数据库,但如果在前15分钟窗口之后的任何时候Rails尝试打开新的数据库连接或重新连接断开的连接,则现在已过期凭证将被拒绝。
使用Rails进行IAM数据库身份验证的最佳方法是什么?我是否需要以某种方式使用在每个连接建立时重新评估的密码进行数据库配置?
答案 0 :(得分:2)
我曾考虑过解决此问题的方法,而我想到的最佳方法是猴子修补Mysql2::Client#initialize
,以便您可以启用IAM数据库身份验证,并将密码属性透明地更改为RDS密码。在mysql
0.5.2。的Rails 5.2.2.1中似乎可以使用。
一个重要的警告是您无法启用客户端的重新连接功能,因为我们需要确保无论何时发生连接错误(在上面的Rails版本中默认都会发生这种情况),Rails都会回收客户端。
# config/database.rb
require 'aws-sdk-rds'
require 'mysql2'
Aws.config.update(
region: 'your_region',
)
class RdsIamPasswordGenerator
def self.generate(region, host, user, port)
Aws::RDS::AuthTokenGenerator
.new(credentials: Aws::InstanceProfileCredentials.new)
.auth_token(
region: region,
endpoint: host.to_s + ':' + port.to_s,
user_name: user
)
end
end
module MysqlClientIamMonkeyPatch
def initialize(opts = {})
opts = opts.dup
aws_iam_auth = opts.delete(:aws_iam_auth)
if aws_iam_auth
raise ArgumentError, 'reconnect must be false if aws_iam_auth is true' if opts[:reconnect]
user = opts[:username] || opts[:user]
host = opts[:host] || opts[:hostname]
port = opts[:port] || 3306
raise ArgumentError, 'username/user and host/hostname must be present' if user.nil? || host.nil?
opts.delete(:pass)
opts.delete(:password)
opts[:password] = RdsIamPasswordGenerator.generate(Aws.config[:region], host, user, port)
opts[:enable_cleartext_plugin] = true # Necessary for IAM auth
end
super(opts)
end
end
Mysql2::Client.prepend(MysqlClientIamMonkeyPatch)
# config/boot.rb
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require 'bundler/setup' # Set up gems listed in the Gemfile.
require 'bootsnap/setup' # Speed up boot time by caching expensive operations.
require_relative './database' # Handles patching in IAM auth
# config/database.yml
production:
adapter: mysql2
database: production
ssl_mode: verify_identity
sslverify: true
sslca: /opt/aws/rds-combined-ca-bundle.pem
aws_iam_auth: true
host: db_host
username: db_user
password: null