cdk-local 0.166.1 → 0.166.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1468 +0,0 @@
1
- import { t as __exportAll } from "./rolldown-runtime-w6R9maHv.js";
2
- import { c as getEmbedConfig, t as getLogger } from "./logger-uzapot2X.js";
3
- import { A as validateAwsEmulatorEnvVars, B as describeCredentialLoadFailure, C as isRealAwsSentinel, E as realAwsEndpointFor, N as displayUntrustedValue, O as realAwsServicesOf, S as isLegacyAwsEmulatorSentinel, T as readAwsEmulatorEnvVarsFile, X as isLoopbackHostname, _ as MIXED_MODE_RESIGN_PORT, a as buildProxyRequestHandler, c as getAwsEmulatorServiceRouting, h as setAwsEndpointOverride, i as buildProxyClientConfig, m as setAwsEmulatorServiceRouting, u as isAwsServiceRoutedToEmulator, v as REAL_AWS_SENTINEL, w as legacyAwsEmulatorSentinelMessage } from "./aws-proxy-Ba_BOPyi.js";
4
- import { existsSync, lstatSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
5
- import { createHash, generateKeyPairSync, randomBytes, sign } from "node:crypto";
6
- import { get } from "node:http";
7
- import { get as get$1 } from "node:https";
8
- import { rootCertificates } from "node:tls";
9
- import * as path$1 from "node:path";
10
- import { homedir, tmpdir } from "node:os";
11
-
12
- //#region src/local/mixed-mode-tls.ts
13
- function der(tag, content) {
14
- const n = content.length;
15
- let len;
16
- if (n < 128) len = Buffer.from([n]);
17
- else {
18
- const bytes = [];
19
- for (let v = n; v > 0; v = Math.floor(v / 256)) bytes.unshift(v & 255);
20
- len = Buffer.from([128 | bytes.length, ...bytes]);
21
- }
22
- return Buffer.concat([
23
- Buffer.from([tag]),
24
- len,
25
- content
26
- ]);
27
- }
28
- const seq = (...parts) => der(48, Buffer.concat(parts));
29
- const set = (...parts) => der(49, Buffer.concat(parts));
30
- const octets = (b) => der(4, b);
31
- const bits = (b, unused = 0) => der(3, Buffer.concat([Buffer.from([unused]), b]));
32
- const bool = (v) => der(1, Buffer.from([v ? 255 : 0]));
33
- const utf8 = (s) => der(12, Buffer.from(s, "utf8"));
34
- const explicit = (n, inner) => der(160 + n, inner);
35
- function integer(b) {
36
- let v = b;
37
- while (v.length > 1 && v[0] === 0 && (v[1] & 128) === 0) v = v.subarray(1);
38
- if ((v[0] & 128) !== 0) v = Buffer.concat([Buffer.from([0]), v]);
39
- return der(2, v);
40
- }
41
- function oid(dotted) {
42
- const parts = dotted.split(".").map(Number);
43
- const out = [40 * parts[0] + parts[1]];
44
- for (const p of parts.slice(2)) {
45
- const stack = [p & 127];
46
- for (let v = Math.floor(p / 128); v > 0; v = Math.floor(v / 128)) stack.unshift(v & 127 | 128);
47
- out.push(...stack);
48
- }
49
- return der(6, Buffer.from(out));
50
- }
51
- function utcTime(d) {
52
- const p = (n) => String(n).padStart(2, "0");
53
- const s = p(d.getUTCFullYear() % 100) + p(d.getUTCMonth() + 1) + p(d.getUTCDate()) + p(d.getUTCHours()) + p(d.getUTCMinutes()) + p(d.getUTCSeconds()) + "Z";
54
- return der(23, Buffer.from(s, "ascii"));
55
- }
56
- const OID_ECDSA_SHA256 = "1.2.840.10045.4.3.2";
57
- const OID_CN = "2.5.4.3";
58
- const OID_SKI = "2.5.29.14";
59
- const OID_KEY_USAGE = "2.5.29.15";
60
- const OID_SAN = "2.5.29.17";
61
- const OID_BASIC_CONSTRAINTS = "2.5.29.19";
62
- const OID_AKI = "2.5.29.35";
63
- const OID_EKU = "2.5.29.37";
64
- const OID_NAME_CONSTRAINTS = "2.5.29.30";
65
- const OID_SERVER_AUTH = "1.3.6.1.5.5.7.3.1";
66
- const name = (cn) => seq(set(seq(oid(OID_CN), utf8(cn))));
67
- function extension(id, critical, value) {
68
- return seq(oid(id), ...critical ? [bool(true)] : [], octets(value));
69
- }
70
- function keyIdentifier(spkiDer) {
71
- const point = spkiDer.subarray(spkiDer.length - 65);
72
- return createHash("sha1").update(point).digest();
73
- }
74
- function serialNumber() {
75
- const b = randomBytes(16);
76
- b[0] = b[0] & 127 | 1;
77
- return b;
78
- }
79
- function issue(spec) {
80
- const sigAlg = seq(oid(OID_ECDSA_SHA256));
81
- const spki = spec.publicKey.export({
82
- type: "spki",
83
- format: "der"
84
- });
85
- const tbs = seq(explicit(0, integer(Buffer.from([2]))), integer(serialNumber()), sigAlg, name(spec.issuer), seq(utcTime(spec.notBefore), utcTime(spec.notAfter)), name(spec.subject), spki, explicit(3, seq(...spec.extensions)));
86
- const signature = sign("sha256", tbs, spec.signingKey);
87
- return `-----BEGIN CERTIFICATE-----\n${seq(tbs, sigAlg, bits(signature)).toString("base64").replace(/(.{64})/g, "$1\n").replace(/\n$/, "")}\n-----END CERTIFICATE-----\n`;
88
- }
89
- function createMixedModeTlsMaterials(now = /* @__PURE__ */ new Date(), leafDnsNames = ["localhost"]) {
90
- const notBefore = /* @__PURE__ */ new Date(now.getTime() - 3600 * 1e3);
91
- const notAfter = new Date(now.getTime() + 720 * 60 * 60 * 1e3);
92
- const ca = generateKeyPairSync("ec", { namedCurve: "prime256v1" });
93
- const leaf = generateKeyPairSync("ec", { namedCurve: "prime256v1" });
94
- const caKeyId = keyIdentifier(ca.publicKey.export({
95
- type: "spki",
96
- format: "der"
97
- }));
98
- const leafKeyId = keyIdentifier(leaf.publicKey.export({
99
- type: "spki",
100
- format: "der"
101
- }));
102
- const aki = (id) => seq(der(128, id));
103
- const caCn = `cdk-local mixed-mode CA ${randomBytes(4).toString("hex")}`;
104
- const caCertPem = issue({
105
- subject: caCn,
106
- issuer: caCn,
107
- publicKey: ca.publicKey,
108
- signingKey: ca.privateKey,
109
- notBefore,
110
- notAfter,
111
- extensions: [
112
- extension(OID_BASIC_CONSTRAINTS, true, seq(bool(true), integer(Buffer.from([0])))),
113
- extension(OID_KEY_USAGE, true, bits(Buffer.from([6]), 1)),
114
- extension(OID_SKI, false, octets(caKeyId)),
115
- extension(OID_AKI, false, aki(caKeyId)),
116
- extension(OID_NAME_CONSTRAINTS, true, seq(der(160, Buffer.concat([
117
- seq(der(135, Buffer.from([
118
- 127,
119
- 0,
120
- 0,
121
- 1,
122
- 255,
123
- 255,
124
- 255,
125
- 255
126
- ]))),
127
- seq(der(135, Buffer.from([
128
- ...new Array(15).fill(0),
129
- 1,
130
- ...new Array(16).fill(255)
131
- ]))),
132
- seq(der(130, Buffer.from("localhost", "ascii")))
133
- ]))))
134
- ]
135
- });
136
- const san = seq(der(135, Buffer.from([
137
- 127,
138
- 0,
139
- 0,
140
- 1
141
- ])), der(135, Buffer.from([
142
- 0,
143
- 0,
144
- 0,
145
- 0,
146
- 0,
147
- 0,
148
- 0,
149
- 0,
150
- 0,
151
- 0,
152
- 0,
153
- 0,
154
- 0,
155
- 0,
156
- 0,
157
- 1
158
- ])), ...leafDnsNames.map((n) => der(130, Buffer.from(n, "ascii"))));
159
- return {
160
- caCertPem,
161
- certPem: issue({
162
- subject: "127.0.0.1",
163
- issuer: caCn,
164
- publicKey: leaf.publicKey,
165
- signingKey: ca.privateKey,
166
- notBefore,
167
- notAfter,
168
- extensions: [
169
- extension(OID_BASIC_CONSTRAINTS, true, seq()),
170
- extension(OID_KEY_USAGE, true, bits(Buffer.from([128]), 7)),
171
- extension(OID_EKU, false, seq(oid(OID_SERVER_AUTH))),
172
- extension(OID_SAN, false, san),
173
- extension(OID_SKI, false, octets(leafKeyId)),
174
- extension(OID_AKI, false, aki(caKeyId))
175
- ]
176
- }),
177
- keyPem: leaf.privateKey.export({
178
- type: "pkcs8",
179
- format: "pem"
180
- }).toString()
181
- };
182
- }
183
- const OID_PKCS7_DATA = "1.2.840.113549.1.7.1";
184
- const OID_CERT_BAG = "1.2.840.113549.1.12.10.1.3";
185
- const OID_X509_CERTIFICATE = "1.2.840.113549.1.9.22.1";
186
- const OID_FRIENDLY_NAME = "1.2.840.113549.1.9.20";
187
- const OID_JDK_TRUSTED_KEY_USAGE = "2.16.840.1.113894.746875.1.1";
188
- const OID_ANY_EXTENDED_KEY_USAGE = "2.5.29.37.0";
189
- function buildJavaTrustStore(pems, aliasPrefix = "cdk-local") {
190
- const bags = [];
191
- for (const pem of pems) for (const block of pem.match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g) ?? []) {
192
- const body = block.replace(/-----(BEGIN|END) CERTIFICATE-----/g, "").replace(/\s+/g, "");
193
- const certDer = Buffer.from(body, "base64");
194
- const alias = `${aliasPrefix}-${bags.length}`;
195
- const bmp = Buffer.from(alias, "utf16le").swap16();
196
- bags.push(seq(oid(OID_CERT_BAG), explicit(0, seq(oid(OID_X509_CERTIFICATE), explicit(0, octets(certDer)))), set(seq(oid(OID_JDK_TRUSTED_KEY_USAGE), set(oid(OID_ANY_EXTENDED_KEY_USAGE))), seq(oid(OID_FRIENDLY_NAME), set(der(30, bmp))))));
197
- }
198
- const safeContents = seq(...bags);
199
- const authSafe = seq(seq(oid(OID_PKCS7_DATA), explicit(0, octets(safeContents))));
200
- return seq(integer(Buffer.from([3])), seq(oid(OID_PKCS7_DATA), explicit(0, octets(authSafe))));
201
- }
202
-
203
- //#endregion
204
- //#region src/local/emulator-resign-sidecar.ts
205
- const MIXED_MODE_RESIGN_BODY_CAP_BYTES = 100 * 1024 * 1024;
206
- const RESIGN_SIDECAR_CORE = String.raw`
207
- var crypto=require('crypto');
208
- function sha256hex(b){return crypto.createHash('sha256').update(b).digest('hex');}
209
- function hmac(k,s){return crypto.createHmac('sha256',k).update(s,'utf8').digest();}
210
- function uriEncode(s){return encodeURIComponent(s).replace(/[!'()*]/g,function(c){return '%'+c.charCodeAt(0).toString(16).toUpperCase();});}
211
- function safeDecode(s){try{return decodeURIComponent(s);}catch(e){return s;}}
212
- function canonicalPath(rawPath,service){
213
- var p=rawPath||'/';
214
- if(service==='s3')return p;
215
- var segs=[];
216
- p.split('/').forEach(function(s){if(s===''||s==='.')return;if(s==='..')segs.pop();else segs.push(s);});
217
- var n=(p.charAt(0)==='/'?'/':'')+segs.join('/')+(segs.length>0&&p.charAt(p.length-1)==='/'?'/':'');
218
- return uriEncode(n).replace(/%2F/g,'/');
219
- }
220
- function splitQuery(q){
221
- if(!q)return [];
222
- return q.split('&').filter(function(x){return x!=='';}).map(function(part){
223
- var i=part.indexOf('=');
224
- return {raw:part,k:safeDecode(i<0?part:part.slice(0,i)),v:i<0?'':safeDecode(part.slice(i+1))};
225
- });
226
- }
227
- function canonicalQuery(pairs){
228
- return pairs.map(function(p){return [uriEncode(p.k),uriEncode(p.v)];})
229
- .sort(function(a,b){return a[0]<b[0]?-1:a[0]>b[0]?1:a[1]<b[1]?-1:a[1]>b[1]?1:0;})
230
- .map(function(e){return e[0]+'='+e[1];}).join('&');
231
- }
232
- var PRESIGN_PARAMS=new Set(['x-amz-algorithm','x-amz-credential','x-amz-date','x-amz-expires','x-amz-signedheaders','x-amz-signature','x-amz-security-token']);
233
- function parseCredentialScope(algo,credential){
234
- var parts=String(credential).split('/');
235
- if(algo==='AWS4-HMAC-SHA256'&&parts.length>=5)return {region:parts[parts.length-3],service:parts[parts.length-2]};
236
- if(algo==='AWS4-ECDSA-P256-SHA256'&&parts.length>=4)return {service:parts[parts.length-2]};
237
- return undefined;
238
- }
239
- function parseAuthScope(authorization){
240
- var m=/^\s*(AWS4-HMAC-SHA256|AWS4-ECDSA-P256-SHA256)\s+(.*)$/.exec(String(authorization));
241
- if(!m)return undefined;
242
- var c=/Credential=([^,\s]+)/.exec(m[2]);
243
- return c?parseCredentialScope(m[1],c[1]):undefined;
244
- }
245
- var DROP_HEADERS=new Set(['authorization','host','connection','keep-alive','proxy-authorization','proxy-connection','te','trailer','transfer-encoding','upgrade','expect','content-length','x-amz-date','x-amz-security-token','x-amz-content-sha256','x-amz-decoded-content-length','x-amz-trailer']);
246
- function upstreamHeaders(incoming){
247
- var out=Object.create(null);
248
- Object.keys(incoming).forEach(function(k){var lk=k.toLowerCase();if(DROP_HEADERS.has(lk))return;var v=incoming[k];if(v===undefined)return;out[lk]=Array.isArray(v)?v.join(', '):String(v);});
249
- return out;
250
- }
251
- function isAwsChunked(headers){
252
- var sha=String(headers['x-amz-content-sha256']||'');
253
- return sha.indexOf('STREAMING-')===0||/(^|,)\s*aws-chunked\s*(,|$)/i.test(String(headers['content-encoding']||''));
254
- }
255
- function stripAwsChunked(ce){
256
- if(!ce)return undefined;
257
- var rest=String(ce).split(',').map(function(s){return s.trim();}).filter(function(s){return s!==''&&s.toLowerCase()!=='aws-chunked';});
258
- return rest.length?rest.join(', '):undefined;
259
- }
260
- function decodeAwsChunked(buf){
261
- var pos=0,parts=[],trailers=Object.create(null);
262
- for(;;){
263
- var eol=buf.indexOf('\r\n',pos);
264
- if(eol<0)throw new Error('aws-chunked body: missing chunk header');
265
- var size=parseInt(buf.toString('latin1',pos,eol).split(';')[0].trim(),16);
266
- if(!(size>=0))throw new Error('aws-chunked body: bad chunk size');
267
- pos=eol+2;
268
- if(size===0)break;
269
- if(pos+size+2>buf.length)throw new Error('aws-chunked body: truncated chunk');
270
- parts.push(buf.subarray(pos,pos+size));
271
- pos+=size;
272
- if(buf[pos]!==13||buf[pos+1]!==10)throw new Error('aws-chunked body: missing chunk terminator');
273
- pos+=2;
274
- }
275
- while(pos<buf.length){
276
- var e=buf.indexOf('\r\n',pos),end=e<0?buf.length:e;
277
- var line=buf.toString('latin1',pos,end);
278
- pos=end+2;
279
- if(line==='')break;
280
- var c=line.indexOf(':');
281
- if(c<=0)continue;
282
- var k=line.slice(0,c).trim().toLowerCase();
283
- if(k==='x-amz-trailer-signature')continue;
284
- var v=line.slice(c+1).trim();
285
- if(!/^[!#$%&'*+.^_|~0-9a-z-]+$/.test(k)||/[^ -~]/.test(v))throw new Error('aws-chunked body: invalid trailer');
286
- trailers[k]=v;
287
- }
288
- return {body:Buffer.concat(parts),trailers:trailers};
289
- }
290
- function tooLargeByHeaders(headers,cap){
291
- var decoded=Number(headers['x-amz-decoded-content-length']);
292
- if(decoded>cap)return decoded;
293
- var raw=Number(headers['content-length']);
294
- if(raw>rawCap(cap))return raw;
295
- return 0;
296
- }
297
- function rawCap(cap){return cap+Math.max(1048576,Math.floor(cap/100));}
298
- function signRequest(o){
299
- var amzDate=o.now.toISOString().replace(/[:-]|\.\d{3}/g,''),date=amzDate.slice(0,8),h=o.headers;
300
- h['x-amz-date']=amzDate;
301
- h['x-amz-content-sha256']=sha256hex(o.body);
302
- if(o.creds.sessionToken)h['x-amz-security-token']=o.creds.sessionToken;
303
- var names=Object.keys(h).filter(function(n){return n==='host'||n==='content-type'||n==='content-md5'||n.indexOf('x-amz-')===0;}).sort();
304
- var canonHeaders=names.map(function(n){return n+':'+String(h[n]).trim().replace(/\s+/g,' ')+'\n';}).join('');
305
- var signed=names.join(';');
306
- var creq=[o.method,canonicalPath(o.path,o.service),canonicalQuery(splitQuery(o.query)),canonHeaders,signed,h['x-amz-content-sha256']].join('\n');
307
- var scope=date+'/'+o.region+'/'+o.service+'/aws4_request';
308
- var sts=['AWS4-HMAC-SHA256',amzDate,scope,sha256hex(creq)].join('\n');
309
- var k=hmac(hmac(hmac(hmac('AWS4'+o.creds.secretAccessKey,date),o.region),o.service),'aws4_request');
310
- var sig=crypto.createHmac('sha256',k).update(sts,'utf8').digest('hex');
311
- h['authorization']='AWS4-HMAC-SHA256 Credential='+o.creds.accessKeyId+'/'+scope+', SignedHeaders='+signed+', Signature='+sig;
312
- return h;
313
- }
314
- function prepareResign(req,body,cfg,now){
315
- var url=String(req.url||'/'),qi=url.indexOf('?');
316
- var path=qi<0?url:url.slice(0,qi),query=qi<0?'':url.slice(qi+1);
317
- var incoming=req.headers,scope,signedRequest=false;
318
- var pairs=splitQuery(query),cred,algo;
319
- pairs.forEach(function(p){var lk=p.k.toLowerCase();if(lk==='x-amz-credential')cred=p.v;if(lk==='x-amz-algorithm')algo=p.v;});
320
- // Presign parameters (a real token or signature among them) never go upstream,
321
- // whether or not the request ALSO carries a header signature.
322
- query=pairs.filter(function(p){return !PRESIGN_PARAMS.has(p.k.toLowerCase());}).map(function(p){return p.raw;}).join('&');
323
- if(incoming['authorization']!==undefined){
324
- signedRequest=true;
325
- scope=parseAuthScope(incoming['authorization']);
326
- }else if(cred!==undefined){
327
- signedRequest=true;
328
- scope=parseCredentialScope(algo||'AWS4-HMAC-SHA256',cred);
329
- }
330
- if(signedRequest&&!scope)return {error:{status:400,code:'IncompleteSignature',message:'cdk-local mixed mode: the request signature has no credential scope the AWS Emulator re-signing sidecar can read.'}};
331
- var service=scope?scope.service:undefined;
332
- var headers=upstreamHeaders(incoming);
333
- if(isAwsChunked(incoming)){
334
- var decoded;
335
- try{decoded=decodeAwsChunked(body);}catch(e){return {error:{status:400,code:'IncompleteBody',message:'cdk-local mixed mode: '+e.message+'.'}};}
336
- body=decoded.body;
337
- Object.keys(decoded.trailers).forEach(function(k){if(!DROP_HEADERS.has(k))headers[k]=decoded.trailers[k];});
338
- var ce=stripAwsChunked(headers['content-encoding']);
339
- if(ce===undefined)delete headers['content-encoding'];else headers['content-encoding']=ce;
340
- }
341
- if(body.length>cfg.capBytes)return {error:tooLargeError(body.length,cfg.capBytes,service)};
342
- headers['host']=cfg.upstreamHost;
343
- headers['content-length']=String(body.length);
344
- if(signedRequest){
345
- var regionSet=incoming['x-amz-region-set'];
346
- pairs.forEach(function(p){if(p.k.toLowerCase()==='x-amz-region-set'&&regionSet===undefined)regionSet=p.v;});
347
- var region=scope.region||String(regionSet||'').split(',')[0].trim()||cfg.region||'us-east-1';
348
- if(region==='*')region=cfg.region||'us-east-1';
349
- signRequest({method:String(req.method||'GET'),path:path,query:query,headers:headers,body:body,region:region,service:service,creds:cfg.credentials,now:now});
350
- }
351
- return {path:query?path+'?'+query:path,headers:headers,body:body,service:service};
352
- }
353
- function tooLargeError(size,cap,service){
354
- return {status:413,code:service==='s3'?'EntityTooLarge':'RequestEntityTooLargeException',message:'cdk-local mixed mode: the request body ('+size+' bytes) is over the '+cap+'-byte cap of the AWS Emulator re-signing sidecar, which holds a body in memory to sign it. Upload a large S3 object with multipart upload (each part under the cap), e.g. boto3 upload_file or @aws-sdk/lib-storage.'};
355
- }
356
- function errorBody(err,service){
357
- if(service==='s3'||service===undefined)return {type:'application/xml',text:'<?xml version="1.0" encoding="UTF-8"?><Error><Code>'+err.code+'</Code><Message>'+err.message.replace(/&/g,'&amp;').replace(/</g,'&lt;')+'</Message></Error>'};
358
- return {type:'application/x-amz-json-1.0',text:JSON.stringify({__type:err.code,message:err.message})};
359
- }
360
- var PASS_DROP_HEADERS=new Set(['connection','keep-alive','proxy-authorization','proxy-connection','te','trailer','transfer-encoding','upgrade','expect']);
361
- function passthroughHeaders(incoming){
362
- var out=Object.create(null);
363
- Object.keys(incoming).forEach(function(k){var lk=k.toLowerCase();if(PASS_DROP_HEADERS.has(lk))return;var v=incoming[k];if(v===undefined)return;out[lk]=v;});
364
- return out;
365
- }
366
- // Only a real SQS queue URL is rewritten: an AWS SQS host (either form, any
367
- // partition suffix), no port, user info, query or fragment, and a path of a
368
- // 12-digit account and a queue name.
369
- var SQS_QUEUE_URL=/^https?:\/\/(?:sqs\.[a-z0-9-]+|[a-z0-9-]+\.queue)\.amazonaws\.com(?:\.cn)?\/([0-9]{12}\/[A-Za-z0-9_-]{1,80}(?:\.fifo)?)$/;
370
- function localQueueUrl(u,origin){var m=SQS_QUEUE_URL.exec(String(u));return m?origin+'/'+m[1]:u;}
371
- var SQS_QUEUE_URL_OPERATIONS=new Set(['CreateQueue','GetQueueUrl','ListQueues','ListDeadLetterSourceQueues']);
372
- // An unsigned request (an emulator run with --auth off and an SDK that signs
373
- // nothing) has no scope: only the JSON protocol's target names SQS then.
374
- function isSqsRequest(headers,service){return service==='sqs'||String(headers['x-amz-target']||'').indexOf('AmazonSQS.')===0;}
375
- // JSON protocol: the target names the operation. Query protocol: unknown here,
376
- // so every response is a candidate.
377
- function sqsResponseMayCarryQueueUrl(headers){
378
- var t=String(headers['x-amz-target']||'');
379
- if(t==='')return true;
380
- return t.indexOf('AmazonSQS.')===0&&SQS_QUEUE_URL_OPERATIONS.has(t.slice('AmazonSQS.'.length));
381
- }
382
- function rewriteSqsQueueUrls(text,contentType,origin){
383
- var ct=String(contentType||'').toLowerCase(),changed=false;
384
- function one(u){if(typeof u!=='string')return u;var n=localQueueUrl(u,origin);if(n!==u)changed=true;return n;}
385
- if(ct.indexOf('json')>=0){
386
- var o;
387
- try{o=JSON.parse(text);}catch(e){return undefined;}
388
- if(!o||typeof o!=='object'||Array.isArray(o))return undefined;
389
- if(typeof o.QueueUrl==='string')o.QueueUrl=one(o.QueueUrl);
390
- ['QueueUrls','queueUrls'].forEach(function(k){if(Array.isArray(o[k]))o[k]=o[k].map(one);});
391
- return changed?JSON.stringify(o):undefined;
392
- }
393
- if(ct.indexOf('xml')>=0){
394
- // A message body inside XML is escaped, so a literal element is never user data.
395
- var out=String(text).replace(/<QueueUrl>([^<]*)<\/QueueUrl>/g,function(all,u){var n=one(u.trim());return n===u.trim()?all:'<QueueUrl>'+n+'</QueueUrl>';});
396
- return changed?out:undefined;
397
- }
398
- return undefined;
399
- }
400
- `;
401
- const RESIGN_SIDECAR_SERVER = String.raw`
402
- function startResigner(cfgPath){return new Promise(function(done){
403
- var fs=require('fs'),https=require('https'),http=require('http'),tls=require('tls'),net=require('net'),zlib=require('zlib');
404
- var cfg;
405
- try{cfg=JSON.parse(fs.readFileSync(cfgPath,'utf8'));}catch(e){done({error:'CONFIG_'+(e.code||'ERROR')});return;}
406
- var passthrough=cfg.passthrough===true;
407
- if(!passthrough&&!cfg.credentials){done({error:'CONFIG_ERROR'});return;}
408
- var label=passthrough?'cdk-local --aws-emulator':'cdk-local mixed mode';
409
- var up=new URL(cfg.upstream),secure=up.protocol==='https:',mod=secure?https:http;
410
- var upHost=up.hostname.replace(/^\[|\]$/g,'');
411
- cfg.upstreamHost=up.host;
412
- var agentOpts={keepAlive:true};
413
- if(secure&&cfg.upstreamCaPem)agentOpts.ca=tls.rootCertificates.concat([cfg.upstreamCaPem]);
414
- var agent=new mod.Agent(agentOpts);
415
- // What a rewritten queue URL points at: this sidecar, the endpoint the workload already uses.
416
- var origin='https://127.0.0.1:'+cfg.port;
417
- var REWRITE_CAP=16*1048576;
418
- // Response bytes held at once across concurrent requests; past it a
419
- // response streams through unrewritten.
420
- var heldResp=0,HELD_RESP_CAP=4*REWRITE_CAP;
421
- var DECODERS={identity:null,gzip:zlib.gunzipSync,'x-gzip':zlib.gunzipSync,deflate:zlib.inflateSync,br:zlib.brotliDecompressSync};
422
- // Relay an emulator response. An SQS response that may carry a queue URL is
423
- // held (up to a cap) and its queue URLs point back here; anything else, and
424
- // a response that needs no change, goes through byte for byte.
425
- function relay(ur,resp,rewrite){
426
- var h={};
427
- Object.keys(ur.headers).forEach(function(k){if(k==='connection'||k==='keep-alive'||k==='transfer-encoding')return;h[k]=ur.headers[k];});
428
- var status=ur.statusCode||502,enc=String(ur.headers['content-encoding']||'identity').trim().toLowerCase();
429
- ur.on('error',function(){resp.destroy();});
430
- if(!rewrite||status<200||status>=300||!Object.prototype.hasOwnProperty.call(DECODERS,enc)||Number(ur.headers['content-length'])>REWRITE_CAP){resp.writeHead(status,h);ur.pipe(resp);return;}
431
- var chunks=[],n=0,released=false;
432
- function release(){if(!released){released=true;heldResp-=n;}}
433
- function onData(c){
434
- n+=c.length;heldResp+=c.length;chunks.push(c);
435
- if(n<=REWRITE_CAP&&heldResp<=HELD_RESP_CAP)return;
436
- ur.removeListener('data',onData);ur.removeListener('end',onEnd);release();
437
- resp.writeHead(status,h);chunks.forEach(function(x){resp.write(x);});chunks=[];
438
- ur.pipe(resp);
439
- }
440
- function onEnd(){
441
- release();
442
- var raw=Buffer.concat(chunks),text,out;chunks=[];
443
- try{var dec=DECODERS[enc];text=(dec?dec(raw,{maxOutputLength:4*REWRITE_CAP}):raw).toString('utf8');}catch(e){text=undefined;}
444
- if(text!==undefined)out=rewriteSqsQueueUrls(text,ur.headers['content-type'],origin);
445
- if(out===undefined){h['content-length']=String(raw.length);resp.writeHead(status,h);resp.end(raw);return;}
446
- var b=Buffer.from(out,'utf8');
447
- delete h['content-encoding'];delete h['content-md5'];delete h['x-amz-crc32'];
448
- h['content-length']=String(b.length);
449
- resp.writeHead(status,h);resp.end(b);
450
- }
451
- ur.on('data',onData);ur.on('end',onEnd);ur.on('close',release);
452
- }
453
- function rewritesResponse(req,service){return isSqsRequest(req.headers,service)&&sqsResponseMayCarryQueueUrl(req.headers);}
454
- function send(resp,status,err,service){
455
- if(resp.headersSent){resp.destroy();return;}
456
- var b=errorBody(err,service);
457
- resp.writeHead(status,{'content-type':b.type,'content-length':Buffer.byteLength(b.text),'connection':'close'});
458
- resp.end(b.text);
459
- }
460
- function serviceOf(req){
461
- var s=parseAuthScope(req.headers['authorization']||'');
462
- if(!s){var m=/[?&]X-Amz-Credential=([^&]*)/i.exec(String(req.url||''));if(m)s=parseCredentialScope('AWS4-HMAC-SHA256',safeDecode(m[1]));}
463
- return s?s.service:undefined;
464
- }
465
- // Bodies held at once, across concurrent requests: twice the per-request cap.
466
- // Each held byte is charged twice: building the request body briefly keeps
467
- // two copies alive (the received chunks while they are joined, then the
468
- // joined body while an aws-chunked body is decoded), so the charged total
469
- // bounds the real peak by inflightCap.
470
- var inflight=0,inflightCap=2*rawCap(cfg.capBytes);
471
- function handle(req,resp){
472
- // held counts toward inflight until the response is over; seen is the
473
- // body size for the 413 message.
474
- var chunks=[],held=0,seen=0,over=false,busy=false,limit=rawCap(cfg.capBytes);
475
- var drop=function(){inflight-=2*held;held=0;chunks=[];};
476
- req.on('data',function(c){seen+=c.length;if(over||busy)return;if(seen>limit){over=true;drop();return;}if(inflight+2*c.length>inflightCap){busy=true;drop();return;}held+=c.length;inflight+=2*c.length;chunks.push(c);});
477
- req.on('error',function(){drop();resp.destroy();});
478
- resp.on('close',drop);
479
- req.on('end',function(){
480
- if(busy){send(resp,503,{code:'SlowDown',message:label+': the AWS Emulator re-signing sidecar is holding too many request bodies at once; retry.'},serviceOf(req));return;}
481
- if(over){process.stdout.write('CDKL-RESIGN rejected a streamed request body over the cap without holding it\n');send(resp,413,tooLargeError(seen,cfg.capBytes,serviceOf(req)),serviceOf(req));return;}
482
- var p;
483
- var joined=Buffer.concat(chunks);chunks=[];
484
- try{p=prepareResign(req,joined,cfg,new Date());}catch(e){p={error:{status:400,code:'InvalidRequest',message:label+': the request could not be re-signed.'}};}
485
- joined=null;
486
- if(p.error){if(p.error.status===413)process.stdout.write('CDKL-RESIGN rejected a request body over the cap\n');send(resp,p.error.status,p.error,serviceOf(req));return;}
487
- // Re-signed anyway (accept-encoding is not a signed header): ask for an
488
- // identity body, so an encoding the sidecar cannot decode never carries
489
- // a real queue URL past it.
490
- if(rewritesResponse(req,p.service))delete p.headers['accept-encoding'];
491
- var r=upstreamRequest(req,resp,p.path,p.headers,p.service,{});
492
- if(r)r.end(p.body);
493
- });
494
- }
495
- // One upstream request; the response is relayed back. Undefined when the
496
- // headers cannot be sent (the client got a 400).
497
- function upstreamRequest(req,resp,path,headers,service,extra){
498
- var r,opts={host:upHost,port:up.port||(secure?443:80),method:req.method,path:path,headers:headers,agent:agent};
499
- Object.keys(extra).forEach(function(k){opts[k]=extra[k];});
500
- try{r=mod.request(opts,function(ur){relay(ur,resp,rewritesResponse(req,service));});}
501
- catch(e){send(resp,400,{code:'InvalidRequest',message:label+': the request has a header the AWS Emulator sidecar cannot forward.'},service);return undefined;}
502
- // A client that hangs up (an aborted GetObject) frees the upstream socket too.
503
- resp.on('close',function(){if(!resp.writableFinished)r.destroy();});
504
- r.setTimeout(300000,function(){r.destroy(Object.assign(new Error('upstream timeout'),{code:'ETIMEDOUT'}));});
505
- r.on('error',function(e){process.stdout.write('CDKL-RESIGN upstream error '+(e.code||'ERROR')+'\n');send(resp,502,{code:'BadGateway',message:label+': the AWS Emulator at '+cfg.upstream+' did not answer ('+(e.code||'ERROR')+').'},service);});
506
- return r;
507
- }
508
- // Full emulator mode: the workload already signs with the emulator's keys,
509
- // so the request goes upstream unchanged (its Host header too, which the
510
- // signature covers) and streams; only hop-by-hop headers are dropped. TLS
511
- // to the emulator is verified against the emulator's host name.
512
- function handlePassthrough(req,resp){
513
- var service=serviceOf(req);
514
- // The incoming Host names the sidecar, not the emulator: SNI (and with it
515
- // the certificate check) uses the emulator's own host name instead.
516
- var extra=secure?{servername:net.isIP(upHost)?'':upHost}:{};
517
- var r=upstreamRequest(req,resp,String(req.url||'/'),passthroughHeaders(req.headers),service,extra);
518
- if(!r){req.resume();return;}
519
- req.on('error',function(){r.destroy();resp.destroy();});
520
- req.pipe(r);
521
- }
522
- var srv=https.createServer({key:cfg.keyPem,cert:cfg.certPem},passthrough?handlePassthrough:handle);
523
- srv.on('checkContinue',function(req,resp){
524
- if(passthrough){resp.writeContinue();handlePassthrough(req,resp);return;}
525
- var n=tooLargeByHeaders(req.headers,cfg.capBytes);
526
- if(n>0){process.stdout.write('CDKL-RESIGN rejected a request body over the cap\n');send(resp,413,tooLargeError(n,cfg.capBytes,serviceOf(req)),serviceOf(req));req.resume();return;}
527
- resp.writeContinue();
528
- handle(req,resp);
529
- });
530
- srv.once('error',function(e){done({error:e.code||'ERROR',port:cfg.port});});
531
- // Loopback only: in mixed mode it signs with the emulator's keys for whoever connects.
532
- srv.listen(cfg.port,'127.0.0.1',function(){done({port:cfg.port,address:srv.address().address});});
533
- });}
534
- `;
535
- const RESIGN_SIDECAR_SCRIPT = RESIGN_SIDECAR_CORE + RESIGN_SIDECAR_SERVER;
536
-
537
- //#endregion
538
- //#region src/local/workload-aws-wiring.ts
539
- var workload_aws_wiring_exports = /* @__PURE__ */ __exportAll({
540
- AUTH_OFF_PLACEHOLDER_CREDENTIALS: () => AUTH_OFF_PLACEHOLDER_CREDENTIALS,
541
- CA_TRUST_ENV_KEYS: () => CA_TRUST_ENV_KEYS,
542
- DEFAULT_AWS_EMULATOR_URL: () => DEFAULT_AWS_EMULATOR_URL,
543
- EMULATOR_SCRUBBED_ENV_KEYS: () => EMULATOR_SCRUBBED_ENV_KEYS,
544
- HOST_CA_TRUST_ENV_KEYS: () => HOST_CA_TRUST_ENV_KEYS,
545
- HOST_DEFAULT_CREDENTIALS_MISS_TTL_MS: () => HOST_DEFAULT_CREDENTIALS_MISS_TTL_MS,
546
- STALE_RESIGN_DIR_AGE_MS: () => STALE_RESIGN_DIR_AGE_MS,
547
- activateWorkloadAwsWiring: () => activateWorkloadAwsWiring,
548
- applyWorkloadAwsWiringToEnv: () => applyWorkloadAwsWiringToEnv,
549
- awsEmulatorEnvName: () => awsEmulatorEnvName,
550
- collectHostEndpointOverrides: () => collectHostEndpointOverrides,
551
- displayEndpointValue: () => displayEndpointValue,
552
- effectiveLoopbackPorts: () => effectiveLoopbackPorts,
553
- envKeepsRealAwsException: () => envKeepsRealAwsException,
554
- getActiveWorkloadAwsWiring: () => getActiveWorkloadAwsWiring,
555
- getContainerCaBundlePath: () => getContainerCaBundlePath,
556
- getContainerJavaTruststorePath: () => getContainerJavaTruststorePath,
557
- javaTruststoreToolOptions: () => javaTruststoreToolOptions,
558
- loopbackForwarderPlan: () => loopbackForwarderPlan,
559
- mergeJavaToolOptions: () => mergeJavaToolOptions,
560
- parseAwsEndpoint: () => parseAwsEndpoint,
561
- parseIniSections: () => parseIniSections,
562
- probeAwsEmulatorHealth: () => probeAwsEmulatorHealth,
563
- readEmulatorRunFiles: () => readEmulatorRunFiles,
564
- readProfileEndpointSettings: () => readProfileEndpointSettings,
565
- resolveAwsEmulatorOption: () => resolveAwsEmulatorOption,
566
- resolveHostDefaultCredentials: () => resolveHostDefaultCredentials,
567
- resolveWorkloadAwsWiring: () => resolveWorkloadAwsWiring,
568
- setActiveWorkloadAwsWiring: () => setActiveWorkloadAwsWiring,
569
- sweepStaleResignDirs: () => sweepStaleResignDirs,
570
- takeAwsEmulatorStateSourceHint: () => takeAwsEmulatorStateSourceHint,
571
- workloadGetsEmulatorKeysOnly: () => workloadGetsEmulatorKeysOnly,
572
- writeCaBundleFile: () => writeCaBundleFile
573
- });
574
- const CA_TRUST_ENV_KEYS = [
575
- "AWS_CA_BUNDLE",
576
- "NODE_EXTRA_CA_CERTS",
577
- "REQUESTS_CA_BUNDLE",
578
- "SSL_CERT_FILE"
579
- ];
580
- const HOST_CA_TRUST_ENV_KEYS = ["AWS_CA_BUNDLE", "NODE_EXTRA_CA_CERTS"];
581
- const EMULATOR_SCRUBBED_ENV_KEYS = [
582
- "AWS_PROFILE",
583
- "AWS_DEFAULT_PROFILE",
584
- "AWS_SHARED_CREDENTIALS_FILE",
585
- "AWS_CONFIG_FILE",
586
- "AWS_WEB_IDENTITY_TOKEN_FILE",
587
- "AWS_ROLE_ARN",
588
- "AWS_ROLE_SESSION_NAME",
589
- "AWS_CONTAINER_CREDENTIALS_FULL_URI",
590
- "AWS_CONTAINER_AUTHORIZATION_TOKEN"
591
- ];
592
- const CREDENTIAL_KEYS = [
593
- "AWS_ACCESS_KEY_ID",
594
- "AWS_SECRET_ACCESS_KEY",
595
- "AWS_SESSION_TOKEN"
596
- ];
597
- function displayEndpointValue(value) {
598
- const scheme = /^\s*https?:[/\\]*/i.exec(value)?.[0] ?? "";
599
- let rest = value.slice(scheme.length);
600
- const at = rest.lastIndexOf("@");
601
- if (at >= 0) rest = `***${rest.slice(at)}`;
602
- const tail = rest.search(/[?#]/);
603
- if (tail >= 0) rest = `${rest.slice(0, tail + 1)}***`;
604
- return displayUntrustedValue(`${scheme}${rest}`);
605
- }
606
- function parseAwsEndpoint(value, label = "--aws-emulator") {
607
- let u;
608
- try {
609
- u = new URL(value);
610
- } catch {
611
- throw new Error(`${label} ${displayEndpointValue(value)} is not a URL (expected e.g. https://127.0.0.1:9297).`);
612
- }
613
- if (u.protocol !== "https:" && u.protocol !== "http:") throw new Error(`${label} must be an http(s) URL, got ${displayEndpointValue(value)}.`);
614
- if (u.username || u.password || u.search || u.hash || u.pathname !== "/" && u.pathname !== "") throw new Error(`${label} must be a bare scheme://host:port URL (no credentials, path or query), got ${displayEndpointValue(value)}.`);
615
- const port = u.port ? Number(u.port) : u.protocol === "https:" ? 443 : 80;
616
- const hostname = u.hostname.replace(/^\[|\]$/g, "");
617
- return {
618
- url: `${u.protocol}//${u.host}`,
619
- hostname,
620
- port,
621
- loopback: isLoopbackHostname(u.hostname)
622
- };
623
- }
624
- function parseIniSections(text) {
625
- const out = {};
626
- let current;
627
- for (const raw of text.split(/\r?\n/)) {
628
- const line = raw.trim();
629
- if (line === "" || line.startsWith("#") || line.startsWith(";")) continue;
630
- const sec = /^\[\s*(.+?)\s*\]$/.exec(line);
631
- if (sec) {
632
- current = Object.create(null);
633
- Object.defineProperty(out, sec[1], {
634
- value: current,
635
- enumerable: true,
636
- configurable: true,
637
- writable: true
638
- });
639
- continue;
640
- }
641
- const eq = line.indexOf("=");
642
- if (current && eq > 0) {
643
- const k = line.slice(0, eq).trim();
644
- Object.defineProperty(current, k, {
645
- value: line.slice(eq + 1).trim(),
646
- enumerable: true,
647
- configurable: true,
648
- writable: true
649
- });
650
- }
651
- }
652
- return out;
653
- }
654
- function readEmulatorRunFiles(port, homeDir = homedir()) {
655
- const dir = path$1.join(homeDir, ".aws", "emulator", String(port));
656
- const present = existsSync(dir);
657
- const result = {
658
- dir,
659
- present
660
- };
661
- if (!present) return result;
662
- try {
663
- const sections = parseIniSections(readFileSync(path$1.join(dir, "emulator_credentials"), "utf8"));
664
- const def = sections["default"] ?? Object.values(sections)[0];
665
- if (def?.["aws_access_key_id"] && def["aws_secret_access_key"]) result.credentials = {
666
- accessKeyId: def["aws_access_key_id"],
667
- secretAccessKey: def["aws_secret_access_key"],
668
- ...def["aws_session_token"] ? { sessionToken: def["aws_session_token"] } : {}
669
- };
670
- } catch {}
671
- const ca = path$1.join(dir, "ca.pem");
672
- if (existsSync(ca)) result.caPath = ca;
673
- const truststore = path$1.join(dir, "truststore.p12");
674
- if (existsSync(truststore)) result.truststorePath = truststore;
675
- return result;
676
- }
677
- const AUTH_OFF_PLACEHOLDER_CREDENTIALS = Object.freeze({
678
- accessKeyId: "EMULATORAUTHOFF00000",
679
- secretAccessKey: "0000000000000000000000000000000000000000"
680
- });
681
- function profileName(env, profile) {
682
- return profile || env["AWS_PROFILE"] || env["AWS_DEFAULT_PROFILE"] || "default";
683
- }
684
- function readProfileEndpointSettings(env, profile, homeDir = homedir()) {
685
- const file = env["AWS_CONFIG_FILE"] || path$1.join(homeDir, ".aws", "config");
686
- let sections;
687
- try {
688
- sections = parseIniSections(readFileSync(file, "utf8"));
689
- } catch {
690
- return {};
691
- }
692
- const name = profileName(env, profile);
693
- const sec = name === "default" ? sections["default"] ?? sections["profile default"] : sections[`profile ${name}`];
694
- if (!sec) return {};
695
- return {
696
- ...sec["endpoint_url"] ? { endpointUrl: sec["endpoint_url"] } : {},
697
- ...sec["ca_bundle"] ? { caBundle: sec["ca_bundle"] } : {},
698
- ...sec["ignore_configured_endpoint_urls"] ? { ignoreConfiguredEndpointUrls: sec["ignore_configured_endpoint_urls"].toLowerCase() === "true" } : {}
699
- };
700
- }
701
- function ignoresConfiguredEndpointUrls(env, profile, homeDir) {
702
- const fromEnv = (env["AWS_IGNORE_CONFIGURED_ENDPOINT_URLS"] ?? "").trim();
703
- if (fromEnv !== "") return fromEnv.toLowerCase() === "true";
704
- return readProfileEndpointSettings(env, profile, homeDir).ignoreConfiguredEndpointUrls === true;
705
- }
706
- function collectHostEndpointOverrides(env, opts = {}) {
707
- if (ignoresConfiguredEndpointUrls(env, opts.profile, opts.homeDir)) return {};
708
- const out = {};
709
- for (const [k, v] of Object.entries(env)) {
710
- if (v === void 0 || v === "") continue;
711
- if (k === "AWS_ENDPOINT_URL" || /^AWS_ENDPOINT_URL_[A-Z0-9_]+$/.test(k)) out[k] = v;
712
- }
713
- if (out["AWS_ENDPOINT_URL"] === void 0) {
714
- const fromProfile = readProfileEndpointSettings(env, opts.profile, opts.homeDir).endpointUrl;
715
- if (fromProfile) out["AWS_ENDPOINT_URL"] = fromProfile;
716
- }
717
- for (const [k, v] of Object.entries(out)) try {
718
- parseAwsEndpoint(v, k);
719
- } catch {
720
- getLogger().warn(`${k} is not an http(s) URL; it is not forwarded to workload containers.`);
721
- delete out[k];
722
- }
723
- return out;
724
- }
725
- function getContainerJavaTruststorePath() {
726
- return `${getEmbedConfig().awsBindMountPath}/truststore.p12`;
727
- }
728
- function javaTruststoreToolOptions(containerPath) {
729
- return `-Djavax.net.ssl.trustStore=${containerPath} -Djavax.net.ssl.trustStoreType=PKCS12`;
730
- }
731
- function mergeJavaToolOptions(existing, wiring) {
732
- const own = (existing ?? "").trim();
733
- if (own === "") return wiring;
734
- if (/-Djavax\.net\.ssl\.trustStore=/.test(own)) return own;
735
- return `${own} ${wiring}`;
736
- }
737
- function copyTruststoreFile(source) {
738
- const bytes = readFileSync(source);
739
- const dir = mkdtempSync(path$1.join(tmpdir(), `${getEmbedConfig().productName}-truststore-`));
740
- const hostPath = path$1.join(dir, "truststore.p12");
741
- writeFileSync(hostPath, bytes, { mode: 420 });
742
- return {
743
- hostPath,
744
- dispose: () => rmSync(dir, {
745
- recursive: true,
746
- force: true
747
- })
748
- };
749
- }
750
- function getContainerCaBundlePath() {
751
- return `${getEmbedConfig().awsBindMountPath}/ca-bundle.pem`;
752
- }
753
- function expandHome(p, homeDir) {
754
- return p === "~" ? homeDir : p.startsWith("~/") ? path$1.join(homeDir, p.slice(2)) : p;
755
- }
756
- function writeCaBundleFile(source, extraCertsPem = []) {
757
- const certs = [];
758
- if (source !== void 0) {
759
- let pem;
760
- try {
761
- pem = readFileSync(source, "utf8");
762
- } catch (err) {
763
- throw new Error(`CA bundle ${displayUntrustedValue(source)} cannot be read (${err.code ?? "error"}).`);
764
- }
765
- const found = pemCertificates(pem);
766
- if (found.length === 0) throw new Error(`CA bundle ${displayUntrustedValue(source)} contains no PEM certificate.`);
767
- certs.push(...found);
768
- }
769
- for (const extra of extraCertsPem) certs.push(...pemCertificates(extra));
770
- const dir = mkdtempSync(path$1.join(tmpdir(), `${getEmbedConfig().productName}-ca-`));
771
- const hostPath = path$1.join(dir, "ca-bundle.pem");
772
- writeFileSync(hostPath, `${certs.join("\n")}\n${rootCertificates.join("\n")}\n`, { mode: 420 });
773
- return {
774
- hostPath,
775
- dispose: () => rmSync(dir, {
776
- recursive: true,
777
- force: true
778
- })
779
- };
780
- }
781
- function pemCertificates(pem) {
782
- return pem.match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g) ?? [];
783
- }
784
- const DEFAULT_AWS_EMULATOR_URL = "https://127.0.0.1:9297";
785
- function probeAwsEmulatorHealth(url, caPath) {
786
- return new Promise((resolve) => {
787
- let ca;
788
- try {
789
- ca = caPath ? [...rootCertificates, readFileSync(caPath, "utf8")] : void 0;
790
- } catch {
791
- ca = void 0;
792
- }
793
- const target = `${url}/__admin/health`;
794
- const onResponse = (res) => {
795
- res.resume();
796
- resolve(res.statusCode === 200 ? void 0 : `HTTP_${res.statusCode ?? 0}`);
797
- };
798
- const req = target.startsWith("https:") ? get$1(target, {
799
- timeout: 3e3,
800
- ...ca ? { ca } : {}
801
- }, onResponse) : get(target, { timeout: 3e3 }, onResponse);
802
- req.on("timeout", () => {
803
- req.destroy();
804
- resolve("ETIMEDOUT");
805
- });
806
- req.on("error", (e) => resolve(e.code ?? "ERROR"));
807
- });
808
- }
809
- function describeEmulatorUnreachable(ep, reason) {
810
- return `--aws-emulator ${ep.url}: no AWS Emulator answers its health check at ${ep.url}/__admin/health (${reason}). Check that it is running on port ${ep.port} (\`aws-emulator -p ${ep.port}\`, or its Docker image published with \`-p 127.0.0.1:${ep.port}:${ep.port}\`), that the URL's port matches, and that it listens on an address this machine reaches (\`-b\`).`;
811
- }
812
- const STALE_RESIGN_DIR_AGE_MS = 10800 * 1e3;
813
- function sweepStaleResignDirs(now = Date.now(), dir = tmpdir()) {
814
- const removed = [];
815
- const prefix = `${getEmbedConfig().productName}-resign-`;
816
- const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
817
- let names;
818
- try {
819
- names = readdirSync(dir);
820
- } catch {
821
- return removed;
822
- }
823
- for (const name of names) {
824
- if (!name.startsWith(prefix)) continue;
825
- const full = path$1.join(dir, name);
826
- try {
827
- const st = lstatSync(full);
828
- if (!st.isDirectory() || uid !== void 0 && st.uid !== uid) continue;
829
- if (now - st.mtimeMs < 108e5) continue;
830
- const pid = Number(readFileSync(path$1.join(full, "owner.pid"), "utf8").trim());
831
- if (!Number.isInteger(pid) || pid <= 0 || processAlive(pid)) continue;
832
- rmSync(full, {
833
- recursive: true,
834
- force: true
835
- });
836
- removed.push(full);
837
- } catch {}
838
- }
839
- return removed;
840
- }
841
- function processAlive(pid) {
842
- try {
843
- process.kill(pid, 0);
844
- return true;
845
- } catch (err) {
846
- return err.code === "EPERM";
847
- }
848
- }
849
- function writeSidecarConfig(config, disposers) {
850
- sweepStaleResignDirs();
851
- const dir = mkdtempSync(path$1.join(tmpdir(), `${getEmbedConfig().productName}-resign-`));
852
- disposers.push(() => rmSync(dir, {
853
- recursive: true,
854
- force: true
855
- }));
856
- writeFileSync(path$1.join(dir, "owner.pid"), String(process.pid), { mode: 384 });
857
- const configPath = path$1.join(dir, "resign.json");
858
- writeFileSync(configPath, JSON.stringify(config), { mode: 384 });
859
- return configPath;
860
- }
861
- function readPemCertificates(sources) {
862
- const out = [];
863
- for (const source of new Set(sources)) try {
864
- out.push(...pemCertificates(readFileSync(source, "utf8")));
865
- } catch (err) {
866
- throw new Error(`--aws-emulator: the CA bundle ${displayUntrustedValue(source)} cannot be read (${err.code ?? "error"}).`);
867
- }
868
- return out;
869
- }
870
- function writeJavaTrustStoreFile(pems) {
871
- const dir = mkdtempSync(path$1.join(tmpdir(), `${getEmbedConfig().productName}-truststore-`));
872
- const hostPath = path$1.join(dir, "truststore.p12");
873
- writeFileSync(hostPath, buildJavaTrustStore(pems), { mode: 420 });
874
- return {
875
- hostPath,
876
- dispose: () => rmSync(dir, {
877
- recursive: true,
878
- force: true
879
- })
880
- };
881
- }
882
- function resolveMixedModeWiring(args) {
883
- const { ep, services, credentials, caSources, disposers } = args;
884
- const resignEndpoint = `https://127.0.0.1:${MIXED_MODE_RESIGN_PORT}`;
885
- const caPems = readPemCertificates(caSources);
886
- const upstreamCaPem = caPems.length > 0 ? caPems.join("\n") : void 0;
887
- const tls = createMixedModeTlsMaterials();
888
- const bundle = writeCaBundleFile(void 0, [...caPems, tls.caCertPem]);
889
- disposers.push(bundle.dispose);
890
- const config = {
891
- port: MIXED_MODE_RESIGN_PORT,
892
- upstream: ep.url,
893
- ...upstreamCaPem ? { upstreamCaPem } : {},
894
- certPem: tls.certPem,
895
- keyPem: tls.keyPem,
896
- credentials: {
897
- accessKeyId: credentials.accessKeyId,
898
- secretAccessKey: credentials.secretAccessKey,
899
- ...credentials.sessionToken ? { sessionToken: credentials.sessionToken } : {}
900
- },
901
- capBytes: MIXED_MODE_RESIGN_BODY_CAP_BYTES,
902
- ...args.region ? { region: args.region } : {}
903
- };
904
- const resignConfigHostPath = writeSidecarConfig(config, disposers);
905
- const containerPath = getContainerCaBundlePath();
906
- const trust = {};
907
- for (const k of CA_TRUST_ENV_KEYS) trust[k] = containerPath;
908
- return {
909
- mode: "forward",
910
- sidecar: {
911
- port: MIXED_MODE_RESIGN_PORT,
912
- endpoint: resignEndpoint,
913
- upstream: ep,
914
- configHostPath: resignConfigHostPath,
915
- passthrough: false
916
- },
917
- mixed: {
918
- realServices: services,
919
- emulatorEndpoint: ep,
920
- resignPort: MIXED_MODE_RESIGN_PORT,
921
- resignEndpoint,
922
- emulatorCredentials: config.credentials,
923
- ...args.region ? { region: args.region } : {},
924
- resignConfigHostPath,
925
- emulatorClientOverride: {
926
- endpoint: ep.url,
927
- ...upstreamCaPem ? { caPem: upstreamCaPem } : {},
928
- credentials: config.credentials
929
- }
930
- },
931
- env: {
932
- AWS_ENDPOINT_URL: resignEndpoint,
933
- AWS_EC2_METADATA_DISABLED: "true",
934
- AWS_DISABLE_HOST_PREFIX_INJECTION: "true",
935
- ...trust
936
- },
937
- scrubEnvKeys: [],
938
- mounts: [{
939
- hostPath: bundle.hostPath,
940
- containerPath
941
- }],
942
- loopbackPorts: ep.loopback ? [ep.port, MIXED_MODE_RESIGN_PORT] : [MIXED_MODE_RESIGN_PORT],
943
- probeHealth: true,
944
- caHostPath: bundle.hostPath,
945
- ...args.skipPull ? { skipPull: true } : {},
946
- dispose: args.dispose
947
- };
948
- }
949
- async function resolveWorkloadAwsWiring(opts) {
950
- const env = opts.env ?? process.env;
951
- const homeDir = opts.homeDir ?? homedir();
952
- const disposers = [];
953
- const dispose = () => {
954
- for (const d of disposers.splice(0)) try {
955
- d();
956
- } catch {}
957
- };
958
- const caMount = (source, keys = CA_TRUST_ENV_KEYS, extraCertsPem = []) => {
959
- const file = writeCaBundleFile(expandHome(source, homeDir), extraCertsPem);
960
- disposers.push(file.dispose);
961
- const containerPath = getContainerCaBundlePath();
962
- const caEnv = {};
963
- for (const k of keys) caEnv[k] = containerPath;
964
- return {
965
- hostPath: file.hostPath,
966
- mounts: [{
967
- hostPath: file.hostPath,
968
- containerPath
969
- }],
970
- env: caEnv
971
- };
972
- };
973
- try {
974
- if (opts.awsEmulator) {
975
- const ep = parseAwsEndpoint(opts.awsEmulator === true ? DEFAULT_AWS_EMULATOR_URL : opts.awsEmulator, "--aws-emulator");
976
- if (ep.hostname === "localhost") {
977
- ep.hostname = "127.0.0.1";
978
- ep.url = ep.url.replace("//localhost", "//127.0.0.1");
979
- }
980
- const run = readEmulatorRunFiles(ep.port, homeDir);
981
- const caSource = opts.caBundle || run.caPath || env["AWS_CA_BUNDLE"];
982
- const mixedServices = realAwsServicesOf(opts.realAwsExceptions ?? []);
983
- const probeCa = mixedServices.length > 0 ? run.caPath || caSource : caSource;
984
- const failure = await (opts.probeHealth ?? probeAwsEmulatorHealth)(ep.url, probeCa ? expandHome(probeCa, homeDir) : void 0);
985
- if (failure) throw new Error(describeEmulatorUnreachable(ep, failure));
986
- let credentials;
987
- if (run.credentials) credentials = run.credentials;
988
- else {
989
- credentials = AUTH_OFF_PLACEHOLDER_CREDENTIALS;
990
- getLogger().info(`--aws-emulator: ${path$1.join(run.dir, "emulator_credentials")} not found but the emulator is healthy, ` + (mixedServices.length > 0 ? "so it runs with --auth off; the re-signing sidecar signs with placeholder credentials." : "so it runs with --auth off; workload containers get placeholder credentials."));
991
- }
992
- if (mixedServices.length > 0) return resolveMixedModeWiring({
993
- ep,
994
- services: mixedServices,
995
- credentials,
996
- caSources: [...new Set([
997
- ep.url.startsWith("https:") ? run.caPath : void 0,
998
- opts.caBundle,
999
- env["AWS_CA_BUNDLE"]
1000
- ].filter((c) => typeof c === "string" && c !== "").map((c) => expandHome(c, homeDir)))],
1001
- disposers,
1002
- dispose,
1003
- skipPull: opts.skipPull,
1004
- region: env["AWS_REGION"] || env["AWS_DEFAULT_REGION"] || void 0
1005
- });
1006
- const https = ep.url.startsWith("https:");
1007
- const sidecarTls = https && run.caPath && getEmbedConfig().awsEmulatorSqsSidecar ? createMixedModeTlsMaterials() : void 0;
1008
- const ca = caSource && https ? caMount(caSource, CA_TRUST_ENV_KEYS, sidecarTls ? [sidecarTls.caCertPem] : []) : void 0;
1009
- let sidecar;
1010
- if (sidecarTls && run.caPath) {
1011
- const upstreamPems = readPemCertificates([run.caPath, ...caSource ? [caSource] : []].map((c) => expandHome(c, homeDir)));
1012
- sidecar = {
1013
- port: MIXED_MODE_RESIGN_PORT,
1014
- endpoint: `https://127.0.0.1:${MIXED_MODE_RESIGN_PORT}`,
1015
- upstream: ep,
1016
- passthrough: true,
1017
- configHostPath: writeSidecarConfig({
1018
- port: MIXED_MODE_RESIGN_PORT,
1019
- upstream: ep.url,
1020
- ...upstreamPems.length > 0 ? { upstreamCaPem: upstreamPems.join("\n") } : {},
1021
- certPem: sidecarTls.certPem,
1022
- keyPem: sidecarTls.keyPem,
1023
- capBytes: MIXED_MODE_RESIGN_BODY_CAP_BYTES,
1024
- passthrough: true
1025
- }, disposers)
1026
- };
1027
- }
1028
- let java;
1029
- if (run.truststorePath && https) {
1030
- let file;
1031
- const source = sidecarTls && run.caPath ? run.caPath : run.truststorePath;
1032
- try {
1033
- file = sidecarTls && run.caPath ? writeJavaTrustStoreFile([readFileSync(run.caPath, "utf8"), sidecarTls.caCertPem]) : copyTruststoreFile(run.truststorePath);
1034
- } catch (err) {
1035
- getLogger().warn(`--aws-emulator: ${source} cannot be read (${err.code ?? "error"}); Java workloads get no JAVA_TOOL_OPTIONS trust store.`);
1036
- }
1037
- if (file) {
1038
- disposers.push(file.dispose);
1039
- const containerPath = getContainerJavaTruststorePath();
1040
- java = {
1041
- mount: {
1042
- hostPath: file.hostPath,
1043
- containerPath
1044
- },
1045
- env: { JAVA_TOOL_OPTIONS: javaTruststoreToolOptions(containerPath) }
1046
- };
1047
- }
1048
- }
1049
- return {
1050
- mode: "emulator",
1051
- emulatorEndpoint: ep,
1052
- ...sidecar ? { sidecar } : {},
1053
- env: {
1054
- AWS_ENDPOINT_URL: ep.url,
1055
- ...sidecar ? { AWS_ENDPOINT_URL_SQS: sidecar.endpoint } : {},
1056
- AWS_EC2_METADATA_DISABLED: "true",
1057
- AWS_DISABLE_HOST_PREFIX_INJECTION: "true",
1058
- AWS_IGNORE_CONFIGURED_ENDPOINT_URLS: "false",
1059
- ...ca?.env ?? {},
1060
- ...java?.env ?? {}
1061
- },
1062
- scrubEnvKeys: EMULATOR_SCRUBBED_ENV_KEYS,
1063
- mounts: [...ca?.mounts ?? [], ...java ? [java.mount] : []],
1064
- loopbackPorts: [...ep.loopback ? [ep.port] : [], ...sidecar ? [sidecar.port] : []],
1065
- probeHealth: ca !== void 0,
1066
- ...ca ? { caHostPath: ca.hostPath } : {},
1067
- emulatorCredentials: credentials,
1068
- ...opts.skipPull ? { skipPull: true } : {},
1069
- dispose
1070
- };
1071
- }
1072
- const endpoints = collectHostEndpointOverrides(env, {
1073
- profile: opts.profile,
1074
- homeDir
1075
- });
1076
- let ca;
1077
- if (opts.caBundle) ca = caMount(opts.caBundle);
1078
- else {
1079
- const hostCa = env["AWS_CA_BUNDLE"] || readProfileEndpointSettings(env, opts.profile, homeDir).caBundle;
1080
- if (hostCa) try {
1081
- ca = caMount(hostCa, HOST_CA_TRUST_ENV_KEYS);
1082
- } catch (err) {
1083
- getLogger().warn(`${err.message} It is not mounted into workload containers.`);
1084
- }
1085
- }
1086
- const ports = /* @__PURE__ */ new Set();
1087
- for (const v of Object.values(endpoints)) {
1088
- const ep = parseAwsEndpoint(v);
1089
- if (ep.loopback) ports.add(ep.port);
1090
- }
1091
- return {
1092
- mode: "forward",
1093
- env: {
1094
- ...endpoints,
1095
- ...ca?.env ?? {}
1096
- },
1097
- scrubEnvKeys: [],
1098
- mounts: ca?.mounts ?? [],
1099
- loopbackPorts: [...ports].sort((a, b) => a - b),
1100
- probeHealth: false,
1101
- ...ca ? { caHostPath: ca.hostPath } : {},
1102
- ...opts.skipPull ? { skipPull: true } : {},
1103
- dispose
1104
- };
1105
- } catch (err) {
1106
- dispose();
1107
- throw err;
1108
- }
1109
- }
1110
- function sidecarOf(wiring) {
1111
- if (wiring.sidecar) return wiring.sidecar;
1112
- const mixed = wiring.mixed;
1113
- if (!mixed) return void 0;
1114
- return {
1115
- port: mixed.resignPort,
1116
- endpoint: mixed.resignEndpoint,
1117
- upstream: mixed.emulatorEndpoint,
1118
- configHostPath: mixed.resignConfigHostPath,
1119
- passthrough: false
1120
- };
1121
- }
1122
- function effectiveLoopbackPorts(env, wiring) {
1123
- const used = /* @__PURE__ */ new Set();
1124
- for (const [k, v] of Object.entries(env)) {
1125
- if (k !== "AWS_ENDPOINT_URL" && !k.startsWith("AWS_ENDPOINT_URL_")) continue;
1126
- try {
1127
- const ep = parseAwsEndpoint(v, k);
1128
- if (ep.loopback) used.add(ep.port);
1129
- } catch {}
1130
- }
1131
- const sidecar = sidecarOf(wiring);
1132
- if (sidecar && used.has(sidecar.port) && sidecar.upstream.loopback) used.add(sidecar.upstream.port);
1133
- return wiring.loopbackPorts.filter((p) => used.has(p));
1134
- }
1135
- function loopbackForwarderPlan(wiring, ports) {
1136
- const sidecar = sidecarOf(wiring);
1137
- if (!sidecar || !ports.includes(sidecar.port)) return { ports: [...ports] };
1138
- return {
1139
- ports: ports.filter((p) => p !== sidecar.port),
1140
- resignConfigHostPath: sidecar.configHostPath
1141
- };
1142
- }
1143
- function applyWorkloadAwsWiringToEnv(env, wiring, defaultCredentials) {
1144
- const out = {};
1145
- for (const [k, v] of Object.entries(env)) Object.defineProperty(out, k, {
1146
- value: v,
1147
- enumerable: true,
1148
- configurable: true,
1149
- writable: true
1150
- });
1151
- let keepsException = false;
1152
- for (const [k, v] of Object.entries(out)) {
1153
- if (isLegacyAwsEmulatorSentinel(k, v)) throw new Error(legacyAwsEmulatorSentinelMessage({
1154
- section: "the container env",
1155
- key: k,
1156
- service: ""
1157
- }));
1158
- if (!isRealAwsSentinel(k, v)) continue;
1159
- if (wiring.mode === "forward" && !wiring.mixed) {
1160
- getLogger().debug(`${k}="${REAL_AWS_SENTINEL}" without --aws-emulator: dropped (a no-op).`);
1161
- delete out[k];
1162
- continue;
1163
- }
1164
- if (!wiring.mixed || k === "AWS_ENDPOINT_URL") throw new Error(`${k}="${REAL_AWS_SENTINEL}" reached a workload container under --aws-emulator without mixed-mode wiring. Mark exceptions in the --env-vars file, on an AWS_ENDPOINT_URL_<SERVICE> variable.`);
1165
- const region = out["AWS_REGION"] || out["AWS_DEFAULT_REGION"] || wiring.mixed.region;
1166
- if (!region) throw new Error(`${k}="${REAL_AWS_SENTINEL}" needs the workload's region to name the real endpoint, and none is set. Pass --region, or set AWS_REGION.`);
1167
- out[k] = realAwsEndpointFor(k.slice(17), region);
1168
- keepsException = true;
1169
- }
1170
- const setCreds = (c) => {
1171
- for (const k of CREDENTIAL_KEYS) delete out[k];
1172
- if (!c) return;
1173
- out["AWS_ACCESS_KEY_ID"] = c.accessKeyId;
1174
- out["AWS_SECRET_ACCESS_KEY"] = c.secretAccessKey;
1175
- if (c.sessionToken) out["AWS_SESSION_TOKEN"] = c.sessionToken;
1176
- };
1177
- if (wiring.mode === "emulator") {
1178
- const ownJavaToolOptions = out["JAVA_TOOL_OPTIONS"];
1179
- const ownSqsEndpoint = out["AWS_ENDPOINT_URL_SQS"];
1180
- for (const k of wiring.scrubEnvKeys) delete out[k];
1181
- Object.assign(out, wiring.env);
1182
- if (ownSqsEndpoint !== void 0) out["AWS_ENDPOINT_URL_SQS"] = ownSqsEndpoint;
1183
- const javaToolOptions = wiring.env["JAVA_TOOL_OPTIONS"];
1184
- if (javaToolOptions !== void 0) out["JAVA_TOOL_OPTIONS"] = mergeJavaToolOptions(ownJavaToolOptions, javaToolOptions);
1185
- setCreds(wiring.emulatorCredentials);
1186
- } else if (wiring.mixed && !keepsException) {
1187
- for (const k of EMULATOR_SCRUBBED_ENV_KEYS) delete out[k];
1188
- delete out["AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"];
1189
- out["AWS_IGNORE_CONFIGURED_ENDPOINT_URLS"] = "false";
1190
- for (const [k, v] of Object.entries(wiring.env)) if (out[k] === void 0) out[k] = v;
1191
- setCreds(wiring.mixed.emulatorCredentials);
1192
- } else {
1193
- if (wiring.mixed) out["AWS_IGNORE_CONFIGURED_ENDPOINT_URLS"] = "false";
1194
- for (const [k, v] of Object.entries(wiring.env)) if (out[k] === void 0) out[k] = v;
1195
- if (defaultCredentials && !out["AWS_ACCESS_KEY_ID"]) setCreds(defaultCredentials);
1196
- }
1197
- if (out["AWS_REGION"] && !out["AWS_DEFAULT_REGION"]) out["AWS_DEFAULT_REGION"] = out["AWS_REGION"];
1198
- return out;
1199
- }
1200
- function envKeepsRealAwsException(env) {
1201
- return Object.entries(env).some(([k, v]) => k !== "AWS_ENDPOINT_URL" && isRealAwsSentinel(k, v));
1202
- }
1203
- function workloadGetsEmulatorKeysOnly(env, wiring) {
1204
- if (!wiring) return false;
1205
- return wiring.mode === "emulator" || wiring.mixed !== void 0 && !envKeepsRealAwsException(env);
1206
- }
1207
- async function resolveHostDefaultCredentials(opts = {}) {
1208
- const name = assumedRoleRecorded() ? profileName(process.env, opts.profile) : opts.profile;
1209
- const key = `${assumedRoleRecorded() ? "noenv" : "chain"}:${name ?? ""}`;
1210
- const miss = chainMisses.get(key);
1211
- if (miss !== void 0 && Date.now() - miss < CHAIN_MISS_TTL_MS) return void 0;
1212
- let provider = chainProviders.get(key);
1213
- if (!provider) {
1214
- const { defaultProvider } = await import("@aws-sdk/credential-provider-node");
1215
- provider = defaultProvider({
1216
- ...name ? { profile: name } : {},
1217
- ignoreCache: true
1218
- });
1219
- chainProviders.set(key, provider);
1220
- }
1221
- try {
1222
- const c = await provider();
1223
- chainMisses.delete(key);
1224
- return {
1225
- accessKeyId: c.accessKeyId,
1226
- secretAccessKey: c.secretAccessKey,
1227
- ...c.sessionToken ? { sessionToken: c.sessionToken } : {}
1228
- };
1229
- } catch (err) {
1230
- chainMisses.set(key, Date.now());
1231
- getLogger().debug(`No credentials from the host default chain for workload containers: ${describeCredentialLoadFailure(err)}`);
1232
- return;
1233
- }
1234
- }
1235
- const HOST_DEFAULT_CREDENTIALS_MISS_TTL_MS = 6e4;
1236
- const CHAIN_MISS_TTL_MS = HOST_DEFAULT_CREDENTIALS_MISS_TTL_MS;
1237
- const chainProviders = /* @__PURE__ */ new Map();
1238
- const chainMisses = /* @__PURE__ */ new Map();
1239
- let active;
1240
- let exitHookInstalled = false;
1241
- function getActiveWorkloadAwsWiring() {
1242
- return active;
1243
- }
1244
- function setActiveWorkloadAwsWiring(wiring) {
1245
- if (active && active !== wiring) active.dispose();
1246
- active = wiring;
1247
- if (wiring && !exitHookInstalled) {
1248
- exitHookInstalled = true;
1249
- process.once("exit", () => active?.dispose());
1250
- }
1251
- }
1252
- function awsEmulatorEnvName() {
1253
- const { envPrefix } = getEmbedConfig();
1254
- return envPrefix === "CDKL" ? "CDK_LOCAL_AWS_EMULATOR" : `${envPrefix}_AWS_EMULATOR`;
1255
- }
1256
- function resolveAwsEmulatorOption(flag, env = process.env) {
1257
- if (typeof flag === "string" && flag !== "") return flag;
1258
- if (flag === true) return true;
1259
- const raw = (env[awsEmulatorEnvName()] ?? "").trim();
1260
- if (raw === "" || /^(0|false)$/i.test(raw)) return void 0;
1261
- return /^(1|true)$/i.test(raw) ? true : raw;
1262
- }
1263
- async function activateWorkloadAwsWiring(options) {
1264
- const awsEmulator = resolveAwsEmulatorOption(options.awsEmulator);
1265
- const scan = readAwsEmulatorEnvVarsFile(options.envVars);
1266
- validateAwsEmulatorEnvVars(scan, awsEmulator !== void 0);
1267
- const { overrides } = scan;
1268
- const wiring = await resolveWorkloadAwsWiring({
1269
- awsEmulator,
1270
- caBundle: options.caBundle,
1271
- profile: options.profile,
1272
- skipPull: options.pull === false,
1273
- ...awsEmulator !== void 0 && { realAwsExceptions: scan.exceptions }
1274
- });
1275
- setActiveWorkloadAwsWiring(wiring);
1276
- if (wiring.mixed) {
1277
- setAwsEndpointOverride(void 0);
1278
- setAwsEmulatorServiceRouting({
1279
- realServices: wiring.mixed.realServices,
1280
- override: wiring.mixed.emulatorClientOverride,
1281
- envOverrides: overrides
1282
- });
1283
- getLogger().info(`Mixed mode: every AWS call goes to AWS Emulator at ${wiring.mixed.emulatorEndpoint.url} (signed with its keys) except ${wiring.mixed.realServices.join(", ")}, which go to real AWS with your real credentials, for the workload and for ${getEmbedConfig().productName}'s own calls.`);
1284
- } else if (wiring.mode === "emulator" && wiring.emulatorEndpoint) {
1285
- setAwsEmulatorServiceRouting(void 0);
1286
- setAwsEndpointOverride({
1287
- endpoint: wiring.emulatorEndpoint.url,
1288
- ...wiring.caHostPath ? { caPem: readFileSync(wiring.caHostPath, "utf8") } : {},
1289
- ...wiring.emulatorCredentials ? { credentials: wiring.emulatorCredentials } : {}
1290
- });
1291
- getLogger().info(`Using AWS Emulator at ${wiring.emulatorEndpoint.url} for ${getEmbedConfig().productName}'s AWS calls and every workload container.`);
1292
- } else {
1293
- setAwsEndpointOverride(void 0);
1294
- setAwsEmulatorServiceRouting(void 0);
1295
- }
1296
- return wiring;
1297
- }
1298
- let stateSourceHintShown = false;
1299
- function takeAwsEmulatorStateSourceHint() {
1300
- const wiring = active;
1301
- if (stateSourceHintShown || !wiring || wiring.mode !== "emulator" && !wiring.mixed) return;
1302
- stateSourceHintShown = true;
1303
- const { cliName, productName, deployCommand } = getEmbedConfig();
1304
- return `Under --aws-emulator, the environment variables above that reference a resource need deployed names: pass ${deployCommand !== void 0 ? `--from-state (the stack deployed into AWS Emulator with \`${deployCommand} --aws-emulator\`)` : cliName === "cdkl" ? "a host CLI's --from-state (the stack deployed into AWS Emulator with that host's own deploy)" : `--from-state (the stack deployed into AWS Emulator with ${productName}'s own deploy and --aws-emulator)`}, or --from-cfn-stack (the stack deployed into AWS Emulator with \`cdk deploy\`), or set the values with --env-vars.`;
1305
- }
1306
-
1307
- //#endregion
1308
- //#region src/utils/workload-identity.ts
1309
- function copyCredentials(c) {
1310
- return c ? {
1311
- accessKeyId: c.accessKeyId,
1312
- secretAccessKey: c.secretAccessKey,
1313
- ...c.sessionToken ? { sessionToken: c.sessionToken } : {}
1314
- } : void 0;
1315
- }
1316
- let record;
1317
- let stripWarned = false;
1318
- const SECOND_ASSUME_MESSAGE = "A role was already assumed in this process; refusing to assume a second one. Pass --role-arn once.";
1319
- function recordAssumedRole(caller, role) {
1320
- if (record !== void 0) throw new Error(SECOND_ASSUME_MESSAGE);
1321
- record = {
1322
- caller: copyCredentials(caller),
1323
- role: copyCredentials(role)
1324
- };
1325
- }
1326
- function assumedRoleRecorded() {
1327
- return record !== void 0;
1328
- }
1329
- function readEnvCallerCredentials(env = process.env) {
1330
- const accessKeyId = env["AWS_ACCESS_KEY_ID"];
1331
- const secretAccessKey = env["AWS_SECRET_ACCESS_KEY"];
1332
- if (!accessKeyId || !secretAccessKey) return void 0;
1333
- const sessionToken = env["AWS_SESSION_TOKEN"];
1334
- return {
1335
- accessKeyId,
1336
- secretAccessKey,
1337
- ...sessionToken ? { sessionToken } : {}
1338
- };
1339
- }
1340
- function resetWorkloadIdentity() {
1341
- record = void 0;
1342
- stripWarned = false;
1343
- }
1344
- function callerRecord() {
1345
- return getEmbedConfig().workloadIdentity === "caller" ? record : void 0;
1346
- }
1347
- const MULTIPLE_CREDENTIAL_SOURCES_WARNING = "Multiple credential sources detected";
1348
- const chainLogger = {
1349
- debug: () => {},
1350
- info: () => {},
1351
- warn: (...args) => {
1352
- const text = args.map(String).join(" ");
1353
- if (text.includes(MULTIPLE_CREDENTIAL_SOURCES_WARNING)) return;
1354
- getLogger().warn(text);
1355
- },
1356
- error: (...args) => {
1357
- getLogger().error(args.map(String).join(" "));
1358
- }
1359
- };
1360
- function callerChainWithoutEnv(proxied) {
1361
- let chain;
1362
- return async (identityProperties) => {
1363
- chain ??= (async () => {
1364
- const { defaultProvider } = await import("@aws-sdk/credential-provider-node");
1365
- return defaultProvider({
1366
- profile: "default",
1367
- logger: chainLogger,
1368
- ...proxied ? { clientConfig: { requestHandler: buildProxyRequestHandler() } } : {}
1369
- });
1370
- })().catch((err) => {
1371
- chain = void 0;
1372
- throw err;
1373
- });
1374
- return (await chain)(identityProperties);
1375
- };
1376
- }
1377
- function workloadClientConfig(opts = {}) {
1378
- const base = buildProxyClientConfig({
1379
- profile: opts.profile,
1380
- service: opts.service,
1381
- workload: opts.workload
1382
- });
1383
- const rec = callerRecord();
1384
- if (!rec) return base;
1385
- if (base.endpoint !== void 0) return base;
1386
- if (opts.profile || process.env["AWS_PROFILE"]) return base;
1387
- if (rec.caller) {
1388
- const caller = rec.caller;
1389
- const credentials = async () => ({
1390
- accessKeyId: caller.accessKeyId,
1391
- secretAccessKey: caller.secretAccessKey,
1392
- ...caller.sessionToken ? { sessionToken: caller.sessionToken } : {}
1393
- });
1394
- return {
1395
- ...base,
1396
- credentials
1397
- };
1398
- }
1399
- return {
1400
- ...base,
1401
- credentials: callerChainWithoutEnv(base.requestHandler !== void 0)
1402
- };
1403
- }
1404
- function workloadStsClientConfig(args) {
1405
- return {
1406
- ...workloadClientConfig({ profile: args.profile }),
1407
- ...args.region && { region: args.region },
1408
- ...args.profile && { profile: args.profile }
1409
- };
1410
- }
1411
- function deployAccountStsClientConfig(args) {
1412
- const role = callerRecord()?.role;
1413
- if (!role) return {
1414
- ...buildProxyClientConfig({ profile: args.profile }),
1415
- ...args.region && { region: args.region },
1416
- ...args.profile && { profile: args.profile }
1417
- };
1418
- const credentials = async () => ({
1419
- accessKeyId: role.accessKeyId,
1420
- secretAccessKey: role.secretAccessKey,
1421
- ...role.sessionToken ? { sessionToken: role.sessionToken } : {}
1422
- });
1423
- return {
1424
- ...buildProxyClientConfig(),
1425
- ...args.region && { region: args.region },
1426
- ...args.profile && { profile: args.profile },
1427
- credentials
1428
- };
1429
- }
1430
- function accountLookupStsClientConfig(args) {
1431
- if (getAwsEmulatorServiceRouting() && isAwsServiceRoutedToEmulator("STS")) return {
1432
- ...buildProxyClientConfig({ service: "STS" }),
1433
- ...args.region && { region: args.region }
1434
- };
1435
- return args.readFromCfnStack ? workloadStsClientConfig({
1436
- region: args.region,
1437
- profile: args.profile
1438
- }) : deployAccountStsClientConfig({
1439
- region: args.region,
1440
- profile: args.profile
1441
- });
1442
- }
1443
- function applyWorkloadEnvCredentials(env) {
1444
- const rec = callerRecord();
1445
- if (!rec) return "unchanged";
1446
- if (rec.caller) {
1447
- env["AWS_ACCESS_KEY_ID"] = rec.caller.accessKeyId;
1448
- env["AWS_SECRET_ACCESS_KEY"] = rec.caller.secretAccessKey;
1449
- if (rec.caller.sessionToken) env["AWS_SESSION_TOKEN"] = rec.caller.sessionToken;
1450
- else delete env["AWS_SESSION_TOKEN"];
1451
- return "restored";
1452
- }
1453
- delete env["AWS_ACCESS_KEY_ID"];
1454
- delete env["AWS_SECRET_ACCESS_KEY"];
1455
- delete env["AWS_SESSION_TOKEN"];
1456
- return "stripped";
1457
- }
1458
- function warnWorkloadCredentialsStripped() {
1459
- const wiring = getActiveWorkloadAwsWiring();
1460
- if (stripWarned || wiring?.mode === "emulator") return;
1461
- stripWarned = true;
1462
- const gets = wiring ? "the container gets what the host default credential chain resolves without the environment (the AWS_PROFILE or default profile in your shared config / credentials files, SSO included), or none when that resolves nothing" : "the container receives none";
1463
- getLogger().warn(`The --role-arn role is not handed to the emulated workload, and your shell had no static AWS credentials to hand it instead, so ${gets}. Pass --profile <name>, or export static credentials, to choose its identity.`);
1464
- }
1465
-
1466
- //#endregion
1467
- export { parseAwsEndpoint as A, workload_aws_wiring_exports as B, effectiveLoopbackPorts as C, javaTruststoreToolOptions as D, getContainerJavaTruststorePath as E, resolveHostDefaultCredentials as F, createMixedModeTlsMaterials as G, MIXED_MODE_RESIGN_BODY_CAP_BYTES as H, resolveWorkloadAwsWiring as I, setActiveWorkloadAwsWiring as L, readEmulatorRunFiles as M, readProfileEndpointSettings as N, loopbackForwarderPlan as O, resolveAwsEmulatorOption as P, takeAwsEmulatorStateSourceHint as R, displayEndpointValue as S, getContainerCaBundlePath as T, RESIGN_SIDECAR_SCRIPT as U, writeCaBundleFile as V, buildJavaTrustStore as W, HOST_DEFAULT_CREDENTIALS_MISS_TTL_MS as _, deployAccountStsClientConfig as a, awsEmulatorEnvName as b, resetWorkloadIdentity as c, workloadStsClientConfig as d, AUTH_OFF_PLACEHOLDER_CREDENTIALS as f, HOST_CA_TRUST_ENV_KEYS as g, EMULATOR_SCRUBBED_ENV_KEYS as h, assumedRoleRecorded as i, probeAwsEmulatorHealth as j, mergeJavaToolOptions as k, warnWorkloadCredentialsStripped as l, DEFAULT_AWS_EMULATOR_URL as m, accountLookupStsClientConfig as n, readEnvCallerCredentials as o, CA_TRUST_ENV_KEYS as p, applyWorkloadEnvCredentials as r, recordAssumedRole as s, SECOND_ASSUME_MESSAGE as t, workloadClientConfig as u, activateWorkloadAwsWiring as v, getActiveWorkloadAwsWiring as w, collectHostEndpointOverrides as x, applyWorkloadAwsWiringToEnv as y, workloadGetsEmulatorKeysOnly as z };
1468
- //# sourceMappingURL=workload-identity-Blv2g1Jp.js.map