JrBenito
JrBenito

Reputation: 1013

AWS SDK can´t connect behind corporate proxy

My workstation is behind a corporate proxy, I have set environment variables and I am able to use everything but aws-sdk with NodeJS. Here a dump of the TCP connection:

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

Notice that three-way handshake goes ok, than client (ip ending on 106) sends some data (psh, ack) on package number 5 and immediately, receiveis proxy´s ACK (packet number 6). Then no communication for a long period (packages between 7 and 19 are not from this tcp conversation), packet 20 is a FIN (proxy timeout due no packages sent?). This conversation was generated by example provided by Amazon.

Node versions: tested on 6.10.0, 6.11.0 and 8.1.3 SDK installed today (2.82.0)

As a comparison, I run an aws cloudformatin describe-stack-resources --stack-name my-stack on the same Ubuntu machine. As known, aws CLI is python, the command runs OK, and conversation goes like:

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

Notice that packets from 1 to 3 are threeway handshake and exact same as with JS SDK, packet 4 is similar to packet 5 of JS SDK, it is not shown on summary but it also has PSH flag and ACK, differences are the content (expected) and packet 5 is the proxy ACK to that data. From this point on things are different, aws CLI sends next pack as soon as the ACK arrives on packet 6. After data received, aws CLI sends FIN, receives ACK, Encrypt Alert and sends a RST (this is due Encrypt Alert not expected).

I can´t find why JS SDK stop to send data after last server ACK. But since proxy times out and send FIN ACK after sometime, my node script seems to hang for long until abort with error below:

{ 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)

message: 'socket hang up', code: 'NetworkingError', region: 'us-west-2', hostname: 'bucket.s3-us-west-2.amazonaws.com', retryable: true, time: 2017-07-07T19:31:29.494Z } null

Any clue?

Upvotes: 0

Views: 2951

Answers (2)

Felix Ebert
Felix Ebert

Reputation: 1151

As of AWS SDK v3, there is no longer a global config for configuring a proxy. Configuration must be passed to each service client that is instantiated.

Example for S3Client, package @aws-sdk/client-s3:

Use either aws-sdk-v3-proxy (uses HTTP_PROXY / HTTPS_PROXY env variables)

import { S3Client } from '@aws-sdk/client-s3';
import { addProxyToClient } from 'aws-sdk-v3-proxy';

const client = addProxyToClient(new S3Client({}));

or configure a custom 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
    })
});

Special case: Temporary Credentials

If you use temporary, limited-privilege credentials for Identity and Access Management (IAM) using AssumeRole, a request has to be made to obtain them. S3Client provides the option credentials for that.

However, as there is no longer a global config object, the client behind the scenes for obtaining the temporary 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 for that.

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
});

Upvotes: 3

Chris White
Chris White

Reputation: 1447

Looking over the output, the CLI connection is using CONNECT (HTTP tunneling) as described 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 to give something like this:

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);
});

While I unfortunately don't have an environment setup to test this I hope it will at least give you a start on how to approach the issue.

Upvotes: 4

Related Questions