class Google::Auth::ExternalAccount::AwsRequestSigner
Implements an AWS request signer based on the AWS Signature Version 4 signing process. docs.aws.amazon.com/general/latest/gr/signature-version-4.html
Public Class Methods
Source
# File lib/googleauth/external_account/aws_credentials.rb, line 219 def initialize region_name @region_name = region_name end
Instantiates an AWS request signer used to compute authenticated signed requests to AWS APIs based on the AWS Signature Version 4 signing process.
@param [string] region_name
The AWS region to use.
Public Instance Methods
Source
# File lib/googleauth/external_account/aws_credentials.rb, line 237 def generate_signed_request aws_credentials, original_request uri = Addressable::URI.parse original_request[:url] raise "Invalid AWS service URL" unless uri.hostname && uri.scheme == "https" service_name = uri.host.split(".").first datetime = Time.now.utc.strftime "%Y%m%dT%H%M%SZ" date = datetime[0, 8] headers = aws_headers aws_credentials, original_request, datetime request_payload = original_request[:data] || "" content_sha256 = sha256_hexdigest request_payload canonical_req = canonical_request original_request[:method], uri, headers, content_sha256 sts = string_to_sign datetime, canonical_req, service_name # Authorization header requires everything else to be properly setup in order to be properly # calculated. headers["Authorization"] = build_authorization_header headers, sts, aws_credentials, service_name, date { url: uri.to_s, headers: headers, method: original_request[:method], data: (request_payload unless request_payload.empty?) }.compact end
Generates the signed request for the provided HTTP request for calling an AWS API. This follows the steps described at: docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
@param [Hash[string, string]] aws_security_credentials
A dictionary containing the AWS security credentials.
@param [string] url
The AWS service URL containing the canonical URI and query string.
@param [string] method
The HTTP method used to call this API.
@return [hash{string => string}]
The AWS signed request dictionary object.
Private Instance Methods
Source
# File lib/googleauth/external_account/aws_credentials.rb, line 267 def aws_headers aws_credentials, original_request, datetime uri = Addressable::URI.parse original_request[:url] temp_headers = original_request[:headers] || {} headers = {} temp_headers.each_key { |k| headers[k.to_s] = temp_headers[k] } headers["host"] = uri.host headers["x-amz-date"] = datetime headers["x-amz-security-token"] = aws_credentials[:session_token] if aws_credentials[:session_token] headers end
Source
# File lib/googleauth/external_account/aws_credentials.rb, line 357 def build_canonical_querystring query params = query.split "&" params = params.map { |p| p.include?("=") ? p : "#{p}=" } params.each.with_index.sort do |(a, a_offset), (b, b_offset)| a_name, a_value = a.split "=" b_name, b_value = b.split "=" if a_name == b_name if a_value == b_value a_offset <=> b_offset else a_value <=> b_value end else a_name <=> b_name end end.map(&:first).join("&") end
Generates the canonical query string given a raw query string. Logic is based on docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html Code is from the AWS SDK for Ruby github.com/aws/aws-sdk-ruby/blob/0ac3d0a393ed216290bfb5f0383380376f6fb1f1/gems/aws-sigv4/lib/aws-sigv4/signer.rb#L532
Source
# File lib/googleauth/external_account/aws_credentials.rb, line 335 def canonical_request http_method, uri, headers, content_sha256 headers = headers.sort_by(&:first) # transforms to a sorted array of [key, value] [ http_method, uri.path.empty? ? "/" : uri.path, build_canonical_querystring(uri.query || ""), headers.map { |k, v| "#{k}:#{v}\n" }.join, # Canonical headers headers.map(&:first).join(";"), # Signed headers content_sha256 ].join("\n") end
Source
# File lib/googleauth/external_account/aws_credentials.rb, line 304 def credential access_key_id, date, service "#{access_key_id}/#{credential_scope date, service}" end
Source
# File lib/googleauth/external_account/aws_credentials.rb, line 308 def credential_scope date, service [ date, @region_name, service, "aws4_request" ].join("/") end
Source
# File lib/googleauth/external_account/aws_credentials.rb, line 300 def hexhmac key, value OpenSSL::HMAC.hexdigest OpenSSL::Digest.new("sha256"), key, value end
Source
# File lib/googleauth/external_account/aws_credentials.rb, line 296 def hmac key, value OpenSSL::HMAC.digest OpenSSL::Digest.new("sha256"), key, value end
Source
# File lib/googleauth/external_account/aws_credentials.rb, line 326 def host uri # Handles known and unknown URI schemes; default_port nil when unknown. if uri.default_port == uri.port uri.host else "#{uri.host}:#{uri.port}" end end
Source
# File lib/googleauth/external_account/aws_credentials.rb, line 348 def sha256_hexdigest string OpenSSL::Digest::SHA256.hexdigest string end
Source
# File lib/googleauth/external_account/aws_credentials.rb, line 287 def signature secret_access_key, date, string_to_sign, service k_date = hmac "AWS4#{secret_access_key}", date k_region = hmac k_date, @region_name k_service = hmac k_region, service k_credentials = hmac k_service, "aws4_request" hexhmac k_credentials, string_to_sign end
Source
# File lib/googleauth/external_account/aws_credentials.rb, line 317 def string_to_sign datetime, canonical_request, service [ "AWS4-HMAC-SHA256", datetime, credential_scope(datetime[0, 8], service), sha256_hexdigest(canonical_request) ].join("\n") end