-
Notifications
You must be signed in to change notification settings - Fork 550
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial pass adding AWS IAM Authentication #1263
This adds AWS IAM authentication as a replacement for defining a password in the configuration. When the configuration option :use_iam_authentication = true, an authentication token (password) will be fetched from IAM and cached for the next 14 minutes (tokens expire in 15 minutes). These can then be reused by all new connections until it expires, at which point a new token will be fetched when next needed. To allow for multiple Mysql2::Client configurations to multiple servers, the cache is keyed by database username, host name, port, and region. Two new configuration options are necessary: - :use_iam_credentials = true - :host_region is a string region name, e.g. 'us-east-1'. If not set, ENV['AWS_REGION'] will be used. If this is not present, authenticaiton will fail. As prerequisites, you must enable IAM authentication on the RDS instance, create an IAM policy, attach the policy to the target IAM user or role, create the database user set to use the AWS Authentication Plugin, and then run your ruby code using that user or role. See https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.Connecting.html for details on these steps. You must include the aws-sdk-rds gem in your bundle to use this feature.
- Loading branch information
1 parent
f6a9b68
commit 5874883
Showing
4 changed files
with
104 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
require 'singleton' | ||
|
||
module Mysql2 | ||
# Generates and caches AWS IAM Authentication tokens to use in place of MySQL user passwords | ||
class AwsIamAuth | ||
include Singleton | ||
attr_reader :mutex | ||
attr_accessor :passwords | ||
|
||
# Tokens are valid for up to 15 minutes. | ||
# We will assume ours expire in 14 minutes to be safe. | ||
TOKEN_EXPIRES_IN = (60 * 14) # 14 minutes | ||
|
||
def initialize | ||
begin | ||
require 'aws-sdk-rds' | ||
rescue LoadError | ||
puts "gem aws-sdk-rds was not found. Please add this gem to your bundle to use AWS IAM Authentication." | ||
exit | ||
end | ||
|
||
@mutex = Mutex.new | ||
# Key identifies a unique set of authentication parameters | ||
# Value is a Hash | ||
# :password is the token value | ||
# :expires_at is (just before) the token was generated plus 14 minutes | ||
@passwords = {} | ||
instance_credentials = Aws::InstanceProfileCredentials.new | ||
@generator = Aws::RDS::AuthTokenGenerator.new(:credentials => instance_credentials) | ||
end | ||
|
||
def password(user, host, port, opts) | ||
params = to_params(user, host, port, opts) | ||
key = key_from_params(params) | ||
passwd = nil | ||
AwsIamAuth.instance.mutex.synchronize do | ||
begin | ||
passwd = @passwords[key][:password] if @passwords.dig(key, :password) && Time.now.utc < @passwords.dig(key, :expires_at) | ||
rescue KeyError | ||
passwd = nil | ||
end | ||
end | ||
return passwd unless passwd.nil? | ||
|
||
AwsIamAuth.instance.mutex.synchronize do | ||
@passwords[key] = {} | ||
@passwords[key][:expires_at] = Time.now.utc + TOKEN_EXPIRES_IN | ||
@passwords[key][:password] = password_from_iam(params) | ||
end | ||
end | ||
|
||
def password_from_iam(params) | ||
@generator.auth_token(params) | ||
end | ||
|
||
def to_params(user, host, port, opts) | ||
params = {} | ||
params[:region] = opts[:host_region] || ENV['AWS_REGION'] | ||
params[:endpoint] = "#{host}:#{port}" | ||
params[:user_name] = user | ||
params | ||
end | ||
|
||
def key_from_params(params) | ||
"#{params[:user_name]}/#{params[:endpoint]}/#{params[:region]}" | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters