@fishawack/lab-env 5.7.0-beta.2 → 5.7.0-beta.4

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/_Test/provision.js +1 -8
  3. package/_Test/prune.js +8 -5
  4. package/bitbucket-pipelines.yml +2 -2
  5. package/cli.js +1 -0
  6. package/commands/create/cmds/dekey.js +13 -9
  7. package/commands/create/cmds/deprovision.js +29 -0
  8. package/commands/create/cmds/key.js +60 -41
  9. package/commands/create/cmds/provision.js +425 -55
  10. package/commands/create/cmds/rekey.js +218 -0
  11. package/commands/create/libs/output-credentials.js +59 -0
  12. package/commands/create/libs/parallel-runner.js +204 -0
  13. package/commands/create/libs/resolve-operator.js +59 -0
  14. package/commands/create/libs/utilities.js +71 -8
  15. package/commands/create/libs/vars.js +70 -86
  16. package/commands/create/services/aws/acm.js +4 -2
  17. package/commands/create/services/aws/cloudfront.js +51 -45
  18. package/commands/create/services/aws/ec2.js +132 -53
  19. package/commands/create/services/aws/elasticache.js +159 -0
  20. package/commands/create/services/aws/elasticbeanstalk.js +141 -60
  21. package/commands/create/services/aws/iam.js +178 -98
  22. package/commands/create/services/aws/index.js +1202 -466
  23. package/commands/create/services/aws/opensearch.js +25 -17
  24. package/commands/create/services/aws/rds.js +22 -34
  25. package/commands/create/services/aws/s3.js +14 -27
  26. package/commands/create/services/aws/secretsmanager.js +8 -15
  27. package/commands/create/services/aws/ses.js +195 -0
  28. package/commands/create/templates/elasticbeanstalk/.ebextensions/laravel/cron.config +45 -0
  29. package/commands/create/templates/elasticbeanstalk/.ebextensions/laravel/queue-worker.config +29 -0
  30. package/commands/create/templates/elasticbeanstalk/.ebextensions/laravel/software.config +12 -0
  31. package/commands/create/templates/elasticbeanstalk/.ebextensions/misc/setvars.config +2 -16
  32. package/commands/create/templates/elasticbeanstalk/.platform/confighooks/postdeploy/rewrite-flush.sh +1 -1
  33. package/commands/create/templates/elasticbeanstalk/.platform/confighooks/postdeploy/setvars.sh +19 -0
  34. package/commands/create/templates/elasticbeanstalk/.platform/hooks/postdeploy/restart_queue.sh +4 -0
  35. package/commands/create/templates/elasticbeanstalk/.platform/hooks/prebuild/setvars.sh +19 -0
  36. package/commands/scan.js +1 -1
  37. package/package.json +5 -2
