一段时间后,我们设法构建了一个具有所有需要功能的类,该类将使用签名版本 4 返回为 aws 保留的 rds 实例以对请求进行签名。这是代码:
#!/usr/local/bin/ruby
require 'rubygems'
require 'net/http'
require 'net/https'
require 'time'
require 'hmac'
require 'hmac-sha2'
require 'base64'
require 'cgi'
class AWSGetSignatureV4
def initialize(aws_key,aws_secretpwd)
@regions=['ap-northeast-1', 'ap-southeast-1', 'eu-west-1', 'us-east-1', 'us-west-1', 'us-west-2', 'sa-east-1']
@rds_list={}
@inst_list={}
@rds_reserves={}
@inst_reserves={}
@aws_key=aws_key
@aws_secret=aws_secretpwd
@canonical_uri="/\n"
@request_type="GET\n"
@request_version='2012-04-23'
@request_headers={
'Host' => ''
}
end
def form_request(requestname, zone)
canonical_request_full(requestname, zone)
form_string_to_sign(zone)
form_signature(requestname, zone)
form_request_url(requestname, zone)
end
def get_data(requestname, zone)
form_request(requestname, zone)
http = Net::HTTP.new(@https_addr, "443")
http.use_ssl = true
headers = { 'Host' => "#{@https_addr}" }
@request_data=""
retval = http.get(@url_to_use, headers) do |chunk|
@request_data+=chunk
end
puts(retval.code)
puts(@request_data)
end
def get_service_type(requestname)
if requestname == 'DescribeReservedDBInstances'
@service_type="rds"
else
raise "No such request type."
end
end
def form_time_values()
@timenowz=Time.now.utc.iso8601
@time_use_now=@timenowz.gsub(/-|:/, '')
@date_to_use=@time_use_now.gsub(/T.*$/,'')
end
def init_param_values(requestname)
@init_params = {
'Action' => requestname,
'Version' => @request_version
}
end
def other_param_values(zone)
@other_params = {
'X-Amz-Algorithm' => 'AWS4-HMAC-SHA256',
'X-Amz-Credential' => @aws_key+"/#{@date_to_use}/#{zone}/#{@service_type}/aws4_request",
'X-Amz-Date' => @time_use_now,
'X-Amz-SignedHeaders' => 'Host'
}
end
def form_canonical_query_string(requestname, zone)
@querystringz = @init_params.sort.collect { |key, value| [CGI.escape(key.to_s), CGI.escape(value.to_s)].join('=') }.join('&')+"&"+@other_params.sort.collect { |key, value| [CGI.escape(key.to_s), CGI.escape(value.to_s)].join('=') }.join('&')
end
def modify_request_headers(requestname, zone)
@request_headers['Host']="#{@service_type}.#{zone}.amazonaws.com"
end
def form_headers()
@queryheaderz = "host:#{@request_headers['Host']}"
@signed_headerz =@request_headers.sort.collect { |key, value| key.to_s.downcase }.join(';')
@canonical_headerz =@request_headers.sort.collect { |key, value| [CGI.escape(key.to_s.downcase), CGI.escape(value.to_s)].join(':') }.join("\n")
end
def form_payload_data()
@payload=@init_params.sort.collect { |key, value| [CGI.escape(key.to_s), CGI.escape(value.to_s)].join('=') }.join('&')
@hex_sign_string=Digest::SHA256.digest("").unpack('H*').first
if @request_type == "GET\n"
@hex_sign_string=Digest::SHA256.digest("").unpack('H*').first
elsif @request_type == "POST\n"
@hex_sign_string=Digest::SHA256.digest(@payload).unpack('H*').first
end
end
def canonical_request_full(requestname, zone)
form_time_values()
get_service_type(requestname)
init_param_values(requestname)
other_param_values(zone)
modify_request_headers(requestname, zone)
form_canonical_query_string(requestname, zone)
form_headers()
form_payload_data()
@canonical_request=@request_type+@canonical_uri+@querystringz+"\n"+@canonical_headerz+"\n\n"+@signed_headerz+"\n"+@hex_sign_string
end
def form_string_to_sign(zone)
hex_sign_sts=Digest::SHA256.digest(@canonical_request).unpack('H*').first
@string_to_sign="#{@other_params['X-Amz-Algorithm']}\n#{@other_params['X-Amz-Date']}\n#{@date_to_use}/#{zone}/#{@service_type}/aws4_request\n#{hex_sign_sts}"
end
def form_signature(requestname, zone)
@kdatez = OpenSSL::HMAC.digest('sha256', "AWS4" + @aws_secret, @date_to_use)
@kregionz = OpenSSL::HMAC.digest('sha256', @kdatez, zone)
@kservicez = OpenSSL::HMAC.digest('sha256', @kregionz, "#{@service_type}")
@ksigningz = OpenSSL::HMAC.digest('sha256', @kservicez, "aws4_request")
@signaturez = OpenSSL::HMAC.digest('sha256', @ksigningz, @string_to_sign)
@other_params['X-Amz-Signature']=@signaturez.unpack('H*').first
end
def form_request_url(requestname, zone)
@url_to_use = @init_params.sort.collect { |key, value| [CGI.escape(key.to_s), CGI.escape(value.to_s)].join('=') }.join('&')+"&"+@other_params.sort.collect { |key, value| [CGI.escape(key.to_s), CGI.escape(value.to_s)].join('=') }.join('&')
if requestname == 'DescribeReservedDBInstances'
@url_to_use="/?"+@url_to_use
@https_addr="#{@service_type}.#{zone}.amazonaws.com"
@url_to_use_full="https://#{@service_type}.#{zone}.amazonaws.com/?"+@url_to_use
end
end
end
billing_obj=AWSGetSignatureV4.new("AWS_KEY","AWS_SECRET")
billing_obj.get_data("DescribeReservedDBInstances", 'us-east-1')