Node.js opentelemetry https插件导致错误的aws请求签名
在NodeJS应用程序中同时使用Node.js opentelemetry https插件导致错误的aws请求签名,node.js,amazon-web-services,aws-sdk-js,open-telemetry,Node.js,Amazon Web Services,Aws Sdk Js,Open Telemetry,在NodeJS应用程序中同时使用@opentelemetry/plugin https和aws sdk时,opentelemetry插件会将traceparent头添加到每个aws请求中。如果不需要在aws sdk中重试,则此功能可以正常工作。aws sdk重试请求时,可能会发生以下错误: InvalidSignatureException:我们计算的请求签名与您提供的签名不匹配。检查您的AWS秘密访问密钥和签名方法。有关详细信息,请参阅维修文档。 SignatureDesNotMatch:我
@opentelemetry/plugin https
和aws sdk
时,opentelemetry插件会将traceparent
头添加到每个aws请求中。如果不需要在aws sdk
中重试,则此功能可以正常工作。aws sdk重试请求时,可能会发生以下错误:
InvalidSignatureException:我们计算的请求签名与您提供的签名不匹配。检查您的AWS秘密访问密钥和签名方法。有关详细信息,请参阅维修文档。
SignatureDesNotMatch:我们计算的请求签名与您提供的签名不匹配。检查您的密钥和签名方法。
traceparent:'00-32c9b7adee1da37fad593ee38e9e479b-875169606368a166-01'
Authorization:'AWS4-HMAC-SHA256 Credential=,SignedHeaders=主机;x-amz-content-sha256;x-amz-date;x-amz-security-token;x-amz-target,签名='
SignedHeaders
不包括traceparent
重试的请求包含以下标头:
traceparent:'00-c573e391a455a207469ffa4fb75b3cab-6F20C35628CFCC0-01'
授权:AWS4-HMAC-SHA256凭证=,签名头=主机;痕迹;x-amz-content-sha256;x-amz-date;x-amz-security-token;x-amz-target,签名=
SignedHeaders
不包括traceparent
在发送重试请求之前,@opentelemetry/plugin https
设置新的traceparent
头,这使得AWS请求的签名无效
下面是一段再现问题的代码(在达到导致重试的速率限制之前,您可能需要运行脚本几次):
可能的解决办法:
@opentelemetry/plugin https
中对aws的所有调用。
- 忽略对aws的调用将导致失去aws请求的所有跨度
traceparent
标题添加到aws sdk
-aws.Signers.V4.prototype.unsignableHeaders.push中的unsignableHeaders
代码>
- 如果另一个节点模块使用不同版本的
aws sdk
,则更改原型似乎是一种黑客行为,也无法处理这种情况
const opentelemetry = require("@opentelemetry/api");
const { NodeTracerProvider } = require("@opentelemetry/node");
const { SimpleSpanProcessor } = require("@opentelemetry/tracing");
const { JaegerExporter } = require("@opentelemetry/exporter-jaeger");
const provider = new NodeTracerProvider({
plugins: {
https: {
enabled: true,
path: "@opentelemetry/plugin-https"
}
}
});
const exporter = new JaegerExporter({ serviceName: "test" });
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
provider.register();
const AWS = require("aws-sdk");
const main = async () => {
const cwl = new AWS.CloudWatchLogs({ region: "us-east-1" });
const promises = new Array(100).fill(true).map(() => new Promise((resolve, reject) => {
cwl.describeLogGroups(function (err, data) {
if (err) {
console.log(err.name);
console.log("Got error:", err.message);
console.log("ERROR Request Authorization:");
console.log(this.request.httpRequest.headers.Authorization);
console.log("ERROR Request traceparent:");
console.log(this.request.httpRequest.headers.traceparent);
console.log("Retry count:", this.retryCount);
reject(err);
return;
}
resolve(data);
});
}));
const result = await Promise.all(promises);
console.log(result.length);
};
main().catch(console.error);
const opentelemetry = require("@opentelemetry/api");
const { NodeTracerProvider } = require("@opentelemetry/node");
const { SimpleSpanProcessor } = require("@opentelemetry/tracing");
const { JaegerExporter } = require("@opentelemetry/exporter-jaeger");
const { CloudWatchLogs } = require("@aws-sdk/client-cloudwatch-logs");
const provider = new NodeTracerProvider({
plugins: {
https: {
enabled: true,
path: "@opentelemetry/plugin-https"
}
}
});
const exporter = new JaegerExporter({ serviceName: "test" });
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
provider.register();
const main = async () => {
const cwl = new CloudWatchLogs({ region: "us-east-1" });
const promises = new Array(100).fill(true).map(() => new Promise((resolve, reject) => {
cwl.describeLogGroups({ limit: 50 })
.then(resolve)
.catch((err) => {
console.log(err.name);
console.log("Got error:", err.message);
reject(err);
});
}));
const result = await Promise.all(promises);
console.log(result.length);
};
main().catch(console.error);