AWS RDS -IAM数据库身份验证带有导轨



我希望使用Ruby在Rails上使用AWS RDS IAM数据库身份验证,因为它允许AWS用户可以方便地管理数据库权限并避免在其代码库中存储数据库密码。<</p>在高级别上,它通过基于您的AWS凭据生成密码来连接到仅15分钟有效的数据库来起作用。如果您想在15分钟后再次连接,则需要生成一个新密码。

此密码可以轻松地使用AWS Ruby SDK生成,因此理论上可以像So一样嵌入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仅在启动时进行一次评估,并且在该状态下仍处于Rails的寿命中。

因此,通过使用此方法,Rails Server最初将成功连接到数据库,但是如果在第一个15分钟之后的任何时候,窗口导轨试图打开新的DB连接或重新连接丢弃的连接,则凭证将被拒绝。

获得与Rails一起使用IAM数据库身份验证的最佳方法是什么?我需要以某种方式具有带有密码的数据库配置,该密码在每个连接机构上都重新评估?

我对解决这个问题的解决方案做了一些思考,我想出的最好的方法是monkeypatch Mysql2::Client#initialize,以便您可以启用IAM数据库身份验证,它将透明地将密码属性更改为RDS密码。这似乎在Rails 5.2.2.1中使用mysql 0.5.2。

关键警告是您不能启用客户端的重新连接功能,因为我们需要确保在连接错误发生时轨道回收客户端(默认情况下在上述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

最新更新