【问题标题】:Proper signing of requests to aws resources through http通过 http 正确签署对 aws 资源的请求
【发布时间】:2016-11-30 16:28:36
【问题描述】:

我有一个 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 } }
}]}

我找到了用于签署 http 请求的 aws4 library。我就是这样使用它的:

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

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

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

我们计算的请求签名与您提供的签名不匹配。检查您的 AWS 秘密访问密钥和签名方法。有关详细信息,请参阅服务文档。

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

【问题讨论】:

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


    【解决方案1】:

    这实际上与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",
    }))
    

    【讨论】:

    • 您能告诉我如何发送签名的 GET 请求吗?我正在这样做,但得到相同的错误“我们计算的请求签名与您提供的签名不匹配。请检查您的 AWS 秘密访问密钥和签名方法。有关详细信息,请参阅服务文档。”这是我的代码: axios(aws4.sign({ host: env('ES_URI'), method: "GET", url: ${url}, query: JSON.stringify(query), path: /${ES_INDEX} }));
    • path需要包含查询字符串
    • 我面临一个非常愚蠢的问题,当我使用这个网址时:search-segment-sandbox-072751898297-cwtklgabkmeb662v4nicf7oepq.… 我没有收到错误:403,但是当我使用这个网址时:search-segment-sandbox-072751898297-cwtklgabkmeb662v4nicf7oepq.… 它给了我 403 错误.你能帮我吗?
    • 请求中有data 是不是错字?看起来像无效的对象表示法
    • @MatthewWoo 这是速记属性语法。它相当于data: data
    【解决方案2】:

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

    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",
    }))
    

    【讨论】:

    • 那不是因为它还带有时间戳记。所以根据时间会有所不同......
    【解决方案3】:

    上述答案有助于将其全部纳入我的解决方案,以便将 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);
    

    【讨论】:

      猜你喜欢
      • 2014-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-24
      • 2016-02-29
      • 2014-09-26
      • 2017-04-01
      相关资源
      最近更新 更多