Class: Gem::S3URISigner
Relationships & Source Files | |
Namespace Children | |
Classes:
| |
Exceptions:
| |
Inherits: | Object |
Defined in: | lib/rubygems/s3_uri_signer.rb |
Overview
S3URISigner
implements AWS SigV4 for S3 Source to avoid a dependency on the aws-sdk-* gems More on AWS SigV4: docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
Constant Summary
-
BASE64_URI_TRANSLATE =
# File 'lib/rubygems/s3_uri_signer.rb', line 174{ "+" => "%2B", "/" => "%2F", "=" => "%3D", "\n" => "" }.freeze
-
EC2_IAM_INFO =
# File 'lib/rubygems/s3_uri_signer.rb', line 175"http://169.254.169.254/latest/meta-data/iam/info"
-
EC2_IAM_SECURITY_CREDENTIALS =
# File 'lib/rubygems/s3_uri_signer.rb', line 176"http://169.254.169.254/latest/meta-data/iam/security-credentials/"
Class Method Summary
- .new(uri) ⇒ S3URISigner constructor
Instance Attribute Summary
- #uri rw
Instance Method Summary
-
#sign(expiration = 86400)
Signs S3 URI using query-params according to the reference: docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html.
- #base64_uri_escape(str) private
- #create_request_pool(uri) private
- #ec2_metadata_credentials_json private
- #ec2_metadata_request(url) private
-
#fetch_s3_config
private
Extracts S3 configuration for S3 bucket.
- #generate_canonical_query_params(s3_config, date_time, credential_info, expiration) private
- #generate_canonical_request(canonical_host, query_params) private
- #generate_signature(s3_config, date, string_to_sign) private
- #generate_string_to_sign(date_time, credential_info, canonical_request) private
Constructor Details
.new(uri) ⇒ S3URISigner
Instance Attribute Details
#uri (rw)
[ GitHub ]# File 'lib/rubygems/s3_uri_signer.rb', line 29
attr_accessor :uri
Instance Method Details
#base64_uri_escape(str) (private)
[ GitHub ]# File 'lib/rubygems/s3_uri_signer.rb', line 138
def base64_uri_escape(str) str.gsub(/[\+\/=\n]/, BASE64_URI_TRANSLATE) end
#create_request_pool(uri) (private)
[ GitHub ]#ec2_metadata_credentials_json (private)
[ GitHub ]# File 'lib/rubygems/s3_uri_signer.rb', line 142
def require "net/http" require_relative "request" require_relative "request/connection_pools" require "json" iam_info = (EC2_IAM_INFO) # Expected format: arn:aws:iam::<id>:instance-profile/<role_name> role_name = iam_info["InstanceProfileArn"].split("/").last (EC2_IAM_SECURITY_CREDENTIALS + role_name) end
#ec2_metadata_request(url) (private)
[ GitHub ]# File 'lib/rubygems/s3_uri_signer.rb', line 154
def (url) uri = URI(url) @request_pool ||= create_request_pool(uri) request = Gem::Request.new(uri, Net::HTTP::Get, nil, @request_pool) response = request.fetch case response when Net::HTTPOK then JSON.parse(response.body) else raise InstanceProfileError.new("Unable to fetch AWS metadata from #{uri}: #{response.} #{response.code}") end end
#fetch_s3_config (private)
Extracts S3 configuration for S3 bucket
# File 'lib/rubygems/s3_uri_signer.rb', line 105
def fetch_s3_config return S3Config.new(uri.user, uri.password, nil, "us-east-1") if uri.user && uri.password s3_source = Gem.configuration[:s3_source] || Gem.configuration["s3_source"] host = uri.host raise ConfigurationError.new("no s3_source key exists in .gemrc") unless s3_source auth = s3_source[host] || s3_source[host.to_sym] raise ConfigurationError.new("no key for host #{host} in s3_source in .gemrc") unless auth provider = auth[:provider] || auth["provider"] case provider when "env" id = ENV["AWS_ACCESS_KEY_ID"] secret = ENV["AWS_SECRET_ACCESS_KEY"] security_token = ENV["AWS_SESSION_TOKEN"] when "instance_profile" credentials = id = credentials["AccessKeyId"] secret = credentials["SecretAccessKey"] security_token = credentials["Token"] else id = auth[:id] || auth["id"] secret = auth[:secret] || auth["secret"] security_token = auth[:security_token] || auth["security_token"] end raise ConfigurationError.new("s3_source for #{host} missing id or secret") unless id && secret region = auth[:region] || auth["region"] || "us-east-1" S3Config.new(id, secret, security_token, region) end
#generate_canonical_query_params(s3_config, date_time, credential_info, expiration) (private)
[ GitHub ]# File 'lib/rubygems/s3_uri_signer.rb', line 59
def generate_canonical_query_params(s3_config, date_time, credential_info, expiration) canonical_params = {} canonical_params["X-Amz-Algorithm"] = "AWS4-HMAC-SHA256" canonical_params["X-Amz-Credential"] = "#{s3_config.access_key_id}/#{credential_info}" canonical_params["X-Amz-Date"] = date_time canonical_params["X-Amz-Expires"] = expiration.to_s canonical_params["X-Amz-SignedHeaders"] = "host" canonical_params["X-Amz-Security-Token"] = s3_config.security_token if s3_config.security_token # Sorting is required to generate proper signature canonical_params.sort.to_h.map do |key, value| "#{base64_uri_escape(key)}=#{base64_uri_escape(value)}" end.join("&") end
#generate_canonical_request(canonical_host, query_params) (private)
[ GitHub ]#generate_signature(s3_config, date, string_to_sign) (private)
[ GitHub ]# File 'lib/rubygems/s3_uri_signer.rb', line 95
def generate_signature(s3_config, date, string_to_sign) date_key = OpenSSL::HMAC.digest("sha256", "AWS4" + s3_config.secret_access_key, date) date_region_key = OpenSSL::HMAC.digest("sha256", date_key, s3_config.region) date_region_service_key = OpenSSL::HMAC.digest("sha256", date_region_key, "s3") signing_key = OpenSSL::HMAC.digest("sha256", date_region_service_key, "aws4_request") OpenSSL::HMAC.hexdigest("sha256", signing_key, string_to_sign) end
#generate_string_to_sign(date_time, credential_info, canonical_request) (private)
[ GitHub ]# File 'lib/rubygems/s3_uri_signer.rb', line 86
def generate_string_to_sign(date_time, credential_info, canonical_request) [ "AWS4-HMAC-SHA256", date_time, credential_info, OpenSSL::Digest::SHA256.hexdigest(canonical_request), ].join("\n") end
#sign(expiration = 86400)
Signs S3 URI using query-params according to the reference: docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
# File 'lib/rubygems/s3_uri_signer.rb', line 37
def sign(expiration = 86400) s3_config = fetch_s3_config current_time = Time.now.utc date_time = current_time.strftime("%Y%m%dT%H%m%SZ") date = date_time[0,8] credential_info = "#{date}/#{s3_config.region}/s3/aws4_request" canonical_host = "#{uri.host}.s3.#{s3_config.region}.amazonaws.com" query_params = generate_canonical_query_params(s3_config, date_time, credential_info, expiration) canonical_request = generate_canonical_request(canonical_host, query_params) string_to_sign = generate_string_to_sign(date_time, credential_info, canonical_request) signature = generate_signature(s3_config, date, string_to_sign) URI.parse("https://#{canonical_host}#{uri.path}?#{query_params}&X-Amz-Signature=#{signature}") end