@cloud-copilot/iam-lens 0.1.25 → 0.1.26
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/dist/cjs/cli.js +9 -3
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/collect/client.d.ts +12 -3
- package/dist/cjs/collect/client.d.ts.map +1 -1
- package/dist/cjs/collect/client.js +237 -152
- package/dist/cjs/collect/client.js.map +1 -1
- package/dist/cjs/collect/collect.d.ts +2 -2
- package/dist/cjs/collect/collect.d.ts.map +1 -1
- package/dist/cjs/collect/collect.js +2 -2
- package/dist/cjs/collect/collect.js.map +1 -1
- package/dist/cjs/principals.d.ts +10 -0
- package/dist/cjs/principals.d.ts.map +1 -1
- package/dist/cjs/principals.js +33 -1
- package/dist/cjs/principals.js.map +1 -1
- package/dist/cjs/simulate/contextKeys.d.ts.map +1 -1
- package/dist/cjs/simulate/contextKeys.js +4 -1
- package/dist/cjs/simulate/contextKeys.js.map +1 -1
- package/dist/cjs/simulate/simulate.d.ts +1 -0
- package/dist/cjs/simulate/simulate.d.ts.map +1 -1
- package/dist/cjs/simulate/simulate.js +4 -0
- package/dist/cjs/simulate/simulate.js.map +1 -1
- package/dist/cjs/test-datasets/testClient.d.ts +2 -0
- package/dist/cjs/test-datasets/testClient.d.ts.map +1 -1
- package/dist/cjs/test-datasets/testClient.js +12 -0
- package/dist/cjs/test-datasets/testClient.js.map +1 -1
- package/dist/cjs/utils/workerScript.d.ts +8 -0
- package/dist/cjs/utils/workerScript.d.ts.map +1 -0
- package/dist/cjs/utils/workerScript.js +18 -0
- package/dist/cjs/utils/workerScript.js.map +1 -0
- package/dist/cjs/whoCan/WhoCanMainThreadWorker.d.ts +14 -0
- package/dist/cjs/whoCan/WhoCanMainThreadWorker.d.ts.map +1 -0
- package/dist/cjs/whoCan/WhoCanMainThreadWorker.js +34 -0
- package/dist/cjs/whoCan/WhoCanMainThreadWorker.js.map +1 -0
- package/dist/cjs/whoCan/WhoCanWorker.d.ts +12 -0
- package/dist/cjs/whoCan/WhoCanWorker.d.ts.map +1 -0
- package/dist/cjs/whoCan/WhoCanWorker.js +71 -0
- package/dist/cjs/whoCan/WhoCanWorker.js.map +1 -0
- package/dist/cjs/whoCan/WhoCanWorkerThreadWorker.d.ts +2 -0
- package/dist/cjs/whoCan/WhoCanWorkerThreadWorker.d.ts.map +1 -0
- package/dist/cjs/whoCan/WhoCanWorkerThreadWorker.js +46 -0
- package/dist/cjs/whoCan/WhoCanWorkerThreadWorker.js.map +1 -0
- package/dist/cjs/whoCan/whoCan.d.ts +2 -1
- package/dist/cjs/whoCan/whoCan.d.ts.map +1 -1
- package/dist/cjs/whoCan/whoCan.js +111 -77
- package/dist/cjs/whoCan/whoCan.js.map +1 -1
- package/dist/cjs/workers/ArrayStreamingWorkQueue.d.ts +15 -0
- package/dist/cjs/workers/ArrayStreamingWorkQueue.d.ts.map +1 -0
- package/dist/cjs/workers/ArrayStreamingWorkQueue.js +35 -0
- package/dist/cjs/workers/ArrayStreamingWorkQueue.js.map +1 -0
- package/dist/cjs/workers/JobRunner.d.ts +47 -0
- package/dist/cjs/workers/JobRunner.d.ts.map +1 -0
- package/dist/cjs/workers/JobRunner.js +101 -0
- package/dist/cjs/workers/JobRunner.js.map +1 -0
- package/dist/cjs/workers/RingQueue.d.ts +14 -0
- package/dist/cjs/workers/RingQueue.d.ts.map +1 -0
- package/dist/cjs/workers/RingQueue.js +43 -0
- package/dist/cjs/workers/RingQueue.js.map +1 -0
- package/dist/cjs/workers/SharedArrayBufferMainCache.d.ts +10 -0
- package/dist/cjs/workers/SharedArrayBufferMainCache.d.ts.map +1 -0
- package/dist/cjs/workers/SharedArrayBufferMainCache.js +37 -0
- package/dist/cjs/workers/SharedArrayBufferMainCache.js.map +1 -0
- package/dist/cjs/workers/SharedArrayBufferWorkerCache.d.ts +10 -0
- package/dist/cjs/workers/SharedArrayBufferWorkerCache.d.ts.map +1 -0
- package/dist/cjs/workers/SharedArrayBufferWorkerCache.js +49 -0
- package/dist/cjs/workers/SharedArrayBufferWorkerCache.js.map +1 -0
- package/dist/cjs/workers/StreamingWorkQueue.d.ts +18 -0
- package/dist/cjs/workers/StreamingWorkQueue.d.ts.map +1 -0
- package/dist/cjs/workers/StreamingWorkQueue.js +67 -0
- package/dist/cjs/workers/StreamingWorkQueue.js.map +1 -0
- package/dist/cjs/workers/buffers.d.ts +4 -0
- package/dist/cjs/workers/buffers.d.ts.map +1 -0
- package/dist/cjs/workers/buffers.js +26 -0
- package/dist/cjs/workers/buffers.js.map +1 -0
- package/dist/esm/cli.js +9 -3
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/collect/client.d.ts +12 -3
- package/dist/esm/collect/client.d.ts.map +1 -1
- package/dist/esm/collect/client.js +236 -150
- package/dist/esm/collect/client.js.map +1 -1
- package/dist/esm/collect/collect.d.ts +2 -2
- package/dist/esm/collect/collect.d.ts.map +1 -1
- package/dist/esm/collect/collect.js +2 -2
- package/dist/esm/collect/collect.js.map +1 -1
- package/dist/esm/principals.d.ts +10 -0
- package/dist/esm/principals.d.ts.map +1 -1
- package/dist/esm/principals.js +30 -1
- package/dist/esm/principals.js.map +1 -1
- package/dist/esm/simulate/contextKeys.d.ts.map +1 -1
- package/dist/esm/simulate/contextKeys.js +4 -1
- package/dist/esm/simulate/contextKeys.js.map +1 -1
- package/dist/esm/simulate/simulate.d.ts +1 -0
- package/dist/esm/simulate/simulate.d.ts.map +1 -1
- package/dist/esm/simulate/simulate.js +5 -1
- package/dist/esm/simulate/simulate.js.map +1 -1
- package/dist/esm/test-datasets/testClient.d.ts +2 -0
- package/dist/esm/test-datasets/testClient.d.ts.map +1 -1
- package/dist/esm/test-datasets/testClient.js +11 -0
- package/dist/esm/test-datasets/testClient.js.map +1 -1
- package/dist/esm/utils/workerScript.d.ts +8 -0
- package/dist/esm/utils/workerScript.d.ts.map +1 -0
- package/dist/esm/utils/workerScript.js +13 -0
- package/dist/esm/utils/workerScript.js.map +1 -0
- package/dist/esm/utils/workerScriptEsm.d.ts.map +1 -0
- package/dist/esm/whoCan/WhoCanMainThreadWorker.d.ts +14 -0
- package/dist/esm/whoCan/WhoCanMainThreadWorker.d.ts.map +1 -0
- package/dist/esm/whoCan/WhoCanMainThreadWorker.js +28 -0
- package/dist/esm/whoCan/WhoCanMainThreadWorker.js.map +1 -0
- package/dist/esm/whoCan/WhoCanWorker.d.ts +12 -0
- package/dist/esm/whoCan/WhoCanWorker.d.ts.map +1 -0
- package/dist/esm/whoCan/WhoCanWorker.js +67 -0
- package/dist/esm/whoCan/WhoCanWorker.js.map +1 -0
- package/dist/esm/whoCan/WhoCanWorkerThreadWorker.d.ts +2 -0
- package/dist/esm/whoCan/WhoCanWorkerThreadWorker.d.ts.map +1 -0
- package/dist/esm/whoCan/WhoCanWorkerThreadWorker.js +44 -0
- package/dist/esm/whoCan/WhoCanWorkerThreadWorker.js.map +1 -0
- package/dist/esm/whoCan/whoCan.d.ts +2 -1
- package/dist/esm/whoCan/whoCan.d.ts.map +1 -1
- package/dist/esm/whoCan/whoCan.js +111 -77
- package/dist/esm/whoCan/whoCan.js.map +1 -1
- package/dist/esm/workers/ArrayStreamingWorkQueue.d.ts +15 -0
- package/dist/esm/workers/ArrayStreamingWorkQueue.d.ts.map +1 -0
- package/dist/esm/workers/ArrayStreamingWorkQueue.js +31 -0
- package/dist/esm/workers/ArrayStreamingWorkQueue.js.map +1 -0
- package/dist/esm/workers/JobRunner.d.ts +47 -0
- package/dist/esm/workers/JobRunner.d.ts.map +1 -0
- package/dist/esm/workers/JobRunner.js +93 -0
- package/dist/esm/workers/JobRunner.js.map +1 -0
- package/dist/esm/workers/RingQueue.d.ts +14 -0
- package/dist/esm/workers/RingQueue.d.ts.map +1 -0
- package/dist/esm/workers/RingQueue.js +36 -0
- package/dist/esm/workers/RingQueue.js.map +1 -0
- package/dist/esm/workers/SharedArrayBufferMainCache.d.ts +10 -0
- package/dist/esm/workers/SharedArrayBufferMainCache.d.ts.map +1 -0
- package/dist/esm/workers/SharedArrayBufferMainCache.js +33 -0
- package/dist/esm/workers/SharedArrayBufferMainCache.js.map +1 -0
- package/dist/esm/workers/SharedArrayBufferWorkerCache.d.ts +10 -0
- package/dist/esm/workers/SharedArrayBufferWorkerCache.d.ts.map +1 -0
- package/dist/esm/workers/SharedArrayBufferWorkerCache.js +44 -0
- package/dist/esm/workers/SharedArrayBufferWorkerCache.js.map +1 -0
- package/dist/esm/workers/StreamingWorkQueue.d.ts +18 -0
- package/dist/esm/workers/StreamingWorkQueue.d.ts.map +1 -0
- package/dist/esm/workers/StreamingWorkQueue.js +61 -0
- package/dist/esm/workers/StreamingWorkQueue.js.map +1 -0
- package/dist/esm/workers/buffers.d.ts +4 -0
- package/dist/esm/workers/buffers.d.ts.map +1 -0
- package/dist/esm/workers/buffers.js +21 -0
- package/dist/esm/workers/buffers.js.map +1 -0
- package/package.json +6 -4
|
@@ -1,25 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.IamCollectClient = void 0;
|
|
3
|
+
exports.IamCollectClient = exports.NoCacheProvider = void 0;
|
|
4
4
|
const iam_utils_1 = require("@cloud-copilot/iam-utils");
|
|
5
|
+
class InMemoryCacheProvider {
|
|
6
|
+
cache = {};
|
|
7
|
+
async withCache(cacheKey, fetcher) {
|
|
8
|
+
if (cacheKey in this.cache) {
|
|
9
|
+
return this.cache[cacheKey];
|
|
10
|
+
}
|
|
11
|
+
const value = await fetcher();
|
|
12
|
+
this.cache[cacheKey] = value;
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
class NoCacheProvider {
|
|
17
|
+
async withCache(cacheKey, fetcher) {
|
|
18
|
+
return fetcher();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.NoCacheProvider = NoCacheProvider;
|
|
5
22
|
class IamCollectClient {
|
|
6
23
|
storageClient;
|
|
7
|
-
|
|
8
|
-
_enableCaching;
|
|
24
|
+
cacheProvider;
|
|
9
25
|
constructor(storageClient, clientOptions) {
|
|
10
26
|
this.storageClient = storageClient;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// Generic cache helper
|
|
14
|
-
async withCache(cacheKey, fetcher) {
|
|
15
|
-
if (this._enableCaching && cacheKey in this._cache) {
|
|
16
|
-
return this._cache[cacheKey];
|
|
27
|
+
if (clientOptions?.cacheProvider === undefined) {
|
|
28
|
+
this.cacheProvider = new InMemoryCacheProvider();
|
|
17
29
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this._cache[cacheKey] = value;
|
|
30
|
+
else {
|
|
31
|
+
this.cacheProvider = clientOptions.cacheProvider;
|
|
21
32
|
}
|
|
22
|
-
|
|
33
|
+
}
|
|
34
|
+
async withCache(cacheKey, fetcher) {
|
|
35
|
+
return this.cacheProvider.withCache(cacheKey, fetcher);
|
|
23
36
|
}
|
|
24
37
|
/**
|
|
25
38
|
* Checks if an account exists in the store.
|
|
@@ -27,8 +40,11 @@ class IamCollectClient {
|
|
|
27
40
|
* @returns True if the account exists, false otherwise.
|
|
28
41
|
*/
|
|
29
42
|
async accountExists(accountId) {
|
|
30
|
-
const
|
|
31
|
-
return
|
|
43
|
+
const cacheKey = `accountExists:${accountId}`;
|
|
44
|
+
return this.withCache(cacheKey, async () => {
|
|
45
|
+
const accounts = await this.storageClient.listAccountIds();
|
|
46
|
+
return accounts.includes(accountId);
|
|
47
|
+
});
|
|
32
48
|
}
|
|
33
49
|
/**
|
|
34
50
|
* Get all account IDs in the store.
|
|
@@ -36,7 +52,10 @@ class IamCollectClient {
|
|
|
36
52
|
* @returns all account IDs in the store
|
|
37
53
|
*/
|
|
38
54
|
async allAccounts() {
|
|
39
|
-
|
|
55
|
+
const cacheKey = `allAccounts`;
|
|
56
|
+
return this.withCache(cacheKey, async () => {
|
|
57
|
+
return this.storageClient.listAccountIds();
|
|
58
|
+
});
|
|
40
59
|
}
|
|
41
60
|
/**
|
|
42
61
|
* Checks if a principal exists in the store.
|
|
@@ -44,9 +63,12 @@ class IamCollectClient {
|
|
|
44
63
|
* @returns True if the principal exists, false otherwise.
|
|
45
64
|
*/
|
|
46
65
|
async principalExists(principalArn) {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
66
|
+
const cacheKey = `principalExists:${principalArn}`;
|
|
67
|
+
return this.withCache(cacheKey, async () => {
|
|
68
|
+
const accountId = (0, iam_utils_1.splitArnParts)(principalArn).accountId;
|
|
69
|
+
const principalData = await this.storageClient.getResourceMetadata(accountId, principalArn, 'metadata');
|
|
70
|
+
return !!principalData;
|
|
71
|
+
});
|
|
50
72
|
}
|
|
51
73
|
/**
|
|
52
74
|
* Gets the SCP Hierarchy for an account. The first element is the root, the last element is the account itself.
|
|
@@ -104,21 +126,24 @@ class IamCollectClient {
|
|
|
104
126
|
* @returns The OUs for the account.
|
|
105
127
|
*/
|
|
106
128
|
async getOrgUnitHierarchyForAccount(accountId) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
let ouId = await this.getOrgUnitIdForAccount(accountId);
|
|
113
|
-
ouIds.push(ouId);
|
|
114
|
-
while (ouId) {
|
|
115
|
-
const parentOuId = await this.getParentOrgUnitIdForOrgUnit(orgId, ouId);
|
|
116
|
-
if (parentOuId) {
|
|
117
|
-
ouIds.unshift(parentOuId);
|
|
129
|
+
const cacheKey = `orgUnitHierarchy:${accountId}`;
|
|
130
|
+
return this.withCache(cacheKey, async () => {
|
|
131
|
+
const orgId = await this.getOrgIdForAccount(accountId);
|
|
132
|
+
if (!orgId) {
|
|
133
|
+
return [];
|
|
118
134
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
135
|
+
const ouIds = [];
|
|
136
|
+
let ouId = await this.getOrgUnitIdForAccount(accountId);
|
|
137
|
+
ouIds.push(ouId);
|
|
138
|
+
while (ouId) {
|
|
139
|
+
const parentOuId = await this.getParentOrgUnitIdForOrgUnit(orgId, ouId);
|
|
140
|
+
if (parentOuId) {
|
|
141
|
+
ouIds.unshift(parentOuId);
|
|
142
|
+
}
|
|
143
|
+
ouId = parentOuId;
|
|
144
|
+
}
|
|
145
|
+
return ouIds;
|
|
146
|
+
});
|
|
122
147
|
}
|
|
123
148
|
/**
|
|
124
149
|
* Gets the org unit ID for an account.
|
|
@@ -126,12 +151,15 @@ class IamCollectClient {
|
|
|
126
151
|
* @returns The org unit ID for the account, or undefined if not found.
|
|
127
152
|
*/
|
|
128
153
|
async getOrgUnitIdForAccount(accountId) {
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
154
|
+
const cacheKey = `orgUnitId:${accountId}`;
|
|
155
|
+
return this.withCache(cacheKey, async () => {
|
|
156
|
+
const orgId = await this.getOrgIdForAccount(accountId);
|
|
157
|
+
if (!orgId) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
const accounts = (await this.getAccountDataForOrg(orgId));
|
|
161
|
+
return accounts[accountId].ou;
|
|
162
|
+
});
|
|
135
163
|
}
|
|
136
164
|
/**
|
|
137
165
|
* Gets the parent org unit ID for a given org unit.
|
|
@@ -140,9 +168,12 @@ class IamCollectClient {
|
|
|
140
168
|
* @returns The parent org unit ID, or undefined if not found.
|
|
141
169
|
*/
|
|
142
170
|
async getParentOrgUnitIdForOrgUnit(orgId, ouId) {
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
171
|
+
const cacheKey = `parentOrgUnit:${orgId}:${ouId}`;
|
|
172
|
+
return this.withCache(cacheKey, async () => {
|
|
173
|
+
const ouData = await this.getOrgUnitsDataForOrg(orgId);
|
|
174
|
+
const ou = ouData[ouId];
|
|
175
|
+
return ou.parent;
|
|
176
|
+
});
|
|
146
177
|
}
|
|
147
178
|
/**
|
|
148
179
|
* Gets the SCPs for an account.
|
|
@@ -159,19 +190,22 @@ class IamCollectClient {
|
|
|
159
190
|
* @returns The org policies for the account.
|
|
160
191
|
*/
|
|
161
192
|
async getOrgPoliciesForAccount(accountId, policyType) {
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
193
|
+
const cacheKey = `orgPoliciesForAccount:${accountId}:${policyType}`;
|
|
194
|
+
return this.withCache(cacheKey, async () => {
|
|
195
|
+
const orgId = await this.getOrgIdForAccount(accountId);
|
|
196
|
+
if (!orgId) {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
const accounts = (await this.getAccountDataForOrg(orgId));
|
|
200
|
+
const orgInformation = accounts[accountId];
|
|
201
|
+
const policyArns = orgInformation[policyType];
|
|
202
|
+
const policies = [];
|
|
203
|
+
for (const policyArn of policyArns) {
|
|
204
|
+
const policyInfo = await this.getOrgPolicy(orgId, policyType, policyArn);
|
|
205
|
+
policies.push(policyInfo);
|
|
206
|
+
}
|
|
207
|
+
return policies;
|
|
208
|
+
});
|
|
175
209
|
}
|
|
176
210
|
/**
|
|
177
211
|
* Gets the account data for an organization.
|
|
@@ -179,7 +213,10 @@ class IamCollectClient {
|
|
|
179
213
|
* @returns The account data for the organization.
|
|
180
214
|
*/
|
|
181
215
|
async getAccountDataForOrg(orgId) {
|
|
182
|
-
|
|
216
|
+
const cacheKey = `accountDataForOrg:${orgId}`;
|
|
217
|
+
return this.withCache(cacheKey, async () => {
|
|
218
|
+
return this.storageClient.getOrganizationMetadata(orgId, 'accounts');
|
|
219
|
+
});
|
|
183
220
|
}
|
|
184
221
|
/**
|
|
185
222
|
* Gets the org units data for an organization.
|
|
@@ -187,7 +224,10 @@ class IamCollectClient {
|
|
|
187
224
|
* @returns The org units data for the organization.
|
|
188
225
|
*/
|
|
189
226
|
async getOrgUnitsDataForOrg(orgId) {
|
|
190
|
-
|
|
227
|
+
const cacheKey = `orgUnitsDataForOrg:${orgId}`;
|
|
228
|
+
return this.withCache(cacheKey, async () => {
|
|
229
|
+
return this.storageClient.getOrganizationMetadata(orgId, 'ous');
|
|
230
|
+
});
|
|
191
231
|
}
|
|
192
232
|
/**
|
|
193
233
|
* Gets a specific org policy.
|
|
@@ -197,17 +237,20 @@ class IamCollectClient {
|
|
|
197
237
|
* @returns The org policy.
|
|
198
238
|
*/
|
|
199
239
|
async getOrgPolicy(orgId, policyType, policyArn) {
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
240
|
+
const cacheKey = `orgPolicy:${orgId}:${policyType}:${policyArn}`;
|
|
241
|
+
return this.withCache(cacheKey, async () => {
|
|
242
|
+
const policyId = policyArn.split('/').at(-1);
|
|
243
|
+
const policyData = await this.storageClient.getOrganizationPolicyMetadata(orgId, policyType, policyId, 'metadata');
|
|
244
|
+
const policyDocument = await this.storageClient.getOrganizationPolicyMetadata(orgId, policyType, policyId, 'policy');
|
|
245
|
+
if (!policyDocument) {
|
|
246
|
+
console.error(`Policy document not found for ${policyArn} in org ${orgId}`);
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
arn: policyData.arn,
|
|
250
|
+
name: policyData.name,
|
|
251
|
+
policy: policyDocument
|
|
252
|
+
};
|
|
253
|
+
});
|
|
211
254
|
}
|
|
212
255
|
/**
|
|
213
256
|
* Gets the RCPs for an account.
|
|
@@ -242,15 +285,18 @@ class IamCollectClient {
|
|
|
242
285
|
* @returns The org policies for the org unit.
|
|
243
286
|
*/
|
|
244
287
|
async getOrgPoliciesForOrgUnit(orgId, orgUnitId, policyType) {
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
288
|
+
const cacheKey = `orgPoliciesForOrgUnit:${orgId}:${orgUnitId}:${policyType}`;
|
|
289
|
+
return this.withCache(cacheKey, async () => {
|
|
290
|
+
const orgUnitInformation = await this.getOrgUnitsDataForOrg(orgId);
|
|
291
|
+
const orgUnit = orgUnitInformation[orgUnitId];
|
|
292
|
+
const orgPolicies = orgUnit[policyType];
|
|
293
|
+
const policies = [];
|
|
294
|
+
for (const policyArn of orgPolicies) {
|
|
295
|
+
const policyInfo = await this.getOrgPolicy(orgId, policyType, policyArn);
|
|
296
|
+
policies.push(policyInfo);
|
|
297
|
+
}
|
|
298
|
+
return policies;
|
|
299
|
+
});
|
|
254
300
|
}
|
|
255
301
|
/**
|
|
256
302
|
* Gets the RCPs for an org unit.
|
|
@@ -267,17 +313,23 @@ class IamCollectClient {
|
|
|
267
313
|
* @returns The org ID for the account, or undefined if not found.
|
|
268
314
|
*/
|
|
269
315
|
async getOrgIdForAccount(accountId) {
|
|
270
|
-
const index = await this.
|
|
316
|
+
const index = await this.getIndex('accounts-to-orgs', {});
|
|
271
317
|
const accountToOrgMap = index.data;
|
|
272
318
|
return accountToOrgMap[accountId];
|
|
273
319
|
}
|
|
320
|
+
async getIndex(indexName, defaultValue) {
|
|
321
|
+
const cacheKey = `index:${indexName}`;
|
|
322
|
+
return this.withCache(cacheKey, async () => {
|
|
323
|
+
return this.storageClient.getIndex(indexName, defaultValue);
|
|
324
|
+
});
|
|
325
|
+
}
|
|
274
326
|
/**
|
|
275
327
|
* Gets the account ID for a given S3 bucket name.
|
|
276
328
|
* @param bucketName The name of the bucket.
|
|
277
329
|
* @returns The account ID for the bucket, or undefined if not found.
|
|
278
330
|
*/
|
|
279
331
|
async getAccountIdForBucket(bucketName) {
|
|
280
|
-
const index = await this.
|
|
332
|
+
const index = await this.getIndex('buckets-to-accounts', {});
|
|
281
333
|
const bucketToAccountMap = index.data;
|
|
282
334
|
return bucketToAccountMap[bucketName]?.accountId;
|
|
283
335
|
}
|
|
@@ -287,7 +339,7 @@ class IamCollectClient {
|
|
|
287
339
|
* @returns The account ID for the API Gateway, or undefined if not found.
|
|
288
340
|
*/
|
|
289
341
|
async getAccountIdForRestApi(apiArn) {
|
|
290
|
-
const index = await this.
|
|
342
|
+
const index = await this.getIndex('apigateways-to-accounts', {});
|
|
291
343
|
const bucketToAccountMap = index.data;
|
|
292
344
|
return bucketToAccountMap[apiArn];
|
|
293
345
|
}
|
|
@@ -309,16 +361,19 @@ class IamCollectClient {
|
|
|
309
361
|
});
|
|
310
362
|
}
|
|
311
363
|
async getManagedPolicy(accountId, policyArn) {
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
364
|
+
const cacheKey = `managedPolicy:${accountId}:${policyArn}`;
|
|
365
|
+
return this.withCache(cacheKey, async () => {
|
|
366
|
+
const policyMetadata = await this.storageClient.getResourceMetadata(accountId, policyArn, 'metadata');
|
|
367
|
+
const policyDocument = await this.storageClient.getResourceMetadata(accountId, policyArn, 'current-policy');
|
|
368
|
+
if (!policyDocument) {
|
|
369
|
+
console.error(`Policy document not found for ${policyArn} in account ${accountId}`);
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
arn: policyMetadata.arn,
|
|
373
|
+
name: policyMetadata.name,
|
|
374
|
+
policy: policyDocument
|
|
375
|
+
};
|
|
376
|
+
});
|
|
322
377
|
}
|
|
323
378
|
/**
|
|
324
379
|
* Gets the inline policies attached to a user.
|
|
@@ -337,9 +392,12 @@ class IamCollectClient {
|
|
|
337
392
|
});
|
|
338
393
|
}
|
|
339
394
|
async getIamUserMetadata(userArn) {
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
395
|
+
const cacheKey = `iamUserMetadata:${userArn}`;
|
|
396
|
+
return this.withCache(cacheKey, async () => {
|
|
397
|
+
const accountId = (0, iam_utils_1.splitArnParts)(userArn).accountId;
|
|
398
|
+
// The permissions boundary is stored as a policy ARN on the user resource metadata
|
|
399
|
+
return this.storageClient.getResourceMetadata(accountId, userArn, 'metadata');
|
|
400
|
+
});
|
|
343
401
|
}
|
|
344
402
|
/**
|
|
345
403
|
* Gets the permissions boundary policy attached to a user, if any.
|
|
@@ -451,7 +509,10 @@ class IamCollectClient {
|
|
|
451
509
|
* @returns the metadata for the organization
|
|
452
510
|
*/
|
|
453
511
|
async getOrganizationMetadata(organizationId) {
|
|
454
|
-
|
|
512
|
+
const cacheKey = `organizationMetadata:${organizationId}`;
|
|
513
|
+
return this.withCache(cacheKey, async () => {
|
|
514
|
+
return this.storageClient.getOrganizationMetadata(organizationId, 'metadata');
|
|
515
|
+
});
|
|
455
516
|
}
|
|
456
517
|
/**
|
|
457
518
|
* Gets the resource policy for a given resource ARN and account.
|
|
@@ -461,13 +522,16 @@ class IamCollectClient {
|
|
|
461
522
|
* @returns The resource policy, or undefined if not found.
|
|
462
523
|
*/
|
|
463
524
|
async getResourcePolicyForArn(resourceArn, accountId) {
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
metadataKey = '
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
525
|
+
const cacheKey = `resourcePolicy:${accountId}:${resourceArn}`;
|
|
526
|
+
return this.withCache(cacheKey, async () => {
|
|
527
|
+
const arnParts = (0, iam_utils_1.splitArnParts)(resourceArn);
|
|
528
|
+
let metadataKey = 'policy';
|
|
529
|
+
if (arnParts.service === 'iam' && arnParts.resourceType === 'role') {
|
|
530
|
+
metadataKey = 'trust-policy';
|
|
531
|
+
}
|
|
532
|
+
const resourcePolicy = await this.storageClient.getResourceMetadata(accountId, resourceArn, metadataKey);
|
|
533
|
+
return resourcePolicy;
|
|
534
|
+
});
|
|
471
535
|
}
|
|
472
536
|
/**
|
|
473
537
|
* Gets the RAM share policy for a given resource ARN and account.
|
|
@@ -477,8 +541,11 @@ class IamCollectClient {
|
|
|
477
541
|
* @returns The RAM share policy, or undefined if not found.
|
|
478
542
|
*/
|
|
479
543
|
async getRamSharePolicyForArn(resourceArn, accountId) {
|
|
480
|
-
const
|
|
481
|
-
return
|
|
544
|
+
const cacheKey = `ramSharePolicy:${accountId}:${resourceArn}`;
|
|
545
|
+
return this.withCache(cacheKey, async () => {
|
|
546
|
+
const armSharePolicy = await this.storageClient.getRamResource(accountId, resourceArn);
|
|
547
|
+
return armSharePolicy?.policy;
|
|
548
|
+
});
|
|
482
549
|
}
|
|
483
550
|
/**
|
|
484
551
|
* Gets the tags for a given resource ARN and account.
|
|
@@ -488,8 +555,11 @@ class IamCollectClient {
|
|
|
488
555
|
* @returns The tags as a record, or undefined if not found.
|
|
489
556
|
*/
|
|
490
557
|
async getTagsForResource(resourceArn, accountId) {
|
|
491
|
-
const
|
|
492
|
-
return
|
|
558
|
+
const cacheKey = `tagsForResource:${accountId}:${resourceArn}`;
|
|
559
|
+
return this.withCache(cacheKey, async () => {
|
|
560
|
+
const tags = await this.storageClient.getResourceMetadata(accountId, resourceArn, 'tags');
|
|
561
|
+
return tags || {};
|
|
562
|
+
});
|
|
493
563
|
}
|
|
494
564
|
/**
|
|
495
565
|
* Gets a unique ID for an IAM resource based on its ARN and account ID.
|
|
@@ -500,9 +570,12 @@ class IamCollectClient {
|
|
|
500
570
|
* @returns a unique ID for the resource, or undefined if not found
|
|
501
571
|
*/
|
|
502
572
|
async getUniqueIdForIamResource(resourceArn) {
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
|
|
573
|
+
const cacheKey = `uniqueIdForIamResource:${resourceArn}`;
|
|
574
|
+
return this.withCache(cacheKey, async () => {
|
|
575
|
+
const accountId = (0, iam_utils_1.splitArnParts)(resourceArn).accountId;
|
|
576
|
+
const resourceMetadata = await this.storageClient.getResourceMetadata(accountId, resourceArn, 'metadata');
|
|
577
|
+
return resourceMetadata?.id;
|
|
578
|
+
});
|
|
506
579
|
}
|
|
507
580
|
/**
|
|
508
581
|
* Get the account IDs for an organization.
|
|
@@ -525,52 +598,61 @@ class IamCollectClient {
|
|
|
525
598
|
* @returns returns the organization structure or undefined if not found
|
|
526
599
|
*/
|
|
527
600
|
async getOrganizationStructure(orgId) {
|
|
528
|
-
|
|
601
|
+
const cacheKey = `organizationStructure:${orgId}`;
|
|
602
|
+
return this.withCache(cacheKey, async () => {
|
|
603
|
+
return this.storageClient.getOrganizationMetadata(orgId, 'structure');
|
|
604
|
+
});
|
|
529
605
|
}
|
|
530
606
|
async getAccountsForOrgPath(orgId, ouIds) {
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
// Now look through the structure to find the OU
|
|
537
|
-
let currentStructure = rootOu;
|
|
538
|
-
for (const ou of ouIds.slice(1)) {
|
|
539
|
-
currentStructure = currentStructure.children?.[ou];
|
|
540
|
-
if (!currentStructure) {
|
|
541
|
-
return [false, []]; // OU not found in the structure
|
|
607
|
+
const cacheKey = `accountsForOrgPath:${orgId}:${ouIds.join('/')}`;
|
|
608
|
+
return this.withCache(cacheKey, async () => {
|
|
609
|
+
const orgUnits = await this.getOrganizationStructure(orgId);
|
|
610
|
+
if (!orgUnits || ouIds.length === 0) {
|
|
611
|
+
return [false, []];
|
|
542
612
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
while (children.length > 0) {
|
|
552
|
-
const child = children.shift();
|
|
553
|
-
if (child?.accounts) {
|
|
554
|
-
accounts.push(...child.accounts.map(getAccountId));
|
|
613
|
+
const rootOu = orgUnits[ouIds[0]];
|
|
614
|
+
// Now look through the structure to find the OU
|
|
615
|
+
let currentStructure = rootOu;
|
|
616
|
+
for (const ou of ouIds.slice(1)) {
|
|
617
|
+
currentStructure = currentStructure.children?.[ou];
|
|
618
|
+
if (!currentStructure) {
|
|
619
|
+
return [false, []]; // OU not found in the structure
|
|
620
|
+
}
|
|
555
621
|
}
|
|
556
|
-
|
|
557
|
-
|
|
622
|
+
const getAccountId = (a) => a.split('/').at(-1);
|
|
623
|
+
const accounts = [];
|
|
624
|
+
if (currentStructure.accounts) {
|
|
625
|
+
accounts.push(...currentStructure.accounts?.map(getAccountId));
|
|
558
626
|
}
|
|
559
|
-
|
|
560
|
-
|
|
627
|
+
const children = Object.values(currentStructure.children || {});
|
|
628
|
+
// Traverse the children to collect all accounts
|
|
629
|
+
while (children.length > 0) {
|
|
630
|
+
const child = children.shift();
|
|
631
|
+
if (child?.accounts) {
|
|
632
|
+
accounts.push(...child.accounts.map(getAccountId));
|
|
633
|
+
}
|
|
634
|
+
if (child?.children) {
|
|
635
|
+
children.push(...Object.values(child.children));
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
return [true, accounts];
|
|
639
|
+
});
|
|
561
640
|
}
|
|
562
641
|
async getAllPrincipalsInAccount(accountId) {
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
642
|
+
const cacheKey = `allPrincipalsInAccount:${accountId}`;
|
|
643
|
+
return this.withCache(cacheKey, async () => {
|
|
644
|
+
const iamUsers = await this.storageClient.findResourceMetadata(accountId, {
|
|
645
|
+
service: 'iam',
|
|
646
|
+
resourceType: 'user',
|
|
647
|
+
account: accountId
|
|
648
|
+
});
|
|
649
|
+
const iamRoles = await this.storageClient.findResourceMetadata(accountId, {
|
|
650
|
+
service: 'iam',
|
|
651
|
+
resourceType: 'role',
|
|
652
|
+
account: accountId
|
|
653
|
+
});
|
|
654
|
+
return [...iamUsers.map((user) => user.arn), ...iamRoles.map((role) => role.arn)];
|
|
572
655
|
});
|
|
573
|
-
return [...iamUsers.map((user) => user.arn), ...iamRoles.map((role) => role.arn)];
|
|
574
656
|
}
|
|
575
657
|
/**
|
|
576
658
|
* Get the VPC endpoint policy for a given VPC endpoint ARN.
|
|
@@ -579,9 +661,12 @@ class IamCollectClient {
|
|
|
579
661
|
* @returns the VPC endpoint policy, or undefined if not found
|
|
580
662
|
*/
|
|
581
663
|
async getVpcEndpointPolicyForArn(vpcEndpointArn) {
|
|
582
|
-
const
|
|
583
|
-
|
|
584
|
-
|
|
664
|
+
const cacheKey = `vpcEndpointPolicy:${vpcEndpointArn}`;
|
|
665
|
+
return this.withCache(cacheKey, async () => {
|
|
666
|
+
const accountId = (0, iam_utils_1.splitArnParts)(vpcEndpointArn).accountId;
|
|
667
|
+
const vpcEndpointPolicy = await this.storageClient.getResourceMetadata(accountId, vpcEndpointArn, 'endpoint-policy');
|
|
668
|
+
return vpcEndpointPolicy;
|
|
669
|
+
});
|
|
585
670
|
}
|
|
586
671
|
/**
|
|
587
672
|
* Get the ARN of a VPC endpoint given its ID.
|
|
@@ -589,7 +674,7 @@ class IamCollectClient {
|
|
|
589
674
|
* @returns the ARN of the VPC endpoint, or undefined if not found
|
|
590
675
|
*/
|
|
591
676
|
async getVpcEndpointArnForVpcEndpointId(vpcEndpointId) {
|
|
592
|
-
const index = await this.
|
|
677
|
+
const index = await this.getIndex('vpcs', {
|
|
593
678
|
endpoints: {},
|
|
594
679
|
vpcs: {}
|
|
595
680
|
});
|
|
@@ -603,7 +688,7 @@ class IamCollectClient {
|
|
|
603
688
|
* @returns the VPC endpoint ID, or undefined if not found
|
|
604
689
|
*/
|
|
605
690
|
async getVpcEndpointIdForVpcService(vpcId, service) {
|
|
606
|
-
const index = await this.
|
|
691
|
+
const index = await this.getIndex('vpcs', {
|
|
607
692
|
endpoints: {},
|
|
608
693
|
vpcs: {}
|
|
609
694
|
});
|
|
@@ -621,7 +706,7 @@ class IamCollectClient {
|
|
|
621
706
|
* @returns the VPC ID, or undefined if not found
|
|
622
707
|
*/
|
|
623
708
|
async getVpcIdForVpcEndpointId(vpcEndpointId) {
|
|
624
|
-
const index = await this.
|
|
709
|
+
const index = await this.getIndex('vpcs', {
|
|
625
710
|
endpoints: {},
|
|
626
711
|
vpcs: {}
|
|
627
712
|
});
|