@friggframework/devtools 2.0.0--canary.461.84ff4f5.0 → 2.0.0--canary.461.ec909cf.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/infrastructure/aws-discovery.js +42 -19
- package/infrastructure/domains/database/aurora-builder.js +307 -0
- package/infrastructure/domains/database/aurora-builder.test.js +482 -0
- package/infrastructure/domains/networking/vpc-builder.js +718 -0
- package/infrastructure/domains/networking/vpc-builder.test.js +772 -0
- package/infrastructure/domains/networking/vpc-discovery.js +159 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.js +445 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.js +385 -0
- package/infrastructure/domains/shared/utilities/handler-path-resolver.js +129 -0
- package/infrastructure/infrastructure-composer.test.js +1895 -0
- package/infrastructure/serverless-template.js +226 -42
- package/infrastructure/serverless-template.test.js +3 -1
- package/package.json +6 -6
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VPC Discovery Service
|
|
3
|
+
*
|
|
4
|
+
* Domain Service - Hexagonal Architecture
|
|
5
|
+
*
|
|
6
|
+
* Discovers VPC and networking resources using the cloud provider adapter.
|
|
7
|
+
* Adds domain-specific validation and transformation logic.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
class VpcDiscovery {
|
|
11
|
+
/**
|
|
12
|
+
* @param {CloudProviderAdapter} provider - Cloud provider adapter instance
|
|
13
|
+
*/
|
|
14
|
+
constructor(provider) {
|
|
15
|
+
this.provider = provider;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Discover VPC and networking resources
|
|
20
|
+
*
|
|
21
|
+
* @param {Object} config - Discovery configuration
|
|
22
|
+
* @param {string} [config.vpcId] - Specific VPC ID to discover
|
|
23
|
+
* @param {string} [config.serviceName] - Service name for tagging/filtering
|
|
24
|
+
* @param {string} [config.stage] - Deployment stage
|
|
25
|
+
* @returns {Promise<Object>} Discovered VPC resources with friendly property names
|
|
26
|
+
*/
|
|
27
|
+
async discover(config) {
|
|
28
|
+
console.log('🔍 Discovering VPC resources...');
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const rawResources = await this.provider.discoverVpc(config);
|
|
32
|
+
|
|
33
|
+
// Transform to Frigg-friendly format
|
|
34
|
+
const result = {
|
|
35
|
+
defaultVpcId: rawResources.vpcId,
|
|
36
|
+
vpcCidr: rawResources.vpcCidr,
|
|
37
|
+
subnets: rawResources.subnets,
|
|
38
|
+
securityGroups: rawResources.securityGroups,
|
|
39
|
+
routeTables: rawResources.routeTables,
|
|
40
|
+
natGateways: rawResources.natGateways,
|
|
41
|
+
internetGateways: rawResources.internetGateways,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Extract specific subnet types
|
|
45
|
+
const privateSubnets = rawResources.subnets.filter(
|
|
46
|
+
s => !s.MapPublicIpOnLaunch
|
|
47
|
+
);
|
|
48
|
+
const publicSubnets = rawResources.subnets.filter(
|
|
49
|
+
s => s.MapPublicIpOnLaunch
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
// Set subnet IDs for Frigg infrastructure
|
|
53
|
+
if (privateSubnets.length >= 1) {
|
|
54
|
+
result.privateSubnetId1 = privateSubnets[0].SubnetId;
|
|
55
|
+
}
|
|
56
|
+
if (privateSubnets.length >= 2) {
|
|
57
|
+
result.privateSubnetId2 = privateSubnets[1].SubnetId;
|
|
58
|
+
}
|
|
59
|
+
if (publicSubnets.length >= 1) {
|
|
60
|
+
result.publicSubnetId = publicSubnets[0].SubnetId;
|
|
61
|
+
result.publicSubnetId1 = publicSubnets[0].SubnetId;
|
|
62
|
+
}
|
|
63
|
+
if (publicSubnets.length >= 2) {
|
|
64
|
+
result.publicSubnetId2 = publicSubnets[1].SubnetId;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Find default security group
|
|
68
|
+
const defaultSg = rawResources.securityGroups.find(
|
|
69
|
+
sg => sg.GroupName === 'default'
|
|
70
|
+
);
|
|
71
|
+
if (defaultSg) {
|
|
72
|
+
result.defaultSecurityGroupId = defaultSg.GroupId;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Find default route table
|
|
76
|
+
const defaultRt = rawResources.routeTables.find(
|
|
77
|
+
rt => rt.Associations?.some(a => a.Main)
|
|
78
|
+
);
|
|
79
|
+
if (defaultRt) {
|
|
80
|
+
result.defaultRouteTableId = defaultRt.RouteTableId;
|
|
81
|
+
result.privateRouteTableId = defaultRt.RouteTableId;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Find NAT gateway
|
|
85
|
+
const activeNat = rawResources.natGateways.find(
|
|
86
|
+
nat => nat.State === 'available'
|
|
87
|
+
);
|
|
88
|
+
if (activeNat) {
|
|
89
|
+
result.existingNatGatewayId = activeNat.NatGatewayId;
|
|
90
|
+
|
|
91
|
+
// Check if NAT is in private subnet (configuration error)
|
|
92
|
+
const natSubnet = rawResources.subnets.find(
|
|
93
|
+
s => s.SubnetId === activeNat.SubnetId
|
|
94
|
+
);
|
|
95
|
+
result.natGatewayInPrivateSubnet = natSubnet && !natSubnet.MapPublicIpOnLaunch;
|
|
96
|
+
|
|
97
|
+
// Get elastic IP allocation
|
|
98
|
+
if (activeNat.NatGatewayAddresses && activeNat.NatGatewayAddresses.length > 0) {
|
|
99
|
+
result.existingElasticIpAllocationId =
|
|
100
|
+
activeNat.NatGatewayAddresses[0].AllocationId;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Find Internet Gateway
|
|
105
|
+
if (rawResources.internetGateways.length > 0) {
|
|
106
|
+
result.internetGatewayId = rawResources.internetGateways[0].InternetGatewayId;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Find VPC Endpoints
|
|
110
|
+
if (rawResources.vpcEndpoints) {
|
|
111
|
+
const s3Endpoint = rawResources.vpcEndpoints.find(
|
|
112
|
+
ep => ep.ServiceName && ep.ServiceName.includes('.s3')
|
|
113
|
+
);
|
|
114
|
+
const dynamodbEndpoint = rawResources.vpcEndpoints.find(
|
|
115
|
+
ep => ep.ServiceName && ep.ServiceName.includes('.dynamodb')
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
if (s3Endpoint) {
|
|
119
|
+
result.s3VpcEndpointId = s3Endpoint.VpcEndpointId;
|
|
120
|
+
}
|
|
121
|
+
if (dynamodbEndpoint) {
|
|
122
|
+
result.dynamodbVpcEndpointId = dynamodbEndpoint.VpcEndpointId;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
console.log(` ✓ Found VPC: ${result.defaultVpcId}`);
|
|
127
|
+
if (result.privateSubnetId1) {
|
|
128
|
+
console.log(` ✓ Found private subnets: ${result.privateSubnetId1}, ${result.privateSubnetId2 || 'N/A'}`);
|
|
129
|
+
}
|
|
130
|
+
if (result.publicSubnetId) {
|
|
131
|
+
console.log(` ✓ Found public subnet: ${result.publicSubnetId}`);
|
|
132
|
+
}
|
|
133
|
+
if (result.existingNatGatewayId) {
|
|
134
|
+
console.log(` ✓ Found NAT Gateway: ${result.existingNatGatewayId}`);
|
|
135
|
+
}
|
|
136
|
+
if (result.s3VpcEndpointId || result.dynamodbVpcEndpointId) {
|
|
137
|
+
console.log(` ✓ Found VPC Endpoints: S3=${result.s3VpcEndpointId ? 'Yes' : 'No'}, DynamoDB=${result.dynamodbVpcEndpointId ? 'Yes' : 'No'}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return result;
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error(' ✗ VPC discovery failed:', error.message);
|
|
143
|
+
return {
|
|
144
|
+
defaultVpcId: null,
|
|
145
|
+
vpcCidr: null,
|
|
146
|
+
privateSubnetId1: null,
|
|
147
|
+
privateSubnetId2: null,
|
|
148
|
+
publicSubnetId: null,
|
|
149
|
+
defaultSecurityGroupId: null,
|
|
150
|
+
defaultRouteTableId: null,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = {
|
|
157
|
+
VpcDiscovery,
|
|
158
|
+
};
|
|
159
|
+
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS Provider Adapter
|
|
3
|
+
*
|
|
4
|
+
* Adapter - Hexagonal Architecture
|
|
5
|
+
*
|
|
6
|
+
* Implements CloudProviderAdapter interface for Amazon Web Services.
|
|
7
|
+
* Handles AWS-specific resource discovery using AWS SDK v3.
|
|
8
|
+
*
|
|
9
|
+
* This adapter lazy-loads AWS SDK clients to minimize cold start time
|
|
10
|
+
* and memory usage when not all discovery features are needed.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { CloudProviderAdapter } = require('./cloud-provider-adapter');
|
|
14
|
+
|
|
15
|
+
// Lazy-loaded AWS SDK clients
|
|
16
|
+
let EC2Client, DescribeVpcsCommand, DescribeSubnetsCommand, DescribeSecurityGroupsCommand,
|
|
17
|
+
DescribeRouteTablesCommand, DescribeNatGatewaysCommand, DescribeInternetGatewaysCommand,
|
|
18
|
+
DescribeVpcEndpointsCommand;
|
|
19
|
+
let KMSClient, ListKeysCommand, DescribeKeyCommand, ListAliasesCommand;
|
|
20
|
+
let RDSClient, DescribeDBClustersCommand, DescribeDBInstancesCommand;
|
|
21
|
+
let SSMClient, GetParameterCommand, GetParametersByPathCommand;
|
|
22
|
+
let SecretsManagerClient, ListSecretsCommand, GetSecretValueCommand;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Lazy load EC2 SDK
|
|
26
|
+
*/
|
|
27
|
+
function loadEC2() {
|
|
28
|
+
if (!EC2Client) {
|
|
29
|
+
const ec2Module = require('@aws-sdk/client-ec2');
|
|
30
|
+
EC2Client = ec2Module.EC2Client;
|
|
31
|
+
DescribeVpcsCommand = ec2Module.DescribeVpcsCommand;
|
|
32
|
+
DescribeSubnetsCommand = ec2Module.DescribeSubnetsCommand;
|
|
33
|
+
DescribeSecurityGroupsCommand = ec2Module.DescribeSecurityGroupsCommand;
|
|
34
|
+
DescribeRouteTablesCommand = ec2Module.DescribeRouteTablesCommand;
|
|
35
|
+
DescribeNatGatewaysCommand = ec2Module.DescribeNatGatewaysCommand;
|
|
36
|
+
DescribeInternetGatewaysCommand = ec2Module.DescribeInternetGatewaysCommand;
|
|
37
|
+
DescribeVpcEndpointsCommand = ec2Module.DescribeVpcEndpointsCommand;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Lazy load KMS SDK
|
|
43
|
+
*/
|
|
44
|
+
function loadKMS() {
|
|
45
|
+
if (!KMSClient) {
|
|
46
|
+
const kmsModule = require('@aws-sdk/client-kms');
|
|
47
|
+
KMSClient = kmsModule.KMSClient;
|
|
48
|
+
ListKeysCommand = kmsModule.ListKeysCommand;
|
|
49
|
+
DescribeKeyCommand = kmsModule.DescribeKeyCommand;
|
|
50
|
+
ListAliasesCommand = kmsModule.ListAliasesCommand;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Lazy load RDS SDK
|
|
56
|
+
*/
|
|
57
|
+
function loadRDS() {
|
|
58
|
+
if (!RDSClient) {
|
|
59
|
+
const rdsModule = require('@aws-sdk/client-rds');
|
|
60
|
+
RDSClient = rdsModule.RDSClient;
|
|
61
|
+
DescribeDBClustersCommand = rdsModule.DescribeDBClustersCommand;
|
|
62
|
+
DescribeDBInstancesCommand = rdsModule.DescribeDBInstancesCommand;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Lazy load SSM SDK
|
|
68
|
+
*/
|
|
69
|
+
function loadSSM() {
|
|
70
|
+
if (!SSMClient) {
|
|
71
|
+
const ssmModule = require('@aws-sdk/client-ssm');
|
|
72
|
+
SSMClient = ssmModule.SSMClient;
|
|
73
|
+
GetParameterCommand = ssmModule.GetParameterCommand;
|
|
74
|
+
GetParametersByPathCommand = ssmModule.GetParametersByPathCommand;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Lazy load Secrets Manager SDK
|
|
80
|
+
*/
|
|
81
|
+
function loadSecretsManager() {
|
|
82
|
+
if (!SecretsManagerClient) {
|
|
83
|
+
const smModule = require('@aws-sdk/client-secrets-manager');
|
|
84
|
+
SecretsManagerClient = smModule.SecretsManagerClient;
|
|
85
|
+
ListSecretsCommand = smModule.ListSecretsCommand;
|
|
86
|
+
GetSecretValueCommand = smModule.GetSecretValueCommand;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
class AWSProviderAdapter extends CloudProviderAdapter {
|
|
91
|
+
constructor(region, credentials = {}) {
|
|
92
|
+
super();
|
|
93
|
+
this.region = region || process.env.AWS_REGION || 'us-east-1';
|
|
94
|
+
this.credentials = credentials;
|
|
95
|
+
|
|
96
|
+
// Initialize clients as null - will be lazy loaded
|
|
97
|
+
this.ec2 = null;
|
|
98
|
+
this.kms = null;
|
|
99
|
+
this.rds = null;
|
|
100
|
+
this.ssm = null;
|
|
101
|
+
this.secretsManager = null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get EC2 client (lazy loaded)
|
|
106
|
+
*/
|
|
107
|
+
getEC2Client() {
|
|
108
|
+
if (!this.ec2) {
|
|
109
|
+
loadEC2();
|
|
110
|
+
this.ec2 = new EC2Client({
|
|
111
|
+
region: this.region,
|
|
112
|
+
...this.credentials,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return this.ec2;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get KMS client (lazy loaded)
|
|
120
|
+
*/
|
|
121
|
+
getKMSClient() {
|
|
122
|
+
if (!this.kms) {
|
|
123
|
+
loadKMS();
|
|
124
|
+
this.kms = new KMSClient({
|
|
125
|
+
region: this.region,
|
|
126
|
+
...this.credentials,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
return this.kms;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Get RDS client (lazy loaded)
|
|
134
|
+
*/
|
|
135
|
+
getRDSClient() {
|
|
136
|
+
if (!this.rds) {
|
|
137
|
+
loadRDS();
|
|
138
|
+
this.rds = new RDSClient({
|
|
139
|
+
region: this.region,
|
|
140
|
+
...this.credentials,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return this.rds;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get SSM client (lazy loaded)
|
|
148
|
+
*/
|
|
149
|
+
getSSMClient() {
|
|
150
|
+
if (!this.ssm) {
|
|
151
|
+
loadSSM();
|
|
152
|
+
this.ssm = new SSMClient({
|
|
153
|
+
region: this.region,
|
|
154
|
+
...this.credentials,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return this.ssm;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get Secrets Manager client (lazy loaded)
|
|
162
|
+
*/
|
|
163
|
+
getSecretsManagerClient() {
|
|
164
|
+
if (!this.secretsManager) {
|
|
165
|
+
loadSecretsManager();
|
|
166
|
+
this.secretsManager = new SecretsManagerClient({
|
|
167
|
+
region: this.region,
|
|
168
|
+
...this.credentials,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return this.secretsManager;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
getName() {
|
|
175
|
+
return 'aws';
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
getSupportedRegions() {
|
|
179
|
+
return [
|
|
180
|
+
'us-east-1', 'us-east-2', 'us-west-1', 'us-west-2',
|
|
181
|
+
'eu-west-1', 'eu-west-2', 'eu-west-3', 'eu-central-1',
|
|
182
|
+
'ap-southeast-1', 'ap-southeast-2', 'ap-northeast-1', 'ap-northeast-2',
|
|
183
|
+
'sa-east-1', 'ca-central-1',
|
|
184
|
+
];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Discover VPC resources
|
|
189
|
+
*
|
|
190
|
+
* @param {Object} config - Discovery configuration
|
|
191
|
+
* @returns {Promise<Object>} Discovered VPC resources
|
|
192
|
+
*/
|
|
193
|
+
async discoverVpc(config) {
|
|
194
|
+
const ec2 = this.getEC2Client();
|
|
195
|
+
const result = {
|
|
196
|
+
vpcId: null,
|
|
197
|
+
vpcCidr: null,
|
|
198
|
+
subnets: [],
|
|
199
|
+
securityGroups: [],
|
|
200
|
+
routeTables: [],
|
|
201
|
+
natGateways: [],
|
|
202
|
+
internetGateways: [],
|
|
203
|
+
vpcEndpoints: [],
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
try {
|
|
207
|
+
// Discover VPC
|
|
208
|
+
const vpcFilter = config.vpcId
|
|
209
|
+
? [{ Name: 'vpc-id', Values: [config.vpcId] }]
|
|
210
|
+
: [{ Name: 'isDefault', Values: ['true'] }];
|
|
211
|
+
|
|
212
|
+
const vpcsResponse = await ec2.send(new DescribeVpcsCommand({
|
|
213
|
+
Filters: vpcFilter,
|
|
214
|
+
}));
|
|
215
|
+
|
|
216
|
+
if (vpcsResponse.Vpcs && vpcsResponse.Vpcs.length > 0) {
|
|
217
|
+
const vpc = vpcsResponse.Vpcs[0];
|
|
218
|
+
result.vpcId = vpc.VpcId;
|
|
219
|
+
result.vpcCidr = vpc.CidrBlock;
|
|
220
|
+
|
|
221
|
+
// Discover subnets in VPC
|
|
222
|
+
const subnetsResponse = await ec2.send(new DescribeSubnetsCommand({
|
|
223
|
+
Filters: [{ Name: 'vpc-id', Values: [result.vpcId] }],
|
|
224
|
+
}));
|
|
225
|
+
result.subnets = subnetsResponse.Subnets || [];
|
|
226
|
+
|
|
227
|
+
// Discover security groups
|
|
228
|
+
const sgResponse = await ec2.send(new DescribeSecurityGroupsCommand({
|
|
229
|
+
Filters: [{ Name: 'vpc-id', Values: [result.vpcId] }],
|
|
230
|
+
}));
|
|
231
|
+
result.securityGroups = sgResponse.SecurityGroups || [];
|
|
232
|
+
|
|
233
|
+
// Discover route tables
|
|
234
|
+
const rtResponse = await ec2.send(new DescribeRouteTablesCommand({
|
|
235
|
+
Filters: [{ Name: 'vpc-id', Values: [result.vpcId] }],
|
|
236
|
+
}));
|
|
237
|
+
result.routeTables = rtResponse.RouteTables || [];
|
|
238
|
+
|
|
239
|
+
// Discover NAT gateways
|
|
240
|
+
const natResponse = await ec2.send(new DescribeNatGatewaysCommand({
|
|
241
|
+
Filter: [{ Name: 'vpc-id', Values: [result.vpcId] }],
|
|
242
|
+
}));
|
|
243
|
+
result.natGateways = natResponse.NatGateways || [];
|
|
244
|
+
|
|
245
|
+
// Discover Internet gateways
|
|
246
|
+
const igwResponse = await ec2.send(new DescribeInternetGatewaysCommand({
|
|
247
|
+
Filters: [
|
|
248
|
+
{ Name: 'attachment.vpc-id', Values: [result.vpcId] },
|
|
249
|
+
],
|
|
250
|
+
}));
|
|
251
|
+
result.internetGateways = igwResponse.InternetGateways || [];
|
|
252
|
+
|
|
253
|
+
// Discover VPC Endpoints
|
|
254
|
+
const vpcEndpointsResponse = await ec2.send(new DescribeVpcEndpointsCommand({
|
|
255
|
+
Filters: [
|
|
256
|
+
{ Name: 'vpc-id', Values: [result.vpcId] },
|
|
257
|
+
],
|
|
258
|
+
}));
|
|
259
|
+
result.vpcEndpoints = vpcEndpointsResponse.VpcEndpoints || [];
|
|
260
|
+
}
|
|
261
|
+
} catch (error) {
|
|
262
|
+
console.error('AWS VPC discovery failed:', error);
|
|
263
|
+
throw new Error(`Failed to discover AWS VPC: ${error.message}`);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Discover KMS keys
|
|
271
|
+
*
|
|
272
|
+
* @param {Object} config - Discovery configuration
|
|
273
|
+
* @returns {Promise<Object>} Discovered KMS keys
|
|
274
|
+
*/
|
|
275
|
+
async discoverKmsKeys(config) {
|
|
276
|
+
const kms = this.getKMSClient();
|
|
277
|
+
const result = {
|
|
278
|
+
keys: [],
|
|
279
|
+
aliases: [],
|
|
280
|
+
defaultKey: null,
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
try {
|
|
284
|
+
// List KMS keys
|
|
285
|
+
const keysResponse = await kms.send(new ListKeysCommand({}));
|
|
286
|
+
|
|
287
|
+
if (keysResponse.Keys && keysResponse.Keys.length > 0) {
|
|
288
|
+
// Get details for each key
|
|
289
|
+
for (const key of keysResponse.Keys) {
|
|
290
|
+
try {
|
|
291
|
+
const keyDetails = await kms.send(new DescribeKeyCommand({
|
|
292
|
+
KeyId: key.KeyId,
|
|
293
|
+
}));
|
|
294
|
+
|
|
295
|
+
if (keyDetails.KeyMetadata && keyDetails.KeyMetadata.Enabled) {
|
|
296
|
+
result.keys.push(keyDetails.KeyMetadata);
|
|
297
|
+
|
|
298
|
+
// Set first enabled key as default
|
|
299
|
+
if (!result.defaultKey) {
|
|
300
|
+
result.defaultKey = keyDetails.KeyMetadata;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
} catch (error) {
|
|
304
|
+
// Skip keys we can't access
|
|
305
|
+
console.warn(`Could not describe key ${key.KeyId}:`, error.message);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// List KMS aliases
|
|
311
|
+
const aliasesResponse = await kms.send(new ListAliasesCommand({}));
|
|
312
|
+
result.aliases = aliasesResponse.Aliases || [];
|
|
313
|
+
|
|
314
|
+
// If a specific alias is requested, find it
|
|
315
|
+
if (config.keyAlias) {
|
|
316
|
+
const alias = result.aliases.find(a => a.AliasName === config.keyAlias);
|
|
317
|
+
if (alias && alias.TargetKeyId) {
|
|
318
|
+
const key = result.keys.find(k => k.KeyId === alias.TargetKeyId);
|
|
319
|
+
if (key) {
|
|
320
|
+
result.defaultKey = key;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
} catch (error) {
|
|
325
|
+
console.error('AWS KMS discovery failed:', error);
|
|
326
|
+
throw new Error(`Failed to discover AWS KMS keys: ${error.message}`);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return result;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Discover database resources (RDS/Aurora)
|
|
334
|
+
*
|
|
335
|
+
* @param {Object} config - Discovery configuration
|
|
336
|
+
* @returns {Promise<Object>} Discovered database resources
|
|
337
|
+
*/
|
|
338
|
+
async discoverDatabase(config) {
|
|
339
|
+
const rds = this.getRDSClient();
|
|
340
|
+
const result = {
|
|
341
|
+
clusters: [],
|
|
342
|
+
instances: [],
|
|
343
|
+
endpoint: null,
|
|
344
|
+
port: null,
|
|
345
|
+
engine: null,
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
try {
|
|
349
|
+
// Discover Aurora clusters
|
|
350
|
+
const clustersResponse = await rds.send(new DescribeDBClustersCommand({}));
|
|
351
|
+
|
|
352
|
+
if (clustersResponse.DBClusters) {
|
|
353
|
+
result.clusters = clustersResponse.DBClusters;
|
|
354
|
+
|
|
355
|
+
// Find cluster matching config
|
|
356
|
+
if (config.databaseId) {
|
|
357
|
+
const cluster = result.clusters.find(c =>
|
|
358
|
+
c.DBClusterIdentifier === config.databaseId
|
|
359
|
+
);
|
|
360
|
+
if (cluster) {
|
|
361
|
+
result.endpoint = cluster.Endpoint;
|
|
362
|
+
result.port = cluster.Port;
|
|
363
|
+
result.engine = cluster.Engine;
|
|
364
|
+
}
|
|
365
|
+
} else if (result.clusters.length > 0) {
|
|
366
|
+
// Use first available cluster
|
|
367
|
+
const cluster = result.clusters[0];
|
|
368
|
+
result.endpoint = cluster.Endpoint;
|
|
369
|
+
result.port = cluster.Port;
|
|
370
|
+
result.engine = cluster.Engine;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Discover RDS instances (if no cluster found)
|
|
375
|
+
if (!result.endpoint) {
|
|
376
|
+
const instancesResponse = await rds.send(new DescribeDBInstancesCommand({}));
|
|
377
|
+
if (instancesResponse.DBInstances) {
|
|
378
|
+
result.instances = instancesResponse.DBInstances;
|
|
379
|
+
|
|
380
|
+
if (config.databaseId) {
|
|
381
|
+
const instance = result.instances.find(i =>
|
|
382
|
+
i.DBInstanceIdentifier === config.databaseId
|
|
383
|
+
);
|
|
384
|
+
if (instance) {
|
|
385
|
+
result.endpoint = instance.Endpoint?.Address;
|
|
386
|
+
result.port = instance.Endpoint?.Port;
|
|
387
|
+
result.engine = instance.Engine;
|
|
388
|
+
}
|
|
389
|
+
} else if (result.instances.length > 0) {
|
|
390
|
+
const instance = result.instances[0];
|
|
391
|
+
result.endpoint = instance.Endpoint?.Address;
|
|
392
|
+
result.port = instance.Endpoint?.Port;
|
|
393
|
+
result.engine = instance.Engine;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
} catch (error) {
|
|
398
|
+
console.error('AWS RDS discovery failed:', error);
|
|
399
|
+
throw new Error(`Failed to discover AWS databases: ${error.message}`);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return result;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Discover SSM parameters
|
|
407
|
+
*
|
|
408
|
+
* @param {Object} config - Discovery configuration
|
|
409
|
+
* @returns {Promise<Object>} Discovered parameters
|
|
410
|
+
*/
|
|
411
|
+
async discoverParameters(config) {
|
|
412
|
+
const ssm = this.getSSMClient();
|
|
413
|
+
const result = {
|
|
414
|
+
parameters: [],
|
|
415
|
+
secrets: [],
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
try {
|
|
419
|
+
if (config.parameterPath) {
|
|
420
|
+
const response = await ssm.send(new GetParametersByPathCommand({
|
|
421
|
+
Path: config.parameterPath,
|
|
422
|
+
Recursive: true,
|
|
423
|
+
}));
|
|
424
|
+
result.parameters = response.Parameters || [];
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Discover secrets if enabled
|
|
428
|
+
if (config.includeSecrets) {
|
|
429
|
+
const sm = this.getSecretsManagerClient();
|
|
430
|
+
const secretsResponse = await sm.send(new ListSecretsCommand({}));
|
|
431
|
+
result.secrets = secretsResponse.SecretList || [];
|
|
432
|
+
}
|
|
433
|
+
} catch (error) {
|
|
434
|
+
console.error('AWS SSM discovery failed:', error);
|
|
435
|
+
throw new Error(`Failed to discover AWS parameters: ${error.message}`);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return result;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
module.exports = {
|
|
443
|
+
AWSProviderAdapter,
|
|
444
|
+
};
|
|
445
|
+
|