@fishawack/lab-env 5.6.1 → 5.7.0-beta.2
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/CHANGELOG.md +35 -0
- package/_Test/provision.js +3 -1
- package/cli.js +1 -0
- package/commands/create/cmds/deprovision.js +37 -6
- package/commands/create/cmds/provision.js +250 -1
- package/commands/create/cmds/sync-secrets.js +198 -0
- package/commands/create/libs/utilities.js +2 -0
- package/commands/create/libs/vars.js +218 -303
- package/commands/create/services/aws/acm.js +59 -0
- package/commands/create/services/aws/ec2.js +699 -2
- package/commands/create/services/aws/elasticbeanstalk.js +70 -0
- package/commands/create/services/aws/iam.js +268 -0
- package/commands/create/services/aws/index.js +804 -52
- package/commands/create/services/aws/opensearch.js +147 -0
- package/commands/create/services/aws/rds.js +284 -0
- package/commands/create/services/aws/s3.js +41 -7
- package/commands/create/services/aws/secretsmanager.js +89 -0
- package/commands/create/templates/elasticbeanstalk/.ebextensions/laravel/rds-ssl.config +5 -0
- package/commands/create/templates/elasticbeanstalk/.ebextensions/misc/setvars.config +16 -1
- package/package.json +5 -1
|
@@ -10,8 +10,11 @@ const {
|
|
|
10
10
|
DescribeEnvironmentsCommand,
|
|
11
11
|
DescribeApplicationsCommand,
|
|
12
12
|
DescribeApplicationVersionsCommand,
|
|
13
|
+
DescribeConfigurationSettingsCommand,
|
|
14
|
+
UpdateEnvironmentCommand,
|
|
13
15
|
CreateApplicationVersionCommand,
|
|
14
16
|
ListAvailableSolutionStacksCommand,
|
|
17
|
+
RestartAppServerCommand,
|
|
15
18
|
} = require("@aws-sdk/client-elastic-beanstalk");
|
|
16
19
|
const { Spinner, poll } = require("../../libs/utilities");
|
|
17
20
|
const { eb } = require("../../libs/vars");
|
|
@@ -31,6 +34,16 @@ module.exports.createElasticBeanstalkApplication = async (name) => {
|
|
|
31
34
|
return res;
|
|
32
35
|
};
|
|
33
36
|
|
|
37
|
+
module.exports.describeEnvironment = async (name) => {
|
|
38
|
+
const client = new ElasticBeanstalkClient({});
|
|
39
|
+
|
|
40
|
+
return client.send(
|
|
41
|
+
new DescribeEnvironmentsCommand({
|
|
42
|
+
EnvironmentNames: [name],
|
|
43
|
+
}),
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
34
47
|
module.exports.createElasticBeanstalkEnvironment = async (
|
|
35
48
|
name,
|
|
36
49
|
{ language },
|
|
@@ -230,3 +243,60 @@ module.exports.deleteApplicationVersion = async (
|
|
|
230
243
|
}),
|
|
231
244
|
);
|
|
232
245
|
};
|
|
246
|
+
|
|
247
|
+
module.exports.describeConfigurationSettings = async (
|
|
248
|
+
applicationName,
|
|
249
|
+
environmentName,
|
|
250
|
+
) => {
|
|
251
|
+
const client = new ElasticBeanstalkClient({});
|
|
252
|
+
|
|
253
|
+
const res = await Spinner.prototype.simple(
|
|
254
|
+
`Retrieving configuration for ${environmentName}`,
|
|
255
|
+
() => {
|
|
256
|
+
return client.send(
|
|
257
|
+
new DescribeConfigurationSettingsCommand({
|
|
258
|
+
ApplicationName: applicationName,
|
|
259
|
+
EnvironmentName: environmentName,
|
|
260
|
+
}),
|
|
261
|
+
);
|
|
262
|
+
},
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
return res.ConfigurationSettings[0]?.OptionSettings || [];
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
module.exports.updateEnvironmentSettings = async (
|
|
269
|
+
environmentName,
|
|
270
|
+
optionSettings = [],
|
|
271
|
+
optionsToRemove = [],
|
|
272
|
+
) => {
|
|
273
|
+
const client = new ElasticBeanstalkClient({});
|
|
274
|
+
|
|
275
|
+
await Spinner.prototype.simple(
|
|
276
|
+
`Updating environment ${environmentName}`,
|
|
277
|
+
() => {
|
|
278
|
+
return client.send(
|
|
279
|
+
new UpdateEnvironmentCommand({
|
|
280
|
+
EnvironmentName: environmentName,
|
|
281
|
+
OptionSettings: optionSettings,
|
|
282
|
+
OptionsToRemove: optionsToRemove,
|
|
283
|
+
}),
|
|
284
|
+
);
|
|
285
|
+
},
|
|
286
|
+
);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
module.exports.restartAppServer = async (environmentName) => {
|
|
290
|
+
const client = new ElasticBeanstalkClient({});
|
|
291
|
+
|
|
292
|
+
await Spinner.prototype.simple(
|
|
293
|
+
`Restarting app server for ${environmentName}`,
|
|
294
|
+
() => {
|
|
295
|
+
return client.send(
|
|
296
|
+
new RestartAppServerCommand({
|
|
297
|
+
EnvironmentName: environmentName,
|
|
298
|
+
}),
|
|
299
|
+
);
|
|
300
|
+
},
|
|
301
|
+
);
|
|
302
|
+
};
|
|
@@ -11,10 +11,18 @@ const {
|
|
|
11
11
|
ListAccessKeysCommand,
|
|
12
12
|
GetRoleCommand,
|
|
13
13
|
CreateRoleCommand,
|
|
14
|
+
DeleteRoleCommand,
|
|
14
15
|
AttachRolePolicyCommand,
|
|
16
|
+
DetachRolePolicyCommand,
|
|
17
|
+
ListAttachedRolePoliciesCommand,
|
|
15
18
|
CreateInstanceProfileCommand,
|
|
19
|
+
DeleteInstanceProfileCommand,
|
|
16
20
|
AddRoleToInstanceProfileCommand,
|
|
21
|
+
RemoveRoleFromInstanceProfileCommand,
|
|
17
22
|
PutRolePolicyCommand,
|
|
23
|
+
DeleteRolePolicyCommand,
|
|
24
|
+
ListRolePoliciesCommand,
|
|
25
|
+
CreateServiceLinkedRoleCommand,
|
|
18
26
|
} = require("@aws-sdk/client-iam");
|
|
19
27
|
const { Spinner } = require("../../libs/utilities");
|
|
20
28
|
|
|
@@ -147,6 +155,11 @@ module.exports.syncFWIAMPolicies = async (
|
|
|
147
155
|
UserName,
|
|
148
156
|
"arn:aws:iam::aws:policy/AmazonElastiCacheFullAccess",
|
|
149
157
|
);
|
|
158
|
+
|
|
159
|
+
await module.exports.attachIAMPolicy(
|
|
160
|
+
UserName,
|
|
161
|
+
"arn:aws:iam::aws:policy/SecretsManagerReadWrite",
|
|
162
|
+
);
|
|
150
163
|
}
|
|
151
164
|
|
|
152
165
|
if (permissions.includes("manage-users")) {
|
|
@@ -393,6 +406,14 @@ module.exports.ensureEBInstanceProfileExists = async () => {
|
|
|
393
406
|
role,
|
|
394
407
|
"arn:aws:iam::aws:policy/AWSElasticBeanstalkMulticontainerDocker",
|
|
395
408
|
);
|
|
409
|
+
await module.exports.attachRolePolicy(
|
|
410
|
+
role,
|
|
411
|
+
"arn:aws:iam::aws:policy/AWSSecretsManagerClientReadOnlyAccess",
|
|
412
|
+
);
|
|
413
|
+
await module.exports.attachRolePolicy(
|
|
414
|
+
role,
|
|
415
|
+
"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore",
|
|
416
|
+
);
|
|
396
417
|
await module.exports.attachInlineRolePolicy(
|
|
397
418
|
role,
|
|
398
419
|
"lab-env-elasticbeanstalk-describe-env",
|
|
@@ -465,6 +486,11 @@ module.exports.ensureEBManagedUpdateProfileExists = async () => {
|
|
|
465
486
|
"arn:aws:iam::aws:policy/AWSElasticBeanstalkManagedUpdatesCustomerRolePolicy",
|
|
466
487
|
);
|
|
467
488
|
|
|
489
|
+
await module.exports.attachRolePolicy(
|
|
490
|
+
role,
|
|
491
|
+
"arn:aws:iam::aws:policy/AWSSecretsManagerClientReadOnlyAccess",
|
|
492
|
+
);
|
|
493
|
+
|
|
468
494
|
await module.exports.attachInlineRolePolicy(
|
|
469
495
|
role,
|
|
470
496
|
"lab-env-elasticbeanstalk-custom-managed-updates-permissions",
|
|
@@ -490,3 +516,245 @@ module.exports.ensureEBManagedUpdateProfileExists = async () => {
|
|
|
490
516
|
}),
|
|
491
517
|
);
|
|
492
518
|
};
|
|
519
|
+
|
|
520
|
+
module.exports.ensureEnvironmentInstanceProfile = async (
|
|
521
|
+
ebSlug,
|
|
522
|
+
s3BucketName,
|
|
523
|
+
opensearchDomainArn,
|
|
524
|
+
) => {
|
|
525
|
+
const role = `${ebSlug}-role`;
|
|
526
|
+
|
|
527
|
+
try {
|
|
528
|
+
await module.exports.getRole(role);
|
|
529
|
+
} catch {
|
|
530
|
+
await module.exports.createRole(
|
|
531
|
+
role,
|
|
532
|
+
JSON.stringify({
|
|
533
|
+
Version: "2012-10-17",
|
|
534
|
+
Statement: [
|
|
535
|
+
{
|
|
536
|
+
Effect: "Allow",
|
|
537
|
+
Action: ["sts:AssumeRole"],
|
|
538
|
+
Principal: {
|
|
539
|
+
Service: ["ec2.amazonaws.com"],
|
|
540
|
+
},
|
|
541
|
+
},
|
|
542
|
+
],
|
|
543
|
+
}),
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
await module.exports.createInstanceProfile(role);
|
|
547
|
+
await module.exports.attachRoleToInstanceProfile(role, role);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
await module.exports.attachRolePolicy(
|
|
551
|
+
role,
|
|
552
|
+
"arn:aws:iam::aws:policy/AWSElasticBeanstalkWebTier",
|
|
553
|
+
);
|
|
554
|
+
await module.exports.attachRolePolicy(
|
|
555
|
+
role,
|
|
556
|
+
"arn:aws:iam::aws:policy/AWSElasticBeanstalkWorkerTier",
|
|
557
|
+
);
|
|
558
|
+
await module.exports.attachRolePolicy(
|
|
559
|
+
role,
|
|
560
|
+
"arn:aws:iam::aws:policy/AWSElasticBeanstalkMulticontainerDocker",
|
|
561
|
+
);
|
|
562
|
+
await module.exports.attachRolePolicy(
|
|
563
|
+
role,
|
|
564
|
+
"arn:aws:iam::aws:policy/AWSSecretsManagerClientReadOnlyAccess",
|
|
565
|
+
);
|
|
566
|
+
await module.exports.attachRolePolicy(
|
|
567
|
+
role,
|
|
568
|
+
"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore",
|
|
569
|
+
);
|
|
570
|
+
await module.exports.attachInlineRolePolicy(
|
|
571
|
+
role,
|
|
572
|
+
"lab-env-elasticbeanstalk-describe-env",
|
|
573
|
+
JSON.stringify({
|
|
574
|
+
Version: "2012-10-17",
|
|
575
|
+
Statement: [
|
|
576
|
+
{
|
|
577
|
+
Sid: "VisualEditor0",
|
|
578
|
+
Effect: "Allow",
|
|
579
|
+
Action: [
|
|
580
|
+
"ec2:DescribeTags",
|
|
581
|
+
"autoscaling:DescribeAutoScalingGroups",
|
|
582
|
+
"elasticbeanstalk:DescribeEvents",
|
|
583
|
+
],
|
|
584
|
+
Resource: "*",
|
|
585
|
+
},
|
|
586
|
+
],
|
|
587
|
+
}),
|
|
588
|
+
);
|
|
589
|
+
|
|
590
|
+
if (s3BucketName) {
|
|
591
|
+
await module.exports.attachInlineRolePolicy(
|
|
592
|
+
role,
|
|
593
|
+
"lab-env-s3-bucket-access",
|
|
594
|
+
JSON.stringify({
|
|
595
|
+
Version: "2012-10-17",
|
|
596
|
+
Statement: [
|
|
597
|
+
{
|
|
598
|
+
Sid: "S3BucketAccess",
|
|
599
|
+
Effect: "Allow",
|
|
600
|
+
Action: [
|
|
601
|
+
"s3:GetObject",
|
|
602
|
+
"s3:PutObject",
|
|
603
|
+
"s3:DeleteObject",
|
|
604
|
+
],
|
|
605
|
+
Resource: `arn:aws:s3:::${s3BucketName}/*`,
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
Sid: "S3BucketList",
|
|
609
|
+
Effect: "Allow",
|
|
610
|
+
Action: ["s3:ListBucket", "s3:GetBucketLocation"],
|
|
611
|
+
Resource: `arn:aws:s3:::${s3BucketName}`,
|
|
612
|
+
},
|
|
613
|
+
],
|
|
614
|
+
}),
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if (opensearchDomainArn) {
|
|
619
|
+
await module.exports.attachInlineRolePolicy(
|
|
620
|
+
role,
|
|
621
|
+
"lab-env-opensearch-access",
|
|
622
|
+
JSON.stringify({
|
|
623
|
+
Version: "2012-10-17",
|
|
624
|
+
Statement: [
|
|
625
|
+
{
|
|
626
|
+
Sid: "OpenSearchAccess",
|
|
627
|
+
Effect: "Allow",
|
|
628
|
+
Action: [
|
|
629
|
+
"es:ESHttpGet",
|
|
630
|
+
"es:ESHttpPost",
|
|
631
|
+
"es:ESHttpPut",
|
|
632
|
+
"es:ESHttpDelete",
|
|
633
|
+
"es:ESHttpHead",
|
|
634
|
+
"es:ESHttpPatch",
|
|
635
|
+
],
|
|
636
|
+
Resource: `${opensearchDomainArn}/*`,
|
|
637
|
+
},
|
|
638
|
+
],
|
|
639
|
+
}),
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
return role;
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
module.exports.ensureOpenSearchServiceRole = async () => {
|
|
647
|
+
const client = new IAMClient({});
|
|
648
|
+
|
|
649
|
+
try {
|
|
650
|
+
await Spinner.prototype.simple(
|
|
651
|
+
"Ensuring OpenSearch service-linked role exists",
|
|
652
|
+
() => {
|
|
653
|
+
return client.send(
|
|
654
|
+
new CreateServiceLinkedRoleCommand({
|
|
655
|
+
AWSServiceName: "opensearchservice.amazonaws.com",
|
|
656
|
+
}),
|
|
657
|
+
);
|
|
658
|
+
},
|
|
659
|
+
);
|
|
660
|
+
} catch (e) {
|
|
661
|
+
if (
|
|
662
|
+
e.Code !== "InvalidInput" &&
|
|
663
|
+
e.name !== "InvalidInputException" &&
|
|
664
|
+
e.name !== "InvalidInput"
|
|
665
|
+
) {
|
|
666
|
+
throw e;
|
|
667
|
+
}
|
|
668
|
+
// Role already exists — safe to continue
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
module.exports.removeEnvironmentInstanceProfile = async (ebSlug) => {
|
|
673
|
+
const client = new IAMClient({});
|
|
674
|
+
const role = `${ebSlug}-role`;
|
|
675
|
+
|
|
676
|
+
try {
|
|
677
|
+
await module.exports.getRole(role);
|
|
678
|
+
} catch {
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const attachedPolicies = await Spinner.prototype.simple(
|
|
683
|
+
`Listing attached policies for ${role}`,
|
|
684
|
+
() => {
|
|
685
|
+
return client.send(
|
|
686
|
+
new ListAttachedRolePoliciesCommand({ RoleName: role }),
|
|
687
|
+
);
|
|
688
|
+
},
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
for (const policy of attachedPolicies.AttachedPolicies || []) {
|
|
692
|
+
await Spinner.prototype.simple(
|
|
693
|
+
`Detaching policy ${policy.PolicyName}`,
|
|
694
|
+
() => {
|
|
695
|
+
return client.send(
|
|
696
|
+
new DetachRolePolicyCommand({
|
|
697
|
+
RoleName: role,
|
|
698
|
+
PolicyArn: policy.PolicyArn,
|
|
699
|
+
}),
|
|
700
|
+
);
|
|
701
|
+
},
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
const inlinePolicies = await Spinner.prototype.simple(
|
|
706
|
+
`Listing inline policies for ${role}`,
|
|
707
|
+
() => {
|
|
708
|
+
return client.send(new ListRolePoliciesCommand({ RoleName: role }));
|
|
709
|
+
},
|
|
710
|
+
);
|
|
711
|
+
|
|
712
|
+
for (const policyName of inlinePolicies.PolicyNames || []) {
|
|
713
|
+
await Spinner.prototype.simple(
|
|
714
|
+
`Deleting inline policy ${policyName}`,
|
|
715
|
+
() => {
|
|
716
|
+
return client.send(
|
|
717
|
+
new DeleteRolePolicyCommand({
|
|
718
|
+
RoleName: role,
|
|
719
|
+
PolicyName: policyName,
|
|
720
|
+
}),
|
|
721
|
+
);
|
|
722
|
+
},
|
|
723
|
+
);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
try {
|
|
727
|
+
await Spinner.prototype.simple(
|
|
728
|
+
`Removing role from instance profile ${role}`,
|
|
729
|
+
() => {
|
|
730
|
+
return client.send(
|
|
731
|
+
new RemoveRoleFromInstanceProfileCommand({
|
|
732
|
+
RoleName: role,
|
|
733
|
+
InstanceProfileName: role,
|
|
734
|
+
}),
|
|
735
|
+
);
|
|
736
|
+
},
|
|
737
|
+
);
|
|
738
|
+
} catch {
|
|
739
|
+
/* empty */
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
try {
|
|
743
|
+
await Spinner.prototype.simple(
|
|
744
|
+
`Deleting instance profile ${role}`,
|
|
745
|
+
() => {
|
|
746
|
+
return client.send(
|
|
747
|
+
new DeleteInstanceProfileCommand({
|
|
748
|
+
InstanceProfileName: role,
|
|
749
|
+
}),
|
|
750
|
+
);
|
|
751
|
+
},
|
|
752
|
+
);
|
|
753
|
+
} catch {
|
|
754
|
+
/* empty */
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
await Spinner.prototype.simple(`Deleting role ${role}`, () => {
|
|
758
|
+
return client.send(new DeleteRoleCommand({ RoleName: role }));
|
|
759
|
+
});
|
|
760
|
+
};
|