Skip to content

Instantly share code, notes, and snippets.

@peterwells
Last active August 17, 2023 18:11
Show Gist options
  • Save peterwells/39a5c31d934fa8eb0f2c to your computer and use it in GitHub Desktop.
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 …
#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
#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
#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