@cloud-copilot/iam-lens 0.1.25 → 0.1.27
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/canWhat/canWhat.d.ts +16 -0
- package/dist/cjs/canWhat/canWhat.d.ts.map +1 -1
- package/dist/cjs/canWhat/canWhat.js +7 -0
- package/dist/cjs/canWhat/canWhat.js.map +1 -1
- package/dist/cjs/cli.js +9 -3
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/collect/client.d.ts +81 -3
- package/dist/cjs/collect/client.d.ts.map +1 -1
- package/dist/cjs/collect/client.js +294 -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/index.d.ts +6 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +15 -0
- package/dist/cjs/index.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 +7 -0
- 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 +32 -0
- package/dist/cjs/simulate/simulate.d.ts.map +1 -1
- package/dist/cjs/simulate/simulate.js +11 -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/canWhat/canWhat.d.ts +16 -0
- package/dist/esm/canWhat/canWhat.d.ts.map +1 -1
- package/dist/esm/canWhat/canWhat.js +7 -0
- package/dist/esm/canWhat/canWhat.js.map +1 -1
- package/dist/esm/cli.js +9 -3
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/collect/client.d.ts +81 -3
- package/dist/esm/collect/client.d.ts.map +1 -1
- package/dist/esm/collect/client.js +292 -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/index.d.ts +6 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +5 -1
- package/dist/esm/index.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 +7 -0
- 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 +32 -0
- package/dist/esm/simulate/simulate.d.ts.map +1 -1
- package/dist/esm/simulate/simulate.js +12 -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,54 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.IamCollectClient = void 0;
|
|
3
|
+
exports.IamCollectClient = exports.NoCacheProvider = exports.InMemoryCacheProvider = void 0;
|
|
4
4
|
const iam_utils_1 = require("@cloud-copilot/iam-utils");
|
|
5
|
+
/**
|
|
6
|
+
* A cache provider that stores results in memory for a single worker.
|
|
7
|
+
*/
|
|
8
|
+
class InMemoryCacheProvider {
|
|
9
|
+
cache = {};
|
|
10
|
+
async withCache(cacheKey, fetcher) {
|
|
11
|
+
if (cacheKey in this.cache) {
|
|
12
|
+
return this.cache[cacheKey];
|
|
13
|
+
}
|
|
14
|
+
const value = await fetcher();
|
|
15
|
+
this.cache[cacheKey] = value;
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.InMemoryCacheProvider = InMemoryCacheProvider;
|
|
20
|
+
/**
|
|
21
|
+
* A cache provider that does not cache results.
|
|
22
|
+
*/
|
|
23
|
+
class NoCacheProvider {
|
|
24
|
+
async withCache(cacheKey, fetcher) {
|
|
25
|
+
return fetcher();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.NoCacheProvider = NoCacheProvider;
|
|
29
|
+
/**
|
|
30
|
+
* A client for simplifying access to the IAM collect data store.
|
|
31
|
+
*/
|
|
5
32
|
class IamCollectClient {
|
|
6
33
|
storageClient;
|
|
7
|
-
|
|
8
|
-
|
|
34
|
+
cacheProvider;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new instance of the IamCollectClient.
|
|
37
|
+
*
|
|
38
|
+
* @param storageClient the iam-collect storage client to use for data access
|
|
39
|
+
* @param clientOptions optional configuration options for the client. By default, uses an in-memory cache provider.
|
|
40
|
+
*/
|
|
9
41
|
constructor(storageClient, clientOptions) {
|
|
10
42
|
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];
|
|
43
|
+
if (clientOptions?.cacheProvider === undefined) {
|
|
44
|
+
this.cacheProvider = new InMemoryCacheProvider();
|
|
17
45
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this._cache[cacheKey] = value;
|
|
46
|
+
else {
|
|
47
|
+
this.cacheProvider = clientOptions.cacheProvider;
|
|
21
48
|
}
|
|
22
|
-
|
|
49
|
+
}
|
|
50
|
+
async withCache(cacheKey, fetcher) {
|
|
51
|
+
return this.cacheProvider.withCache(cacheKey, fetcher);
|
|
23
52
|
}
|
|
24
53
|
/**
|
|
25
54
|
* Checks if an account exists in the store.
|
|
@@ -27,8 +56,11 @@ class IamCollectClient {
|
|
|
27
56
|
* @returns True if the account exists, false otherwise.
|
|
28
57
|
*/
|
|
29
58
|
async accountExists(accountId) {
|
|
30
|
-
const
|
|
31
|
-
return
|
|
59
|
+
const cacheKey = `accountExists:${accountId}`;
|
|
60
|
+
return this.withCache(cacheKey, async () => {
|
|
61
|
+
const accounts = await this.storageClient.listAccountIds();
|
|
62
|
+
return accounts.includes(accountId);
|
|
63
|
+
});
|
|
32
64
|
}
|
|
33
65
|
/**
|
|
34
66
|
* Get all account IDs in the store.
|
|
@@ -36,7 +68,10 @@ class IamCollectClient {
|
|
|
36
68
|
* @returns all account IDs in the store
|
|
37
69
|
*/
|
|
38
70
|
async allAccounts() {
|
|
39
|
-
|
|
71
|
+
const cacheKey = `allAccounts`;
|
|
72
|
+
return this.withCache(cacheKey, async () => {
|
|
73
|
+
return this.storageClient.listAccountIds();
|
|
74
|
+
});
|
|
40
75
|
}
|
|
41
76
|
/**
|
|
42
77
|
* Checks if a principal exists in the store.
|
|
@@ -44,9 +79,12 @@ class IamCollectClient {
|
|
|
44
79
|
* @returns True if the principal exists, false otherwise.
|
|
45
80
|
*/
|
|
46
81
|
async principalExists(principalArn) {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
82
|
+
const cacheKey = `principalExists:${principalArn}`;
|
|
83
|
+
return this.withCache(cacheKey, async () => {
|
|
84
|
+
const accountId = (0, iam_utils_1.splitArnParts)(principalArn).accountId;
|
|
85
|
+
const principalData = await this.storageClient.getResourceMetadata(accountId, principalArn, 'metadata');
|
|
86
|
+
return !!principalData;
|
|
87
|
+
});
|
|
50
88
|
}
|
|
51
89
|
/**
|
|
52
90
|
* Gets the SCP Hierarchy for an account. The first element is the root, the last element is the account itself.
|
|
@@ -104,21 +142,24 @@ class IamCollectClient {
|
|
|
104
142
|
* @returns The OUs for the account.
|
|
105
143
|
*/
|
|
106
144
|
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);
|
|
145
|
+
const cacheKey = `orgUnitHierarchy:${accountId}`;
|
|
146
|
+
return this.withCache(cacheKey, async () => {
|
|
147
|
+
const orgId = await this.getOrgIdForAccount(accountId);
|
|
148
|
+
if (!orgId) {
|
|
149
|
+
return [];
|
|
118
150
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
151
|
+
const ouIds = [];
|
|
152
|
+
let ouId = await this.getOrgUnitIdForAccount(accountId);
|
|
153
|
+
ouIds.push(ouId);
|
|
154
|
+
while (ouId) {
|
|
155
|
+
const parentOuId = await this.getParentOrgUnitIdForOrgUnit(orgId, ouId);
|
|
156
|
+
if (parentOuId) {
|
|
157
|
+
ouIds.unshift(parentOuId);
|
|
158
|
+
}
|
|
159
|
+
ouId = parentOuId;
|
|
160
|
+
}
|
|
161
|
+
return ouIds;
|
|
162
|
+
});
|
|
122
163
|
}
|
|
123
164
|
/**
|
|
124
165
|
* Gets the org unit ID for an account.
|
|
@@ -126,12 +167,15 @@ class IamCollectClient {
|
|
|
126
167
|
* @returns The org unit ID for the account, or undefined if not found.
|
|
127
168
|
*/
|
|
128
169
|
async getOrgUnitIdForAccount(accountId) {
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
170
|
+
const cacheKey = `orgUnitId:${accountId}`;
|
|
171
|
+
return this.withCache(cacheKey, async () => {
|
|
172
|
+
const orgId = await this.getOrgIdForAccount(accountId);
|
|
173
|
+
if (!orgId) {
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
const accounts = (await this.getAccountDataForOrg(orgId));
|
|
177
|
+
return accounts[accountId].ou;
|
|
178
|
+
});
|
|
135
179
|
}
|
|
136
180
|
/**
|
|
137
181
|
* Gets the parent org unit ID for a given org unit.
|
|
@@ -140,9 +184,12 @@ class IamCollectClient {
|
|
|
140
184
|
* @returns The parent org unit ID, or undefined if not found.
|
|
141
185
|
*/
|
|
142
186
|
async getParentOrgUnitIdForOrgUnit(orgId, ouId) {
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
187
|
+
const cacheKey = `parentOrgUnit:${orgId}:${ouId}`;
|
|
188
|
+
return this.withCache(cacheKey, async () => {
|
|
189
|
+
const ouData = await this.getOrgUnitsDataForOrg(orgId);
|
|
190
|
+
const ou = ouData[ouId];
|
|
191
|
+
return ou.parent;
|
|
192
|
+
});
|
|
146
193
|
}
|
|
147
194
|
/**
|
|
148
195
|
* Gets the SCPs for an account.
|
|
@@ -159,19 +206,22 @@ class IamCollectClient {
|
|
|
159
206
|
* @returns The org policies for the account.
|
|
160
207
|
*/
|
|
161
208
|
async getOrgPoliciesForAccount(accountId, policyType) {
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
209
|
+
const cacheKey = `orgPoliciesForAccount:${accountId}:${policyType}`;
|
|
210
|
+
return this.withCache(cacheKey, async () => {
|
|
211
|
+
const orgId = await this.getOrgIdForAccount(accountId);
|
|
212
|
+
if (!orgId) {
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
const accounts = (await this.getAccountDataForOrg(orgId));
|
|
216
|
+
const orgInformation = accounts[accountId];
|
|
217
|
+
const policyArns = orgInformation[policyType];
|
|
218
|
+
const policies = [];
|
|
219
|
+
for (const policyArn of policyArns) {
|
|
220
|
+
const policyInfo = await this.getOrgPolicy(orgId, policyType, policyArn);
|
|
221
|
+
policies.push(policyInfo);
|
|
222
|
+
}
|
|
223
|
+
return policies;
|
|
224
|
+
});
|
|
175
225
|
}
|
|
176
226
|
/**
|
|
177
227
|
* Gets the account data for an organization.
|
|
@@ -179,7 +229,10 @@ class IamCollectClient {
|
|
|
179
229
|
* @returns The account data for the organization.
|
|
180
230
|
*/
|
|
181
231
|
async getAccountDataForOrg(orgId) {
|
|
182
|
-
|
|
232
|
+
const cacheKey = `accountDataForOrg:${orgId}`;
|
|
233
|
+
return this.withCache(cacheKey, async () => {
|
|
234
|
+
return this.storageClient.getOrganizationMetadata(orgId, 'accounts');
|
|
235
|
+
});
|
|
183
236
|
}
|
|
184
237
|
/**
|
|
185
238
|
* Gets the org units data for an organization.
|
|
@@ -187,7 +240,10 @@ class IamCollectClient {
|
|
|
187
240
|
* @returns The org units data for the organization.
|
|
188
241
|
*/
|
|
189
242
|
async getOrgUnitsDataForOrg(orgId) {
|
|
190
|
-
|
|
243
|
+
const cacheKey = `orgUnitsDataForOrg:${orgId}`;
|
|
244
|
+
return this.withCache(cacheKey, async () => {
|
|
245
|
+
return this.storageClient.getOrganizationMetadata(orgId, 'ous');
|
|
246
|
+
});
|
|
191
247
|
}
|
|
192
248
|
/**
|
|
193
249
|
* Gets a specific org policy.
|
|
@@ -197,17 +253,20 @@ class IamCollectClient {
|
|
|
197
253
|
* @returns The org policy.
|
|
198
254
|
*/
|
|
199
255
|
async getOrgPolicy(orgId, policyType, policyArn) {
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
256
|
+
const cacheKey = `orgPolicy:${orgId}:${policyType}:${policyArn}`;
|
|
257
|
+
return this.withCache(cacheKey, async () => {
|
|
258
|
+
const policyId = policyArn.split('/').at(-1);
|
|
259
|
+
const policyData = await this.storageClient.getOrganizationPolicyMetadata(orgId, policyType, policyId, 'metadata');
|
|
260
|
+
const policyDocument = await this.storageClient.getOrganizationPolicyMetadata(orgId, policyType, policyId, 'policy');
|
|
261
|
+
if (!policyDocument) {
|
|
262
|
+
console.error(`Policy document not found for ${policyArn} in org ${orgId}`);
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
arn: policyData.arn,
|
|
266
|
+
name: policyData.name,
|
|
267
|
+
policy: policyDocument
|
|
268
|
+
};
|
|
269
|
+
});
|
|
211
270
|
}
|
|
212
271
|
/**
|
|
213
272
|
* Gets the RCPs for an account.
|
|
@@ -242,15 +301,18 @@ class IamCollectClient {
|
|
|
242
301
|
* @returns The org policies for the org unit.
|
|
243
302
|
*/
|
|
244
303
|
async getOrgPoliciesForOrgUnit(orgId, orgUnitId, policyType) {
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
304
|
+
const cacheKey = `orgPoliciesForOrgUnit:${orgId}:${orgUnitId}:${policyType}`;
|
|
305
|
+
return this.withCache(cacheKey, async () => {
|
|
306
|
+
const orgUnitInformation = await this.getOrgUnitsDataForOrg(orgId);
|
|
307
|
+
const orgUnit = orgUnitInformation[orgUnitId];
|
|
308
|
+
const orgPolicies = orgUnit[policyType];
|
|
309
|
+
const policies = [];
|
|
310
|
+
for (const policyArn of orgPolicies) {
|
|
311
|
+
const policyInfo = await this.getOrgPolicy(orgId, policyType, policyArn);
|
|
312
|
+
policies.push(policyInfo);
|
|
313
|
+
}
|
|
314
|
+
return policies;
|
|
315
|
+
});
|
|
254
316
|
}
|
|
255
317
|
/**
|
|
256
318
|
* Gets the RCPs for an org unit.
|
|
@@ -267,17 +329,23 @@ class IamCollectClient {
|
|
|
267
329
|
* @returns The org ID for the account, or undefined if not found.
|
|
268
330
|
*/
|
|
269
331
|
async getOrgIdForAccount(accountId) {
|
|
270
|
-
const index = await this.
|
|
332
|
+
const index = await this.getIndex('accounts-to-orgs', {});
|
|
271
333
|
const accountToOrgMap = index.data;
|
|
272
334
|
return accountToOrgMap[accountId];
|
|
273
335
|
}
|
|
336
|
+
async getIndex(indexName, defaultValue) {
|
|
337
|
+
const cacheKey = `index:${indexName}`;
|
|
338
|
+
return this.withCache(cacheKey, async () => {
|
|
339
|
+
return this.storageClient.getIndex(indexName, defaultValue);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
274
342
|
/**
|
|
275
343
|
* Gets the account ID for a given S3 bucket name.
|
|
276
344
|
* @param bucketName The name of the bucket.
|
|
277
345
|
* @returns The account ID for the bucket, or undefined if not found.
|
|
278
346
|
*/
|
|
279
347
|
async getAccountIdForBucket(bucketName) {
|
|
280
|
-
const index = await this.
|
|
348
|
+
const index = await this.getIndex('buckets-to-accounts', {});
|
|
281
349
|
const bucketToAccountMap = index.data;
|
|
282
350
|
return bucketToAccountMap[bucketName]?.accountId;
|
|
283
351
|
}
|
|
@@ -287,7 +355,7 @@ class IamCollectClient {
|
|
|
287
355
|
* @returns The account ID for the API Gateway, or undefined if not found.
|
|
288
356
|
*/
|
|
289
357
|
async getAccountIdForRestApi(apiArn) {
|
|
290
|
-
const index = await this.
|
|
358
|
+
const index = await this.getIndex('apigateways-to-accounts', {});
|
|
291
359
|
const bucketToAccountMap = index.data;
|
|
292
360
|
return bucketToAccountMap[apiArn];
|
|
293
361
|
}
|
|
@@ -309,16 +377,19 @@ class IamCollectClient {
|
|
|
309
377
|
});
|
|
310
378
|
}
|
|
311
379
|
async getManagedPolicy(accountId, policyArn) {
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
380
|
+
const cacheKey = `managedPolicy:${accountId}:${policyArn}`;
|
|
381
|
+
return this.withCache(cacheKey, async () => {
|
|
382
|
+
const policyMetadata = await this.storageClient.getResourceMetadata(accountId, policyArn, 'metadata');
|
|
383
|
+
const policyDocument = await this.storageClient.getResourceMetadata(accountId, policyArn, 'current-policy');
|
|
384
|
+
if (!policyDocument) {
|
|
385
|
+
console.error(`Policy document not found for ${policyArn} in account ${accountId}`);
|
|
386
|
+
}
|
|
387
|
+
return {
|
|
388
|
+
arn: policyMetadata.arn,
|
|
389
|
+
name: policyMetadata.name,
|
|
390
|
+
policy: policyDocument
|
|
391
|
+
};
|
|
392
|
+
});
|
|
322
393
|
}
|
|
323
394
|
/**
|
|
324
395
|
* Gets the inline policies attached to a user.
|
|
@@ -336,10 +407,19 @@ class IamCollectClient {
|
|
|
336
407
|
}));
|
|
337
408
|
});
|
|
338
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* Gets metadata for an IAM user.
|
|
412
|
+
*
|
|
413
|
+
* @param userArn the ARN of the user.
|
|
414
|
+
* @returns the metadata for the user, or undefined if not found.
|
|
415
|
+
*/
|
|
339
416
|
async getIamUserMetadata(userArn) {
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
417
|
+
const cacheKey = `iamUserMetadata:${userArn}`;
|
|
418
|
+
return this.withCache(cacheKey, async () => {
|
|
419
|
+
const accountId = (0, iam_utils_1.splitArnParts)(userArn).accountId;
|
|
420
|
+
// The permissions boundary is stored as a policy ARN on the user resource metadata
|
|
421
|
+
return this.storageClient.getResourceMetadata(accountId, userArn, 'metadata');
|
|
422
|
+
});
|
|
343
423
|
}
|
|
344
424
|
/**
|
|
345
425
|
* Gets the permissions boundary policy attached to a user, if any.
|
|
@@ -394,6 +474,12 @@ class IamCollectClient {
|
|
|
394
474
|
return results;
|
|
395
475
|
});
|
|
396
476
|
}
|
|
477
|
+
/**
|
|
478
|
+
* Get the inline policies attached to a group.
|
|
479
|
+
*
|
|
480
|
+
* @param groupArn the ARN of the group.
|
|
481
|
+
* @returns the inline policies for the group.
|
|
482
|
+
*/
|
|
397
483
|
async getInlinePoliciesForGroup(groupArn) {
|
|
398
484
|
const cacheKey = `groupInlinePolicies:${groupArn}`;
|
|
399
485
|
return this.withCache(cacheKey, async () => {
|
|
@@ -405,6 +491,11 @@ class IamCollectClient {
|
|
|
405
491
|
}));
|
|
406
492
|
});
|
|
407
493
|
}
|
|
494
|
+
/**
|
|
495
|
+
* Gets the managed policies attached to a role.
|
|
496
|
+
* @param roleArn the ARN of the role.
|
|
497
|
+
* @returns the managed policies attached to the role.
|
|
498
|
+
*/
|
|
408
499
|
async getManagedPoliciesForRole(roleArn) {
|
|
409
500
|
const cacheKey = `managedPoliciesForRole:${roleArn}`;
|
|
410
501
|
return this.withCache(cacheKey, async () => {
|
|
@@ -417,6 +508,12 @@ class IamCollectClient {
|
|
|
417
508
|
return results;
|
|
418
509
|
});
|
|
419
510
|
}
|
|
511
|
+
/**
|
|
512
|
+
* Get the inline policies attached to a role.
|
|
513
|
+
*
|
|
514
|
+
* @param roleArn the ARN of the role.
|
|
515
|
+
* @returns the inline policies for the role.
|
|
516
|
+
*/
|
|
420
517
|
async getInlinePoliciesForRole(roleArn) {
|
|
421
518
|
const cacheKey = `inlinePoliciesForRole:${roleArn}`;
|
|
422
519
|
return this.withCache(cacheKey, async () => {
|
|
@@ -428,6 +525,11 @@ class IamCollectClient {
|
|
|
428
525
|
}));
|
|
429
526
|
});
|
|
430
527
|
}
|
|
528
|
+
/**
|
|
529
|
+
* Get the permissions boundary policy attached to a role, if any.
|
|
530
|
+
* @param roleArn the ARN of the role.
|
|
531
|
+
* @returns the permissions boundary policy as a ManagedPolicy, or undefined if none is set.
|
|
532
|
+
*/
|
|
431
533
|
async getPermissionsBoundaryForRole(roleArn) {
|
|
432
534
|
const cacheKey = `permissionBoundaryForRole:${roleArn}`;
|
|
433
535
|
return this.withCache(cacheKey, async () => {
|
|
@@ -451,7 +553,10 @@ class IamCollectClient {
|
|
|
451
553
|
* @returns the metadata for the organization
|
|
452
554
|
*/
|
|
453
555
|
async getOrganizationMetadata(organizationId) {
|
|
454
|
-
|
|
556
|
+
const cacheKey = `organizationMetadata:${organizationId}`;
|
|
557
|
+
return this.withCache(cacheKey, async () => {
|
|
558
|
+
return this.storageClient.getOrganizationMetadata(organizationId, 'metadata');
|
|
559
|
+
});
|
|
455
560
|
}
|
|
456
561
|
/**
|
|
457
562
|
* Gets the resource policy for a given resource ARN and account.
|
|
@@ -461,13 +566,16 @@ class IamCollectClient {
|
|
|
461
566
|
* @returns The resource policy, or undefined if not found.
|
|
462
567
|
*/
|
|
463
568
|
async getResourcePolicyForArn(resourceArn, accountId) {
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
metadataKey = '
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
569
|
+
const cacheKey = `resourcePolicy:${accountId}:${resourceArn}`;
|
|
570
|
+
return this.withCache(cacheKey, async () => {
|
|
571
|
+
const arnParts = (0, iam_utils_1.splitArnParts)(resourceArn);
|
|
572
|
+
let metadataKey = 'policy';
|
|
573
|
+
if (arnParts.service === 'iam' && arnParts.resourceType === 'role') {
|
|
574
|
+
metadataKey = 'trust-policy';
|
|
575
|
+
}
|
|
576
|
+
const resourcePolicy = await this.storageClient.getResourceMetadata(accountId, resourceArn, metadataKey);
|
|
577
|
+
return resourcePolicy;
|
|
578
|
+
});
|
|
471
579
|
}
|
|
472
580
|
/**
|
|
473
581
|
* Gets the RAM share policy for a given resource ARN and account.
|
|
@@ -477,8 +585,11 @@ class IamCollectClient {
|
|
|
477
585
|
* @returns The RAM share policy, or undefined if not found.
|
|
478
586
|
*/
|
|
479
587
|
async getRamSharePolicyForArn(resourceArn, accountId) {
|
|
480
|
-
const
|
|
481
|
-
return
|
|
588
|
+
const cacheKey = `ramSharePolicy:${accountId}:${resourceArn}`;
|
|
589
|
+
return this.withCache(cacheKey, async () => {
|
|
590
|
+
const armSharePolicy = await this.storageClient.getRamResource(accountId, resourceArn);
|
|
591
|
+
return armSharePolicy?.policy;
|
|
592
|
+
});
|
|
482
593
|
}
|
|
483
594
|
/**
|
|
484
595
|
* Gets the tags for a given resource ARN and account.
|
|
@@ -488,8 +599,11 @@ class IamCollectClient {
|
|
|
488
599
|
* @returns The tags as a record, or undefined if not found.
|
|
489
600
|
*/
|
|
490
601
|
async getTagsForResource(resourceArn, accountId) {
|
|
491
|
-
const
|
|
492
|
-
return
|
|
602
|
+
const cacheKey = `tagsForResource:${accountId}:${resourceArn}`;
|
|
603
|
+
return this.withCache(cacheKey, async () => {
|
|
604
|
+
const tags = await this.storageClient.getResourceMetadata(accountId, resourceArn, 'tags');
|
|
605
|
+
return tags || {};
|
|
606
|
+
});
|
|
493
607
|
}
|
|
494
608
|
/**
|
|
495
609
|
* Gets a unique ID for an IAM resource based on its ARN and account ID.
|
|
@@ -500,9 +614,12 @@ class IamCollectClient {
|
|
|
500
614
|
* @returns a unique ID for the resource, or undefined if not found
|
|
501
615
|
*/
|
|
502
616
|
async getUniqueIdForIamResource(resourceArn) {
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
|
|
617
|
+
const cacheKey = `uniqueIdForIamResource:${resourceArn}`;
|
|
618
|
+
return this.withCache(cacheKey, async () => {
|
|
619
|
+
const accountId = (0, iam_utils_1.splitArnParts)(resourceArn).accountId;
|
|
620
|
+
const resourceMetadata = await this.storageClient.getResourceMetadata(accountId, resourceArn, 'metadata');
|
|
621
|
+
return resourceMetadata?.id;
|
|
622
|
+
});
|
|
506
623
|
}
|
|
507
624
|
/**
|
|
508
625
|
* Get the account IDs for an organization.
|
|
@@ -525,52 +642,74 @@ class IamCollectClient {
|
|
|
525
642
|
* @returns returns the organization structure or undefined if not found
|
|
526
643
|
*/
|
|
527
644
|
async getOrganizationStructure(orgId) {
|
|
528
|
-
|
|
645
|
+
const cacheKey = `organizationStructure:${orgId}`;
|
|
646
|
+
return this.withCache(cacheKey, async () => {
|
|
647
|
+
return this.storageClient.getOrganizationMetadata(orgId, 'structure');
|
|
648
|
+
});
|
|
529
649
|
}
|
|
650
|
+
/**
|
|
651
|
+
* Get the accounts for a given organization path.
|
|
652
|
+
*
|
|
653
|
+
* @param orgId the ID of the organization
|
|
654
|
+
* @param ouIds the ids of the organizational units in the path
|
|
655
|
+
* @returns a tuple containing a boolean indicating success and an array of account IDs
|
|
656
|
+
*/
|
|
530
657
|
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
|
|
658
|
+
const cacheKey = `accountsForOrgPath:${orgId}:${ouIds.join('/')}`;
|
|
659
|
+
return this.withCache(cacheKey, async () => {
|
|
660
|
+
const orgUnits = await this.getOrganizationStructure(orgId);
|
|
661
|
+
if (!orgUnits || ouIds.length === 0) {
|
|
662
|
+
return [false, []];
|
|
542
663
|
}
|
|
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));
|
|
664
|
+
const rootOu = orgUnits[ouIds[0]];
|
|
665
|
+
// Now look through the structure to find the OU
|
|
666
|
+
let currentStructure = rootOu;
|
|
667
|
+
for (const ou of ouIds.slice(1)) {
|
|
668
|
+
currentStructure = currentStructure.children?.[ou];
|
|
669
|
+
if (!currentStructure) {
|
|
670
|
+
return [false, []]; // OU not found in the structure
|
|
671
|
+
}
|
|
555
672
|
}
|
|
556
|
-
|
|
557
|
-
|
|
673
|
+
const getAccountId = (a) => a.split('/').at(-1);
|
|
674
|
+
const accounts = [];
|
|
675
|
+
if (currentStructure.accounts) {
|
|
676
|
+
accounts.push(...currentStructure.accounts?.map(getAccountId));
|
|
558
677
|
}
|
|
559
|
-
|
|
560
|
-
|
|
678
|
+
const children = Object.values(currentStructure.children || {});
|
|
679
|
+
// Traverse the children to collect all accounts
|
|
680
|
+
while (children.length > 0) {
|
|
681
|
+
const child = children.shift();
|
|
682
|
+
if (child?.accounts) {
|
|
683
|
+
accounts.push(...child.accounts.map(getAccountId));
|
|
684
|
+
}
|
|
685
|
+
if (child?.children) {
|
|
686
|
+
children.push(...Object.values(child.children));
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return [true, accounts];
|
|
690
|
+
});
|
|
561
691
|
}
|
|
692
|
+
/**
|
|
693
|
+
* Get all the principals (users and roles) in a given account.
|
|
694
|
+
*
|
|
695
|
+
* @param accountId the ID of the account
|
|
696
|
+
* @returns a list of all principal ARNs in the account
|
|
697
|
+
*/
|
|
562
698
|
async getAllPrincipalsInAccount(accountId) {
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
699
|
+
const cacheKey = `allPrincipalsInAccount:${accountId}`;
|
|
700
|
+
return this.withCache(cacheKey, async () => {
|
|
701
|
+
const iamUsers = await this.storageClient.findResourceMetadata(accountId, {
|
|
702
|
+
service: 'iam',
|
|
703
|
+
resourceType: 'user',
|
|
704
|
+
account: accountId
|
|
705
|
+
});
|
|
706
|
+
const iamRoles = await this.storageClient.findResourceMetadata(accountId, {
|
|
707
|
+
service: 'iam',
|
|
708
|
+
resourceType: 'role',
|
|
709
|
+
account: accountId
|
|
710
|
+
});
|
|
711
|
+
return [...iamUsers.map((user) => user.arn), ...iamRoles.map((role) => role.arn)];
|
|
572
712
|
});
|
|
573
|
-
return [...iamUsers.map((user) => user.arn), ...iamRoles.map((role) => role.arn)];
|
|
574
713
|
}
|
|
575
714
|
/**
|
|
576
715
|
* Get the VPC endpoint policy for a given VPC endpoint ARN.
|
|
@@ -579,9 +718,12 @@ class IamCollectClient {
|
|
|
579
718
|
* @returns the VPC endpoint policy, or undefined if not found
|
|
580
719
|
*/
|
|
581
720
|
async getVpcEndpointPolicyForArn(vpcEndpointArn) {
|
|
582
|
-
const
|
|
583
|
-
|
|
584
|
-
|
|
721
|
+
const cacheKey = `vpcEndpointPolicy:${vpcEndpointArn}`;
|
|
722
|
+
return this.withCache(cacheKey, async () => {
|
|
723
|
+
const accountId = (0, iam_utils_1.splitArnParts)(vpcEndpointArn).accountId;
|
|
724
|
+
const vpcEndpointPolicy = await this.storageClient.getResourceMetadata(accountId, vpcEndpointArn, 'endpoint-policy');
|
|
725
|
+
return vpcEndpointPolicy;
|
|
726
|
+
});
|
|
585
727
|
}
|
|
586
728
|
/**
|
|
587
729
|
* Get the ARN of a VPC endpoint given its ID.
|
|
@@ -589,7 +731,7 @@ class IamCollectClient {
|
|
|
589
731
|
* @returns the ARN of the VPC endpoint, or undefined if not found
|
|
590
732
|
*/
|
|
591
733
|
async getVpcEndpointArnForVpcEndpointId(vpcEndpointId) {
|
|
592
|
-
const index = await this.
|
|
734
|
+
const index = await this.getIndex('vpcs', {
|
|
593
735
|
endpoints: {},
|
|
594
736
|
vpcs: {}
|
|
595
737
|
});
|
|
@@ -603,7 +745,7 @@ class IamCollectClient {
|
|
|
603
745
|
* @returns the VPC endpoint ID, or undefined if not found
|
|
604
746
|
*/
|
|
605
747
|
async getVpcEndpointIdForVpcService(vpcId, service) {
|
|
606
|
-
const index = await this.
|
|
748
|
+
const index = await this.getIndex('vpcs', {
|
|
607
749
|
endpoints: {},
|
|
608
750
|
vpcs: {}
|
|
609
751
|
});
|
|
@@ -621,7 +763,7 @@ class IamCollectClient {
|
|
|
621
763
|
* @returns the VPC ID, or undefined if not found
|
|
622
764
|
*/
|
|
623
765
|
async getVpcIdForVpcEndpointId(vpcEndpointId) {
|
|
624
|
-
const index = await this.
|
|
766
|
+
const index = await this.getIndex('vpcs', {
|
|
625
767
|
endpoints: {},
|
|
626
768
|
vpcs: {}
|
|
627
769
|
});
|