2012-07-17 102 views
1

我试图从RDS amazon web服务部件中使用存在的ruby库获取预留数据库实例列表并返回此数据,主要是使用雾图书馆。我注意到他们不会很遗憾地返回这些数据,因此我继续前进并开始调查。通过API调用从aws获取保留的DB RDS实例列表

我发现当使用签名版本4时,这个数据被返回,当使用rds cli(AWS提供的工具)时发现它,而雾库使用签名版本2发出请求。这导致我开始开发一个简单的解决方案,它将使用ruby脚本返回RDS保留实例,但由于我目前卡在这里的文档量很少。此时,解决方法是调用rds cli脚本,但这是一个糟糕的选择。

也花了一些时间搜索一个现成的解决方案(可以用任何语言)的案件,但无法找到任何。问题是,有没有人有最好的书面解决方案,使用签名版本4来进行AWS的API调用?

回答

1

经过一段时间,我们成功构建了一个类,其中包含所有必需的功能,这些功能将使用签名版本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 
    @[email protected](/-|:/, '') 
    @[email protected]_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('&')+"&"[email protected]_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 [email protected]_headers.sort.collect { |key, value| key.to_s.downcase }.join(';') 
    @canonical_headerz [email protected]_headers.sort.collect { |key, value| [CGI.escape(key.to_s.downcase), CGI.escape(value.to_s)].join(':') }.join("\n") 
end 

def form_payload_data() 
    @[email protected]_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() 
    @[email protected][email protected][email protected]+"\n"[email protected]_headerz+"\n\n"[email protected]_headerz+"\n"[email protected]_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'][email protected]('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('&')+"&"[email protected]_params.sort.collect { |key, value| [CGI.escape(key.to_s), CGI.escape(value.to_s)].join('=') }.join('&') 
    if requestname == 'DescribeReservedDBInstances' 
    @url_to_use="/?"[email protected]_to_use 
    @https_addr="#{@service_type}.#{zone}.amazonaws.com" 
    @url_to_use_full="https://#{@service_type}.#{zone}.amazonaws.com/?"[email protected]_to_use 
    end 
end 

end 

billing_obj=AWSGetSignatureV4.new("AWS_KEY","AWS_SECRET") 
billing_obj.get_data("DescribeReservedDBInstances", 'us-east-1')