1

我试图使用存在的 ruby​​ 库从 RDS amazon Web 服务部分获取保留的数据库实例列表并返回此数据,主要是使用雾库。我注意到虽然他们没有返回这些数据,但很遗憾,因此我继续进行调查。

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

还花了一些时间在谷歌上搜索该案例的现成解决方案(可以是任何语言),但找不到任何解决方案。因此,问题是,是否有人有一个现成的解决方案,最好用 ruby​​ 编写,使用签名版本 4 对 AWS 进行 API 调用?

4

1 回答 1

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
  @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')
于 2012-07-18T14:23:30.240 回答