AWS SDK 无法连接到企业代理
AWS SDK can´t connect behind corporate proxy
我的工作站在公司代理后面,我已经设置了环境变量,我可以使用除 aws-sdk 之外的所有东西和 NodeJS。这里是 TCP 连接的转储:
No. Time Source Destination Protocol Length Info
2 1.834143 105.103.15.106 105.103.82.47 TCP 74 54952 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=497254718 TSecr=0 WS=128
3 1.836141 105.103.82.47 105.103.15.106 TCP 74 8080 → 54952 [SYN, ACK] Seq=0 Ack=1 Win=14480 Len=0 MSS=1460 SACK_PERM=1 TSval=3399116010 TSecr=497254718 WS=128
4 1.836165 105.103.15.106 105.103.82.47 TCP 66 54952 → 8080 [ACK] Seq=1 Ack=1 Win=29312 Len=0 TSval=497254719 TSecr=3399116010
5 1.836779 105.103.15.106 105.103.82.47 TCP 310 54952 → 8080 [PSH, ACK] Seq=1 Ack=1 Win=29312 Len=244 TSval=497254719 TSecr=3399116010
6 1.838250 105.103.82.47 105.103.15.106 TCP 66 8080 → 54952 [ACK] Seq=1 Ack=245 Win=15616 Len=0 TSval=3399116012 TSecr=497254719
20 123.670911 105.103.82.47 105.103.15.106 TCP 66 8080 → 54952 [FIN, ACK] Seq=1 Ack=245 Win=15616 Len=0 TSval=3399237839 TSecr=497254719
21 123.674168 105.103.15.106 105.103.82.47 TCP 66 54952 → 8080 [FIN, ACK] Seq=245 Ack=2 Win=29312 Len=0 TSval=497285178 TSecr=3399237839
22 123.676592 105.103.82.47 105.103.15.106 TCP 66 8080 → 54952 [ACK] Seq=2 Ack=246 Win=15616 Len=0 TSval=3399237843 TSecr=497285178
请注意,三向握手正常,客户端(ip 以 106 结尾)在包号 5 上发送一些数据(psh、ack),并立即收到代理的 ACK(包号 6)。然后很长一段时间没有通信(7 到 19 之间的包不是来自这个 tcp 对话),包 20 是一个 FIN(代理超时由于没有包发送?)。此对话由 example provided by Amazon.
生成
节点版本:在 6.10.0、6.11.0 和 8.1.3 上测试
今天安装的 SDK (2.82.0)
作为比较,我在同一台 Ubuntu 机器上 运行 一个 aws cloudformatin describe-stack-resources --stack-name my-stack
。众所周知,aws
CLI 是 python,命令 运行 OK,对话如下:
No. Time Source Destination Protocol Length Info
1 0.000000 105.103.15.106 105.103.82.47 TCP 74 54940 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=496906305 TSecr=0 WS=128
2 0.001987 105.103.82.47 105.103.15.106 TCP 74 8080 → 54940 [SYN, ACK] Seq=0 Ack=1 Win=14480 Len=0 MSS=1460 SACK_PERM=1 TSval=3397722434 TSecr=496906305 WS=128
3 0.002008 105.103.15.106 105.103.82.47 TCP 66 54940 → 8080 [ACK] Seq=1 Ack=1 Win=29312 Len=0 TSval=496906305 TSecr=3397722434
4 0.002100 105.103.15.106 105.103.82.47 TCP 127 [TCP segment of a reassembled PDU]
5 0.003967 105.103.82.47 105.103.15.106 TCP 66 8080 → 54940 [ACK] Seq=1 Ack=62 Win=14592 Len=0 TSval=3397722436 TSecr=496906306
6 0.003974 105.103.15.106 105.103.82.47 HTTP 68 CONNECT cloudformation.us-east-1.amazonaws.com:443 HTTP/1.0
7 0.006035 105.103.82.47 105.103.15.106 TCP 66 8080 → 54940 [ACK] Seq=1 Ack=64 Win=14592 Len=0 TSval=3397722438 TSecr=496906306
8 0.247802 105.103.82.47 105.103.15.106 HTTP 185 HTTP/1.0 200 Connection established
9 0.247810 105.103.15.106 105.103.82.47 TCP 66 54940 → 8080 [ACK] Seq=64 Ack=120 Win=29312 Len=0 TSval=496906367 TSecr=3397722681
10 0.248938 105.103.15.106 105.103.82.47 TLSv1.2 583 Client Hello
11 0.250985 105.103.82.47 105.103.15.106 TCP 66 8080 → 54940 [ACK] Seq=120 Ack=581 Win=15616 Len=0 TSval=3397722683 TSecr=496906367
12 0.684003 105.103.82.47 105.103.15.106 TLSv1.2 1995 Server Hello
13 0.684011 105.103.15.106 105.103.82.47 TCP 66 54940 → 8080 [ACK] Seq=581 Ack=2049 Win=33152 Len=0 TSval=496906476 TSecr=3397723117
14 0.690001 105.103.82.47 105.103.15.106 TLSv1.2 1488 CertificateServer Key Exchange, Server Hello Done
15 0.690866 105.103.15.106 105.103.82.47 TLSv1.2 216 Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
16 0.692974 105.103.82.47 105.103.15.106 TCP 66 8080 → 54940 [ACK] Seq=3471 Ack=731 Win=16640 Len=0 TSval=3397723125 TSecr=496906478
17 0.968807 105.103.82.47 105.103.15.106 TLSv1.2 141 Change Cipher Spec, Encrypted Handshake Message
18 0.969476 105.103.15.106 105.103.82.47 TLSv1.2 679 Application Data
19 0.970992 105.103.82.47 105.103.15.106 TCP 66 8080 → 54940 [ACK] Seq=3546 Ack=1344 Win=17920 Len=0 TSval=3397723403 TSecr=496906547
20 1.319977 105.103.82.47 105.103.15.106 TLSv1.2 617 Application Data
21 1.324998 105.103.82.47 105.103.15.106 TCP 2114 [TCP segment of a reassembled PDU]
22 1.325003 105.103.15.106 105.103.82.47 TCP 66 54940 → 8080 [ACK] Seq=1344 Ack=6145 Win=43008 Len=0 TSval=496906636 TSecr=3397723753
23 1.329979 105.103.82.47 105.103.15.106 TLSv1.2 133 Application Data
24 1.332987 105.103.15.106 105.103.82.47 TCP 66 54940 → 8080 [FIN, ACK] Seq=1344 Ack=6212 Win=43008 Len=0 TSval=496906638 TSecr=3397723763
25 1.373825 105.103.82.47 105.103.15.106 TCP 66 8080 → 54940 [ACK] Seq=6212 Ack=1345 Win=17920 Len=0 TSval=3397723807 TSecr=496906638
26 1.606041 105.103.82.47 105.103.15.106 TLSv1.2 119 Encrypted Alert
27 1.606063 105.103.15.106 105.103.82.47 TCP 54 54940 → 8080 [RST] Seq=1345 Win=0 Len=0
注意数据包1到3是三次握手,和JS SDK完全一样,数据包4和JS SDK的数据包5类似,总结中没有显示,但也有PSH标志和ACK,区别是内容(预期),数据包 5 是对该数据的代理 ACK。从这一点开始,情况有所不同,aws
CLI 在 ACK 到达数据包 6 后立即发送下一个数据包。收到数据后,aws
CLI 发送 FIN,接收 ACK,加密警报并发送 RST(这是由于加密警报不是预期的)。
我找不到为什么 JS SDK 在最后一个服务器 ACK 后停止发送数据。但是由于代理超时并在一段时间后发送 FIN ACK,我的节点脚本似乎挂了很长时间,直到中止并出现以下错误:
{ NetworkingError: socket hang up
at TLSSocket.onHangUp (_tls_wrap.js:1124:19)
at TLSSocket.g (events.js:292:16)
at emitNone (events.js:91:20)
at TLSSocket.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:974:12)
at _combinedTickCallback (internal/process/next_tick.js:80:11)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
留言:'socket hang up',
代码:'NetworkingError',
区域:'us-west-2',
主机名:'bucket.s3-us-west-2.amazonaws.com',
可重试:真,
时间:2017-07-07T19:31:29.494Z } null
有线索吗?
查看输出,CLI 连接正在使用 CONNECT(HTTP 隧道),如 here while your NodeJS SDK call doesn't appear to be doing so. It seems that NodeJS SDK with CONNECT type proxies is a bit weird. I'd recommend looking over the bug on it which mentions using node-tunnel 所述,给出如下内容:
var AWS = require('aws-sdk');
var tunnel = require('tunnel');
var tunnelingAgent = tunnel.httpsOverHttp({
proxy: { // Proxy settings
host: 'proxyhost',
port: 8080,
proxyAuth: "user:pass",
}
});
AWS.config.update({
httpOptions: {
agent: tunnelingAgent
}
});
var s3 = new AWS.S3({region: 'us-west-2'});
s3.getObject({Bucket: 'bucket', Key: 'key'}, function (err, data) {
console.log(err, data);
});
虽然不幸的是我没有环境设置来测试它,但我希望它至少能让你开始了解如何解决这个问题。
从 AWS SDK v3 开始,有 no longer a global config 用于配置代理。配置必须传递给每个实例化的服务客户端。
示例 S3Client
,包 @aws-sdk/client-s3
:
使用 aws-sdk-v3-proxy(使用 HTTP_PROXY / HTTPS_PROXY 环境变量)
import { S3Client } from '@aws-sdk/client-s3';
import { addProxyToClient } from 'aws-sdk-v3-proxy';
const client = addProxyToClient(new S3Client({}));
或配置自定义 requestHandler
import { S3Client } from '@aws-sdk/client-s3';
import { NodeHttpHandler } from "@aws-sdk/node-http-handler";
import ProxyAgent from "proxy-agent";
// omit proxy url argument to use env variables HTTP_PROXY / HTTPS_PROXY
const proxyAgent = new ProxyAgent("http://internal.proxy.com");
new S3Client({
requestHandler: new NodeHttpHandler({
httpAgent: proxyAgent,
httpsAgent: proxyAgent
})
});
特例:临时凭证
如果您使用 AssumeRole 为身份和访问管理 (IAM) 使用临时的、有限权限的凭据,则必须发出请求才能获取它们。 S3Client
为此提供了选项 credentials
。
但是,由于不再有全局配置对象,客户端在幕后获取临时凭证-STSClient
-has to be configured as well to work behind a proxy. fromIni
, fromTokenFile
and other functions provided by @aws-sdk/credential-providers
have a clientConfig option那。
import { S3Client } from '@aws-sdk/client-s3';
import { NodeHttpHandler } from "@aws-sdk/node-http-handler";
import ProxyAgent from "proxy-agent";
import { fromIni } from "@aws-sdk/credential-providers";
// omit proxy url argument to use env variables HTTP_PROXY / HTTPS_PROXY
const proxyAgent = new ProxyAgent("http://internal.proxy.com");
const requestHandler = new NodeHttpHandler({
httpAgent: proxyAgent,
httpsAgent: proxyAgent
})
new S3Client({
credentials: fromIni({
profile: "YourRoleProfile",
clientConfig: {
requestHandler
}
}),
region: "eu-central-1",
requestHandler
});
我的工作站在公司代理后面,我已经设置了环境变量,我可以使用除 aws-sdk 之外的所有东西和 NodeJS。这里是 TCP 连接的转储:
No. Time Source Destination Protocol Length Info
2 1.834143 105.103.15.106 105.103.82.47 TCP 74 54952 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=497254718 TSecr=0 WS=128
3 1.836141 105.103.82.47 105.103.15.106 TCP 74 8080 → 54952 [SYN, ACK] Seq=0 Ack=1 Win=14480 Len=0 MSS=1460 SACK_PERM=1 TSval=3399116010 TSecr=497254718 WS=128
4 1.836165 105.103.15.106 105.103.82.47 TCP 66 54952 → 8080 [ACK] Seq=1 Ack=1 Win=29312 Len=0 TSval=497254719 TSecr=3399116010
5 1.836779 105.103.15.106 105.103.82.47 TCP 310 54952 → 8080 [PSH, ACK] Seq=1 Ack=1 Win=29312 Len=244 TSval=497254719 TSecr=3399116010
6 1.838250 105.103.82.47 105.103.15.106 TCP 66 8080 → 54952 [ACK] Seq=1 Ack=245 Win=15616 Len=0 TSval=3399116012 TSecr=497254719
20 123.670911 105.103.82.47 105.103.15.106 TCP 66 8080 → 54952 [FIN, ACK] Seq=1 Ack=245 Win=15616 Len=0 TSval=3399237839 TSecr=497254719
21 123.674168 105.103.15.106 105.103.82.47 TCP 66 54952 → 8080 [FIN, ACK] Seq=245 Ack=2 Win=29312 Len=0 TSval=497285178 TSecr=3399237839
22 123.676592 105.103.82.47 105.103.15.106 TCP 66 8080 → 54952 [ACK] Seq=2 Ack=246 Win=15616 Len=0 TSval=3399237843 TSecr=497285178
请注意,三向握手正常,客户端(ip 以 106 结尾)在包号 5 上发送一些数据(psh、ack),并立即收到代理的 ACK(包号 6)。然后很长一段时间没有通信(7 到 19 之间的包不是来自这个 tcp 对话),包 20 是一个 FIN(代理超时由于没有包发送?)。此对话由 example provided by Amazon.
生成节点版本:在 6.10.0、6.11.0 和 8.1.3 上测试 今天安装的 SDK (2.82.0)
作为比较,我在同一台 Ubuntu 机器上 运行 一个 aws cloudformatin describe-stack-resources --stack-name my-stack
。众所周知,aws
CLI 是 python,命令 运行 OK,对话如下:
No. Time Source Destination Protocol Length Info
1 0.000000 105.103.15.106 105.103.82.47 TCP 74 54940 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=496906305 TSecr=0 WS=128
2 0.001987 105.103.82.47 105.103.15.106 TCP 74 8080 → 54940 [SYN, ACK] Seq=0 Ack=1 Win=14480 Len=0 MSS=1460 SACK_PERM=1 TSval=3397722434 TSecr=496906305 WS=128
3 0.002008 105.103.15.106 105.103.82.47 TCP 66 54940 → 8080 [ACK] Seq=1 Ack=1 Win=29312 Len=0 TSval=496906305 TSecr=3397722434
4 0.002100 105.103.15.106 105.103.82.47 TCP 127 [TCP segment of a reassembled PDU]
5 0.003967 105.103.82.47 105.103.15.106 TCP 66 8080 → 54940 [ACK] Seq=1 Ack=62 Win=14592 Len=0 TSval=3397722436 TSecr=496906306
6 0.003974 105.103.15.106 105.103.82.47 HTTP 68 CONNECT cloudformation.us-east-1.amazonaws.com:443 HTTP/1.0
7 0.006035 105.103.82.47 105.103.15.106 TCP 66 8080 → 54940 [ACK] Seq=1 Ack=64 Win=14592 Len=0 TSval=3397722438 TSecr=496906306
8 0.247802 105.103.82.47 105.103.15.106 HTTP 185 HTTP/1.0 200 Connection established
9 0.247810 105.103.15.106 105.103.82.47 TCP 66 54940 → 8080 [ACK] Seq=64 Ack=120 Win=29312 Len=0 TSval=496906367 TSecr=3397722681
10 0.248938 105.103.15.106 105.103.82.47 TLSv1.2 583 Client Hello
11 0.250985 105.103.82.47 105.103.15.106 TCP 66 8080 → 54940 [ACK] Seq=120 Ack=581 Win=15616 Len=0 TSval=3397722683 TSecr=496906367
12 0.684003 105.103.82.47 105.103.15.106 TLSv1.2 1995 Server Hello
13 0.684011 105.103.15.106 105.103.82.47 TCP 66 54940 → 8080 [ACK] Seq=581 Ack=2049 Win=33152 Len=0 TSval=496906476 TSecr=3397723117
14 0.690001 105.103.82.47 105.103.15.106 TLSv1.2 1488 CertificateServer Key Exchange, Server Hello Done
15 0.690866 105.103.15.106 105.103.82.47 TLSv1.2 216 Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
16 0.692974 105.103.82.47 105.103.15.106 TCP 66 8080 → 54940 [ACK] Seq=3471 Ack=731 Win=16640 Len=0 TSval=3397723125 TSecr=496906478
17 0.968807 105.103.82.47 105.103.15.106 TLSv1.2 141 Change Cipher Spec, Encrypted Handshake Message
18 0.969476 105.103.15.106 105.103.82.47 TLSv1.2 679 Application Data
19 0.970992 105.103.82.47 105.103.15.106 TCP 66 8080 → 54940 [ACK] Seq=3546 Ack=1344 Win=17920 Len=0 TSval=3397723403 TSecr=496906547
20 1.319977 105.103.82.47 105.103.15.106 TLSv1.2 617 Application Data
21 1.324998 105.103.82.47 105.103.15.106 TCP 2114 [TCP segment of a reassembled PDU]
22 1.325003 105.103.15.106 105.103.82.47 TCP 66 54940 → 8080 [ACK] Seq=1344 Ack=6145 Win=43008 Len=0 TSval=496906636 TSecr=3397723753
23 1.329979 105.103.82.47 105.103.15.106 TLSv1.2 133 Application Data
24 1.332987 105.103.15.106 105.103.82.47 TCP 66 54940 → 8080 [FIN, ACK] Seq=1344 Ack=6212 Win=43008 Len=0 TSval=496906638 TSecr=3397723763
25 1.373825 105.103.82.47 105.103.15.106 TCP 66 8080 → 54940 [ACK] Seq=6212 Ack=1345 Win=17920 Len=0 TSval=3397723807 TSecr=496906638
26 1.606041 105.103.82.47 105.103.15.106 TLSv1.2 119 Encrypted Alert
27 1.606063 105.103.15.106 105.103.82.47 TCP 54 54940 → 8080 [RST] Seq=1345 Win=0 Len=0
注意数据包1到3是三次握手,和JS SDK完全一样,数据包4和JS SDK的数据包5类似,总结中没有显示,但也有PSH标志和ACK,区别是内容(预期),数据包 5 是对该数据的代理 ACK。从这一点开始,情况有所不同,aws
CLI 在 ACK 到达数据包 6 后立即发送下一个数据包。收到数据后,aws
CLI 发送 FIN,接收 ACK,加密警报并发送 RST(这是由于加密警报不是预期的)。
我找不到为什么 JS SDK 在最后一个服务器 ACK 后停止发送数据。但是由于代理超时并在一段时间后发送 FIN ACK,我的节点脚本似乎挂了很长时间,直到中止并出现以下错误:
{ NetworkingError: socket hang up
at TLSSocket.onHangUp (_tls_wrap.js:1124:19)
at TLSSocket.g (events.js:292:16)
at emitNone (events.js:91:20)
at TLSSocket.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:974:12)
at _combinedTickCallback (internal/process/next_tick.js:80:11)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
留言:'socket hang up', 代码:'NetworkingError', 区域:'us-west-2', 主机名:'bucket.s3-us-west-2.amazonaws.com', 可重试:真, 时间:2017-07-07T19:31:29.494Z } null
有线索吗?
查看输出,CLI 连接正在使用 CONNECT(HTTP 隧道),如 here while your NodeJS SDK call doesn't appear to be doing so. It seems that NodeJS SDK with CONNECT type proxies is a bit weird. I'd recommend looking over the bug on it which mentions using node-tunnel 所述,给出如下内容:
var AWS = require('aws-sdk');
var tunnel = require('tunnel');
var tunnelingAgent = tunnel.httpsOverHttp({
proxy: { // Proxy settings
host: 'proxyhost',
port: 8080,
proxyAuth: "user:pass",
}
});
AWS.config.update({
httpOptions: {
agent: tunnelingAgent
}
});
var s3 = new AWS.S3({region: 'us-west-2'});
s3.getObject({Bucket: 'bucket', Key: 'key'}, function (err, data) {
console.log(err, data);
});
虽然不幸的是我没有环境设置来测试它,但我希望它至少能让你开始了解如何解决这个问题。
从 AWS SDK v3 开始,有 no longer a global config 用于配置代理。配置必须传递给每个实例化的服务客户端。
示例 S3Client
,包 @aws-sdk/client-s3
:
使用 aws-sdk-v3-proxy(使用 HTTP_PROXY / HTTPS_PROXY 环境变量)
import { S3Client } from '@aws-sdk/client-s3';
import { addProxyToClient } from 'aws-sdk-v3-proxy';
const client = addProxyToClient(new S3Client({}));
或配置自定义 requestHandler
import { S3Client } from '@aws-sdk/client-s3';
import { NodeHttpHandler } from "@aws-sdk/node-http-handler";
import ProxyAgent from "proxy-agent";
// omit proxy url argument to use env variables HTTP_PROXY / HTTPS_PROXY
const proxyAgent = new ProxyAgent("http://internal.proxy.com");
new S3Client({
requestHandler: new NodeHttpHandler({
httpAgent: proxyAgent,
httpsAgent: proxyAgent
})
});
特例:临时凭证
如果您使用 AssumeRole 为身份和访问管理 (IAM) 使用临时的、有限权限的凭据,则必须发出请求才能获取它们。 S3Client
为此提供了选项 credentials
。
但是,由于不再有全局配置对象,客户端在幕后获取临时凭证-STSClient
-has to be configured as well to work behind a proxy. fromIni
, fromTokenFile
and other functions provided by @aws-sdk/credential-providers
have a clientConfig option那。
import { S3Client } from '@aws-sdk/client-s3';
import { NodeHttpHandler } from "@aws-sdk/node-http-handler";
import ProxyAgent from "proxy-agent";
import { fromIni } from "@aws-sdk/credential-providers";
// omit proxy url argument to use env variables HTTP_PROXY / HTTPS_PROXY
const proxyAgent = new ProxyAgent("http://internal.proxy.com");
const requestHandler = new NodeHttpHandler({
httpAgent: proxyAgent,
httpsAgent: proxyAgent
})
new S3Client({
credentials: fromIni({
profile: "YourRoleProfile",
clientConfig: {
requestHandler
}
}),
region: "eu-central-1",
requestHandler
});