Получение списка зарезервированных экземпляров БД RDS из aws с помощью вызова API

Я пытался получить список зарезервированных экземпляров БД из части веб-сервисов RDS amazon, используя имеющиеся библиотеки ruby, и вернуть эти данные, в основном с помощью библиотеки тумана. Однако я заметил, что они, к сожалению, не возвращают эти данные, поэтому я пошел дальше и начал расследование.

Я обнаружил, что при использовании сигнатуры версии 4 эти данные возвращаются, нашел их при использовании rds cli (инструмент, предоставленный AWS), в то время как библиотека тумана использует сигнатуру версии 2 для выполнения запросов. Это побудило меня приступить к разработке простого решения, которое возвращало бы зарезервированные экземпляры RDS с помощью скрипта ruby, но из-за небольшого количества документации я сейчас застрял здесь. На данный момент обходным путем является вызов скрипта rds cli, но это плохой вариант.

Также потратил некоторое время на поиск готового решения (может быть на любом языке) для этого случая, но не смог его найти. Таким образом, вопрос в том, есть ли у кого-нибудь готовое решение, написанное предпочтительно на ruby, которое использует сигнатуру версии 4 для вызовов API в AWS?


person Logic Wreck    schedule 17.07.2012    source источник


Ответы (1)


Через какое-то время нам удалось построить класс со всем необходимым функционалом, который бы возвращал зарезервированные экземпляры rds для aws, используя сигнатуру версии 4 для подписи запроса. Вот код:

#!/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](/-|:/, '')
  @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'][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('&')+"&"+@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')
person Logic Wreck    schedule 18.07.2012