通过http正确签署对aws资源的请求

时间:2016-07-26 20:59:26

标签: node.js amazon-web-services elasticsearch aws-sdk aws-lambda

我有一个lambda函数,它将一些数据写入我也通过AWS设置的Elasticsearch域。目前,我的域上的访问策略只是允许我自己的IP地址与域

一起使用
{"Version": "2012-10-17", "Statement": [{
 "Effect": "Allow", "Principal": {"AWS": "*"},
 "Action": "es:*",
 "Resource": "arn:aws:es:us-east-1:$ACCOUNT:domain/DOMAIN/*",
 "Condition": { "IpAddress": { "aws:SourceIp": $MYIP } }
}]}

我找到了aws4 library来签署http请求。我正在使用它:

axios(aws4.sign({
    host: process.env.ES_ENDPOINT,
    method: "post",
    url: `https://${process.env.ES_ENDPOINT}/foobot/foobot`,
    data,
}))

这实际上是在没有aws4.sign的情况下工作,因为我已经完全打开了ES域,但现在我已经应用了上面的IP地址策略。

现在,我不断收到这样的错误:

  

我们计算的请求签名与您提供的签名不符。检查您的AWS Secret Access Key和签名方法。有关详细信息,请参阅服务文档。

我需要做些什么来正确签署请求吗?

3 个答案:

答案 0 :(得分:2)

这实际上与两个库axiosaws4有关。 aws4将根据正常的NodeJS http请求进行签名,并在POST请求中使用正文正文来正确签署请求。

通过传递bodypath

,这很简单
axios(aws4.sign({
    host: process.env.ES_ENDPOINT,
    method: "POST",
    url: `https://${process.env.ES_ENDPOINT}/foobot/foobot`,
    data,
    body: JSON.stringify(data),
    path: "/foobot/foobot",
}))

答案 1 :(得分:0)

是的,我使用相同的示例,它成功运行。但是每次它返回不同的签名。即使是相同的值。

axios(aws4.sign({
    host: process.env.ES_ENDPOINT,
    method: "POST",
    url: `https://${process.env.ES_ENDPOINT}/foobot/foobot`,
    data,
    body: JSON.stringify(data),
    path: "/foobot/foobot",
}))

答案 2 :(得分:0)

上述答案有助于将其全部引入我的解决方案,以便将 WS 消息从 lambda 发布到 API 网关中的 Websocket API。

这样做的原因是为了避免使用 aws-sdk,它在第一次运行(预热)时至少增加了约 2500 毫秒。

这是我的代码,希望它可以帮助其他人:

const data = {'success': true};
const request = {
    host: process.env.AWS_API_GATEWAY_ENDPOINT,
    method: 'POST',
    url: `https://${process.env.AWS_API_GATEWAY_ENDPOINT}/wss/@connections/${connectionId}`, // this is for axios
    path: `/wss/@connections/${connectionId}`,
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(data),
    data, // this is needed for axios
}

const signedRequest = aws4.sign(request,
    {
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
        accessKeyId: process.env.AWS_ACCESS_KEY_ID,
        sessionToken: process.env.AWS_SESSION_TOKEN // needed when sending from a lambda
    });

    delete signedRequest.headers['Host']; // delete Host to not potentially mess with axios
    const response = await axios(signedRequest);