@@ -9,6 +9,7 @@ const {
9
9
  CreateAccessKeyCommand,
10
10
  DeleteAccessKeyCommand,
11
11
  ListAccessKeysCommand,
12
+ AddUserToGroupCommand,
12
13
  GetRoleCommand,
13
14
  CreateRoleCommand,
14
15
  DeleteRoleCommand,
@@ -25,17 +26,18 @@ const {
25
26
  CreateServiceLinkedRoleCommand,
26
27
  } = require("@aws-sdk/client-iam");
27
28
  const { Spinner } = require("../../libs/utilities");
29
+ const { awsClientConfig } = require("../../libs/vars");
28
30
 
29
- module.exports.createIAMUser = async (UserName, tags = []) => {
30
- const client = new IAMClient({});
31
+ const getClient = () => new IAMClient(awsClientConfig);
31
32
 
33
+ module.exports.createIAMUser = async (UserName, tags = []) => {
32
34
  let res;
33
35
 
34
36
  try {
35
37
  res = await Spinner.prototype.simple(
36
38
  `Creating IAM user ${UserName}`,
37
39
  () => {
38
- return client.send(
40
+ return getClient().send(
39
41
  new CreateUserCommand({
40
42
  UserName,
41
43
  Tags: [
@@ -49,7 +51,7 @@ module.exports.createIAMUser = async (UserName, tags = []) => {
49
51
  res = await Spinner.prototype.simple(
50
52
  `Retrieving the already existing IAM user ${UserName}`,
51
53
  () => {
52
- return client.send(new GetUserCommand({ UserName }));
54
+ return getClient().send(new GetUserCommand({ UserName }));
53
55
  },
54
56
  );
55
57
  }
@@ -67,16 +69,25 @@ module.exports.createFWIAMUser = async (UserName, permissions) => {
67
69
  return res;
68
70
  };
69
71
 
70
- module.exports.removeIAMUser = async (UserName) => {
71
- const client = new IAMClient({});
72
+ module.exports.addUserToGroup = async (UserName, GroupName, iamClient) => {
73
+ const c = iamClient || getClient();
74
+
75
+ await Spinner.prototype.simple(
76
+ `Adding IAM user ${UserName} to group ${GroupName}`,
77
+ () => {
78
+ return c.send(new AddUserToGroupCommand({ UserName, GroupName }));
79
+ },
80
+ );
81
+ };
72
82
 
83
+ module.exports.removeIAMUser = async (UserName) => {
73
84
  let res;
74
85
 
75
86
  try {
76
87
  await Spinner.prototype.simple(
77
88
  `Checking if IAM user ${UserName} exists`,
78
89
  () => {
79
- return client.send(new GetUserCommand({ UserName }));
90
+ return getClient().send(new GetUserCommand({ UserName }));
80
91
  },
81
92
  );
82
93
 
@@ -87,7 +98,7 @@ module.exports.removeIAMUser = async (UserName) => {
87
98
  res = await Spinner.prototype.simple(
88
99
  `Removing IAM user ${UserName}`,
89
100
  () => {
90
- return client.send(new DeleteUserCommand({ UserName }));
101
+ return getClient().send(new DeleteUserCommand({ UserName }));
91
102
  },
92
103
  );
93
104
  } catch {
@@ -98,12 +109,10 @@ module.exports.removeIAMUser = async (UserName) => {
98
109
  };
99
110
 
100
111
  module.exports.attachIAMPolicy = async (UserName, policy) => {
101
- const client = new IAMClient({});
102
-
103
112
  let res = await Spinner.prototype.simple(
104
113
  `Attaching IAM policy ${policy}`,
105
114
  () => {
106
- return client.send(
115
+ return getClient().send(
107
116
  new AttachUserPolicyCommand({ UserName, PolicyArn: policy }),
108
117
  );
109
118
  },
@@ -115,68 +124,84 @@ module.exports.attachIAMPolicy = async (UserName, policy) => {
115
124
  module.exports.syncFWIAMPolicies = async (
116
125
  UserName,
117
126
  permissions = ["auto-content", "deploy-static"],
127
+ preserve = [],
118
128
  ) => {
119
- await module.exports.removeAllIAMPolicies(UserName);
129
+ let res = await module.exports.listIAMPolicies(UserName);
130
+
131
+ // Detach existing policies in parallel
132
+ const toDetach = res.AttachedPolicies.filter(
133
+ (p) => !preserve.includes(p.PolicyArn),
134
+ );
135
+ if (toDetach.length) {
136
+ await Spinner.prototype.simple(
137
+ `Detaching ${toDetach.length} IAM policies`,
138
+ () =>
139
+ Promise.all(
140
+ toDetach.map((p) =>
141
+ getClient().send(
142
+ new DetachUserPolicyCommand({
143
+ UserName,
144
+ PolicyArn: p.PolicyArn,
145
+ }),
146
+ ),
147
+ ),
148
+ ),
149
+ );
150
+ }
151
+
152
+ // Collect policies to attach
153
+ const policies = [];
120
154
 
121
155
  if (
122
156
  permissions.includes("auto-content") ||
123
157
  permissions.includes("deploy-static")
124
158
  ) {
125
- await module.exports.attachIAMPolicy(
126
- UserName,
127
- "arn:aws:iam::aws:policy/AmazonS3FullAccess",
128
- );
159
+ policies.push("arn:aws:iam::aws:policy/AmazonS3FullAccess");
129
160
  }
130
161
 
131
162
  if (permissions.includes("deploy-static")) {
132
- await module.exports.attachIAMPolicy(
133
- UserName,
134
- "arn:aws:iam::aws:policy/CloudFrontFullAccess",
135
- );
163
+ policies.push("arn:aws:iam::aws:policy/CloudFrontFullAccess");
136
164
  }
137
165
 
138
166
  if (permissions.includes("deploy-fullstack")) {
139
- await module.exports.attachIAMPolicy(
140
- UserName,
167
+ policies.push(
141
168
  "arn:aws:iam::aws:policy/AdministratorAccess-AWSElasticBeanstalk",
142
- );
143
-
144
- await module.exports.attachIAMPolicy(
145
- UserName,
146
169
  "arn:aws:iam::aws:policy/AmazonOpenSearchServiceFullAccess",
147
- );
148
-
149
- await module.exports.attachIAMPolicy(
150
- UserName,
151
170
  "arn:aws:iam::aws:policy/AmazonRDSFullAccess",
152
- );
153
-
154
- await module.exports.attachIAMPolicy(
155
- UserName,
156
171
  "arn:aws:iam::aws:policy/AmazonElastiCacheFullAccess",
157
- );
158
-
159
- await module.exports.attachIAMPolicy(
160
- UserName,
161
172
  "arn:aws:iam::aws:policy/SecretsManagerReadWrite",
173
+ "arn:aws:iam::aws:policy/AmazonSESFullAccess",
162
174
  );
163
175
  }
164
176
 
165
177
  if (permissions.includes("manage-users")) {
166
- await module.exports.attachIAMPolicy(
167
- UserName,
168
- "arn:aws:iam::aws:policy/IAMFullAccess",
178
+ policies.push("arn:aws:iam::aws:policy/IAMFullAccess");
179
+ }
180
+
181
+ // Attach all policies in parallel
182
+ if (policies.length) {
183
+ await Spinner.prototype.simple(
184
+ `Attaching ${policies.length} IAM policies`,
185
+ () =>
186
+ Promise.all(
187
+ policies.map((p) =>
188
+ getClient().send(
189
+ new AttachUserPolicyCommand({
190
+ UserName,
191
+ PolicyArn: p,
192
+ }),
193
+ ),
194
+ ),
195
+ ),
169
196
  );
170
197
  }
171
198
  };
172
199
 
173
200
  module.exports.removeIAMPolicy = async (UserName, policy) => {
174
- const client = new IAMClient({});
175
-
176
201
  let res = await Spinner.prototype.simple(
177
202
  `Detaching IAM policy ${policy}`,
178
203
  () => {
179
- return client.send(
204
+ return getClient().send(
180
205
  new DetachUserPolicyCommand({ UserName, PolicyArn: policy }),
181
206
  );
182
207
  },
@@ -186,10 +211,10 @@ module.exports.removeIAMPolicy = async (UserName, policy) => {
186
211
  };
187
212
 
188
213
  module.exports.listIAMPolicies = async (UserName) => {
189
- const client = new IAMClient({});
190
-
191
214
  let res = await Spinner.prototype.simple(`Listing IAM policies`, () => {
192
- return client.send(new ListAttachedUserPoliciesCommand({ UserName }));
215
+ return getClient().send(
216
+ new ListAttachedUserPoliciesCommand({ UserName }),
217
+ );
193
218
  });
194
219
 
195
220
  return res;
@@ -198,10 +223,20 @@ module.exports.listIAMPolicies = async (UserName) => {
198
223
  module.exports.removeAllIAMPolicies = async (UserName) => {
199
224
  let res = await module.exports.listIAMPolicies(UserName);
200
225
 
201
- for (let i = 0; i < res.AttachedPolicies.length; i++) {
202
- await module.exports.removeIAMPolicy(
203
- UserName,
204
- res.AttachedPolicies[i].PolicyArn,
226
+ if (res.AttachedPolicies.length) {
227
+ await Spinner.prototype.simple(
228
+ `Detaching ${res.AttachedPolicies.length} IAM policies`,
229
+ () =>
230
+ Promise.all(
231
+ res.AttachedPolicies.map((p) =>
232
+ getClient().send(
233
+ new DetachUserPolicyCommand({
234
+ UserName,
235
+ PolicyArn: p.PolicyArn,
236
+ }),
237
+ ),
238
+ ),
239
+ ),
205
240
  );
206
241
  }
207
242
 
@@ -209,22 +244,18 @@ module.exports.removeAllIAMPolicies = async (UserName) => {
209
244
  };
210
245
 
211
246
  module.exports.createAccessKey = async (UserName) => {
212
- const client = new IAMClient({});
213
-
214
247
  let res = await Spinner.prototype.simple(`Creating access key`, () => {
215
- return client.send(new CreateAccessKeyCommand({ UserName }));
248
+ return getClient().send(new CreateAccessKeyCommand({ UserName }));
216
249
  });
217
250
 
218
251
  return res;
219
252
  };
220
253
 
221
254
  module.exports.removeAccessKey = async (UserName, AccessKeyId) => {
222
- const client = new IAMClient({});
223
-
224
255
  let res = await Spinner.prototype.simple(
225
256
  `Removing access key ${AccessKeyId}`,
226
257
  () => {
227
- return client.send(
258
+ return getClient().send(
228
259
  new DeleteAccessKeyCommand({ AccessKeyId, UserName }),
229
260
  );
230
261
  },
@@ -234,10 +265,8 @@ module.exports.removeAccessKey = async (UserName, AccessKeyId) => {
234
265
  };
235
266
 
236
267
  module.exports.listAccessKeys = async (UserName) => {
237
- const client = new IAMClient({});
238
-
239
268
  let res = await Spinner.prototype.simple(`Listing access keys`, () => {
240
- return client.send(new ListAccessKeysCommand({ UserName }));
269
+ return getClient().send(new ListAccessKeysCommand({ UserName }));
241
270
  });
242
271
 
243
272
  return res;
@@ -246,10 +275,20 @@ module.exports.listAccessKeys = async (UserName) => {
246
275
  module.exports.removeAllAccessKeys = async (UserName) => {
247
276
  let res = await module.exports.listAccessKeys(UserName);
248
277
 
249
- for (let i = 0; i < res.AccessKeyMetadata.length; i++) {
250
- await module.exports.removeAccessKey(
251
- UserName,
252
- res.AccessKeyMetadata[i].AccessKeyId,
278
+ if (res.AccessKeyMetadata.length) {
279
+ await Spinner.prototype.simple(
280
+ `Removing ${res.AccessKeyMetadata.length} access keys`,
281
+ () =>
282
+ Promise.all(
283
+ res.AccessKeyMetadata.map((k) =>
284
+ getClient().send(
285
+ new DeleteAccessKeyCommand({
286
+ UserName,
287
+ AccessKeyId: k.AccessKeyId,
288
+ }),
289
+ ),
290
+ ),
291
+ ),
253
292
  );
254
293
  }
255
294
 
@@ -266,27 +305,72 @@ module.exports.createAccessKeySafe = async (UserName) => {
266
305
  return res;
267
306
  };
268
307
 
269
- module.exports.getRole = async (RoleName) => {
270
- const client = new IAMClient({});
308
+ module.exports.rotateAccessKey = async (UserName) => {
309
+ let res = await module.exports.listAccessKeys(UserName);
310
+ let keys = res.AccessKeyMetadata;
311
+
312
+ if (keys.length === 2) {
313
+ console.log(
314
+ `\n⚠ ${UserName} has 2 existing keys (likely from a failed previous rotation). Removing the older key to make room.\n`,
315
+ );
316
+
317
+ keys.sort((a, b) => new Date(a.CreateDate) - new Date(b.CreateDate));
318
+
319
+ await module.exports.removeAccessKey(UserName, keys[0].AccessKeyId);
320
+
321
+ keys = [keys[1]];
322
+ }
323
+
324
+ let newKey = await module.exports.createAccessKey(UserName);
325
+
326
+ if (keys.length === 1) {
327
+ await module.exports.removeAccessKey(UserName, keys[0].AccessKeyId);
328
+ }
329
+
330
+ return newKey;
331
+ };
332
+
333
+ module.exports.rotateFWIAMUser = async (UserName, permissions) => {
334
+ await module.exports.createIAMUser(UserName);
335
+
336
+ let preserve = [];
337
+
338
+ if (permissions && permissions.includes("manage-users")) {
339
+ preserve.push("arn:aws:iam::aws:policy/IAMFullAccess");
340
+ }
341
+
342
+ await module.exports.syncFWIAMPolicies(UserName, permissions, preserve);
271
343
 
344
+ let res = await module.exports.rotateAccessKey(UserName);
345
+
346
+ return res;
347
+ };
348
+
349
+ module.exports.getRole = async (RoleName) => {
272
350
  let res = await Spinner.prototype.simple(
273
351
  `Retrieving the role ${RoleName}`,
274
352
  () => {
275
- return client.send(new GetRoleCommand({ RoleName }));
353
+ return getClient().send(new GetRoleCommand({ RoleName }));
276
354
  },
277
355
  );
278
356
 
279
357
  return res;
280
358
  };
281
359
 
282
- module.exports.createRole = async (RoleName, AssumeRolePolicyDocument) => {
283
- const client = new IAMClient({});
284
-
360
+ module.exports.createRole = async (
361
+ RoleName,
362
+ AssumeRolePolicyDocument,
363
+ Tags,
364
+ ) => {
285
365
  let res = await Spinner.prototype.simple(
286
366
  `Creating the role ${RoleName}`,
287
367
  () => {
288
- return client.send(
289
- new CreateRoleCommand({ RoleName, AssumeRolePolicyDocument }),
368
+ return getClient().send(
369
+ new CreateRoleCommand({
370
+ RoleName,
371
+ AssumeRolePolicyDocument,
372
+ ...(Tags && Tags.length ? { Tags } : {}),
373
+ }),
290
374
  );
291
375
  },
292
376
  );
@@ -294,14 +378,15 @@ module.exports.createRole = async (RoleName, AssumeRolePolicyDocument) => {
294
378
  return res;
295
379
  };
296
380
 
297
- module.exports.createInstanceProfile = async (InstanceProfileName) => {
298
- const client = new IAMClient({});
299
-
381
+ module.exports.createInstanceProfile = async (InstanceProfileName, Tags) => {
300
382
  let res = await Spinner.prototype.simple(
301
383
  `Creating the instance profile ${InstanceProfileName}`,
302
384
  () => {
303
- return client.send(
304
- new CreateInstanceProfileCommand({ InstanceProfileName }),
385
+ return getClient().send(
386
+ new CreateInstanceProfileCommand({
387
+ InstanceProfileName,
388
+ ...(Tags && Tags.length ? { Tags } : {}),
389
+ }),
305
390
  );
306
391
  },
307
392
  );
@@ -313,12 +398,10 @@ module.exports.attachRoleToInstanceProfile = async (
313
398
  RoleName,
314
399
  InstanceProfileName,
315
400
  ) => {
316
- const client = new IAMClient({});
317
-
318
401
  let res = await Spinner.prototype.simple(
319
402
  `Attaching role ${RoleName} to the instance profile ${InstanceProfileName}`,
320
403
  () => {
321
- return client.send(
404
+ return getClient().send(
322
405
  new AddRoleToInstanceProfileCommand({
323
406
  RoleName,
324
407
  InstanceProfileName,
@@ -331,12 +414,10 @@ module.exports.attachRoleToInstanceProfile = async (
331
414
  };
332
415
 
333
416
  module.exports.attachRolePolicy = async (RoleName, PolicyArn) => {
334
- const client = new IAMClient({});
335
-
336
417
  let res = await Spinner.prototype.simple(
337
418
  `Attaching Role policy ${PolicyArn}`,
338
419
  () => {
339
- return client.send(
420
+ return getClient().send(
340
421
  new AttachRolePolicyCommand({ RoleName, PolicyArn }),
341
422
  );
342
423
  },
@@ -350,12 +431,10 @@ module.exports.attachInlineRolePolicy = async (
350
431
  PolicyName,
351
432
  PolicyDocument,
352
433
  ) => {
353
- const client = new IAMClient({});
354
-
355
434
  let res = await Spinner.prototype.simple(
356
435
  `Attaching Inline Role policy ${PolicyName}`,
357
436
  () => {
358
- return client.send(
437
+ return getClient().send(
359
438
  new PutRolePolicyCommand({
360
439
  RoleName,
361
440
  PolicyName,
@@ -521,6 +600,7 @@ module.exports.ensureEnvironmentInstanceProfile = async (
521
600
  ebSlug,
522
601
  s3BucketName,
523
602
  opensearchDomainArn,
603
+ tags,
524
604
  ) => {
525
605
  const role = `${ebSlug}-role`;
526
606
 
@@ -541,9 +621,10 @@ module.exports.ensureEnvironmentInstanceProfile = async (
541
621
  },
542
622
  ],
543
623
  }),
624
+ tags,
544
625
  );
545
626
 
546
- await module.exports.createInstanceProfile(role);
627
+ await module.exports.createInstanceProfile(role, tags);
547
628
  await module.exports.attachRoleToInstanceProfile(role, role);
548
629
  }
549
630
 
@@ -644,13 +725,11 @@ module.exports.ensureEnvironmentInstanceProfile = async (
644
725
  };
645
726
 
646
727
  module.exports.ensureOpenSearchServiceRole = async () => {
647
- const client = new IAMClient({});
648
-
649
728
  try {
650
729
  await Spinner.prototype.simple(
651
730
  "Ensuring OpenSearch service-linked role exists",
652
731
  () => {
653
- return client.send(
732
+ return getClient().send(
654
733
  new CreateServiceLinkedRoleCommand({
655
734
  AWSServiceName: "opensearchservice.amazonaws.com",
656
735
  }),
@@ -670,7 +749,6 @@ module.exports.ensureOpenSearchServiceRole = async () => {
670
749
  };
671
750
 
672
751
  module.exports.removeEnvironmentInstanceProfile = async (ebSlug) => {
673
- const client = new IAMClient({});
674
752
  const role = `${ebSlug}-role`;
675
753
 
676
754
  try {
@@ -682,7 +760,7 @@ module.exports.removeEnvironmentInstanceProfile = async (ebSlug) => {
682
760
  const attachedPolicies = await Spinner.prototype.simple(
683
761
  `Listing attached policies for ${role}`,
684
762
  () => {
685
- return client.send(
763
+ return getClient().send(
686
764
  new ListAttachedRolePoliciesCommand({ RoleName: role }),
687
765
  );
688
766
  },
@@ -692,7 +770,7 @@ module.exports.removeEnvironmentInstanceProfile = async (ebSlug) => {
692
770
  await Spinner.prototype.simple(
693
771
  `Detaching policy ${policy.PolicyName}`,
694
772
  () => {
695
- return client.send(
773
+ return getClient().send(
696
774
  new DetachRolePolicyCommand({
697
775
  RoleName: role,
698
776
  PolicyArn: policy.PolicyArn,
@@ -705,7 +783,9 @@ module.exports.removeEnvironmentInstanceProfile = async (ebSlug) => {
705
783
  const inlinePolicies = await Spinner.prototype.simple(
706
784
  `Listing inline policies for ${role}`,
707
785
  () => {
708
- return client.send(new ListRolePoliciesCommand({ RoleName: role }));
786
+ return getClient().send(
787
+ new ListRolePoliciesCommand({ RoleName: role }),
788
+ );
709
789
  },
710
790
  );
711
791
 
@@ -713,7 +793,7 @@ module.exports.removeEnvironmentInstanceProfile = async (ebSlug) => {
713
793
  await Spinner.prototype.simple(
714
794
  `Deleting inline policy ${policyName}`,
715
795
  () => {
716
- return client.send(
796
+ return getClient().send(
717
797
  new DeleteRolePolicyCommand({
718
798
  RoleName: role,
719
799
  PolicyName: policyName,
@@ -727,7 +807,7 @@ module.exports.removeEnvironmentInstanceProfile = async (ebSlug) => {
727
807
  await Spinner.prototype.simple(
728
808
  `Removing role from instance profile ${role}`,
729
809
  () => {
730
- return client.send(
810
+ return getClient().send(
731
811
  new RemoveRoleFromInstanceProfileCommand({
732
812
  RoleName: role,
733
813
  InstanceProfileName: role,
@@ -743,7 +823,7 @@ module.exports.removeEnvironmentInstanceProfile = async (ebSlug) => {
743
823
  await Spinner.prototype.simple(
744
824
  `Deleting instance profile ${role}`,
745
825
  () => {
746
- return client.send(
826
+ return getClient().send(
747
827
  new DeleteInstanceProfileCommand({
748
828
  InstanceProfileName: role,
749
829
  }),
@@ -755,6 +835,6 @@ module.exports.removeEnvironmentInstanceProfile = async (ebSlug) => {
755
835
  }
756
836
 
757
837
  await Spinner.prototype.simple(`Deleting role ${role}`, () => {
758
- return client.send(new DeleteRoleCommand({ RoleName: role }));
838
+ return getClient().send(new DeleteRoleCommand({ RoleName: role }));
759
839
  });
760
840
  };