Проблемы аутентификации R + httr и EC2 API

Я хотел бы использовать пакет R httr для доступа к службам EC2 через их API. Но я немного не уверен, как начать, поскольку он не подпадает под обычный формат аутентификации «Oauth2.0», в котором у вас есть обычная система: ключ, секрет, токен и система подписи. Я думаю, что EC2 использует метод «подписи версии 2», но мне неясно, как это работает.

Просмотрите документацию, которую EC2 предоставляет в отношении выполнения запросов, по адресу http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/using-query-api.html

Я думаю, что мне нужно значение для подписи.... но не знаю, как его получить

Я попытался использовать некоторые из данных команд, используя httr, как показано ниже. Я могу адаптировать большинство параметров в строке URL, чтобы представить меня и то, что я хочу сделать, например, AWSAccessKeyId, ImageId, endpoint и Action и т. д.... но просто не знаю, куда идти, чтобы получить значение подписи.

Кроме того, в некоторых приведенных примерах они, похоже, не предоставляют секретный ключ доступа...

Таким образом, испытанные команды следующие: они изменили некоторые значения, чтобы представить меня, но получили следующее:

require(httr)
GET("https://ec2.amazonaws.com/
?Action=RunInstances
&ImageId=ami-60a54009
&MaxCount=3
&MinCount=1
&Placement.AvailabilityZone=us-east-1b
&Monitoring.Enabled=true
&AWSAccessKeyId=0GS7553JW74RRM612K02EXAMPLE
&Version=2012-10-01
&Expires=2010-10-10T12:00:00Z
&Signature=lBP67vCvGlDMBQ1dofZxg8E8SUEXAMPLE
&SignatureVersion=2
&SignatureMethod=HmacSHA256")

на что получаю ответ:

Response [http://aws.amazon.com/ec2/]
  Status: 200
  Content-type: text/html; charset=UTF-8


  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>

<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <link rel="icon" type="image/ico" href="//d36cz9buwru1tt.cloudfront.net/favicon.ico">
  <link rel="shortcut icon" type="image/ico" href="//d36cz9buwru1tt.cloudfront.net/favicon.ico">
  <meta name="description" content="Amazon Elastic Compute Cloud delivers scalable, pay-as-you-go compute capacity in the cloud. " /><meta name="keywords" content="" /> ...

Есть ли у кого-нибудь опыт работы с API EC2 и его процедурой аутентификации, и будет ли достаточно просто использовать R, чтобы иметь возможность настраивать и запускать экземпляры Linux с выбранными мной AMI (на которые загружены R и другие соответствующие пакеты), затем запустить несколько команд R в этих экземплярах и вернуть вывод?

Не думаю, что это действительно связано с моим sessionInfo, но на всякий случай вот оно:

sessionInfo()
R version 2.15.1 (2012-06-22)
Platform: x86_64-apple-darwin9.8.0/x86_64 (64-bit)

locale:
[1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] httr_0.2

loaded via a namespace (and not attached):
[1] digest_0.5.2   plyr_1.7.1     RCurl_1.95-1.1 stringr_0.6.1  tools_2.15.1  

ИЗМЕНИТЬ:

Итак, в дальнейшей попытке следовать документации, предложенной @hadley, это то, что я пробовал и получил... буду очень признателен за любые более полезные советы о том, где я ошибаюсь...:

require(httr)

aws.key <- "xxxxxxx"
aws.secret <- "xxxxxxxxxxxx"

verb <- "GET"
zone <- "ec2.amazonaws.com"
func <- "DescribeImages"

ami.number <- "ami-xxxxxxxxx"

params <- list(paste0("ImageId.1=",ami.number),
    "Version=2012-10-01",
    "Expires=2012-11-20T12%3A00%3A00Z")


# adding in method and key parameters for creation of string to sign
orig.len.params <- length(params)
params.w.method.key <- params
params.w.method.key[[orig.len.params+1]] <- "SignatureVersion=2"
params.w.method.key[[orig.len.params+2]] <- "SignatureMethod=HmacSHA1"
params.w.method.key[[orig.len.params+3]] <- paste0("AWSAccessKeyId=",aws.key)

# String to sign (s2s)
s2s <- paste(c(paste0(verb,"\n",zone,"\n","/\n","AWSAccessKeyId=",aws.key),paste0("Action=",func),paste(sort(unlist(params.w.method.key)),collapse="&")),collapse="&")

# Signature(sig)
sig <- hmac_sha1(aws.secret, s2s)

# adding in signature, method and key parameters for signed request url generation
params.w.sig.method.key <- params
params.w.sig.method.key[[orig.len.params+1]] <- paste0("Signature=",sig)
params.w.sig.method.key[[orig.len.params+2]] <- "SignatureVersion=2"
params.w.sig.method.key[[orig.len.params+3]] <- "SignatureMethod=HmacSHA1"
params.w.sig.method.key[[orig.len.params+4]] <- paste0("AWSAccessKeyId=",aws.key)

# Signed request (sr)
sr <- paste(c(paste0("https://",zone,paste0("?Action=",func)),paste(unlist(params.w.sig.method.key),collapse="&")),collapse="&")

# GET signed request
GET(sr)

на что получаю ответ:

 Response [https://ec2.amazonaws.com?Action=DescribeImages&ImageId.1=[ami.number.from.before]&Version=2012-10-01&Expires=2012-11-20T12%3A00%3A00Z&Signature=[sig.value.from.before]&SignatureVersion=2&SignatureMethod=HmacSHA1&AWSAccessKeyId=[aws.key.from.before]/]
  Status: 401
  Content-type: 
 <?xml version="1.0" encoding="UTF-8"?>
 <Response><Errors><Error><Code>AuthFailure</Code><Message>AWS was not able to validate the provided access credentials</Message></Error></Errors><RequestID>5e10fb0b-f304-4677-9c64-98b4537c659a</RequestID></Response> 

person h.l.m    schedule 16.11.2012    source источник
comment
Основной алгоритм создания подписи изложен в docs.amazonwebservices.com/AWSEC2/latest/UserGuide/httr имеет функцию hmac для шага 3.   -  person hadley    schedule 20.11.2012
comment
спасибо ... я видел это, но не был уверен, что понял, что это значит ... есть ли возможность, которую вы могли бы привести пример?   -  person h.l.m    schedule 20.11.2012
comment
или потенциально увидеть, где я ошибаюсь, учитывая мои правки? Я думаю, я близок...   -  person h.l.m    schedule 20.11.2012


Ответы (1)


Вот моя попытка пошагового преобразования алгоритма в R-код. По моему опыту, вы действительно хотите делать каждый шаг отдельно, чтобы на каждом этапе можно было проверить правильность результатов.

require("httr")
require("RCurl")
require("stringr")

# 0: get key and secret from envvars, and set up request parameters

aws.key <- Sys.getenv("AWS_KEY")
aws.secret <- Sys.getenv("AWS_SECRET_KEY")

verb <- "GET"
zone <- "ec2.amazonaws.com"

ami.number <- "ami-xxxxxxxxx"

params <- list(
  Action = "DescribeImages",
  ImageId.1 = ami.number,
  Version = "2012-10-01",
  Expires = "2012-11-20T12:00:00Z",
  SignatureVersion = 2,
  SignatureMethod = "HmacSHA1",
  AWSAccessKeyId = aws.key)

# 1a: Sort the UTF-8 query string components by parameter name
params <- params[order(names(params))]

# 1b: URL encode the parameter name and values
params_e <- lapply(params, curlEscape)
names(params_e) <- curlEscape(names(params_e))
params_str <- str_c(names(params_e), "=", unlist(params_e), collapse = "&")
params_str <- gsub("%2E",".",gsub("%2D","-",params_str))

# 2: Create the string to sign
string_to_sign <- str_c(
  toupper(verb), "\n",
  tolower(zone), "\n",
  "/", "\n",
  params_str
)

# 3: Calculate an RFC 2104-compliant HMAC
# 4: Convert the resulting value to base64.
hmac <- hmac_sha1(aws.secret, string_to_sign)

params$Signature <- hmac

GET(paste0("https://",zone),query=params)
person hadley    schedule 20.11.2012
comment
извините, возможно, я что-то упустил, но что мне делать с объектом params? чтобы иметь возможность использовать функцию GET из httr - person h.l.m; 20.11.2012
comment
хм... кажется, все еще получаю код ошибки из ответа GET("https://ec2.amazonaws.com", query=params), получая: <Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.</Message> значения секрета и доступа выглядят нормально... - person h.l.m; 21.11.2012
comment
Да, диагностика проблем - это кошмар. В прошлый раз, когда мне приходилось это делать, я прочитал спецификацию 3 или 4 раза, а затем нашел реализацию ruby, которую я мог разобрать и проверить. К сожалению, сейчас я занят другими делами, поэтому не могу вдаваться в подробности. - person hadley; 21.11.2012
comment
А!!! Наконец исправлено... вам просто нужно добавить params_str <- gsub("%2E",".",gsub("%2D","-",params_str)) под param_str, чтобы он работал... curlEscape преобразовал дефис (-) и точку (.) в шестнадцатеричный, когда этого не должно было быть... поэтому он преобразуется вернемся в конец... отредактируем и примем ответ... - person h.l.m; 21.11.2012
comment
@h.l.m вы можете написать свою собственную функцию кодирования - см. oauth_encode1 в oauth-signature.r для одного подхода. - person hadley; 22.11.2012
comment
кто-нибудь пробовал, все еще работает? или их в настоящее время другое решение? Я все время получаю эту ошибку SignatureDoesNotMatch. - person Markus Schmidberger; 07.02.2015
comment
Для части 1a может потребоваться расширение: AWS необходимо, чтобы параметры были упорядочены по байтам. См. здесь: stackoverflow.com/questions/32798526/ - person Rentrop; 08.05.2016