s3db.js 13.5.1 → 13.6.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/README.md +25 -10
- package/dist/{s3db.cjs.js → s3db.cjs} +30323 -24958
- package/dist/s3db.cjs.map +1 -0
- package/dist/s3db.es.js +24026 -18654
- package/dist/s3db.es.js.map +1 -1
- package/package.json +216 -20
- package/src/concerns/id.js +90 -6
- package/src/concerns/index.js +2 -1
- package/src/concerns/password-hashing.js +150 -0
- package/src/database.class.js +4 -0
- package/src/plugins/api/auth/basic-auth.js +23 -1
- package/src/plugins/api/auth/index.js +49 -3
- package/src/plugins/api/auth/oauth2-auth.js +171 -0
- package/src/plugins/api/auth/oidc-auth.js +789 -0
- package/src/plugins/api/auth/oidc-client.js +462 -0
- package/src/plugins/api/auth/path-auth-matcher.js +284 -0
- package/src/plugins/api/concerns/event-emitter.js +134 -0
- package/src/plugins/api/concerns/failban-manager.js +651 -0
- package/src/plugins/api/concerns/guards-helpers.js +402 -0
- package/src/plugins/api/concerns/metrics-collector.js +346 -0
- package/src/plugins/api/index.js +503 -54
- package/src/plugins/api/middlewares/failban.js +305 -0
- package/src/plugins/api/middlewares/rate-limit.js +301 -0
- package/src/plugins/api/middlewares/request-id.js +74 -0
- package/src/plugins/api/middlewares/security-headers.js +120 -0
- package/src/plugins/api/middlewares/session-tracking.js +194 -0
- package/src/plugins/api/routes/auth-routes.js +23 -3
- package/src/plugins/api/routes/resource-routes.js +71 -29
- package/src/plugins/api/server.js +1017 -94
- package/src/plugins/api/utils/guards.js +213 -0
- package/src/plugins/api/utils/mime-types.js +154 -0
- package/src/plugins/api/utils/openapi-generator.js +44 -11
- package/src/plugins/api/utils/path-matcher.js +173 -0
- package/src/plugins/api/utils/static-filesystem.js +262 -0
- package/src/plugins/api/utils/static-s3.js +231 -0
- package/src/plugins/api/utils/template-engine.js +188 -0
- package/src/plugins/cloud-inventory/drivers/alibaba-driver.js +853 -0
- package/src/plugins/cloud-inventory/drivers/aws-driver.js +2554 -0
- package/src/plugins/cloud-inventory/drivers/azure-driver.js +637 -0
- package/src/plugins/cloud-inventory/drivers/base-driver.js +99 -0
- package/src/plugins/cloud-inventory/drivers/cloudflare-driver.js +620 -0
- package/src/plugins/cloud-inventory/drivers/digitalocean-driver.js +698 -0
- package/src/plugins/cloud-inventory/drivers/gcp-driver.js +645 -0
- package/src/plugins/cloud-inventory/drivers/hetzner-driver.js +559 -0
- package/src/plugins/cloud-inventory/drivers/linode-driver.js +614 -0
- package/src/plugins/cloud-inventory/drivers/mock-drivers.js +449 -0
- package/src/plugins/cloud-inventory/drivers/mongodb-atlas-driver.js +771 -0
- package/src/plugins/cloud-inventory/drivers/oracle-driver.js +768 -0
- package/src/plugins/cloud-inventory/drivers/vultr-driver.js +636 -0
- package/src/plugins/cloud-inventory/index.js +20 -0
- package/src/plugins/cloud-inventory/registry.js +146 -0
- package/src/plugins/cloud-inventory/terraform-exporter.js +362 -0
- package/src/plugins/cloud-inventory.plugin.js +1333 -0
- package/src/plugins/concerns/plugin-dependencies.js +61 -1
- package/src/plugins/eventual-consistency/analytics.js +1 -0
- package/src/plugins/identity/README.md +335 -0
- package/src/plugins/identity/concerns/mfa-manager.js +204 -0
- package/src/plugins/identity/concerns/password.js +138 -0
- package/src/plugins/identity/concerns/resource-schemas.js +273 -0
- package/src/plugins/identity/concerns/token-generator.js +172 -0
- package/src/plugins/identity/email-service.js +422 -0
- package/src/plugins/identity/index.js +1052 -0
- package/src/plugins/identity/oauth2-server.js +1033 -0
- package/src/plugins/identity/oidc-discovery.js +285 -0
- package/src/plugins/identity/rsa-keys.js +323 -0
- package/src/plugins/identity/server.js +500 -0
- package/src/plugins/identity/session-manager.js +453 -0
- package/src/plugins/identity/ui/layouts/base.js +251 -0
- package/src/plugins/identity/ui/middleware.js +135 -0
- package/src/plugins/identity/ui/pages/admin/client-form.js +247 -0
- package/src/plugins/identity/ui/pages/admin/clients.js +179 -0
- package/src/plugins/identity/ui/pages/admin/dashboard.js +181 -0
- package/src/plugins/identity/ui/pages/admin/user-form.js +283 -0
- package/src/plugins/identity/ui/pages/admin/users.js +263 -0
- package/src/plugins/identity/ui/pages/consent.js +262 -0
- package/src/plugins/identity/ui/pages/forgot-password.js +104 -0
- package/src/plugins/identity/ui/pages/login.js +144 -0
- package/src/plugins/identity/ui/pages/mfa-backup-codes.js +180 -0
- package/src/plugins/identity/ui/pages/mfa-enrollment.js +187 -0
- package/src/plugins/identity/ui/pages/mfa-verification.js +178 -0
- package/src/plugins/identity/ui/pages/oauth-error.js +225 -0
- package/src/plugins/identity/ui/pages/profile.js +361 -0
- package/src/plugins/identity/ui/pages/register.js +226 -0
- package/src/plugins/identity/ui/pages/reset-password.js +128 -0
- package/src/plugins/identity/ui/pages/verify-email.js +172 -0
- package/src/plugins/identity/ui/routes.js +2541 -0
- package/src/plugins/identity/ui/styles/main.css +465 -0
- package/src/plugins/index.js +4 -1
- package/src/plugins/ml/base-model.class.js +32 -7
- package/src/plugins/ml/classification-model.class.js +1 -1
- package/src/plugins/ml/timeseries-model.class.js +3 -1
- package/src/plugins/ml.plugin.js +124 -32
- package/src/plugins/shared/error-handler.js +147 -0
- package/src/plugins/shared/index.js +9 -0
- package/src/plugins/shared/middlewares/compression.js +117 -0
- package/src/plugins/shared/middlewares/cors.js +49 -0
- package/src/plugins/shared/middlewares/index.js +11 -0
- package/src/plugins/shared/middlewares/logging.js +54 -0
- package/src/plugins/shared/middlewares/rate-limit.js +73 -0
- package/src/plugins/shared/middlewares/security.js +158 -0
- package/src/plugins/shared/response-formatter.js +264 -0
- package/src/resource.class.js +140 -12
- package/src/schema.class.js +30 -1
- package/src/validator.class.js +57 -6
- package/dist/s3db.cjs.js.map +0 -1
|
@@ -0,0 +1,2554 @@
|
|
|
1
|
+
import { fromNodeProviderChain, fromIni, fromProcess } from '@aws-sdk/credential-providers';
|
|
2
|
+
import { STSClient, GetCallerIdentityCommand } from '@aws-sdk/client-sts';
|
|
3
|
+
import {
|
|
4
|
+
EC2Client,
|
|
5
|
+
paginateDescribeInstances,
|
|
6
|
+
paginateDescribeVpcs,
|
|
7
|
+
paginateDescribeSubnets,
|
|
8
|
+
paginateDescribeSecurityGroups,
|
|
9
|
+
paginateDescribeRouteTables,
|
|
10
|
+
paginateDescribeInternetGateways,
|
|
11
|
+
paginateDescribeNatGateways,
|
|
12
|
+
paginateDescribeNetworkAcls
|
|
13
|
+
} from '@aws-sdk/client-ec2';
|
|
14
|
+
import {
|
|
15
|
+
S3Client,
|
|
16
|
+
ListBucketsCommand,
|
|
17
|
+
GetBucketLocationCommand,
|
|
18
|
+
GetBucketTaggingCommand
|
|
19
|
+
} from '@aws-sdk/client-s3';
|
|
20
|
+
import {
|
|
21
|
+
RDSClient,
|
|
22
|
+
paginateDescribeDBInstances,
|
|
23
|
+
ListTagsForResourceCommand
|
|
24
|
+
} from '@aws-sdk/client-rds';
|
|
25
|
+
import {
|
|
26
|
+
IAMClient,
|
|
27
|
+
paginateListUsers,
|
|
28
|
+
paginateListRoles,
|
|
29
|
+
ListUserTagsCommand,
|
|
30
|
+
ListRoleTagsCommand
|
|
31
|
+
} from '@aws-sdk/client-iam';
|
|
32
|
+
import {
|
|
33
|
+
LambdaClient,
|
|
34
|
+
paginateListFunctions,
|
|
35
|
+
ListTagsCommand as ListLambdaTagsCommand
|
|
36
|
+
} from '@aws-sdk/client-lambda';
|
|
37
|
+
import {
|
|
38
|
+
ElasticLoadBalancingClient,
|
|
39
|
+
paginateDescribeLoadBalancers as paginateDescribeClassicLoadBalancers,
|
|
40
|
+
DescribeTagsCommand as DescribeClassicLBTagsCommand
|
|
41
|
+
} from '@aws-sdk/client-elastic-load-balancing';
|
|
42
|
+
import {
|
|
43
|
+
ElasticLoadBalancingV2Client,
|
|
44
|
+
paginateDescribeLoadBalancers,
|
|
45
|
+
paginateDescribeTargetGroups,
|
|
46
|
+
DescribeTagsCommand as DescribeELBv2TagsCommand
|
|
47
|
+
} from '@aws-sdk/client-elastic-load-balancing-v2';
|
|
48
|
+
import {
|
|
49
|
+
DynamoDBClient,
|
|
50
|
+
paginateListTables,
|
|
51
|
+
DescribeTableCommand,
|
|
52
|
+
ListTagsOfResourceCommand as ListDynamoDBTagsCommand
|
|
53
|
+
} from '@aws-sdk/client-dynamodb';
|
|
54
|
+
import {
|
|
55
|
+
SQSClient,
|
|
56
|
+
paginateListQueues,
|
|
57
|
+
GetQueueAttributesCommand,
|
|
58
|
+
ListQueueTagsCommand
|
|
59
|
+
} from '@aws-sdk/client-sqs';
|
|
60
|
+
import {
|
|
61
|
+
SNSClient,
|
|
62
|
+
paginateListTopics,
|
|
63
|
+
GetTopicAttributesCommand,
|
|
64
|
+
ListTagsForResourceCommand as ListSNSTagsCommand
|
|
65
|
+
} from '@aws-sdk/client-sns';
|
|
66
|
+
import {
|
|
67
|
+
ECSClient,
|
|
68
|
+
paginateListClusters,
|
|
69
|
+
paginateListServices,
|
|
70
|
+
paginateListTaskDefinitions,
|
|
71
|
+
DescribeServicesCommand,
|
|
72
|
+
DescribeTaskDefinitionCommand,
|
|
73
|
+
ListTagsForResourceCommand as ListECSTagsCommand
|
|
74
|
+
} from '@aws-sdk/client-ecs';
|
|
75
|
+
import {
|
|
76
|
+
EKSClient,
|
|
77
|
+
paginateListClusters as paginateListEKSClusters,
|
|
78
|
+
paginateListNodegroups,
|
|
79
|
+
DescribeClusterCommand,
|
|
80
|
+
DescribeNodegroupCommand,
|
|
81
|
+
ListTagsForResourceCommand as ListEKSTagsCommand
|
|
82
|
+
} from '@aws-sdk/client-eks';
|
|
83
|
+
import {
|
|
84
|
+
APIGatewayClient,
|
|
85
|
+
paginateGetRestApis,
|
|
86
|
+
GetTagsCommand as GetAPIGatewayTagsCommand
|
|
87
|
+
} from '@aws-sdk/client-api-gateway';
|
|
88
|
+
import {
|
|
89
|
+
ApiGatewayV2Client,
|
|
90
|
+
paginateGetApis,
|
|
91
|
+
GetTagsCommand as GetAPIGatewayV2TagsCommand
|
|
92
|
+
} from '@aws-sdk/client-apigatewayv2';
|
|
93
|
+
import {
|
|
94
|
+
CloudFrontClient,
|
|
95
|
+
paginateListDistributions,
|
|
96
|
+
ListTagsForResourceCommand as ListCloudFrontTagsCommand
|
|
97
|
+
} from '@aws-sdk/client-cloudfront';
|
|
98
|
+
import {
|
|
99
|
+
Route53Client,
|
|
100
|
+
paginateListHostedZones,
|
|
101
|
+
ListTagsForResourceCommand as ListRoute53TagsCommand
|
|
102
|
+
} from '@aws-sdk/client-route-53';
|
|
103
|
+
import {
|
|
104
|
+
KMSClient,
|
|
105
|
+
paginateListKeys,
|
|
106
|
+
DescribeKeyCommand,
|
|
107
|
+
ListResourceTagsCommand
|
|
108
|
+
} from '@aws-sdk/client-kms';
|
|
109
|
+
import {
|
|
110
|
+
SecretsManagerClient,
|
|
111
|
+
paginateListSecrets,
|
|
112
|
+
DescribeSecretCommand
|
|
113
|
+
} from '@aws-sdk/client-secrets-manager';
|
|
114
|
+
import {
|
|
115
|
+
SSMClient,
|
|
116
|
+
paginateDescribeParameters,
|
|
117
|
+
ListTagsForResourceCommand as ListSSMTagsCommand
|
|
118
|
+
} from '@aws-sdk/client-ssm';
|
|
119
|
+
import {
|
|
120
|
+
ElastiCacheClient,
|
|
121
|
+
paginateDescribeCacheClusters,
|
|
122
|
+
ListTagsForResourceCommand as ListElastiCacheTagsCommand
|
|
123
|
+
} from '@aws-sdk/client-elasticache';
|
|
124
|
+
import {
|
|
125
|
+
EFSClient,
|
|
126
|
+
paginateDescribeFileSystems,
|
|
127
|
+
DescribeTagsCommand as DescribeEFSTagsCommand
|
|
128
|
+
} from '@aws-sdk/client-efs';
|
|
129
|
+
import {
|
|
130
|
+
ECRClient,
|
|
131
|
+
paginateDescribeRepositories,
|
|
132
|
+
ListTagsForResourceCommand as ListECRTagsCommand
|
|
133
|
+
} from '@aws-sdk/client-ecr';
|
|
134
|
+
import {
|
|
135
|
+
SFNClient,
|
|
136
|
+
paginateListStateMachines,
|
|
137
|
+
ListTagsForResourceCommand as ListSFNTagsCommand
|
|
138
|
+
} from '@aws-sdk/client-sfn';
|
|
139
|
+
import {
|
|
140
|
+
EventBridgeClient,
|
|
141
|
+
paginateListEventBuses,
|
|
142
|
+
paginateListRules,
|
|
143
|
+
ListTagsForResourceCommand as ListEventBridgeTagsCommand
|
|
144
|
+
} from '@aws-sdk/client-eventbridge';
|
|
145
|
+
import {
|
|
146
|
+
CloudWatchClient,
|
|
147
|
+
paginateDescribeAlarms,
|
|
148
|
+
ListTagsForResourceCommand as ListCloudWatchTagsCommand
|
|
149
|
+
} from '@aws-sdk/client-cloudwatch';
|
|
150
|
+
import {
|
|
151
|
+
CloudWatchLogsClient,
|
|
152
|
+
paginateDescribeLogGroups,
|
|
153
|
+
ListTagsForResourceCommand as ListCWLogsTagsCommand
|
|
154
|
+
} from '@aws-sdk/client-cloudwatch-logs';
|
|
155
|
+
import {
|
|
156
|
+
CloudTrailClient,
|
|
157
|
+
paginateListTrails,
|
|
158
|
+
GetTrailCommand,
|
|
159
|
+
ListTagsCommand as ListCloudTrailTagsCommand
|
|
160
|
+
} from '@aws-sdk/client-cloudtrail';
|
|
161
|
+
import {
|
|
162
|
+
ConfigServiceClient,
|
|
163
|
+
DescribeConfigurationRecordersCommand,
|
|
164
|
+
DescribeDeliveryChannelsCommand
|
|
165
|
+
} from '@aws-sdk/client-config-service';
|
|
166
|
+
import {
|
|
167
|
+
ACMClient,
|
|
168
|
+
paginateListCertificates,
|
|
169
|
+
DescribeCertificateCommand,
|
|
170
|
+
ListTagsForCertificateCommand
|
|
171
|
+
} from '@aws-sdk/client-acm';
|
|
172
|
+
import {
|
|
173
|
+
WAFClient,
|
|
174
|
+
paginateListWebACLs as paginateListWAFWebACLs,
|
|
175
|
+
ListTagsForResourceCommand as ListWAFTagsCommand
|
|
176
|
+
} from '@aws-sdk/client-waf';
|
|
177
|
+
import {
|
|
178
|
+
WAFV2Client,
|
|
179
|
+
paginateListWebACLs as paginateListWAFV2WebACLs,
|
|
180
|
+
ListTagsForResourceCommand as ListWAFV2TagsCommand
|
|
181
|
+
} from '@aws-sdk/client-wafv2';
|
|
182
|
+
import {
|
|
183
|
+
CognitoIdentityProviderClient,
|
|
184
|
+
paginateListUserPools,
|
|
185
|
+
DescribeUserPoolCommand,
|
|
186
|
+
ListTagsForResourceCommand as ListCognitoTagsCommand
|
|
187
|
+
} from '@aws-sdk/client-cognito-identity-provider';
|
|
188
|
+
import {
|
|
189
|
+
paginateDescribeVolumes,
|
|
190
|
+
paginateDescribeSnapshots as paginateDescribeEBSSnapshots,
|
|
191
|
+
DescribeVpnConnectionsCommand,
|
|
192
|
+
DescribeCustomerGatewaysCommand,
|
|
193
|
+
DescribeTransitGatewaysCommand,
|
|
194
|
+
DescribeTransitGatewayAttachmentsCommand
|
|
195
|
+
} from '@aws-sdk/client-ec2';
|
|
196
|
+
import {
|
|
197
|
+
BackupClient,
|
|
198
|
+
paginateListBackupPlans,
|
|
199
|
+
paginateListBackupVaults,
|
|
200
|
+
ListTagsCommand as ListBackupTagsCommand
|
|
201
|
+
} from '@aws-sdk/client-backup';
|
|
202
|
+
import {
|
|
203
|
+
KinesisClient,
|
|
204
|
+
paginateListStreams,
|
|
205
|
+
DescribeStreamCommand,
|
|
206
|
+
ListTagsForStreamCommand
|
|
207
|
+
} from '@aws-sdk/client-kinesis';
|
|
208
|
+
|
|
209
|
+
import { BaseCloudDriver } from './base-driver.js';
|
|
210
|
+
|
|
211
|
+
const DEFAULT_SERVICES = [
|
|
212
|
+
'ec2', 's3', 'rds', 'iam', 'lambda',
|
|
213
|
+
'vpc', 'elb', 'alb', 'nlb',
|
|
214
|
+
'dynamodb', 'sqs', 'sns',
|
|
215
|
+
'ecs', 'eks', 'apigateway', 'cloudfront', 'route53',
|
|
216
|
+
'kms', 'secretsmanager', 'ssm',
|
|
217
|
+
'elasticache', 'efs', 'ecr',
|
|
218
|
+
'stepfunctions', 'eventbridge', 'cloudwatch', 'logs',
|
|
219
|
+
'cloudtrail', 'config', 'acm', 'waf', 'wafv2', 'cognito',
|
|
220
|
+
'ebs', 'vpn', 'transitgateway', 'backup', 'kinesis'
|
|
221
|
+
];
|
|
222
|
+
const GLOBAL_REGION = 'us-east-1';
|
|
223
|
+
|
|
224
|
+
function normaliseServiceName(name) {
|
|
225
|
+
return (name || '').toString().trim().toLowerCase();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function buildTagObject(entries, keyKey = 'Key', valueKey = 'Value') {
|
|
229
|
+
if (!Array.isArray(entries) || entries.length === 0) {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
const out = {};
|
|
233
|
+
for (const entry of entries) {
|
|
234
|
+
if (!entry || typeof entry !== 'object') continue;
|
|
235
|
+
const key = entry[keyKey];
|
|
236
|
+
if (!key) continue;
|
|
237
|
+
out[key] = entry[valueKey] ?? null;
|
|
238
|
+
}
|
|
239
|
+
return Object.keys(out).length ? out : null;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function buildCredentialProvider(credentials = {}) {
|
|
243
|
+
if (!credentials || typeof credentials !== 'object') {
|
|
244
|
+
return fromNodeProviderChain();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (credentials.accessKeyId && credentials.secretAccessKey) {
|
|
248
|
+
const staticCredentials = {
|
|
249
|
+
accessKeyId: credentials.accessKeyId,
|
|
250
|
+
secretAccessKey: credentials.secretAccessKey,
|
|
251
|
+
sessionToken: credentials.sessionToken
|
|
252
|
+
};
|
|
253
|
+
return async () => staticCredentials;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (credentials.profile) {
|
|
257
|
+
return fromIni({ profile: credentials.profile });
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (credentials.processProfile) {
|
|
261
|
+
return fromProcess({ profile: credentials.processProfile });
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return fromNodeProviderChain();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function ensureArray(value, fallback = []) {
|
|
268
|
+
if (!value) return fallback;
|
|
269
|
+
if (Array.isArray(value)) return value;
|
|
270
|
+
return [value];
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function shouldCollect(service, includeSet, excludeSet) {
|
|
274
|
+
const name = normaliseServiceName(service);
|
|
275
|
+
if (excludeSet.has(name)) return false;
|
|
276
|
+
if (includeSet.size > 0 && !includeSet.has(name)) return false;
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function extractEc2Tags(instance) {
|
|
281
|
+
if (!instance?.Tags) return null;
|
|
282
|
+
const tags = {};
|
|
283
|
+
for (const { Key, Value } of instance.Tags) {
|
|
284
|
+
if (!Key) continue;
|
|
285
|
+
tags[Key] = Value ?? null;
|
|
286
|
+
}
|
|
287
|
+
return Object.keys(tags).length ? tags : null;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export class AwsInventoryDriver extends BaseCloudDriver {
|
|
291
|
+
constructor(options = {}) {
|
|
292
|
+
super({ ...options, driver: options.driver || 'aws' });
|
|
293
|
+
this._clients = {
|
|
294
|
+
ec2: new Map(),
|
|
295
|
+
s3: null,
|
|
296
|
+
rds: new Map(),
|
|
297
|
+
iam: null,
|
|
298
|
+
lambda: new Map(),
|
|
299
|
+
sts: null,
|
|
300
|
+
elb: new Map(),
|
|
301
|
+
elbv2: new Map(),
|
|
302
|
+
dynamodb: new Map(),
|
|
303
|
+
sqs: new Map(),
|
|
304
|
+
sns: new Map(),
|
|
305
|
+
ecs: new Map(),
|
|
306
|
+
eks: new Map(),
|
|
307
|
+
apigateway: new Map(),
|
|
308
|
+
apigatewayv2: new Map(),
|
|
309
|
+
cloudfront: null,
|
|
310
|
+
route53: null,
|
|
311
|
+
kms: new Map(),
|
|
312
|
+
secretsmanager: new Map(),
|
|
313
|
+
ssm: new Map(),
|
|
314
|
+
elasticache: new Map(),
|
|
315
|
+
efs: new Map(),
|
|
316
|
+
ecr: new Map(),
|
|
317
|
+
sfn: new Map(),
|
|
318
|
+
eventbridge: new Map(),
|
|
319
|
+
cloudwatch: new Map(),
|
|
320
|
+
logs: new Map(),
|
|
321
|
+
cloudtrail: new Map(),
|
|
322
|
+
config: new Map(),
|
|
323
|
+
acm: new Map(),
|
|
324
|
+
waf: null,
|
|
325
|
+
wafv2: new Map(),
|
|
326
|
+
cognito: new Map(),
|
|
327
|
+
backup: new Map(),
|
|
328
|
+
kinesis: new Map()
|
|
329
|
+
};
|
|
330
|
+
this._accountId = null;
|
|
331
|
+
this._credentialProvider = buildCredentialProvider(this.credentials);
|
|
332
|
+
this._services = ensureArray(this.config?.services, DEFAULT_SERVICES)
|
|
333
|
+
.map(normaliseServiceName)
|
|
334
|
+
.filter(Boolean);
|
|
335
|
+
if (!this._services.length) {
|
|
336
|
+
this._services = [...DEFAULT_SERVICES];
|
|
337
|
+
}
|
|
338
|
+
this._regions = ensureArray(this.config?.regions, [this.config?.region || GLOBAL_REGION]);
|
|
339
|
+
if (!this._regions.length) {
|
|
340
|
+
this._regions = [GLOBAL_REGION];
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
async initialize() {
|
|
345
|
+
await this._initializeSts();
|
|
346
|
+
this.logger('info', 'AWS driver initialized', {
|
|
347
|
+
accountId: this._accountId,
|
|
348
|
+
services: this._services,
|
|
349
|
+
regions: this._regions
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
async *_collectEc2Instances() {
|
|
354
|
+
for (const region of this._regions) {
|
|
355
|
+
const client = this._getEc2Client(region);
|
|
356
|
+
const paginator = paginateDescribeInstances({ client }, {});
|
|
357
|
+
for await (const page of paginator) {
|
|
358
|
+
const reservations = page.Reservations || [];
|
|
359
|
+
for (const reservation of reservations) {
|
|
360
|
+
const instances = reservation.Instances || [];
|
|
361
|
+
for (const instance of instances) {
|
|
362
|
+
const instanceId = instance.InstanceId;
|
|
363
|
+
if (!instanceId) continue;
|
|
364
|
+
yield {
|
|
365
|
+
provider: 'aws',
|
|
366
|
+
accountId: this._accountId,
|
|
367
|
+
region,
|
|
368
|
+
service: 'ec2',
|
|
369
|
+
resourceType: 'ec2.instance',
|
|
370
|
+
resourceId: instanceId,
|
|
371
|
+
name: extractInstanceName(instance),
|
|
372
|
+
tags: extractEc2Tags(instance),
|
|
373
|
+
configuration: sanitizeConfiguration(instance)
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
async *_collectS3Buckets() {
|
|
382
|
+
const client = this._getS3Client();
|
|
383
|
+
const response = await client.send(new ListBucketsCommand({}));
|
|
384
|
+
const buckets = response.Buckets || [];
|
|
385
|
+
|
|
386
|
+
for (const bucket of buckets) {
|
|
387
|
+
const bucketName = bucket.Name;
|
|
388
|
+
if (!bucketName) continue;
|
|
389
|
+
|
|
390
|
+
const region = await this._resolveBucketRegion(client, bucketName);
|
|
391
|
+
const tags = await this._resolveBucketTags(client, bucketName);
|
|
392
|
+
|
|
393
|
+
yield {
|
|
394
|
+
provider: 'aws',
|
|
395
|
+
accountId: this._accountId,
|
|
396
|
+
region,
|
|
397
|
+
service: 's3',
|
|
398
|
+
resourceType: 's3.bucket',
|
|
399
|
+
resourceId: bucketName,
|
|
400
|
+
name: bucketName,
|
|
401
|
+
tags,
|
|
402
|
+
configuration: sanitizeConfiguration({
|
|
403
|
+
...bucket,
|
|
404
|
+
Region: region,
|
|
405
|
+
Owner: response.Owner || null
|
|
406
|
+
})
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async *_collectRdsInstances() {
|
|
412
|
+
for (const region of this._regions) {
|
|
413
|
+
const client = this._getRdsClient(region);
|
|
414
|
+
const paginator = paginateDescribeDBInstances({ client }, {});
|
|
415
|
+
for await (const page of paginator) {
|
|
416
|
+
const instances = page.DBInstances || [];
|
|
417
|
+
for (const instance of instances) {
|
|
418
|
+
const resourceId = instance.DbiResourceId || instance.DBInstanceIdentifier;
|
|
419
|
+
if (!resourceId) continue;
|
|
420
|
+
const arn = instance.DBInstanceArn;
|
|
421
|
+
const tags = await this._safeListTagsForResource(client, arn);
|
|
422
|
+
yield {
|
|
423
|
+
provider: 'aws',
|
|
424
|
+
accountId: this._accountId,
|
|
425
|
+
region,
|
|
426
|
+
service: 'rds',
|
|
427
|
+
resourceType: 'rds.instance',
|
|
428
|
+
resourceId,
|
|
429
|
+
name: instance.DBInstanceIdentifier || resourceId,
|
|
430
|
+
tags,
|
|
431
|
+
configuration: sanitizeConfiguration(instance)
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
async *_collectIamIdentities() {
|
|
439
|
+
const client = this._getIamClient();
|
|
440
|
+
const userPaginator = paginateListUsers({ client }, {});
|
|
441
|
+
for await (const page of userPaginator) {
|
|
442
|
+
const users = page.Users || [];
|
|
443
|
+
for (const user of users) {
|
|
444
|
+
const tags = await this._safeListIamTags(client, new ListUserTagsCommand({ UserName: user.UserName }));
|
|
445
|
+
yield {
|
|
446
|
+
provider: 'aws',
|
|
447
|
+
accountId: this._accountId,
|
|
448
|
+
region: null,
|
|
449
|
+
service: 'iam',
|
|
450
|
+
resourceType: 'iam.user',
|
|
451
|
+
resourceId: user.Arn || user.UserId || user.UserName,
|
|
452
|
+
name: user.UserName,
|
|
453
|
+
tags,
|
|
454
|
+
configuration: sanitizeConfiguration(user)
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const rolePaginator = paginateListRoles({ client }, {});
|
|
460
|
+
for await (const page of rolePaginator) {
|
|
461
|
+
const roles = page.Roles || [];
|
|
462
|
+
for (const role of roles) {
|
|
463
|
+
const tags = await this._safeListIamTags(client, new ListRoleTagsCommand({ RoleName: role.RoleName }));
|
|
464
|
+
yield {
|
|
465
|
+
provider: 'aws',
|
|
466
|
+
accountId: this._accountId,
|
|
467
|
+
region: null,
|
|
468
|
+
service: 'iam',
|
|
469
|
+
resourceType: 'iam.role',
|
|
470
|
+
resourceId: role.Arn || role.RoleId || role.RoleName,
|
|
471
|
+
name: role.RoleName,
|
|
472
|
+
tags,
|
|
473
|
+
configuration: sanitizeConfiguration(role)
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
async *_collectLambdaFunctions() {
|
|
480
|
+
for (const region of this._regions) {
|
|
481
|
+
const client = this._getLambdaClient(region);
|
|
482
|
+
const paginator = paginateListFunctions({ client }, {});
|
|
483
|
+
for await (const page of paginator) {
|
|
484
|
+
const functions = page.Functions || [];
|
|
485
|
+
for (const lambda of functions) {
|
|
486
|
+
const arn = lambda.FunctionArn;
|
|
487
|
+
let tags = null;
|
|
488
|
+
if (arn) {
|
|
489
|
+
tags = await this._safeListLambdaTags(client, arn);
|
|
490
|
+
}
|
|
491
|
+
yield {
|
|
492
|
+
provider: 'aws',
|
|
493
|
+
accountId: this._accountId,
|
|
494
|
+
region,
|
|
495
|
+
service: 'lambda',
|
|
496
|
+
resourceType: 'lambda.function',
|
|
497
|
+
resourceId: arn || lambda.FunctionName,
|
|
498
|
+
name: lambda.FunctionName,
|
|
499
|
+
tags,
|
|
500
|
+
configuration: sanitizeConfiguration(lambda)
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
async *_collectVpcResources() {
|
|
508
|
+
for (const region of this._regions) {
|
|
509
|
+
const client = this._getEc2Client(region);
|
|
510
|
+
|
|
511
|
+
// VPCs
|
|
512
|
+
const vpcPaginator = paginateDescribeVpcs({ client }, {});
|
|
513
|
+
for await (const page of vpcPaginator) {
|
|
514
|
+
const vpcs = page.Vpcs || [];
|
|
515
|
+
for (const vpc of vpcs) {
|
|
516
|
+
yield {
|
|
517
|
+
provider: 'aws',
|
|
518
|
+
accountId: this._accountId,
|
|
519
|
+
region,
|
|
520
|
+
service: 'vpc',
|
|
521
|
+
resourceType: 'vpc.vpc',
|
|
522
|
+
resourceId: vpc.VpcId,
|
|
523
|
+
name: extractEc2Tags(vpc)?.Name || vpc.VpcId,
|
|
524
|
+
tags: extractEc2Tags(vpc),
|
|
525
|
+
configuration: sanitizeConfiguration(vpc)
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Subnets
|
|
531
|
+
const subnetPaginator = paginateDescribeSubnets({ client }, {});
|
|
532
|
+
for await (const page of subnetPaginator) {
|
|
533
|
+
const subnets = page.Subnets || [];
|
|
534
|
+
for (const subnet of subnets) {
|
|
535
|
+
yield {
|
|
536
|
+
provider: 'aws',
|
|
537
|
+
accountId: this._accountId,
|
|
538
|
+
region,
|
|
539
|
+
service: 'vpc',
|
|
540
|
+
resourceType: 'vpc.subnet',
|
|
541
|
+
resourceId: subnet.SubnetId,
|
|
542
|
+
name: extractEc2Tags(subnet)?.Name || subnet.SubnetId,
|
|
543
|
+
tags: extractEc2Tags(subnet),
|
|
544
|
+
configuration: sanitizeConfiguration(subnet)
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Security Groups
|
|
550
|
+
const sgPaginator = paginateDescribeSecurityGroups({ client }, {});
|
|
551
|
+
for await (const page of sgPaginator) {
|
|
552
|
+
const groups = page.SecurityGroups || [];
|
|
553
|
+
for (const sg of groups) {
|
|
554
|
+
yield {
|
|
555
|
+
provider: 'aws',
|
|
556
|
+
accountId: this._accountId,
|
|
557
|
+
region,
|
|
558
|
+
service: 'vpc',
|
|
559
|
+
resourceType: 'vpc.security-group',
|
|
560
|
+
resourceId: sg.GroupId,
|
|
561
|
+
name: sg.GroupName,
|
|
562
|
+
tags: extractEc2Tags(sg),
|
|
563
|
+
configuration: sanitizeConfiguration(sg)
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Route Tables
|
|
569
|
+
const rtPaginator = paginateDescribeRouteTables({ client }, {});
|
|
570
|
+
for await (const page of rtPaginator) {
|
|
571
|
+
const tables = page.RouteTables || [];
|
|
572
|
+
for (const rt of tables) {
|
|
573
|
+
yield {
|
|
574
|
+
provider: 'aws',
|
|
575
|
+
accountId: this._accountId,
|
|
576
|
+
region,
|
|
577
|
+
service: 'vpc',
|
|
578
|
+
resourceType: 'vpc.route-table',
|
|
579
|
+
resourceId: rt.RouteTableId,
|
|
580
|
+
name: extractEc2Tags(rt)?.Name || rt.RouteTableId,
|
|
581
|
+
tags: extractEc2Tags(rt),
|
|
582
|
+
configuration: sanitizeConfiguration(rt)
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Internet Gateways
|
|
588
|
+
const igwPaginator = paginateDescribeInternetGateways({ client }, {});
|
|
589
|
+
for await (const page of igwPaginator) {
|
|
590
|
+
const gateways = page.InternetGateways || [];
|
|
591
|
+
for (const igw of gateways) {
|
|
592
|
+
yield {
|
|
593
|
+
provider: 'aws',
|
|
594
|
+
accountId: this._accountId,
|
|
595
|
+
region,
|
|
596
|
+
service: 'vpc',
|
|
597
|
+
resourceType: 'vpc.internet-gateway',
|
|
598
|
+
resourceId: igw.InternetGatewayId,
|
|
599
|
+
name: extractEc2Tags(igw)?.Name || igw.InternetGatewayId,
|
|
600
|
+
tags: extractEc2Tags(igw),
|
|
601
|
+
configuration: sanitizeConfiguration(igw)
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// NAT Gateways
|
|
607
|
+
const natPaginator = paginateDescribeNatGateways({ client }, {});
|
|
608
|
+
for await (const page of natPaginator) {
|
|
609
|
+
const gateways = page.NatGateways || [];
|
|
610
|
+
for (const nat of gateways) {
|
|
611
|
+
yield {
|
|
612
|
+
provider: 'aws',
|
|
613
|
+
accountId: this._accountId,
|
|
614
|
+
region,
|
|
615
|
+
service: 'vpc',
|
|
616
|
+
resourceType: 'vpc.nat-gateway',
|
|
617
|
+
resourceId: nat.NatGatewayId,
|
|
618
|
+
name: extractEc2Tags(nat)?.Name || nat.NatGatewayId,
|
|
619
|
+
tags: extractEc2Tags(nat),
|
|
620
|
+
configuration: sanitizeConfiguration(nat)
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Network ACLs
|
|
626
|
+
const aclPaginator = paginateDescribeNetworkAcls({ client }, {});
|
|
627
|
+
for await (const page of aclPaginator) {
|
|
628
|
+
const acls = page.NetworkAcls || [];
|
|
629
|
+
for (const acl of acls) {
|
|
630
|
+
yield {
|
|
631
|
+
provider: 'aws',
|
|
632
|
+
accountId: this._accountId,
|
|
633
|
+
region,
|
|
634
|
+
service: 'vpc',
|
|
635
|
+
resourceType: 'vpc.network-acl',
|
|
636
|
+
resourceId: acl.NetworkAclId,
|
|
637
|
+
name: extractEc2Tags(acl)?.Name || acl.NetworkAclId,
|
|
638
|
+
tags: extractEc2Tags(acl),
|
|
639
|
+
configuration: sanitizeConfiguration(acl)
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
async *_collectLoadBalancers() {
|
|
647
|
+
for (const region of this._regions) {
|
|
648
|
+
// Classic Load Balancers
|
|
649
|
+
const elbClient = this._getElbClient(region);
|
|
650
|
+
const classicPaginator = paginateDescribeClassicLoadBalancers({ client: elbClient }, {});
|
|
651
|
+
for await (const page of classicPaginator) {
|
|
652
|
+
const lbs = page.LoadBalancerDescriptions || [];
|
|
653
|
+
for (const lb of lbs) {
|
|
654
|
+
const tags = await this._safeListClassicLBTags(elbClient, lb.LoadBalancerName);
|
|
655
|
+
yield {
|
|
656
|
+
provider: 'aws',
|
|
657
|
+
accountId: this._accountId,
|
|
658
|
+
region,
|
|
659
|
+
service: 'elb',
|
|
660
|
+
resourceType: 'elb.classic',
|
|
661
|
+
resourceId: lb.LoadBalancerName,
|
|
662
|
+
name: lb.LoadBalancerName,
|
|
663
|
+
tags,
|
|
664
|
+
configuration: sanitizeConfiguration(lb)
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// ALB/NLB (ELBv2)
|
|
670
|
+
const elbv2Client = this._getElbv2Client(region);
|
|
671
|
+
const v2Paginator = paginateDescribeLoadBalancers({ client: elbv2Client }, {});
|
|
672
|
+
for await (const page of v2Paginator) {
|
|
673
|
+
const lbs = page.LoadBalancers || [];
|
|
674
|
+
for (const lb of lbs) {
|
|
675
|
+
const arn = lb.LoadBalancerArn;
|
|
676
|
+
const tags = await this._safeListELBv2Tags(elbv2Client, [arn]);
|
|
677
|
+
const lbType = lb.Type === 'application' ? 'alb' : lb.Type === 'network' ? 'nlb' : 'elb';
|
|
678
|
+
yield {
|
|
679
|
+
provider: 'aws',
|
|
680
|
+
accountId: this._accountId,
|
|
681
|
+
region,
|
|
682
|
+
service: lbType,
|
|
683
|
+
resourceType: `${lbType}.load-balancer`,
|
|
684
|
+
resourceId: arn,
|
|
685
|
+
name: lb.LoadBalancerName,
|
|
686
|
+
tags,
|
|
687
|
+
configuration: sanitizeConfiguration(lb)
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// Target Groups
|
|
693
|
+
const tgPaginator = paginateDescribeTargetGroups({ client: elbv2Client }, {});
|
|
694
|
+
for await (const page of tgPaginator) {
|
|
695
|
+
const groups = page.TargetGroups || [];
|
|
696
|
+
for (const tg of groups) {
|
|
697
|
+
const arn = tg.TargetGroupArn;
|
|
698
|
+
const tags = await this._safeListELBv2Tags(elbv2Client, [arn]);
|
|
699
|
+
yield {
|
|
700
|
+
provider: 'aws',
|
|
701
|
+
accountId: this._accountId,
|
|
702
|
+
region,
|
|
703
|
+
service: 'elb',
|
|
704
|
+
resourceType: 'elb.target-group',
|
|
705
|
+
resourceId: arn,
|
|
706
|
+
name: tg.TargetGroupName,
|
|
707
|
+
tags,
|
|
708
|
+
configuration: sanitizeConfiguration(tg)
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
async *_collectDynamoDBTables() {
|
|
716
|
+
for (const region of this._regions) {
|
|
717
|
+
const client = this._getDynamoDBClient(region);
|
|
718
|
+
const paginator = paginateListTables({ client }, {});
|
|
719
|
+
for await (const page of paginator) {
|
|
720
|
+
const tables = page.TableNames || [];
|
|
721
|
+
for (const tableName of tables) {
|
|
722
|
+
const description = await client.send(new DescribeTableCommand({ TableName: tableName }));
|
|
723
|
+
const table = description.Table;
|
|
724
|
+
const arn = table?.TableArn;
|
|
725
|
+
let tags = null;
|
|
726
|
+
if (arn) {
|
|
727
|
+
tags = await this._safeListDynamoDBTags(client, arn);
|
|
728
|
+
}
|
|
729
|
+
yield {
|
|
730
|
+
provider: 'aws',
|
|
731
|
+
accountId: this._accountId,
|
|
732
|
+
region,
|
|
733
|
+
service: 'dynamodb',
|
|
734
|
+
resourceType: 'dynamodb.table',
|
|
735
|
+
resourceId: arn || tableName,
|
|
736
|
+
name: tableName,
|
|
737
|
+
tags,
|
|
738
|
+
configuration: sanitizeConfiguration(table)
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
async *_collectSQSQueues() {
|
|
746
|
+
for (const region of this._regions) {
|
|
747
|
+
const client = this._getSqsClient(region);
|
|
748
|
+
const paginator = paginateListQueues({ client }, {});
|
|
749
|
+
for await (const page of paginator) {
|
|
750
|
+
const urls = page.QueueUrls || [];
|
|
751
|
+
for (const queueUrl of urls) {
|
|
752
|
+
const attributes = await this._safeGetQueueAttributes(client, queueUrl);
|
|
753
|
+
const tags = await this._safeListQueueTags(client, queueUrl);
|
|
754
|
+
const queueName = queueUrl.split('/').pop();
|
|
755
|
+
const arn = attributes?.QueueArn;
|
|
756
|
+
yield {
|
|
757
|
+
provider: 'aws',
|
|
758
|
+
accountId: this._accountId,
|
|
759
|
+
region,
|
|
760
|
+
service: 'sqs',
|
|
761
|
+
resourceType: 'sqs.queue',
|
|
762
|
+
resourceId: arn || queueUrl,
|
|
763
|
+
name: queueName,
|
|
764
|
+
tags,
|
|
765
|
+
configuration: sanitizeConfiguration({ ...attributes, QueueUrl: queueUrl })
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
async *_collectSNSTopics() {
|
|
773
|
+
for (const region of this._regions) {
|
|
774
|
+
const client = this._getSnsClient(region);
|
|
775
|
+
const paginator = paginateListTopics({ client }, {});
|
|
776
|
+
for await (const page of paginator) {
|
|
777
|
+
const topics = page.Topics || [];
|
|
778
|
+
for (const topic of topics) {
|
|
779
|
+
const arn = topic.TopicArn;
|
|
780
|
+
const attributes = await this._safeGetTopicAttributes(client, arn);
|
|
781
|
+
const tags = await this._safeListSNSTags(client, arn);
|
|
782
|
+
const topicName = arn?.split(':').pop();
|
|
783
|
+
yield {
|
|
784
|
+
provider: 'aws',
|
|
785
|
+
accountId: this._accountId,
|
|
786
|
+
region,
|
|
787
|
+
service: 'sns',
|
|
788
|
+
resourceType: 'sns.topic',
|
|
789
|
+
resourceId: arn,
|
|
790
|
+
name: topicName,
|
|
791
|
+
tags,
|
|
792
|
+
configuration: sanitizeConfiguration({ ...attributes, TopicArn: arn })
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
async *_collectECSResources() {
|
|
800
|
+
for (const region of this._regions) {
|
|
801
|
+
const client = this._getEcsClient(region);
|
|
802
|
+
|
|
803
|
+
// ECS Clusters
|
|
804
|
+
const clusterPaginator = paginateListClusters({ client }, {});
|
|
805
|
+
for await (const page of clusterPaginator) {
|
|
806
|
+
const arns = page.clusterArns || [];
|
|
807
|
+
for (const arn of arns) {
|
|
808
|
+
const tags = await this._safeListECSTags(client, arn);
|
|
809
|
+
const name = arn.split('/').pop();
|
|
810
|
+
yield {
|
|
811
|
+
provider: 'aws',
|
|
812
|
+
accountId: this._accountId,
|
|
813
|
+
region,
|
|
814
|
+
service: 'ecs',
|
|
815
|
+
resourceType: 'ecs.cluster',
|
|
816
|
+
resourceId: arn,
|
|
817
|
+
name,
|
|
818
|
+
tags,
|
|
819
|
+
configuration: sanitizeConfiguration({ clusterArn: arn })
|
|
820
|
+
};
|
|
821
|
+
|
|
822
|
+
// Services per cluster
|
|
823
|
+
const servicePaginator = paginateListServices({ client }, { cluster: arn });
|
|
824
|
+
for await (const servicePage of servicePaginator) {
|
|
825
|
+
const serviceArns = servicePage.serviceArns || [];
|
|
826
|
+
if (serviceArns.length === 0) continue;
|
|
827
|
+
const described = await client.send(new DescribeServicesCommand({
|
|
828
|
+
cluster: arn,
|
|
829
|
+
services: serviceArns,
|
|
830
|
+
include: ['TAGS']
|
|
831
|
+
}));
|
|
832
|
+
const services = described.services || [];
|
|
833
|
+
for (const service of services) {
|
|
834
|
+
yield {
|
|
835
|
+
provider: 'aws',
|
|
836
|
+
accountId: this._accountId,
|
|
837
|
+
region,
|
|
838
|
+
service: 'ecs',
|
|
839
|
+
resourceType: 'ecs.service',
|
|
840
|
+
resourceId: service.serviceArn,
|
|
841
|
+
name: service.serviceName,
|
|
842
|
+
tags: buildTagObject(service.tags),
|
|
843
|
+
configuration: sanitizeConfiguration(service)
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// Task Definitions
|
|
851
|
+
const taskDefPaginator = paginateListTaskDefinitions({ client }, {});
|
|
852
|
+
for await (const page of taskDefPaginator) {
|
|
853
|
+
const arns = page.taskDefinitionArns || [];
|
|
854
|
+
for (const arn of arns) {
|
|
855
|
+
const described = await client.send(new DescribeTaskDefinitionCommand({
|
|
856
|
+
taskDefinition: arn,
|
|
857
|
+
include: ['TAGS']
|
|
858
|
+
}));
|
|
859
|
+
const taskDef = described.taskDefinition;
|
|
860
|
+
const tags = buildTagObject(described.tags);
|
|
861
|
+
yield {
|
|
862
|
+
provider: 'aws',
|
|
863
|
+
accountId: this._accountId,
|
|
864
|
+
region,
|
|
865
|
+
service: 'ecs',
|
|
866
|
+
resourceType: 'ecs.task-definition',
|
|
867
|
+
resourceId: taskDef?.taskDefinitionArn || arn,
|
|
868
|
+
name: taskDef?.family,
|
|
869
|
+
tags,
|
|
870
|
+
configuration: sanitizeConfiguration(taskDef)
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
async *_collectEKSClusters() {
|
|
878
|
+
for (const region of this._regions) {
|
|
879
|
+
const client = this._getEksClient(region);
|
|
880
|
+
const clusterPaginator = paginateListEKSClusters({ client }, {});
|
|
881
|
+
for await (const page of clusterPaginator) {
|
|
882
|
+
const names = page.clusters || [];
|
|
883
|
+
for (const name of names) {
|
|
884
|
+
const described = await client.send(new DescribeClusterCommand({ name }));
|
|
885
|
+
const cluster = described.cluster;
|
|
886
|
+
const arn = cluster?.arn;
|
|
887
|
+
const tags = await this._safeListEKSTags(client, arn);
|
|
888
|
+
yield {
|
|
889
|
+
provider: 'aws',
|
|
890
|
+
accountId: this._accountId,
|
|
891
|
+
region,
|
|
892
|
+
service: 'eks',
|
|
893
|
+
resourceType: 'eks.cluster',
|
|
894
|
+
resourceId: arn || name,
|
|
895
|
+
name,
|
|
896
|
+
tags,
|
|
897
|
+
configuration: sanitizeConfiguration(cluster)
|
|
898
|
+
};
|
|
899
|
+
|
|
900
|
+
// Node Groups
|
|
901
|
+
const ngPaginator = paginateListNodegroups({ client }, { clusterName: name });
|
|
902
|
+
for await (const ngPage of ngPaginator) {
|
|
903
|
+
const nodegroups = ngPage.nodegroups || [];
|
|
904
|
+
for (const ngName of nodegroups) {
|
|
905
|
+
const ngDescribed = await client.send(new DescribeNodegroupCommand({
|
|
906
|
+
clusterName: name,
|
|
907
|
+
nodegroupName: ngName
|
|
908
|
+
}));
|
|
909
|
+
const ng = ngDescribed.nodegroup;
|
|
910
|
+
const ngArn = ng?.nodegroupArn;
|
|
911
|
+
const ngTags = await this._safeListEKSTags(client, ngArn);
|
|
912
|
+
yield {
|
|
913
|
+
provider: 'aws',
|
|
914
|
+
accountId: this._accountId,
|
|
915
|
+
region,
|
|
916
|
+
service: 'eks',
|
|
917
|
+
resourceType: 'eks.nodegroup',
|
|
918
|
+
resourceId: ngArn || ngName,
|
|
919
|
+
name: ngName,
|
|
920
|
+
tags: ngTags,
|
|
921
|
+
configuration: sanitizeConfiguration(ng)
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
async *_collectAPIGateways() {
|
|
931
|
+
for (const region of this._regions) {
|
|
932
|
+
// REST APIs (v1)
|
|
933
|
+
const v1Client = this._getApiGatewayClient(region);
|
|
934
|
+
const v1Paginator = paginateGetRestApis({ client: v1Client }, {});
|
|
935
|
+
for await (const page of v1Paginator) {
|
|
936
|
+
const apis = page.items || [];
|
|
937
|
+
for (const api of apis) {
|
|
938
|
+
const tags = await this._safeGetAPIGatewayTags(v1Client, api.id);
|
|
939
|
+
yield {
|
|
940
|
+
provider: 'aws',
|
|
941
|
+
accountId: this._accountId,
|
|
942
|
+
region,
|
|
943
|
+
service: 'apigateway',
|
|
944
|
+
resourceType: 'apigateway.rest-api',
|
|
945
|
+
resourceId: api.id,
|
|
946
|
+
name: api.name,
|
|
947
|
+
tags,
|
|
948
|
+
configuration: sanitizeConfiguration(api)
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
// HTTP/WebSocket APIs (v2)
|
|
954
|
+
const v2Client = this._getApiGatewayV2Client(region);
|
|
955
|
+
const v2Paginator = paginateGetApis({ client: v2Client }, {});
|
|
956
|
+
for await (const page of v2Paginator) {
|
|
957
|
+
const apis = page.Items || [];
|
|
958
|
+
for (const api of apis) {
|
|
959
|
+
const tags = await this._safeGetAPIGatewayV2Tags(v2Client, api.ApiId);
|
|
960
|
+
const type = api.ProtocolType?.toLowerCase() || 'http';
|
|
961
|
+
yield {
|
|
962
|
+
provider: 'aws',
|
|
963
|
+
accountId: this._accountId,
|
|
964
|
+
region,
|
|
965
|
+
service: 'apigateway',
|
|
966
|
+
resourceType: `apigateway.${type}-api`,
|
|
967
|
+
resourceId: api.ApiId,
|
|
968
|
+
name: api.Name,
|
|
969
|
+
tags,
|
|
970
|
+
configuration: sanitizeConfiguration(api)
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
async *_collectCloudFrontDistributions() {
|
|
978
|
+
const client = this._getCloudFrontClient();
|
|
979
|
+
const paginator = paginateListDistributions({ client }, {});
|
|
980
|
+
for await (const page of paginator) {
|
|
981
|
+
const items = page.DistributionList?.Items || [];
|
|
982
|
+
for (const dist of items) {
|
|
983
|
+
const arn = dist.ARN;
|
|
984
|
+
const tags = await this._safeListCloudFrontTags(client, arn);
|
|
985
|
+
yield {
|
|
986
|
+
provider: 'aws',
|
|
987
|
+
accountId: this._accountId,
|
|
988
|
+
region: null,
|
|
989
|
+
service: 'cloudfront',
|
|
990
|
+
resourceType: 'cloudfront.distribution',
|
|
991
|
+
resourceId: dist.Id,
|
|
992
|
+
name: dist.DomainName,
|
|
993
|
+
tags,
|
|
994
|
+
configuration: sanitizeConfiguration(dist)
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
async *_collectRoute53HostedZones() {
|
|
1001
|
+
const client = this._getRoute53Client();
|
|
1002
|
+
const paginator = paginateListHostedZones({ client }, {});
|
|
1003
|
+
for await (const page of paginator) {
|
|
1004
|
+
const zones = page.HostedZones || [];
|
|
1005
|
+
for (const zone of zones) {
|
|
1006
|
+
const zoneId = zone.Id?.replace('/hostedzone/', '');
|
|
1007
|
+
const tags = await this._safeListRoute53Tags(client, zone.Id);
|
|
1008
|
+
yield {
|
|
1009
|
+
provider: 'aws',
|
|
1010
|
+
accountId: this._accountId,
|
|
1011
|
+
region: null,
|
|
1012
|
+
service: 'route53',
|
|
1013
|
+
resourceType: 'route53.hosted-zone',
|
|
1014
|
+
resourceId: zoneId,
|
|
1015
|
+
name: zone.Name,
|
|
1016
|
+
tags,
|
|
1017
|
+
configuration: sanitizeConfiguration(zone)
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
async *_collectKMSKeys() {
|
|
1024
|
+
for (const region of this._regions) {
|
|
1025
|
+
const client = this._getKmsClient(region);
|
|
1026
|
+
const paginator = paginateListKeys({ client }, {});
|
|
1027
|
+
for await (const page of paginator) {
|
|
1028
|
+
const keys = page.Keys || [];
|
|
1029
|
+
for (const key of keys) {
|
|
1030
|
+
const described = await client.send(new DescribeKeyCommand({ KeyId: key.KeyId }));
|
|
1031
|
+
const metadata = described.KeyMetadata;
|
|
1032
|
+
const tags = await this._safeListKMSTags(client, key.KeyId);
|
|
1033
|
+
yield {
|
|
1034
|
+
provider: 'aws',
|
|
1035
|
+
accountId: this._accountId,
|
|
1036
|
+
region,
|
|
1037
|
+
service: 'kms',
|
|
1038
|
+
resourceType: 'kms.key',
|
|
1039
|
+
resourceId: metadata?.Arn || key.KeyId,
|
|
1040
|
+
name: metadata?.Description || key.KeyId,
|
|
1041
|
+
tags,
|
|
1042
|
+
configuration: sanitizeConfiguration(metadata)
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
async *_collectSecretsManagerSecrets() {
|
|
1050
|
+
for (const region of this._regions) {
|
|
1051
|
+
const client = this._getSecretsManagerClient(region);
|
|
1052
|
+
const paginator = paginateListSecrets({ client }, {});
|
|
1053
|
+
for await (const page of paginator) {
|
|
1054
|
+
const secrets = page.SecretList || [];
|
|
1055
|
+
for (const secret of secrets) {
|
|
1056
|
+
const described = await client.send(new DescribeSecretCommand({ SecretId: secret.ARN }));
|
|
1057
|
+
const tags = buildTagObject(described.Tags);
|
|
1058
|
+
yield {
|
|
1059
|
+
provider: 'aws',
|
|
1060
|
+
accountId: this._accountId,
|
|
1061
|
+
region,
|
|
1062
|
+
service: 'secretsmanager',
|
|
1063
|
+
resourceType: 'secretsmanager.secret',
|
|
1064
|
+
resourceId: described.ARN || secret.ARN,
|
|
1065
|
+
name: described.Name || secret.Name,
|
|
1066
|
+
tags,
|
|
1067
|
+
configuration: sanitizeConfiguration(described)
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
async *_collectSSMParameters() {
|
|
1075
|
+
for (const region of this._regions) {
|
|
1076
|
+
const client = this._getSsmClient(region);
|
|
1077
|
+
const paginator = paginateDescribeParameters({ client }, {});
|
|
1078
|
+
for await (const page of paginator) {
|
|
1079
|
+
const params = page.Parameters || [];
|
|
1080
|
+
for (const param of params) {
|
|
1081
|
+
const tags = await this._safeListSSMTags(client, param.Name);
|
|
1082
|
+
yield {
|
|
1083
|
+
provider: 'aws',
|
|
1084
|
+
accountId: this._accountId,
|
|
1085
|
+
region,
|
|
1086
|
+
service: 'ssm',
|
|
1087
|
+
resourceType: 'ssm.parameter',
|
|
1088
|
+
resourceId: param.Name,
|
|
1089
|
+
name: param.Name,
|
|
1090
|
+
tags,
|
|
1091
|
+
configuration: sanitizeConfiguration(param)
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
async *_collectElastiCacheClusters() {
|
|
1099
|
+
for (const region of this._regions) {
|
|
1100
|
+
const client = this._getElastiCacheClient(region);
|
|
1101
|
+
const paginator = paginateDescribeCacheClusters({ client }, { ShowCacheNodeInfo: true });
|
|
1102
|
+
for await (const page of paginator) {
|
|
1103
|
+
const clusters = page.CacheClusters || [];
|
|
1104
|
+
for (const cluster of clusters) {
|
|
1105
|
+
const arn = cluster.ARN;
|
|
1106
|
+
const tags = await this._safeListElastiCacheTags(client, arn);
|
|
1107
|
+
yield {
|
|
1108
|
+
provider: 'aws',
|
|
1109
|
+
accountId: this._accountId,
|
|
1110
|
+
region,
|
|
1111
|
+
service: 'elasticache',
|
|
1112
|
+
resourceType: 'elasticache.cluster',
|
|
1113
|
+
resourceId: arn || cluster.CacheClusterId,
|
|
1114
|
+
name: cluster.CacheClusterId,
|
|
1115
|
+
tags,
|
|
1116
|
+
configuration: sanitizeConfiguration(cluster)
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
async *_collectEFSFileSystems() {
|
|
1124
|
+
for (const region of this._regions) {
|
|
1125
|
+
const client = this._getEfsClient(region);
|
|
1126
|
+
const paginator = paginateDescribeFileSystems({ client }, {});
|
|
1127
|
+
for await (const page of paginator) {
|
|
1128
|
+
const filesystems = page.FileSystems || [];
|
|
1129
|
+
for (const fs of filesystems) {
|
|
1130
|
+
const tags = await this._safeDescribeEFSTags(client, fs.FileSystemId);
|
|
1131
|
+
yield {
|
|
1132
|
+
provider: 'aws',
|
|
1133
|
+
accountId: this._accountId,
|
|
1134
|
+
region,
|
|
1135
|
+
service: 'efs',
|
|
1136
|
+
resourceType: 'efs.filesystem',
|
|
1137
|
+
resourceId: fs.FileSystemArn || fs.FileSystemId,
|
|
1138
|
+
name: fs.Name || fs.FileSystemId,
|
|
1139
|
+
tags,
|
|
1140
|
+
configuration: sanitizeConfiguration(fs)
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
async *_collectECRRepositories() {
|
|
1148
|
+
for (const region of this._regions) {
|
|
1149
|
+
const client = this._getEcrClient(region);
|
|
1150
|
+
const paginator = paginateDescribeRepositories({ client }, {});
|
|
1151
|
+
for await (const page of paginator) {
|
|
1152
|
+
const repos = page.repositories || [];
|
|
1153
|
+
for (const repo of repos) {
|
|
1154
|
+
const tags = await this._safeListECRTags(client, repo.repositoryArn);
|
|
1155
|
+
yield {
|
|
1156
|
+
provider: 'aws',
|
|
1157
|
+
accountId: this._accountId,
|
|
1158
|
+
region,
|
|
1159
|
+
service: 'ecr',
|
|
1160
|
+
resourceType: 'ecr.repository',
|
|
1161
|
+
resourceId: repo.repositoryArn,
|
|
1162
|
+
name: repo.repositoryName,
|
|
1163
|
+
tags,
|
|
1164
|
+
configuration: sanitizeConfiguration(repo)
|
|
1165
|
+
};
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
async *_collectStepFunctionsStateMachines() {
|
|
1172
|
+
for (const region of this._regions) {
|
|
1173
|
+
const client = this._getSfnClient(region);
|
|
1174
|
+
const paginator = paginateListStateMachines({ client }, {});
|
|
1175
|
+
for await (const page of paginator) {
|
|
1176
|
+
const machines = page.stateMachines || [];
|
|
1177
|
+
for (const machine of machines) {
|
|
1178
|
+
const tags = await this._safeListSFNTags(client, machine.stateMachineArn);
|
|
1179
|
+
yield {
|
|
1180
|
+
provider: 'aws',
|
|
1181
|
+
accountId: this._accountId,
|
|
1182
|
+
region,
|
|
1183
|
+
service: 'stepfunctions',
|
|
1184
|
+
resourceType: 'stepfunctions.statemachine',
|
|
1185
|
+
resourceId: machine.stateMachineArn,
|
|
1186
|
+
name: machine.name,
|
|
1187
|
+
tags,
|
|
1188
|
+
configuration: sanitizeConfiguration(machine)
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
async *_collectEventBridgeResources() {
|
|
1196
|
+
for (const region of this._regions) {
|
|
1197
|
+
const client = this._getEventBridgeClient(region);
|
|
1198
|
+
|
|
1199
|
+
// Event Buses
|
|
1200
|
+
const busPaginator = paginateListEventBuses({ client }, {});
|
|
1201
|
+
for await (const page of busPaginator) {
|
|
1202
|
+
const buses = page.EventBuses || [];
|
|
1203
|
+
for (const bus of buses) {
|
|
1204
|
+
const tags = await this._safeListEventBridgeTags(client, bus.Arn);
|
|
1205
|
+
yield {
|
|
1206
|
+
provider: 'aws',
|
|
1207
|
+
accountId: this._accountId,
|
|
1208
|
+
region,
|
|
1209
|
+
service: 'eventbridge',
|
|
1210
|
+
resourceType: 'eventbridge.bus',
|
|
1211
|
+
resourceId: bus.Arn || bus.Name,
|
|
1212
|
+
name: bus.Name,
|
|
1213
|
+
tags,
|
|
1214
|
+
configuration: sanitizeConfiguration(bus)
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
// Rules
|
|
1220
|
+
const rulePaginator = paginateListRules({ client }, {});
|
|
1221
|
+
for await (const page of rulePaginator) {
|
|
1222
|
+
const rules = page.Rules || [];
|
|
1223
|
+
for (const rule of rules) {
|
|
1224
|
+
const tags = await this._safeListEventBridgeTags(client, rule.Arn);
|
|
1225
|
+
yield {
|
|
1226
|
+
provider: 'aws',
|
|
1227
|
+
accountId: this._accountId,
|
|
1228
|
+
region,
|
|
1229
|
+
service: 'eventbridge',
|
|
1230
|
+
resourceType: 'eventbridge.rule',
|
|
1231
|
+
resourceId: rule.Arn || rule.Name,
|
|
1232
|
+
name: rule.Name,
|
|
1233
|
+
tags,
|
|
1234
|
+
configuration: sanitizeConfiguration(rule)
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
async *_collectCloudWatchResources() {
|
|
1242
|
+
for (const region of this._regions) {
|
|
1243
|
+
// CloudWatch Alarms
|
|
1244
|
+
const cwClient = this._getCloudWatchClient(region);
|
|
1245
|
+
const alarmPaginator = paginateDescribeAlarms({ client: cwClient }, {});
|
|
1246
|
+
for await (const page of alarmPaginator) {
|
|
1247
|
+
const alarms = page.MetricAlarms || [];
|
|
1248
|
+
for (const alarm of alarms) {
|
|
1249
|
+
const tags = await this._safeListCloudWatchTags(cwClient, alarm.AlarmArn);
|
|
1250
|
+
yield {
|
|
1251
|
+
provider: 'aws',
|
|
1252
|
+
accountId: this._accountId,
|
|
1253
|
+
region,
|
|
1254
|
+
service: 'cloudwatch',
|
|
1255
|
+
resourceType: 'cloudwatch.alarm',
|
|
1256
|
+
resourceId: alarm.AlarmArn || alarm.AlarmName,
|
|
1257
|
+
name: alarm.AlarmName,
|
|
1258
|
+
tags,
|
|
1259
|
+
configuration: sanitizeConfiguration(alarm)
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
// CloudWatch Log Groups
|
|
1265
|
+
const logsClient = this._getCloudWatchLogsClient(region);
|
|
1266
|
+
const logsPaginator = paginateDescribeLogGroups({ client: logsClient }, {});
|
|
1267
|
+
for await (const page of logsPaginator) {
|
|
1268
|
+
const groups = page.logGroups || [];
|
|
1269
|
+
for (const group of groups) {
|
|
1270
|
+
const tags = await this._safeListCWLogsTags(logsClient, group.logGroupName);
|
|
1271
|
+
yield {
|
|
1272
|
+
provider: 'aws',
|
|
1273
|
+
accountId: this._accountId,
|
|
1274
|
+
region,
|
|
1275
|
+
service: 'logs',
|
|
1276
|
+
resourceType: 'logs.group',
|
|
1277
|
+
resourceId: group.arn || group.logGroupName,
|
|
1278
|
+
name: group.logGroupName,
|
|
1279
|
+
tags,
|
|
1280
|
+
configuration: sanitizeConfiguration(group)
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
async *_collectCloudTrails() {
|
|
1288
|
+
for (const region of this._regions) {
|
|
1289
|
+
const client = this._getCloudTrailClient(region);
|
|
1290
|
+
const paginator = paginateListTrails({ client }, {});
|
|
1291
|
+
for await (const page of paginator) {
|
|
1292
|
+
const trails = page.Trails || [];
|
|
1293
|
+
for (const trailInfo of trails) {
|
|
1294
|
+
const described = await client.send(new GetTrailCommand({ Name: trailInfo.TrailARN || trailInfo.Name }));
|
|
1295
|
+
const trail = described.Trail;
|
|
1296
|
+
const tags = await this._safeListCloudTrailTags(client, trail?.TrailARN);
|
|
1297
|
+
yield {
|
|
1298
|
+
provider: 'aws',
|
|
1299
|
+
accountId: this._accountId,
|
|
1300
|
+
region,
|
|
1301
|
+
service: 'cloudtrail',
|
|
1302
|
+
resourceType: 'cloudtrail.trail',
|
|
1303
|
+
resourceId: trail?.TrailARN || trail?.Name,
|
|
1304
|
+
name: trail?.Name,
|
|
1305
|
+
tags,
|
|
1306
|
+
configuration: sanitizeConfiguration(trail)
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
async *_collectConfigResources() {
|
|
1314
|
+
for (const region of this._regions) {
|
|
1315
|
+
const client = this._getConfigServiceClient(region);
|
|
1316
|
+
|
|
1317
|
+
// Configuration Recorders
|
|
1318
|
+
const recorderResponse = await client.send(new DescribeConfigurationRecordersCommand({}));
|
|
1319
|
+
const recorders = recorderResponse.ConfigurationRecorders || [];
|
|
1320
|
+
for (const recorder of recorders) {
|
|
1321
|
+
yield {
|
|
1322
|
+
provider: 'aws',
|
|
1323
|
+
accountId: this._accountId,
|
|
1324
|
+
region,
|
|
1325
|
+
service: 'config',
|
|
1326
|
+
resourceType: 'config.recorder',
|
|
1327
|
+
resourceId: recorder.name,
|
|
1328
|
+
name: recorder.name,
|
|
1329
|
+
tags: null,
|
|
1330
|
+
configuration: sanitizeConfiguration(recorder)
|
|
1331
|
+
};
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// Delivery Channels
|
|
1335
|
+
const channelResponse = await client.send(new DescribeDeliveryChannelsCommand({}));
|
|
1336
|
+
const channels = channelResponse.DeliveryChannels || [];
|
|
1337
|
+
for (const channel of channels) {
|
|
1338
|
+
yield {
|
|
1339
|
+
provider: 'aws',
|
|
1340
|
+
accountId: this._accountId,
|
|
1341
|
+
region,
|
|
1342
|
+
service: 'config',
|
|
1343
|
+
resourceType: 'config.delivery-channel',
|
|
1344
|
+
resourceId: channel.name,
|
|
1345
|
+
name: channel.name,
|
|
1346
|
+
tags: null,
|
|
1347
|
+
configuration: sanitizeConfiguration(channel)
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
async *_collectACMCertificates() {
|
|
1354
|
+
for (const region of this._regions) {
|
|
1355
|
+
const client = this._getAcmClient(region);
|
|
1356
|
+
const paginator = paginateListCertificates({ client }, {});
|
|
1357
|
+
for await (const page of paginator) {
|
|
1358
|
+
const certs = page.CertificateSummaryList || [];
|
|
1359
|
+
for (const certSummary of certs) {
|
|
1360
|
+
const arn = certSummary.CertificateArn;
|
|
1361
|
+
const described = await client.send(new DescribeCertificateCommand({ CertificateArn: arn }));
|
|
1362
|
+
const cert = described.Certificate;
|
|
1363
|
+
const tags = await this._safeListACMTags(client, arn);
|
|
1364
|
+
yield {
|
|
1365
|
+
provider: 'aws',
|
|
1366
|
+
accountId: this._accountId,
|
|
1367
|
+
region,
|
|
1368
|
+
service: 'acm',
|
|
1369
|
+
resourceType: 'acm.certificate',
|
|
1370
|
+
resourceId: arn,
|
|
1371
|
+
name: cert?.DomainName,
|
|
1372
|
+
tags,
|
|
1373
|
+
configuration: sanitizeConfiguration(cert)
|
|
1374
|
+
};
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
async *_collectWAFResources() {
|
|
1381
|
+
// WAF Classic (global)
|
|
1382
|
+
const wafClient = this._getWafClient();
|
|
1383
|
+
const classicPaginator = paginateListWAFWebACLs({ client: wafClient }, {});
|
|
1384
|
+
for await (const page of classicPaginator) {
|
|
1385
|
+
const webACLs = page.WebACLs || [];
|
|
1386
|
+
for (const acl of webACLs) {
|
|
1387
|
+
const tags = await this._safeListWAFTags(wafClient, acl.WebACLId);
|
|
1388
|
+
yield {
|
|
1389
|
+
provider: 'aws',
|
|
1390
|
+
accountId: this._accountId,
|
|
1391
|
+
region: null,
|
|
1392
|
+
service: 'waf',
|
|
1393
|
+
resourceType: 'waf.webacl',
|
|
1394
|
+
resourceId: acl.WebACLId,
|
|
1395
|
+
name: acl.Name,
|
|
1396
|
+
tags,
|
|
1397
|
+
configuration: sanitizeConfiguration(acl)
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
async *_collectWAFV2Resources() {
|
|
1404
|
+
for (const region of this._regions) {
|
|
1405
|
+
const client = this._getWafv2Client(region);
|
|
1406
|
+
|
|
1407
|
+
// Regional WebACLs
|
|
1408
|
+
const regionalPaginator = paginateListWAFV2WebACLs({ client }, { Scope: 'REGIONAL' });
|
|
1409
|
+
for await (const page of regionalPaginator) {
|
|
1410
|
+
const webACLs = page.WebACLs || [];
|
|
1411
|
+
for (const acl of webACLs) {
|
|
1412
|
+
const tags = await this._safeListWAFV2Tags(client, acl.ARN);
|
|
1413
|
+
yield {
|
|
1414
|
+
provider: 'aws',
|
|
1415
|
+
accountId: this._accountId,
|
|
1416
|
+
region,
|
|
1417
|
+
service: 'wafv2',
|
|
1418
|
+
resourceType: 'wafv2.webacl',
|
|
1419
|
+
resourceId: acl.ARN,
|
|
1420
|
+
name: acl.Name,
|
|
1421
|
+
tags,
|
|
1422
|
+
configuration: sanitizeConfiguration(acl)
|
|
1423
|
+
};
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
// CloudFront WebACLs (us-east-1 only)
|
|
1429
|
+
const cfClient = this._getWafv2Client(GLOBAL_REGION);
|
|
1430
|
+
const cfPaginator = paginateListWAFV2WebACLs({ client: cfClient }, { Scope: 'CLOUDFRONT' });
|
|
1431
|
+
for await (const page of cfPaginator) {
|
|
1432
|
+
const webACLs = page.WebACLs || [];
|
|
1433
|
+
for (const acl of webACLs) {
|
|
1434
|
+
const tags = await this._safeListWAFV2Tags(cfClient, acl.ARN);
|
|
1435
|
+
yield {
|
|
1436
|
+
provider: 'aws',
|
|
1437
|
+
accountId: this._accountId,
|
|
1438
|
+
region: GLOBAL_REGION,
|
|
1439
|
+
service: 'wafv2',
|
|
1440
|
+
resourceType: 'wafv2.webacl-cloudfront',
|
|
1441
|
+
resourceId: acl.ARN,
|
|
1442
|
+
name: acl.Name,
|
|
1443
|
+
tags,
|
|
1444
|
+
configuration: sanitizeConfiguration(acl)
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
async *_collectCognitoUserPools() {
|
|
1451
|
+
for (const region of this._regions) {
|
|
1452
|
+
const client = this._getCognitoClient(region);
|
|
1453
|
+
const paginator = paginateListUserPools({ client }, { MaxResults: 60 });
|
|
1454
|
+
for await (const page of paginator) {
|
|
1455
|
+
const pools = page.UserPools || [];
|
|
1456
|
+
for (const pool of pools) {
|
|
1457
|
+
const described = await client.send(new DescribeUserPoolCommand({ UserPoolId: pool.Id }));
|
|
1458
|
+
const fullPool = described.UserPool;
|
|
1459
|
+
const tags = await this._safeListCognitoTags(client, fullPool?.Arn);
|
|
1460
|
+
yield {
|
|
1461
|
+
provider: 'aws',
|
|
1462
|
+
accountId: this._accountId,
|
|
1463
|
+
region,
|
|
1464
|
+
service: 'cognito',
|
|
1465
|
+
resourceType: 'cognito.userpool',
|
|
1466
|
+
resourceId: fullPool?.Arn || pool.Id,
|
|
1467
|
+
name: pool.Name,
|
|
1468
|
+
tags,
|
|
1469
|
+
configuration: sanitizeConfiguration(fullPool)
|
|
1470
|
+
};
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
async *_collectEBSResources() {
|
|
1477
|
+
for (const region of this._regions) {
|
|
1478
|
+
const client = this._getEc2Client(region);
|
|
1479
|
+
|
|
1480
|
+
// EBS Volumes
|
|
1481
|
+
const volPaginator = paginateDescribeVolumes({ client }, {});
|
|
1482
|
+
for await (const page of volPaginator) {
|
|
1483
|
+
const volumes = page.Volumes || [];
|
|
1484
|
+
for (const volume of volumes) {
|
|
1485
|
+
yield {
|
|
1486
|
+
provider: 'aws',
|
|
1487
|
+
accountId: this._accountId,
|
|
1488
|
+
region,
|
|
1489
|
+
service: 'ebs',
|
|
1490
|
+
resourceType: 'ebs.volume',
|
|
1491
|
+
resourceId: volume.VolumeId,
|
|
1492
|
+
name: extractEc2Tags(volume)?.Name || volume.VolumeId,
|
|
1493
|
+
tags: extractEc2Tags(volume),
|
|
1494
|
+
configuration: sanitizeConfiguration(volume)
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
// EBS Snapshots
|
|
1500
|
+
const snapPaginator = paginateDescribeEBSSnapshots({ client }, { OwnerIds: ['self'] });
|
|
1501
|
+
for await (const page of snapPaginator) {
|
|
1502
|
+
const snapshots = page.Snapshots || [];
|
|
1503
|
+
for (const snapshot of snapshots) {
|
|
1504
|
+
yield {
|
|
1505
|
+
provider: 'aws',
|
|
1506
|
+
accountId: this._accountId,
|
|
1507
|
+
region,
|
|
1508
|
+
service: 'ebs',
|
|
1509
|
+
resourceType: 'ebs.snapshot',
|
|
1510
|
+
resourceId: snapshot.SnapshotId,
|
|
1511
|
+
name: extractEc2Tags(snapshot)?.Name || snapshot.SnapshotId,
|
|
1512
|
+
tags: extractEc2Tags(snapshot),
|
|
1513
|
+
configuration: sanitizeConfiguration(snapshot)
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
async *_collectVPNResources() {
|
|
1521
|
+
for (const region of this._regions) {
|
|
1522
|
+
const client = this._getEc2Client(region);
|
|
1523
|
+
|
|
1524
|
+
// VPN Connections
|
|
1525
|
+
const vpnResult = await client.send(new DescribeVpnConnectionsCommand({}));
|
|
1526
|
+
const connections = vpnResult.VpnConnections || [];
|
|
1527
|
+
for (const vpn of connections) {
|
|
1528
|
+
yield {
|
|
1529
|
+
provider: 'aws',
|
|
1530
|
+
accountId: this._accountId,
|
|
1531
|
+
region,
|
|
1532
|
+
service: 'vpn',
|
|
1533
|
+
resourceType: 'vpn.connection',
|
|
1534
|
+
resourceId: vpn.VpnConnectionId,
|
|
1535
|
+
name: extractEc2Tags(vpn)?.Name || vpn.VpnConnectionId,
|
|
1536
|
+
tags: extractEc2Tags(vpn),
|
|
1537
|
+
configuration: sanitizeConfiguration(vpn)
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
// Customer Gateways
|
|
1542
|
+
const cgwResult = await client.send(new DescribeCustomerGatewaysCommand({}));
|
|
1543
|
+
const gateways = cgwResult.CustomerGateways || [];
|
|
1544
|
+
for (const cgw of gateways) {
|
|
1545
|
+
yield {
|
|
1546
|
+
provider: 'aws',
|
|
1547
|
+
accountId: this._accountId,
|
|
1548
|
+
region,
|
|
1549
|
+
service: 'vpn',
|
|
1550
|
+
resourceType: 'vpn.customer-gateway',
|
|
1551
|
+
resourceId: cgw.CustomerGatewayId,
|
|
1552
|
+
name: extractEc2Tags(cgw)?.Name || cgw.CustomerGatewayId,
|
|
1553
|
+
tags: extractEc2Tags(cgw),
|
|
1554
|
+
configuration: sanitizeConfiguration(cgw)
|
|
1555
|
+
};
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
async *_collectTransitGatewayResources() {
|
|
1561
|
+
for (const region of this._regions) {
|
|
1562
|
+
const client = this._getEc2Client(region);
|
|
1563
|
+
|
|
1564
|
+
// Transit Gateways
|
|
1565
|
+
const tgwResult = await client.send(new DescribeTransitGatewaysCommand({}));
|
|
1566
|
+
const gateways = tgwResult.TransitGateways || [];
|
|
1567
|
+
for (const tgw of gateways) {
|
|
1568
|
+
yield {
|
|
1569
|
+
provider: 'aws',
|
|
1570
|
+
accountId: this._accountId,
|
|
1571
|
+
region,
|
|
1572
|
+
service: 'transitgateway',
|
|
1573
|
+
resourceType: 'transitgateway.gateway',
|
|
1574
|
+
resourceId: tgw.TransitGatewayId,
|
|
1575
|
+
name: extractEc2Tags(tgw)?.Name || tgw.TransitGatewayId,
|
|
1576
|
+
tags: extractEc2Tags(tgw),
|
|
1577
|
+
configuration: sanitizeConfiguration(tgw)
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
// Transit Gateway Attachments
|
|
1582
|
+
const attResult = await client.send(new DescribeTransitGatewayAttachmentsCommand({}));
|
|
1583
|
+
const attachments = attResult.TransitGatewayAttachments || [];
|
|
1584
|
+
for (const att of attachments) {
|
|
1585
|
+
yield {
|
|
1586
|
+
provider: 'aws',
|
|
1587
|
+
accountId: this._accountId,
|
|
1588
|
+
region,
|
|
1589
|
+
service: 'transitgateway',
|
|
1590
|
+
resourceType: 'transitgateway.attachment',
|
|
1591
|
+
resourceId: att.TransitGatewayAttachmentId,
|
|
1592
|
+
name: extractEc2Tags(att)?.Name || att.TransitGatewayAttachmentId,
|
|
1593
|
+
tags: extractEc2Tags(att),
|
|
1594
|
+
configuration: sanitizeConfiguration(att)
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
async *_collectBackupResources() {
|
|
1601
|
+
for (const region of this._regions) {
|
|
1602
|
+
const client = this._getBackupClient(region);
|
|
1603
|
+
|
|
1604
|
+
// Backup Plans
|
|
1605
|
+
const planPaginator = paginateListBackupPlans({ client }, {});
|
|
1606
|
+
for await (const page of planPaginator) {
|
|
1607
|
+
const plans = page.BackupPlansList || [];
|
|
1608
|
+
for (const plan of plans) {
|
|
1609
|
+
const tags = await this._safeListBackupTags(client, plan.BackupPlanArn);
|
|
1610
|
+
yield {
|
|
1611
|
+
provider: 'aws',
|
|
1612
|
+
accountId: this._accountId,
|
|
1613
|
+
region,
|
|
1614
|
+
service: 'backup',
|
|
1615
|
+
resourceType: 'backup.plan',
|
|
1616
|
+
resourceId: plan.BackupPlanArn,
|
|
1617
|
+
name: plan.BackupPlanName,
|
|
1618
|
+
tags,
|
|
1619
|
+
configuration: sanitizeConfiguration(plan)
|
|
1620
|
+
};
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
// Backup Vaults
|
|
1625
|
+
const vaultPaginator = paginateListBackupVaults({ client }, {});
|
|
1626
|
+
for await (const page of vaultPaginator) {
|
|
1627
|
+
const vaults = page.BackupVaultList || [];
|
|
1628
|
+
for (const vault of vaults) {
|
|
1629
|
+
const tags = await this._safeListBackupTags(client, vault.BackupVaultArn);
|
|
1630
|
+
yield {
|
|
1631
|
+
provider: 'aws',
|
|
1632
|
+
accountId: this._accountId,
|
|
1633
|
+
region,
|
|
1634
|
+
service: 'backup',
|
|
1635
|
+
resourceType: 'backup.vault',
|
|
1636
|
+
resourceId: vault.BackupVaultArn,
|
|
1637
|
+
name: vault.BackupVaultName,
|
|
1638
|
+
tags,
|
|
1639
|
+
configuration: sanitizeConfiguration(vault)
|
|
1640
|
+
};
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
async *_collectKinesisStreams() {
|
|
1647
|
+
for (const region of this._regions) {
|
|
1648
|
+
const client = this._getKinesisClient(region);
|
|
1649
|
+
const paginator = paginateListStreams({ client }, {});
|
|
1650
|
+
for await (const page of paginator) {
|
|
1651
|
+
const streamNames = page.StreamNames || [];
|
|
1652
|
+
for (const streamName of streamNames) {
|
|
1653
|
+
const described = await client.send(new DescribeStreamCommand({ StreamName: streamName }));
|
|
1654
|
+
const stream = described.StreamDescription;
|
|
1655
|
+
const arn = stream?.StreamARN;
|
|
1656
|
+
const tags = await this._safeListKinesisTags(client, streamName);
|
|
1657
|
+
yield {
|
|
1658
|
+
provider: 'aws',
|
|
1659
|
+
accountId: this._accountId,
|
|
1660
|
+
region,
|
|
1661
|
+
service: 'kinesis',
|
|
1662
|
+
resourceType: 'kinesis.stream',
|
|
1663
|
+
resourceId: arn || streamName,
|
|
1664
|
+
name: streamName,
|
|
1665
|
+
tags,
|
|
1666
|
+
configuration: sanitizeConfiguration(stream)
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
async *listResources(options = {}) {
|
|
1674
|
+
const discoveryInclude = ensureArray(options.discovery?.include)
|
|
1675
|
+
.map(normaliseServiceName)
|
|
1676
|
+
.filter(Boolean);
|
|
1677
|
+
const discoveryExclude = ensureArray(options.discovery?.exclude)
|
|
1678
|
+
.map(normaliseServiceName)
|
|
1679
|
+
.filter(Boolean);
|
|
1680
|
+
|
|
1681
|
+
const includeSet = new Set(discoveryInclude);
|
|
1682
|
+
const excludeSet = new Set(discoveryExclude);
|
|
1683
|
+
|
|
1684
|
+
const runtime = options.runtime || {};
|
|
1685
|
+
const emitProgress = typeof runtime.emitProgress === 'function'
|
|
1686
|
+
? runtime.emitProgress.bind(runtime)
|
|
1687
|
+
: null;
|
|
1688
|
+
|
|
1689
|
+
const collectors = {
|
|
1690
|
+
ec2: this._collectEc2Instances.bind(this),
|
|
1691
|
+
s3: this._collectS3Buckets.bind(this),
|
|
1692
|
+
rds: this._collectRdsInstances.bind(this),
|
|
1693
|
+
iam: this._collectIamIdentities.bind(this),
|
|
1694
|
+
lambda: this._collectLambdaFunctions.bind(this),
|
|
1695
|
+
vpc: this._collectVpcResources.bind(this),
|
|
1696
|
+
elb: this._collectLoadBalancers.bind(this),
|
|
1697
|
+
alb: this._collectLoadBalancers.bind(this),
|
|
1698
|
+
nlb: this._collectLoadBalancers.bind(this),
|
|
1699
|
+
dynamodb: this._collectDynamoDBTables.bind(this),
|
|
1700
|
+
sqs: this._collectSQSQueues.bind(this),
|
|
1701
|
+
sns: this._collectSNSTopics.bind(this),
|
|
1702
|
+
ecs: this._collectECSResources.bind(this),
|
|
1703
|
+
eks: this._collectEKSClusters.bind(this),
|
|
1704
|
+
apigateway: this._collectAPIGateways.bind(this),
|
|
1705
|
+
cloudfront: this._collectCloudFrontDistributions.bind(this),
|
|
1706
|
+
route53: this._collectRoute53HostedZones.bind(this),
|
|
1707
|
+
kms: this._collectKMSKeys.bind(this),
|
|
1708
|
+
secretsmanager: this._collectSecretsManagerSecrets.bind(this),
|
|
1709
|
+
ssm: this._collectSSMParameters.bind(this),
|
|
1710
|
+
elasticache: this._collectElastiCacheClusters.bind(this),
|
|
1711
|
+
efs: this._collectEFSFileSystems.bind(this),
|
|
1712
|
+
ecr: this._collectECRRepositories.bind(this),
|
|
1713
|
+
stepfunctions: this._collectStepFunctionsStateMachines.bind(this),
|
|
1714
|
+
eventbridge: this._collectEventBridgeResources.bind(this),
|
|
1715
|
+
cloudwatch: this._collectCloudWatchResources.bind(this),
|
|
1716
|
+
logs: this._collectCloudWatchResources.bind(this),
|
|
1717
|
+
cloudtrail: this._collectCloudTrails.bind(this),
|
|
1718
|
+
config: this._collectConfigResources.bind(this),
|
|
1719
|
+
acm: this._collectACMCertificates.bind(this),
|
|
1720
|
+
waf: this._collectWAFResources.bind(this),
|
|
1721
|
+
wafv2: this._collectWAFV2Resources.bind(this),
|
|
1722
|
+
cognito: this._collectCognitoUserPools.bind(this),
|
|
1723
|
+
ebs: this._collectEBSResources.bind(this),
|
|
1724
|
+
vpn: this._collectVPNResources.bind(this),
|
|
1725
|
+
transitgateway: this._collectTransitGatewayResources.bind(this),
|
|
1726
|
+
backup: this._collectBackupResources.bind(this),
|
|
1727
|
+
kinesis: this._collectKinesisStreams.bind(this)
|
|
1728
|
+
};
|
|
1729
|
+
|
|
1730
|
+
for (const service of this._services) {
|
|
1731
|
+
if (!collectors[service]) {
|
|
1732
|
+
this.logger('debug', 'AWS service collector not implemented, skipping', { service });
|
|
1733
|
+
continue;
|
|
1734
|
+
}
|
|
1735
|
+
if (!shouldCollect(service, includeSet, excludeSet)) {
|
|
1736
|
+
this.logger('debug', 'AWS service filtered out', { service });
|
|
1737
|
+
continue;
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
try {
|
|
1741
|
+
for await (const resource of collectors[service]()) {
|
|
1742
|
+
if (emitProgress) {
|
|
1743
|
+
emitProgress({
|
|
1744
|
+
service,
|
|
1745
|
+
resourceId: resource.resourceId,
|
|
1746
|
+
resourceType: resource.resourceType
|
|
1747
|
+
});
|
|
1748
|
+
}
|
|
1749
|
+
yield resource;
|
|
1750
|
+
}
|
|
1751
|
+
} catch (err) {
|
|
1752
|
+
this.logger('error', 'AWS service collection failed, skipping to next service', {
|
|
1753
|
+
service,
|
|
1754
|
+
error: err.message,
|
|
1755
|
+
errorName: err.name,
|
|
1756
|
+
stack: err.stack
|
|
1757
|
+
});
|
|
1758
|
+
// Continue with next service instead of failing entire sync
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
async _initializeSts() {
|
|
1764
|
+
if (this._accountId) return;
|
|
1765
|
+
const client = this._getStsClient();
|
|
1766
|
+
const response = await client.send(new GetCallerIdentityCommand({}));
|
|
1767
|
+
this._accountId = response.Account || null;
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
_getStsClient() {
|
|
1771
|
+
if (!this._clients.sts) {
|
|
1772
|
+
this._clients.sts = new STSClient({
|
|
1773
|
+
region: this.config?.region || GLOBAL_REGION,
|
|
1774
|
+
credentials: this._credentialProvider
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1777
|
+
return this._clients.sts;
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
_getEc2Client(region) {
|
|
1781
|
+
if (!this._clients.ec2.has(region)) {
|
|
1782
|
+
this._clients.ec2.set(region, new EC2Client({
|
|
1783
|
+
region,
|
|
1784
|
+
credentials: this._credentialProvider
|
|
1785
|
+
}));
|
|
1786
|
+
}
|
|
1787
|
+
return this._clients.ec2.get(region);
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
_getS3Client() {
|
|
1791
|
+
if (!this._clients.s3) {
|
|
1792
|
+
this._clients.s3 = new S3Client({
|
|
1793
|
+
region: this.config?.s3Region || GLOBAL_REGION,
|
|
1794
|
+
credentials: this._credentialProvider
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
return this._clients.s3;
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
_getRdsClient(region) {
|
|
1801
|
+
if (!this._clients.rds.has(region)) {
|
|
1802
|
+
this._clients.rds.set(region, new RDSClient({
|
|
1803
|
+
region,
|
|
1804
|
+
credentials: this._credentialProvider
|
|
1805
|
+
}));
|
|
1806
|
+
}
|
|
1807
|
+
return this._clients.rds.get(region);
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
_getIamClient() {
|
|
1811
|
+
if (!this._clients.iam) {
|
|
1812
|
+
this._clients.iam = new IAMClient({
|
|
1813
|
+
region: this.config?.iamRegion || GLOBAL_REGION,
|
|
1814
|
+
credentials: this._credentialProvider
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
return this._clients.iam;
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
_getLambdaClient(region) {
|
|
1821
|
+
if (!this._clients.lambda.has(region)) {
|
|
1822
|
+
this._clients.lambda.set(region, new LambdaClient({
|
|
1823
|
+
region,
|
|
1824
|
+
credentials: this._credentialProvider
|
|
1825
|
+
}));
|
|
1826
|
+
}
|
|
1827
|
+
return this._clients.lambda.get(region);
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
_getElbClient(region) {
|
|
1831
|
+
if (!this._clients.elb.has(region)) {
|
|
1832
|
+
this._clients.elb.set(region, new ElasticLoadBalancingClient({
|
|
1833
|
+
region,
|
|
1834
|
+
credentials: this._credentialProvider
|
|
1835
|
+
}));
|
|
1836
|
+
}
|
|
1837
|
+
return this._clients.elb.get(region);
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
_getElbv2Client(region) {
|
|
1841
|
+
if (!this._clients.elbv2.has(region)) {
|
|
1842
|
+
this._clients.elbv2.set(region, new ElasticLoadBalancingV2Client({
|
|
1843
|
+
region,
|
|
1844
|
+
credentials: this._credentialProvider
|
|
1845
|
+
}));
|
|
1846
|
+
}
|
|
1847
|
+
return this._clients.elbv2.get(region);
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
_getDynamoDBClient(region) {
|
|
1851
|
+
if (!this._clients.dynamodb.has(region)) {
|
|
1852
|
+
this._clients.dynamodb.set(region, new DynamoDBClient({
|
|
1853
|
+
region,
|
|
1854
|
+
credentials: this._credentialProvider
|
|
1855
|
+
}));
|
|
1856
|
+
}
|
|
1857
|
+
return this._clients.dynamodb.get(region);
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
_getSqsClient(region) {
|
|
1861
|
+
if (!this._clients.sqs.has(region)) {
|
|
1862
|
+
this._clients.sqs.set(region, new SQSClient({
|
|
1863
|
+
region,
|
|
1864
|
+
credentials: this._credentialProvider
|
|
1865
|
+
}));
|
|
1866
|
+
}
|
|
1867
|
+
return this._clients.sqs.get(region);
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
_getSnsClient(region) {
|
|
1871
|
+
if (!this._clients.sns.has(region)) {
|
|
1872
|
+
this._clients.sns.set(region, new SNSClient({
|
|
1873
|
+
region,
|
|
1874
|
+
credentials: this._credentialProvider
|
|
1875
|
+
}));
|
|
1876
|
+
}
|
|
1877
|
+
return this._clients.sns.get(region);
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
_getEcsClient(region) {
|
|
1881
|
+
if (!this._clients.ecs.has(region)) {
|
|
1882
|
+
this._clients.ecs.set(region, new ECSClient({
|
|
1883
|
+
region,
|
|
1884
|
+
credentials: this._credentialProvider
|
|
1885
|
+
}));
|
|
1886
|
+
}
|
|
1887
|
+
return this._clients.ecs.get(region);
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
_getEksClient(region) {
|
|
1891
|
+
if (!this._clients.eks.has(region)) {
|
|
1892
|
+
this._clients.eks.set(region, new EKSClient({
|
|
1893
|
+
region,
|
|
1894
|
+
credentials: this._credentialProvider
|
|
1895
|
+
}));
|
|
1896
|
+
}
|
|
1897
|
+
return this._clients.eks.get(region);
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
_getApiGatewayClient(region) {
|
|
1901
|
+
if (!this._clients.apigateway.has(region)) {
|
|
1902
|
+
this._clients.apigateway.set(region, new APIGatewayClient({
|
|
1903
|
+
region,
|
|
1904
|
+
credentials: this._credentialProvider
|
|
1905
|
+
}));
|
|
1906
|
+
}
|
|
1907
|
+
return this._clients.apigateway.get(region);
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
_getApiGatewayV2Client(region) {
|
|
1911
|
+
if (!this._clients.apigatewayv2.has(region)) {
|
|
1912
|
+
this._clients.apigatewayv2.set(region, new ApiGatewayV2Client({
|
|
1913
|
+
region,
|
|
1914
|
+
credentials: this._credentialProvider
|
|
1915
|
+
}));
|
|
1916
|
+
}
|
|
1917
|
+
return this._clients.apigatewayv2.get(region);
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
_getCloudFrontClient() {
|
|
1921
|
+
if (!this._clients.cloudfront) {
|
|
1922
|
+
this._clients.cloudfront = new CloudFrontClient({
|
|
1923
|
+
region: GLOBAL_REGION,
|
|
1924
|
+
credentials: this._credentialProvider
|
|
1925
|
+
});
|
|
1926
|
+
}
|
|
1927
|
+
return this._clients.cloudfront;
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
_getRoute53Client() {
|
|
1931
|
+
if (!this._clients.route53) {
|
|
1932
|
+
this._clients.route53 = new Route53Client({
|
|
1933
|
+
region: GLOBAL_REGION,
|
|
1934
|
+
credentials: this._credentialProvider
|
|
1935
|
+
});
|
|
1936
|
+
}
|
|
1937
|
+
return this._clients.route53;
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
_getKmsClient(region) {
|
|
1941
|
+
if (!this._clients.kms.has(region)) {
|
|
1942
|
+
this._clients.kms.set(region, new KMSClient({
|
|
1943
|
+
region,
|
|
1944
|
+
credentials: this._credentialProvider
|
|
1945
|
+
}));
|
|
1946
|
+
}
|
|
1947
|
+
return this._clients.kms.get(region);
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
_getSecretsManagerClient(region) {
|
|
1951
|
+
if (!this._clients.secretsmanager.has(region)) {
|
|
1952
|
+
this._clients.secretsmanager.set(region, new SecretsManagerClient({
|
|
1953
|
+
region,
|
|
1954
|
+
credentials: this._credentialProvider
|
|
1955
|
+
}));
|
|
1956
|
+
}
|
|
1957
|
+
return this._clients.secretsmanager.get(region);
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
_getSsmClient(region) {
|
|
1961
|
+
if (!this._clients.ssm.has(region)) {
|
|
1962
|
+
this._clients.ssm.set(region, new SSMClient({
|
|
1963
|
+
region,
|
|
1964
|
+
credentials: this._credentialProvider
|
|
1965
|
+
}));
|
|
1966
|
+
}
|
|
1967
|
+
return this._clients.ssm.get(region);
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
_getElastiCacheClient(region) {
|
|
1971
|
+
if (!this._clients.elasticache.has(region)) {
|
|
1972
|
+
this._clients.elasticache.set(region, new ElastiCacheClient({
|
|
1973
|
+
region,
|
|
1974
|
+
credentials: this._credentialProvider
|
|
1975
|
+
}));
|
|
1976
|
+
}
|
|
1977
|
+
return this._clients.elasticache.get(region);
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1980
|
+
_getEfsClient(region) {
|
|
1981
|
+
if (!this._clients.efs.has(region)) {
|
|
1982
|
+
this._clients.efs.set(region, new EFSClient({
|
|
1983
|
+
region,
|
|
1984
|
+
credentials: this._credentialProvider
|
|
1985
|
+
}));
|
|
1986
|
+
}
|
|
1987
|
+
return this._clients.efs.get(region);
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
_getEcrClient(region) {
|
|
1991
|
+
if (!this._clients.ecr.has(region)) {
|
|
1992
|
+
this._clients.ecr.set(region, new ECRClient({
|
|
1993
|
+
region,
|
|
1994
|
+
credentials: this._credentialProvider
|
|
1995
|
+
}));
|
|
1996
|
+
}
|
|
1997
|
+
return this._clients.ecr.get(region);
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
_getSfnClient(region) {
|
|
2001
|
+
if (!this._clients.sfn.has(region)) {
|
|
2002
|
+
this._clients.sfn.set(region, new SFNClient({
|
|
2003
|
+
region,
|
|
2004
|
+
credentials: this._credentialProvider
|
|
2005
|
+
}));
|
|
2006
|
+
}
|
|
2007
|
+
return this._clients.sfn.get(region);
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
_getEventBridgeClient(region) {
|
|
2011
|
+
if (!this._clients.eventbridge.has(region)) {
|
|
2012
|
+
this._clients.eventbridge.set(region, new EventBridgeClient({
|
|
2013
|
+
region,
|
|
2014
|
+
credentials: this._credentialProvider
|
|
2015
|
+
}));
|
|
2016
|
+
}
|
|
2017
|
+
return this._clients.eventbridge.get(region);
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
_getCloudWatchClient(region) {
|
|
2021
|
+
if (!this._clients.cloudwatch.has(region)) {
|
|
2022
|
+
this._clients.cloudwatch.set(region, new CloudWatchClient({
|
|
2023
|
+
region,
|
|
2024
|
+
credentials: this._credentialProvider
|
|
2025
|
+
}));
|
|
2026
|
+
}
|
|
2027
|
+
return this._clients.cloudwatch.get(region);
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
_getCloudWatchLogsClient(region) {
|
|
2031
|
+
if (!this._clients.logs.has(region)) {
|
|
2032
|
+
this._clients.logs.set(region, new CloudWatchLogsClient({
|
|
2033
|
+
region,
|
|
2034
|
+
credentials: this._credentialProvider
|
|
2035
|
+
}));
|
|
2036
|
+
}
|
|
2037
|
+
return this._clients.logs.get(region);
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
_getCloudTrailClient(region) {
|
|
2041
|
+
if (!this._clients.cloudtrail.has(region)) {
|
|
2042
|
+
this._clients.cloudtrail.set(region, new CloudTrailClient({
|
|
2043
|
+
region,
|
|
2044
|
+
credentials: this._credentialProvider
|
|
2045
|
+
}));
|
|
2046
|
+
}
|
|
2047
|
+
return this._clients.cloudtrail.get(region);
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
_getConfigServiceClient(region) {
|
|
2051
|
+
if (!this._clients.config.has(region)) {
|
|
2052
|
+
this._clients.config.set(region, new ConfigServiceClient({
|
|
2053
|
+
region,
|
|
2054
|
+
credentials: this._credentialProvider
|
|
2055
|
+
}));
|
|
2056
|
+
}
|
|
2057
|
+
return this._clients.config.get(region);
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
_getAcmClient(region) {
|
|
2061
|
+
if (!this._clients.acm.has(region)) {
|
|
2062
|
+
this._clients.acm.set(region, new ACMClient({
|
|
2063
|
+
region,
|
|
2064
|
+
credentials: this._credentialProvider
|
|
2065
|
+
}));
|
|
2066
|
+
}
|
|
2067
|
+
return this._clients.acm.get(region);
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
_getWafClient() {
|
|
2071
|
+
if (!this._clients.waf) {
|
|
2072
|
+
this._clients.waf = new WAFClient({
|
|
2073
|
+
region: GLOBAL_REGION,
|
|
2074
|
+
credentials: this._credentialProvider
|
|
2075
|
+
});
|
|
2076
|
+
}
|
|
2077
|
+
return this._clients.waf;
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
_getWafv2Client(region) {
|
|
2081
|
+
if (!this._clients.wafv2.has(region)) {
|
|
2082
|
+
this._clients.wafv2.set(region, new WAFV2Client({
|
|
2083
|
+
region,
|
|
2084
|
+
credentials: this._credentialProvider
|
|
2085
|
+
}));
|
|
2086
|
+
}
|
|
2087
|
+
return this._clients.wafv2.get(region);
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
_getCognitoClient(region) {
|
|
2091
|
+
if (!this._clients.cognito.has(region)) {
|
|
2092
|
+
this._clients.cognito.set(region, new CognitoIdentityProviderClient({
|
|
2093
|
+
region,
|
|
2094
|
+
credentials: this._credentialProvider
|
|
2095
|
+
}));
|
|
2096
|
+
}
|
|
2097
|
+
return this._clients.cognito.get(region);
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
_getBackupClient(region) {
|
|
2101
|
+
if (!this._clients.backup.has(region)) {
|
|
2102
|
+
this._clients.backup.set(region, new BackupClient({
|
|
2103
|
+
region,
|
|
2104
|
+
credentials: this._credentialProvider
|
|
2105
|
+
}));
|
|
2106
|
+
}
|
|
2107
|
+
return this._clients.backup.get(region);
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
_getKinesisClient(region) {
|
|
2111
|
+
if (!this._clients.kinesis.has(region)) {
|
|
2112
|
+
this._clients.kinesis.set(region, new KinesisClient({
|
|
2113
|
+
region,
|
|
2114
|
+
credentials: this._credentialProvider
|
|
2115
|
+
}));
|
|
2116
|
+
}
|
|
2117
|
+
return this._clients.kinesis.get(region);
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
async _resolveBucketRegion(client, bucketName) {
|
|
2121
|
+
try {
|
|
2122
|
+
const output = await client.send(new GetBucketLocationCommand({ Bucket: bucketName }));
|
|
2123
|
+
if (!output?.LocationConstraint) return 'us-east-1';
|
|
2124
|
+
if (output.LocationConstraint === 'EU') return 'eu-west-1';
|
|
2125
|
+
return output.LocationConstraint;
|
|
2126
|
+
} catch (err) {
|
|
2127
|
+
this.logger('warn', 'Failed to resolve bucket region', { bucketName, error: err.message });
|
|
2128
|
+
return null;
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
async _resolveBucketTags(client, bucketName) {
|
|
2133
|
+
try {
|
|
2134
|
+
const output = await client.send(new GetBucketTaggingCommand({ Bucket: bucketName }));
|
|
2135
|
+
return buildTagObject(output?.TagSet);
|
|
2136
|
+
} catch (err) {
|
|
2137
|
+
if (err?.name === 'NoSuchTagSet' || err?.$metadata?.httpStatusCode === 404) {
|
|
2138
|
+
return null;
|
|
2139
|
+
}
|
|
2140
|
+
this.logger('warn', 'Failed to resolve bucket tags', { bucketName, error: err.message });
|
|
2141
|
+
return null;
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
async _safeListTagsForResource(client, arn) {
|
|
2146
|
+
if (!arn) return null;
|
|
2147
|
+
try {
|
|
2148
|
+
const output = await client.send(new ListTagsForResourceCommand({ ResourceName: arn }));
|
|
2149
|
+
return buildTagObject(output?.TagList);
|
|
2150
|
+
} catch (err) {
|
|
2151
|
+
this.logger('warn', 'Failed to list RDS tags', { arn, error: err.message });
|
|
2152
|
+
return null;
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
async _safeListIamTags(client, command) {
|
|
2157
|
+
try {
|
|
2158
|
+
const output = await client.send(command);
|
|
2159
|
+
return buildTagObject(output?.Tags);
|
|
2160
|
+
} catch (err) {
|
|
2161
|
+
if (err?.name === 'NoSuchEntity') {
|
|
2162
|
+
return null;
|
|
2163
|
+
}
|
|
2164
|
+
this.logger('warn', 'Failed to list IAM tags', { error: err.message });
|
|
2165
|
+
return null;
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
async _safeListLambdaTags(client, functionArn) {
|
|
2170
|
+
try {
|
|
2171
|
+
const output = await client.send(new ListLambdaTagsCommand({ Resource: functionArn }));
|
|
2172
|
+
return output?.Tags || null;
|
|
2173
|
+
} catch (err) {
|
|
2174
|
+
this.logger('warn', 'Failed to list Lambda tags', { functionArn, error: err.message });
|
|
2175
|
+
return null;
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
async _safeListClassicLBTags(client, loadBalancerName) {
|
|
2180
|
+
try {
|
|
2181
|
+
const output = await client.send(new DescribeClassicLBTagsCommand({
|
|
2182
|
+
LoadBalancerNames: [loadBalancerName]
|
|
2183
|
+
}));
|
|
2184
|
+
const tagDescriptions = output?.TagDescriptions?.[0];
|
|
2185
|
+
return buildTagObject(tagDescriptions?.Tags);
|
|
2186
|
+
} catch (err) {
|
|
2187
|
+
this.logger('warn', 'Failed to list Classic LB tags', { loadBalancerName, error: err.message });
|
|
2188
|
+
return null;
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
async _safeListELBv2Tags(client, resourceArns) {
|
|
2193
|
+
try {
|
|
2194
|
+
const output = await client.send(new DescribeELBv2TagsCommand({
|
|
2195
|
+
ResourceArns: resourceArns
|
|
2196
|
+
}));
|
|
2197
|
+
const tagDescription = output?.TagDescriptions?.[0];
|
|
2198
|
+
return buildTagObject(tagDescription?.Tags);
|
|
2199
|
+
} catch (err) {
|
|
2200
|
+
this.logger('warn', 'Failed to list ELBv2 tags', { error: err.message });
|
|
2201
|
+
return null;
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2204
|
+
|
|
2205
|
+
async _safeListDynamoDBTags(client, resourceArn) {
|
|
2206
|
+
try {
|
|
2207
|
+
const output = await client.send(new ListDynamoDBTagsCommand({
|
|
2208
|
+
ResourceArn: resourceArn
|
|
2209
|
+
}));
|
|
2210
|
+
return buildTagObject(output?.Tags);
|
|
2211
|
+
} catch (err) {
|
|
2212
|
+
this.logger('warn', 'Failed to list DynamoDB tags', { resourceArn, error: err.message });
|
|
2213
|
+
return null;
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2217
|
+
async _safeGetQueueAttributes(client, queueUrl) {
|
|
2218
|
+
try {
|
|
2219
|
+
const output = await client.send(new GetQueueAttributesCommand({
|
|
2220
|
+
QueueUrl: queueUrl,
|
|
2221
|
+
AttributeNames: ['All']
|
|
2222
|
+
}));
|
|
2223
|
+
return output?.Attributes || null;
|
|
2224
|
+
} catch (err) {
|
|
2225
|
+
this.logger('warn', 'Failed to get queue attributes', { queueUrl, error: err.message });
|
|
2226
|
+
return null;
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
async _safeListQueueTags(client, queueUrl) {
|
|
2231
|
+
try {
|
|
2232
|
+
const output = await client.send(new ListQueueTagsCommand({
|
|
2233
|
+
QueueUrl: queueUrl
|
|
2234
|
+
}));
|
|
2235
|
+
return output?.Tags || null;
|
|
2236
|
+
} catch (err) {
|
|
2237
|
+
if (err?.name === 'QueueDoesNotExist') {
|
|
2238
|
+
return null;
|
|
2239
|
+
}
|
|
2240
|
+
this.logger('warn', 'Failed to list queue tags', { queueUrl, error: err.message });
|
|
2241
|
+
return null;
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
async _safeGetTopicAttributes(client, topicArn) {
|
|
2246
|
+
try {
|
|
2247
|
+
const output = await client.send(new GetTopicAttributesCommand({
|
|
2248
|
+
TopicArn: topicArn
|
|
2249
|
+
}));
|
|
2250
|
+
return output?.Attributes || null;
|
|
2251
|
+
} catch (err) {
|
|
2252
|
+
this.logger('warn', 'Failed to get topic attributes', { topicArn, error: err.message });
|
|
2253
|
+
return null;
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
async _safeListSNSTags(client, resourceArn) {
|
|
2258
|
+
try {
|
|
2259
|
+
const output = await client.send(new ListSNSTagsCommand({
|
|
2260
|
+
ResourceArn: resourceArn
|
|
2261
|
+
}));
|
|
2262
|
+
return buildTagObject(output?.Tags);
|
|
2263
|
+
} catch (err) {
|
|
2264
|
+
this.logger('warn', 'Failed to list SNS tags', { resourceArn, error: err.message });
|
|
2265
|
+
return null;
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
async _safeListECSTags(client, resourceArn) {
|
|
2270
|
+
try {
|
|
2271
|
+
const output = await client.send(new ListECSTagsCommand({
|
|
2272
|
+
resourceArn
|
|
2273
|
+
}));
|
|
2274
|
+
return buildTagObject(output?.tags);
|
|
2275
|
+
} catch (err) {
|
|
2276
|
+
this.logger('warn', 'Failed to list ECS tags', { resourceArn, error: err.message });
|
|
2277
|
+
return null;
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2281
|
+
async _safeListEKSTags(client, resourceArn) {
|
|
2282
|
+
if (!resourceArn) return null;
|
|
2283
|
+
try {
|
|
2284
|
+
const output = await client.send(new ListEKSTagsCommand({
|
|
2285
|
+
resourceArn
|
|
2286
|
+
}));
|
|
2287
|
+
return output?.tags || null;
|
|
2288
|
+
} catch (err) {
|
|
2289
|
+
this.logger('warn', 'Failed to list EKS tags', { resourceArn, error: err.message });
|
|
2290
|
+
return null;
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
async _safeGetAPIGatewayTags(client, resourceId) {
|
|
2295
|
+
try {
|
|
2296
|
+
const output = await client.send(new GetAPIGatewayTagsCommand({
|
|
2297
|
+
resourceArn: `arn:aws:apigateway:${this._regions[0]}::/restapis/${resourceId}`
|
|
2298
|
+
}));
|
|
2299
|
+
return output?.tags || null;
|
|
2300
|
+
} catch (err) {
|
|
2301
|
+
this.logger('warn', 'Failed to get API Gateway tags', { resourceId, error: err.message });
|
|
2302
|
+
return null;
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
async _safeGetAPIGatewayV2Tags(client, resourceId) {
|
|
2307
|
+
try {
|
|
2308
|
+
const output = await client.send(new GetAPIGatewayV2TagsCommand({
|
|
2309
|
+
ResourceArn: resourceId
|
|
2310
|
+
}));
|
|
2311
|
+
return output?.Tags || null;
|
|
2312
|
+
} catch (err) {
|
|
2313
|
+
this.logger('warn', 'Failed to get API Gateway v2 tags', { resourceId, error: err.message });
|
|
2314
|
+
return null;
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2318
|
+
async _safeListCloudFrontTags(client, resourceArn) {
|
|
2319
|
+
try {
|
|
2320
|
+
const output = await client.send(new ListCloudFrontTagsCommand({
|
|
2321
|
+
Resource: resourceArn
|
|
2322
|
+
}));
|
|
2323
|
+
return buildTagObject(output?.Tags?.Items);
|
|
2324
|
+
} catch (err) {
|
|
2325
|
+
this.logger('warn', 'Failed to list CloudFront tags', { resourceArn, error: err.message });
|
|
2326
|
+
return null;
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
|
|
2330
|
+
async _safeListRoute53Tags(client, resourceId) {
|
|
2331
|
+
try {
|
|
2332
|
+
const output = await client.send(new ListRoute53TagsCommand({
|
|
2333
|
+
ResourceType: 'hostedzone',
|
|
2334
|
+
ResourceId: resourceId.replace('/hostedzone/', '')
|
|
2335
|
+
}));
|
|
2336
|
+
return buildTagObject(output?.ResourceTagSet?.Tags);
|
|
2337
|
+
} catch (err) {
|
|
2338
|
+
this.logger('warn', 'Failed to list Route53 tags', { resourceId, error: err.message });
|
|
2339
|
+
return null;
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
|
|
2343
|
+
async _safeListKMSTags(client, keyId) {
|
|
2344
|
+
try {
|
|
2345
|
+
const output = await client.send(new ListResourceTagsCommand({
|
|
2346
|
+
KeyId: keyId
|
|
2347
|
+
}));
|
|
2348
|
+
return buildTagObject(output?.Tags);
|
|
2349
|
+
} catch (err) {
|
|
2350
|
+
this.logger('warn', 'Failed to list KMS tags', { keyId, error: err.message });
|
|
2351
|
+
return null;
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
async _safeListSSMTags(client, resourceId) {
|
|
2356
|
+
try {
|
|
2357
|
+
const output = await client.send(new ListSSMTagsCommand({
|
|
2358
|
+
ResourceType: 'Parameter',
|
|
2359
|
+
ResourceId: resourceId
|
|
2360
|
+
}));
|
|
2361
|
+
return buildTagObject(output?.TagList);
|
|
2362
|
+
} catch (err) {
|
|
2363
|
+
this.logger('warn', 'Failed to list SSM tags', { resourceId, error: err.message });
|
|
2364
|
+
return null;
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
async _safeListElastiCacheTags(client, resourceArn) {
|
|
2369
|
+
if (!resourceArn) return null;
|
|
2370
|
+
try {
|
|
2371
|
+
const output = await client.send(new ListElastiCacheTagsCommand({
|
|
2372
|
+
ResourceName: resourceArn
|
|
2373
|
+
}));
|
|
2374
|
+
return buildTagObject(output?.TagList);
|
|
2375
|
+
} catch (err) {
|
|
2376
|
+
this.logger('warn', 'Failed to list ElastiCache tags', { resourceArn, error: err.message });
|
|
2377
|
+
return null;
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2381
|
+
async _safeDescribeEFSTags(client, fileSystemId) {
|
|
2382
|
+
try {
|
|
2383
|
+
const output = await client.send(new DescribeEFSTagsCommand({
|
|
2384
|
+
FileSystemId: fileSystemId
|
|
2385
|
+
}));
|
|
2386
|
+
return buildTagObject(output?.Tags);
|
|
2387
|
+
} catch (err) {
|
|
2388
|
+
this.logger('warn', 'Failed to describe EFS tags', { fileSystemId, error: err.message });
|
|
2389
|
+
return null;
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
async _safeListECRTags(client, resourceArn) {
|
|
2394
|
+
try {
|
|
2395
|
+
const output = await client.send(new ListECRTagsCommand({
|
|
2396
|
+
resourceArn
|
|
2397
|
+
}));
|
|
2398
|
+
return buildTagObject(output?.tags);
|
|
2399
|
+
} catch (err) {
|
|
2400
|
+
this.logger('warn', 'Failed to list ECR tags', { resourceArn, error: err.message });
|
|
2401
|
+
return null;
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
async _safeListSFNTags(client, resourceArn) {
|
|
2406
|
+
try {
|
|
2407
|
+
const output = await client.send(new ListSFNTagsCommand({
|
|
2408
|
+
resourceArn
|
|
2409
|
+
}));
|
|
2410
|
+
return buildTagObject(output?.tags);
|
|
2411
|
+
} catch (err) {
|
|
2412
|
+
this.logger('warn', 'Failed to list Step Functions tags', { resourceArn, error: err.message });
|
|
2413
|
+
return null;
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
|
|
2417
|
+
async _safeListEventBridgeTags(client, resourceArn) {
|
|
2418
|
+
if (!resourceArn) return null;
|
|
2419
|
+
try {
|
|
2420
|
+
const output = await client.send(new ListEventBridgeTagsCommand({
|
|
2421
|
+
ResourceARN: resourceArn
|
|
2422
|
+
}));
|
|
2423
|
+
return buildTagObject(output?.Tags);
|
|
2424
|
+
} catch (err) {
|
|
2425
|
+
this.logger('warn', 'Failed to list EventBridge tags', { resourceArn, error: err.message });
|
|
2426
|
+
return null;
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2430
|
+
async _safeListCloudWatchTags(client, resourceArn) {
|
|
2431
|
+
if (!resourceArn) return null;
|
|
2432
|
+
try {
|
|
2433
|
+
const output = await client.send(new ListCloudWatchTagsCommand({
|
|
2434
|
+
ResourceARN: resourceArn
|
|
2435
|
+
}));
|
|
2436
|
+
return buildTagObject(output?.Tags);
|
|
2437
|
+
} catch (err) {
|
|
2438
|
+
this.logger('warn', 'Failed to list CloudWatch tags', { resourceArn, error: err.message });
|
|
2439
|
+
return null;
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2443
|
+
async _safeListCWLogsTags(client, logGroupName) {
|
|
2444
|
+
try {
|
|
2445
|
+
const output = await client.send(new ListCWLogsTagsCommand({
|
|
2446
|
+
resourceArn: logGroupName
|
|
2447
|
+
}));
|
|
2448
|
+
return output?.tags || null;
|
|
2449
|
+
} catch (err) {
|
|
2450
|
+
this.logger('warn', 'Failed to list CloudWatch Logs tags', { logGroupName, error: err.message });
|
|
2451
|
+
return null;
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
|
|
2455
|
+
async _safeListCloudTrailTags(client, resourceArn) {
|
|
2456
|
+
if (!resourceArn) return null;
|
|
2457
|
+
try {
|
|
2458
|
+
const output = await client.send(new ListCloudTrailTagsCommand({
|
|
2459
|
+
ResourceIdList: [resourceArn]
|
|
2460
|
+
}));
|
|
2461
|
+
const tagsList = output?.ResourceTagList?.[0]?.TagsList;
|
|
2462
|
+
return buildTagObject(tagsList);
|
|
2463
|
+
} catch (err) {
|
|
2464
|
+
this.logger('warn', 'Failed to list CloudTrail tags', { resourceArn, error: err.message });
|
|
2465
|
+
return null;
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
async _safeListACMTags(client, certificateArn) {
|
|
2470
|
+
try {
|
|
2471
|
+
const output = await client.send(new ListTagsForCertificateCommand({
|
|
2472
|
+
CertificateArn: certificateArn
|
|
2473
|
+
}));
|
|
2474
|
+
return buildTagObject(output?.Tags);
|
|
2475
|
+
} catch (err) {
|
|
2476
|
+
this.logger('warn', 'Failed to list ACM tags', { certificateArn, error: err.message });
|
|
2477
|
+
return null;
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2481
|
+
async _safeListWAFTags(client, resourceId) {
|
|
2482
|
+
try {
|
|
2483
|
+
const output = await client.send(new ListWAFTagsCommand({
|
|
2484
|
+
ResourceARN: `arn:aws:waf::${this._accountId}:webacl/${resourceId}`
|
|
2485
|
+
}));
|
|
2486
|
+
return buildTagObject(output?.Tags);
|
|
2487
|
+
} catch (err) {
|
|
2488
|
+
this.logger('warn', 'Failed to list WAF tags', { resourceId, error: err.message });
|
|
2489
|
+
return null;
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2493
|
+
async _safeListWAFV2Tags(client, resourceArn) {
|
|
2494
|
+
try {
|
|
2495
|
+
const output = await client.send(new ListWAFV2TagsCommand({
|
|
2496
|
+
ResourceARN: resourceArn
|
|
2497
|
+
}));
|
|
2498
|
+
return buildTagObject(output?.TagInfoForResource?.TagList);
|
|
2499
|
+
} catch (err) {
|
|
2500
|
+
this.logger('warn', 'Failed to list WAFv2 tags', { resourceArn, error: err.message });
|
|
2501
|
+
return null;
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2505
|
+
async _safeListCognitoTags(client, resourceArn) {
|
|
2506
|
+
if (!resourceArn) return null;
|
|
2507
|
+
try {
|
|
2508
|
+
const output = await client.send(new ListCognitoTagsCommand({
|
|
2509
|
+
ResourceArn: resourceArn
|
|
2510
|
+
}));
|
|
2511
|
+
return output?.Tags || null;
|
|
2512
|
+
} catch (err) {
|
|
2513
|
+
this.logger('warn', 'Failed to list Cognito tags', { resourceArn, error: err.message });
|
|
2514
|
+
return null;
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2518
|
+
async _safeListBackupTags(client, resourceArn) {
|
|
2519
|
+
try {
|
|
2520
|
+
const output = await client.send(new ListBackupTagsCommand({
|
|
2521
|
+
ResourceArn: resourceArn
|
|
2522
|
+
}));
|
|
2523
|
+
return output?.Tags || null;
|
|
2524
|
+
} catch (err) {
|
|
2525
|
+
this.logger('warn', 'Failed to list Backup tags', { resourceArn, error: err.message });
|
|
2526
|
+
return null;
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2530
|
+
async _safeListKinesisTags(client, streamName) {
|
|
2531
|
+
try {
|
|
2532
|
+
const output = await client.send(new ListTagsForStreamCommand({
|
|
2533
|
+
StreamName: streamName
|
|
2534
|
+
}));
|
|
2535
|
+
return buildTagObject(output?.Tags);
|
|
2536
|
+
} catch (err) {
|
|
2537
|
+
this.logger('warn', 'Failed to list Kinesis tags', { streamName, error: err.message });
|
|
2538
|
+
return null;
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
|
|
2543
|
+
function extractInstanceName(instance) {
|
|
2544
|
+
if (!instance?.Tags) return null;
|
|
2545
|
+
const nameTag = instance.Tags.find(tag => tag.Key === 'Name');
|
|
2546
|
+
return nameTag?.Value || null;
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
function sanitizeConfiguration(payload) {
|
|
2550
|
+
if (!payload || typeof payload !== 'object') return payload;
|
|
2551
|
+
return JSON.parse(JSON.stringify(payload));
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
export default AwsInventoryDriver;
|