Last active
August 17, 2023 18:11
-
-
Save peterwells/39a5c31d934fa8eb0f2c to your computer and use it in GitHub Desktop.
This Gist shows how I was able to implement AWS assume role functionality within my application using the Ruby AWS SDK, Fog, and Carrierwave. Currently Fog has no concept of one role assuming another. They do, however, have an existing mechanism for re-negotiating soon-to-expire credentials. By monkey-patching this function, we can leverage the …
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
#resides in app/models/connectors/ | |
class Connectors::Aws | |
attr_reader :aws_access_key_id, :aws_secret_access_key, :aws_security_token, :expires_at | |
def initialize | |
if ENV.has_key?('AWS_SECURITY_TOKEN') #localhost | |
@aws_access_key_id = ENV['AWS_ACCESS_KEY_ID'] | |
@aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY'] | |
@aws_security_token = ENV['AWS_SECURITY_TOKEN'] | |
@expires_at = Time.now + 10.hours | |
else #ec2 | |
sts = Aws::STS::Client.new | |
session = sts.assume_role(role_arn: ENV['ROLE_ARN'], role_session_name: ENV['ROLE_SESSION_NAME']) | |
@aws_access_key_id = session.credentials.access_key_id | |
@aws_secret_access_key = session.credentials.secret_access_key | |
@aws_security_token = session.credentials.session_token | |
@expires_at = session.credentials.expiration | |
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
#resides in app/models/configs/ | |
module AssumeRoleCredentials | |
def fetch_credentials(options) | |
if options[:use_iam_profile] | |
begin | |
#connection = options[:connection] || Excon.new(INSTANCE_METADATA_HOST) | |
#role_name = connection.get(:path => INSTANCE_METADATA_PATH, :expects => 200).body | |
#role_data = connection.get(:path => INSTANCE_METADATA_PATH+role_name, :expects => 200).body | |
#session = Fog::JSON.decode(role_data) | |
credentials = {} | |
connector = Connectors::Aws.new | |
credentials[:aws_access_key_id] = connector.aws_access_key_id #session['AccessKeyId'] | |
credentials[:aws_secret_access_key] = connector.aws_secret_access_key #session['SecretAccessKey'] | |
credentials[:aws_session_token] = connector.aws_security_token #session['Token'] | |
credentials[:aws_credentials_expire_at] = connector.expires_at #session['Expiration'] | |
#these indicate the metadata service is unavailable or has no profile setup | |
credentials | |
rescue Excon::Errors::Error => e | |
Fog::Logger.warning("Unable to fetch credentials: #{e.message}") | |
super | |
end | |
else | |
super | |
end | |
end | |
end | |
#bring in the existing functionality | |
include Fog::AWS::CredentialFetcher::ServiceMethods | |
#overwrite the fetch_credential method with our custom one | |
Fog::AWS::CredentialFetcher::ServiceMethods.module_eval{include AssumeRoleCredentials} | |
class Configs::Carrierwave | |
def self.configure | |
CarrierWave.configure do |config| | |
config.fog_provider = 'fog/aws' | |
config.fog_directory = ENV['S3_BUCKET_NAME'] | |
if ENV.has_key?('AWS_SECURITY_TOKEN') #localhost | |
connector = Connectors::Aws.new | |
config.fog_credentials = { | |
# Configuration for Amazon S3 | |
:provider => 'AWS', | |
:aws_access_key_id => connector.aws_access_key_id, | |
:aws_secret_access_key => connector.aws_secret_access_key, | |
:aws_session_token => connector.aws_security_token, | |
:region => ENV['AWS_REGION'], | |
:path_style => true | |
} | |
else #ec2 | |
config.fog_credentials = { | |
# Configuration for Amazon S3 | |
:provider => 'AWS', | |
:use_iam_profile => true, | |
:region => ENV['AWS_REGION'], | |
:path_style => true | |
} | |
end | |
#For testing, upload files to local `tmp` folder. | |
if Rails.env.rspec? | |
config.storage = :file | |
config.enable_processing = false | |
config.root = "#{Rails.root}/tmp/#{Rails.env}" | |
else | |
config.storage = :fog | |
end | |
config.cache_dir = "#{Rails.root}/tmp/uploads" # To let CarrierWave work on heroku | |
config.delete_tmp_file_after_storage = true | |
config.fog_public = false | |
config.fog_attributes = {} | |
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
#resides in config/initializers/ | |
Configs::Carrierwave.configure() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment