@friggframework/core 2.0.0--canary.428.49aae81.0 → 2.0.0--canary.428.ade056e.0
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.
- package/handlers/routers/health.js +88 -66
- package/package.json +5 -5
|
@@ -425,7 +425,9 @@ const detectVpcConfiguration = async () => {
|
|
|
425
425
|
try {
|
|
426
426
|
await Promise.race([
|
|
427
427
|
dns.resolve4('www.google.com'),
|
|
428
|
-
new Promise((_, reject) =>
|
|
428
|
+
new Promise((_, reject) =>
|
|
429
|
+
setTimeout(() => reject(new Error('timeout')), 2000)
|
|
430
|
+
),
|
|
429
431
|
]);
|
|
430
432
|
results.canResolvePublicDns = true;
|
|
431
433
|
} catch (e) {
|
|
@@ -436,10 +438,14 @@ const detectVpcConfiguration = async () => {
|
|
|
436
438
|
try {
|
|
437
439
|
const https = require('https');
|
|
438
440
|
await new Promise((resolve, reject) => {
|
|
439
|
-
const req = https.get(
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
441
|
+
const req = https.get(
|
|
442
|
+
'https://www.google.com',
|
|
443
|
+
{ timeout: 2000 },
|
|
444
|
+
(res) => {
|
|
445
|
+
res.destroy();
|
|
446
|
+
resolve(true);
|
|
447
|
+
}
|
|
448
|
+
);
|
|
443
449
|
req.on('error', reject);
|
|
444
450
|
req.on('timeout', () => {
|
|
445
451
|
req.destroy();
|
|
@@ -452,7 +458,7 @@ const detectVpcConfiguration = async () => {
|
|
|
452
458
|
}
|
|
453
459
|
|
|
454
460
|
// Test 3: Check for VPC endpoints by trying to resolve internal AWS endpoints
|
|
455
|
-
const region = process.env.AWS_REGION
|
|
461
|
+
const region = process.env.AWS_REGION; // Lambda always provides this
|
|
456
462
|
const vpcEndpointDomains = [
|
|
457
463
|
`com.amazonaws.${region}.kms`,
|
|
458
464
|
`com.amazonaws.vpce.${region}`,
|
|
@@ -463,14 +469,17 @@ const detectVpcConfiguration = async () => {
|
|
|
463
469
|
try {
|
|
464
470
|
const addresses = await Promise.race([
|
|
465
471
|
dns.resolve4(domain).catch(() => dns.resolve6(domain)),
|
|
466
|
-
new Promise((_, reject) =>
|
|
472
|
+
new Promise((_, reject) =>
|
|
473
|
+
setTimeout(() => reject(new Error('timeout')), 1000)
|
|
474
|
+
),
|
|
467
475
|
]);
|
|
468
476
|
if (addresses && addresses.length > 0) {
|
|
469
477
|
// Check if it's a private IP (VPC endpoint indicator)
|
|
470
|
-
const isPrivateIp = addresses.some(
|
|
471
|
-
ip
|
|
472
|
-
|
|
473
|
-
|
|
478
|
+
const isPrivateIp = addresses.some(
|
|
479
|
+
(ip) =>
|
|
480
|
+
ip.startsWith('10.') ||
|
|
481
|
+
ip.startsWith('172.') ||
|
|
482
|
+
ip.startsWith('192.168.')
|
|
474
483
|
);
|
|
475
484
|
if (isPrivateIp) {
|
|
476
485
|
results.vpcEndpoints.push(domain);
|
|
@@ -481,9 +490,10 @@ const detectVpcConfiguration = async () => {
|
|
|
481
490
|
}
|
|
482
491
|
}
|
|
483
492
|
|
|
484
|
-
results.isInVpc =
|
|
485
|
-
|
|
486
|
-
|
|
493
|
+
results.isInVpc =
|
|
494
|
+
!results.hasInternetAccess || results.vpcEndpoints.length > 0;
|
|
495
|
+
results.canConnectToAws =
|
|
496
|
+
results.hasInternetAccess || results.vpcEndpoints.length > 0;
|
|
487
497
|
} catch (error) {
|
|
488
498
|
console.error('VPC detection error:', error.message);
|
|
489
499
|
}
|
|
@@ -507,7 +517,6 @@ const checkKmsDecryptCapability = async () => {
|
|
|
507
517
|
hasKmsKeyArn: !!KMS_KEY_ARN,
|
|
508
518
|
kmsKeyArnPrefix: KMS_KEY_ARN?.substring(0, 30),
|
|
509
519
|
awsRegion: process.env.AWS_REGION,
|
|
510
|
-
awsDefaultRegion: process.env.AWS_DEFAULT_REGION,
|
|
511
520
|
hasDiscoveryKey: !!process.env.AWS_DISCOVERY_KMS_KEY_ID,
|
|
512
521
|
});
|
|
513
522
|
|
|
@@ -518,7 +527,7 @@ const checkKmsDecryptCapability = async () => {
|
|
|
518
527
|
// Test DNS resolution for KMS endpoint
|
|
519
528
|
try {
|
|
520
529
|
const dns = require('dns').promises;
|
|
521
|
-
const region = process.env.AWS_REGION
|
|
530
|
+
const region = process.env.AWS_REGION; // Lambda always provides this
|
|
522
531
|
const kmsEndpoint = `kms.${region}.amazonaws.com`;
|
|
523
532
|
console.log('Testing DNS resolution for:', kmsEndpoint);
|
|
524
533
|
|
|
@@ -532,39 +541,43 @@ const checkKmsDecryptCapability = async () => {
|
|
|
532
541
|
console.log('KMS endpoint resolved to:', addresses);
|
|
533
542
|
|
|
534
543
|
// Check if resolved to private IP (VPC endpoint)
|
|
535
|
-
const isVpcEndpoint = addresses.some(
|
|
536
|
-
ip
|
|
537
|
-
|
|
538
|
-
|
|
544
|
+
const isVpcEndpoint = addresses.some(
|
|
545
|
+
(ip) =>
|
|
546
|
+
ip.startsWith('10.') ||
|
|
547
|
+
ip.startsWith('172.') ||
|
|
548
|
+
ip.startsWith('192.168.')
|
|
539
549
|
);
|
|
540
550
|
|
|
541
551
|
if (isVpcEndpoint) {
|
|
542
|
-
console.log(
|
|
552
|
+
console.log(
|
|
553
|
+
'KMS VPC Endpoint detected - using private connectivity'
|
|
554
|
+
);
|
|
543
555
|
}
|
|
544
556
|
|
|
545
557
|
// Test TCP connectivity to KMS (port 443)
|
|
546
558
|
const net = require('net');
|
|
547
|
-
const testConnection = () =>
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
+
const testConnection = () =>
|
|
560
|
+
new Promise((resolve) => {
|
|
561
|
+
const socket = new net.Socket();
|
|
562
|
+
const connectionTimeout = setTimeout(() => {
|
|
563
|
+
socket.destroy();
|
|
564
|
+
resolve({ connected: false, error: 'Connection timeout' });
|
|
565
|
+
}, 3000);
|
|
566
|
+
|
|
567
|
+
socket.on('connect', () => {
|
|
568
|
+
clearTimeout(connectionTimeout);
|
|
569
|
+
socket.destroy();
|
|
570
|
+
resolve({ connected: true });
|
|
571
|
+
});
|
|
559
572
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
573
|
+
socket.on('error', (err) => {
|
|
574
|
+
clearTimeout(connectionTimeout);
|
|
575
|
+
resolve({ connected: false, error: err.message });
|
|
576
|
+
});
|
|
564
577
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
578
|
+
// Try connecting to first resolved address on HTTPS port
|
|
579
|
+
socket.connect(443, addresses[0]);
|
|
580
|
+
});
|
|
568
581
|
|
|
569
582
|
const connResult = await testConnection();
|
|
570
583
|
console.log('TCP connectivity test:', connResult);
|
|
@@ -591,36 +604,36 @@ const checkKmsDecryptCapability = async () => {
|
|
|
591
604
|
}
|
|
592
605
|
|
|
593
606
|
try {
|
|
594
|
-
//
|
|
607
|
+
// Use AWS SDK v3 for consistency with the rest of the codebase
|
|
595
608
|
// eslint-disable-next-line global-require
|
|
596
|
-
const
|
|
609
|
+
const {
|
|
610
|
+
KMSClient,
|
|
611
|
+
GenerateDataKeyCommand,
|
|
612
|
+
DecryptCommand,
|
|
613
|
+
} = require('@aws-sdk/client-kms');
|
|
597
614
|
|
|
598
|
-
//
|
|
599
|
-
const region = process.env.AWS_REGION
|
|
600
|
-
if (!region) {
|
|
601
|
-
return {
|
|
602
|
-
status: 'unhealthy',
|
|
603
|
-
error: 'AWS_REGION not configured',
|
|
604
|
-
latencyMs: Date.now() - start,
|
|
605
|
-
};
|
|
606
|
-
}
|
|
615
|
+
// Lambda always provides AWS_REGION
|
|
616
|
+
const region = process.env.AWS_REGION;
|
|
607
617
|
|
|
608
|
-
const kms = new
|
|
618
|
+
const kms = new KMSClient({
|
|
609
619
|
region,
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
620
|
+
requestHandler: {
|
|
621
|
+
connectionTimeout: 10000, // 10 second connection timeout
|
|
622
|
+
requestTimeout: 25000, // 25 second timeout for slow VPC connections
|
|
613
623
|
},
|
|
614
|
-
|
|
624
|
+
maxAttempts: 1, // No retries on health checks
|
|
615
625
|
});
|
|
616
626
|
|
|
617
627
|
// Generate a data key (without plaintext logging) then immediately decrypt ciphertext to ensure decrypt perms.
|
|
618
|
-
const dataKeyResp = await kms
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
628
|
+
const dataKeyResp = await kms.send(
|
|
629
|
+
new GenerateDataKeyCommand({
|
|
630
|
+
KeyId: KMS_KEY_ARN,
|
|
631
|
+
KeySpec: 'AES_256',
|
|
632
|
+
})
|
|
633
|
+
);
|
|
634
|
+
const decryptResp = await kms.send(
|
|
635
|
+
new DecryptCommand({ CiphertextBlob: dataKeyResp.CiphertextBlob })
|
|
636
|
+
);
|
|
624
637
|
|
|
625
638
|
const success = Boolean(
|
|
626
639
|
dataKeyResp.CiphertextBlob && decryptResp.Plaintext
|
|
@@ -674,8 +687,11 @@ router.get('/health/detailed', async (_req, res) => {
|
|
|
674
687
|
response.checks.network = await Promise.race([
|
|
675
688
|
detectVpcConfiguration(),
|
|
676
689
|
new Promise((_, reject) =>
|
|
677
|
-
setTimeout(
|
|
678
|
-
|
|
690
|
+
setTimeout(
|
|
691
|
+
() => reject(new Error('Network diagnostics timeout')),
|
|
692
|
+
5000
|
|
693
|
+
)
|
|
694
|
+
),
|
|
679
695
|
]);
|
|
680
696
|
response.checks.network.latencyMs = Date.now() - networkStart;
|
|
681
697
|
console.log('Network diagnostics completed:', response.checks.network);
|
|
@@ -693,10 +709,16 @@ router.get('/health/detailed', async (_req, res) => {
|
|
|
693
709
|
// Wrap the entire KMS check in a timeout (allow up to 25 seconds for slow VPC)
|
|
694
710
|
const kmsCheckPromise = checkKmsDecryptCapability();
|
|
695
711
|
const kmsTimeoutPromise = new Promise((_, reject) =>
|
|
696
|
-
setTimeout(
|
|
712
|
+
setTimeout(
|
|
713
|
+
() => reject(new Error('KMS check timeout after 25 seconds')),
|
|
714
|
+
25000
|
|
715
|
+
)
|
|
697
716
|
);
|
|
698
717
|
|
|
699
|
-
response.checks.kms = await Promise.race([
|
|
718
|
+
response.checks.kms = await Promise.race([
|
|
719
|
+
kmsCheckPromise,
|
|
720
|
+
kmsTimeoutPromise,
|
|
721
|
+
]);
|
|
700
722
|
if (response.checks.kms.status === 'unhealthy') {
|
|
701
723
|
response.status = 'unhealthy';
|
|
702
724
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/core",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.428.
|
|
4
|
+
"version": "2.0.0--canary.428.ade056e.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@hapi/boom": "^10.0.1",
|
|
7
7
|
"aws-sdk": "^2.1200.0",
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
"uuid": "^9.0.1"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@friggframework/eslint-config": "2.0.0--canary.428.
|
|
26
|
-
"@friggframework/prettier-config": "2.0.0--canary.428.
|
|
27
|
-
"@friggframework/test": "2.0.0--canary.428.
|
|
25
|
+
"@friggframework/eslint-config": "2.0.0--canary.428.ade056e.0",
|
|
26
|
+
"@friggframework/prettier-config": "2.0.0--canary.428.ade056e.0",
|
|
27
|
+
"@friggframework/test": "2.0.0--canary.428.ade056e.0",
|
|
28
28
|
"@types/lodash": "4.17.15",
|
|
29
29
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
30
30
|
"chai": "^4.3.6",
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
"publishConfig": {
|
|
57
57
|
"access": "public"
|
|
58
58
|
},
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "ade056ef7772afeb2d7eae1b90e698feae9cb4c9"
|
|
60
60
|
}
|