Exp*_*lls 4 amazon-web-services node.js 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 } }
}]}
Run Code Online (Sandbox Code Playgroud)
我找到了用于签署 http 请求的aws4
库。我这样使用它:
axios(aws4.sign({
host: process.env.ES_ENDPOINT,
method: "post",
url: `https://${process.env.ES_ENDPOINT}/foobot/foobot`,
data,
}))
Run Code Online (Sandbox Code Playgroud)
这实际上在没有该块的情况下工作aws4.sign
,因为我完全开放了 ES 域,但现在我应用了上面的 IP 地址策略。
现在,我不断收到这样的错误响应:
我们计算的请求签名与您提供的签名不匹配。检查您的 AWS 秘密访问密钥和签名方法。有关详细信息,请参阅服务文档。
我还需要做些什么才能正确签署请求吗?
这实际上与两个库有关,axios
并且aws4
. aws4
将基于正常的 NodeJShttp
请求进行签名,并且在带有正文的 POST 请求中,需要正文才能正确签署请求。
通过传入body
和就可以很简单地解决这个问题path
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",
}))
Run Code Online (Sandbox Code Playgroud)
我们发现有些 AWS 库可以顺利处理事务,而无需通过环境变量与 lambda 共享您的凭证。
下面是一个完整的示例,允许 lambda 调用 appysync 端点。
将其适应任何其他服务应该不难。
希望它能帮助某人。
const { defaultProvider } = require('@aws-sdk/credential-provider-node');
const { SignatureV4 } = require('@aws-sdk/signature-v4');
const { Sha256 } = require('@aws-crypto/sha256-js');
const { HttpRequest } = require('@aws-sdk/protocol-http');
const axios = require('axios');
const signer = new SignatureV4({
credentials: defaultProvider(),
region: 'eu-west-1',
service: 'appsync',
sha256: Sha256,
});
/**
* Send a signed graphQl request via http to appsync
*
* @param {string} appsyncUrl URL to reach GraphQL
* @param {object} requestBody JSON stringified request object.
* @returns {Promise} Request that has been sent
*/
async function send(appsyncUrl, requestBody) {
const parsedUrl = new UrlParse(appsyncUrl);
const endpoint = parsedUrl.hostname.toString();
const path = parsedUrl.pathname.toString();
const req = new HttpRequest({
hostname: endpoint,
path,
method: 'POST',
body: requestBody,
headers: {
host: endpoint,
'Content-Type': 'application/json',
},
});
const signed = await signer.sign(req, { signingDate: new Date() });
return axios
.post(appsyncUrl, signed.body, { headers: signed.headers })
.then((response) => {
if (response.data && response.data.errors) {
console.error({ error: response.data.errors }, 'Updating data failed');
} else if (response.data) {
return response.data;
}
})
.catch((error) => console.error({ error, endpoint }, 'Failed to connect to graphQL server'));
}
Run Code Online (Sandbox Code Playgroud)
用法:
const myGraphQlMutation = /* GraphQL */ `
mutation MyMutation($id: ID!, $status: String!) {
myMutation(result: { id: $id, status: $status }) {
id
status
}
}
`;
const sendToAppSync = async (id, status) => {
const requestBody = JSON.stringify({
query: myGraphQlMutation,
variables: {
id: id,
status: status,
},
});
try {
const response = await send(process.env.APPSYNC_ENDPOINT, requestBody);
} catch (error) {
logger.error(`[ERROR] Error calling appsync: ${JSON.stringify(error, null, 2)}`);
throw error;
}
Run Code Online (Sandbox Code Playgroud)
当然,您需要为您的 lambda IAM 角色授予适当的权限。(这篇博文给出了很好的指导)
归档时间: |
|
查看次数: |
10639 次 |
最近记录: |