@fishawack/lab-env 5.6.1 → 5.7.0-beta.1

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.
@@ -250,11 +250,6 @@ module.exports.eb = {
250
250
  Value: "false",
251
251
  Namespace: "aws:ec2:vpc",
252
252
  },
253
- {
254
- OptionName: "APP_ENV",
255
- Value: "production",
256
- Namespace: "aws:elasticbeanstalk:application:environment",
257
- },
258
253
  ],
259
254
  },
260
255
  php: {
@@ -284,233 +279,17 @@ module.exports.eb = {
284
279
  high: [],
285
280
  },
286
281
  wordpress: {
287
- shared: [
288
- {
289
- OptionName: "AUTH_KEY",
290
- Value: generateSafeKey({
291
- length: 64,
292
- numbers: true,
293
- symbols: true,
294
- }),
295
- Namespace: "aws:elasticbeanstalk:application:environment",
296
- },
297
- {
298
- OptionName: "SECURE_AUTH_KEY",
299
- Value: generateSafeKey({
300
- length: 64,
301
- numbers: true,
302
- symbols: true,
303
- }),
304
- Namespace: "aws:elasticbeanstalk:application:environment",
305
- },
306
- {
307
- OptionName: "LOGGED_IN_KEY",
308
- Value: generateSafeKey({
309
- length: 64,
310
- numbers: true,
311
- symbols: true,
312
- }),
313
- Namespace: "aws:elasticbeanstalk:application:environment",
314
- },
315
- {
316
- OptionName: "NONCE_KEY",
317
- Value: generateSafeKey({
318
- length: 64,
319
- numbers: true,
320
- symbols: true,
321
- }),
322
- Namespace: "aws:elasticbeanstalk:application:environment",
323
- },
324
- {
325
- OptionName: "AUTH_SALT",
326
- Value: generateSafeKey({
327
- length: 64,
328
- numbers: true,
329
- symbols: true,
330
- }),
331
- Namespace: "aws:elasticbeanstalk:application:environment",
332
- },
333
- {
334
- OptionName: "SECURE_AUTH_SALT",
335
- Value: generateSafeKey({
336
- length: 64,
337
- numbers: true,
338
- symbols: true,
339
- }),
340
- Namespace: "aws:elasticbeanstalk:application:environment",
341
- },
342
- {
343
- OptionName: "LOGGED_IN_SALT",
344
- Value: generateSafeKey({
345
- length: 64,
346
- numbers: true,
347
- symbols: true,
348
- }),
349
- Namespace: "aws:elasticbeanstalk:application:environment",
350
- },
351
- {
352
- OptionName: "NONCE_SALT",
353
- Value: generateSafeKey({
354
- length: 64,
355
- numbers: true,
356
- symbols: true,
357
- }),
358
- Namespace: "aws:elasticbeanstalk:application:environment",
359
- },
360
- {
361
- OptionName: "S3_UPLOADS_BUCKET",
362
- Value: "<%= s3Slug %>",
363
- Namespace: "aws:elasticbeanstalk:application:environment",
364
- },
365
- {
366
- OptionName: "S3_UPLOADS_REGION",
367
- Value: "<%= AWS_REGION %>",
368
- Namespace: "aws:elasticbeanstalk:application:environment",
369
- },
370
- {
371
- OptionName: "S3_UPLOADS_KEY",
372
- Value: "<%= AccessKeyId %>",
373
- Namespace: "aws:elasticbeanstalk:application:environment",
374
- },
375
- {
376
- OptionName: "S3_UPLOADS_SECRET",
377
- Value: "<%= SecretAccessKey %>",
378
- Namespace: "aws:elasticbeanstalk:application:environment",
379
- },
380
- ],
282
+ shared: [],
381
283
  low: [],
382
284
  high: [],
383
285
  },
384
286
  laravel: {
385
- shared: [
386
- {
387
- OptionName: "APP_ENV",
388
- Value: "production",
389
- Namespace: "aws:elasticbeanstalk:application:environment",
390
- },
391
- {
392
- OptionName: "APP_KEY",
393
- Value: `base64:${Buffer.from(generator.generate({ length: 32, numbers: true, symbols: true })).toString("base64")}`,
394
- Namespace: "aws:elasticbeanstalk:application:environment",
395
- },
396
- {
397
- OptionName: "APP_DEBUG",
398
- Value: "false",
399
- Namespace: "aws:elasticbeanstalk:application:environment",
400
- },
401
- {
402
- OptionName: "APP_URL",
403
- Value: "https://<%= DOMAIN_LINK %>",
404
- Namespace: "aws:elasticbeanstalk:application:environment",
405
- },
406
- {
407
- OptionName: "AWS_BUCKET",
408
- Value: "<%= s3Slug %>",
409
- Namespace: "aws:elasticbeanstalk:application:environment",
410
- },
411
- {
412
- OptionName: "AWS_DEFAULT_REGION",
413
- Value: "<%= AWS_REGION %>",
414
- Namespace: "aws:elasticbeanstalk:application:environment",
415
- },
416
- {
417
- OptionName: "AWS_ACCESS_KEY_ID",
418
- Value: "<%= AccessKeyId %>",
419
- Namespace: "aws:elasticbeanstalk:application:environment",
420
- },
421
- {
422
- OptionName: "AWS_SECRET_ACCESS_KEY",
423
- Value: "<%= SecretAccessKey %>",
424
- Namespace: "aws:elasticbeanstalk:application:environment",
425
- },
426
- {
427
- OptionName: "FILESYSTEM_DISK",
428
- Value: "s3",
429
- Namespace: "aws:elasticbeanstalk:application:environment",
430
- },
431
- {
432
- OptionName: "FILESYSTEM_DISK_PUBLIC",
433
- Value: "s3-public",
434
- Namespace: "aws:elasticbeanstalk:application:environment",
435
- },
436
- ],
287
+ shared: [],
437
288
  low: [],
438
- high: [
439
- {
440
- OptionName: "SESSION_DRIVER",
441
- Value: "cookie",
442
- Namespace: "aws:elasticbeanstalk:application:environment",
443
- },
444
- {
445
- OptionName: "SESSION_SECURE_COOKIE",
446
- Value: "true",
447
- Namespace: "aws:elasticbeanstalk:application:environment",
448
- },
449
- ],
289
+ high: [],
450
290
  },
451
291
  adonis: {
452
- shared: [
453
- {
454
- OptionName: "NODE_ENV",
455
- Value: "production",
456
- Namespace: "aws:elasticbeanstalk:application:environment",
457
- },
458
- {
459
- OptionName: "APP_KEY",
460
- Value: `base64:${Buffer.from(generator.generate({ length: 32, numbers: true, symbols: true })).toString("base64")}`,
461
- Namespace: "aws:elasticbeanstalk:application:environment",
462
- },
463
- {
464
- OptionName: "APP_URL",
465
- Value: "https://<%= DOMAIN_LINK %>",
466
- Namespace: "aws:elasticbeanstalk:application:environment",
467
- },
468
- {
469
- OptionName: "SESSION_DRIVER",
470
- Value: "cookie",
471
- Namespace: "aws:elasticbeanstalk:application:environment",
472
- },
473
- {
474
- OptionName: "AWS_BUCKET",
475
- Value: "<%= s3Slug %>",
476
- Namespace: "aws:elasticbeanstalk:application:environment",
477
- },
478
- {
479
- OptionName: "AWS_DEFAULT_REGION",
480
- Value: "<%= AWS_REGION %>",
481
- Namespace: "aws:elasticbeanstalk:application:environment",
482
- },
483
- {
484
- OptionName: "AWS_ACCESS_KEY_ID",
485
- Value: "<%= AccessKeyId %>",
486
- Namespace: "aws:elasticbeanstalk:application:environment",
487
- },
488
- {
489
- OptionName: "AWS_SECRET_ACCESS_KEY",
490
- Value: "<%= SecretAccessKey %>",
491
- Namespace: "aws:elasticbeanstalk:application:environment",
492
- },
493
- {
494
- OptionName: "FILESYSTEM_DISK",
495
- Value: "s3",
496
- Namespace: "aws:elasticbeanstalk:application:environment",
497
- },
498
- {
499
- OptionName: "FILESYSTEM_DISK_PUBLIC",
500
- Value: "s3-public",
501
- Namespace: "aws:elasticbeanstalk:application:environment",
502
- },
503
- {
504
- OptionName: "PORT",
505
- Value: "3333",
506
- Namespace: "aws:elasticbeanstalk:application:environment",
507
- },
508
- {
509
- OptionName: "LOG_LEVEL",
510
- Value: "info",
511
- Namespace: "aws:elasticbeanstalk:application:environment",
512
- },
513
- ],
292
+ shared: [],
514
293
  low: [],
515
294
  high: [],
516
295
  },
@@ -530,27 +309,6 @@ module.exports.eb = {
530
309
  Value: "aws-elasticbeanstalk-ec2-role",
531
310
  Namespace: "aws:autoscaling:launchconfiguration",
532
311
  },
533
- ({ database }) =>
534
- database && [
535
- {
536
- OptionName: "HasCoupledDatabase",
537
- Value: "true",
538
- Namespace: "aws:rds:dbinstance",
539
- },
540
- {
541
- OptionName: "DBEngineVersion",
542
- Value: "8.0.43",
543
- Namespace: "aws:rds:dbinstance",
544
- },
545
- {
546
- OptionName: "DBPassword",
547
- Value: generator.generate({
548
- length: 10,
549
- numbers: true,
550
- }),
551
- Namespace: "aws:rds:dbinstance",
552
- },
553
- ],
554
312
  ],
555
313
  low: [
556
314
  {
@@ -558,16 +316,6 @@ module.exports.eb = {
558
316
  Value: "SingleInstance",
559
317
  Namespace: "aws:elasticbeanstalk:environment",
560
318
  },
561
- {
562
- OptionName: "DOMAIN_LINK",
563
- Value: "<%= DOMAIN_LINK %>",
564
- Namespace: "aws:elasticbeanstalk:application:environment",
565
- },
566
- {
567
- OptionName: "EMAIL_LINK",
568
- Value: "mike.mellor@fishawack.com",
569
- Namespace: "aws:elasticbeanstalk:application:environment",
570
- },
571
319
  ],
572
320
  high: [
573
321
  {
@@ -612,6 +360,172 @@ module.exports.eb = {
612
360
  },
613
361
  ],
614
362
  },
363
+ secretPayloads: {
364
+ shared: {
365
+ database: ({ database }) =>
366
+ database && {
367
+ RDS_HOSTNAME: "<%= RDS_HOSTNAME %>",
368
+ RDS_PORT: "<%= RDS_PORT %>",
369
+ RDS_DB_NAME: "ebdb",
370
+ RDS_USERNAME: "ebroot",
371
+ RDS_PASSWORD: "<%= RDS_PASSWORD %>",
372
+ MYSQL_ATTR_SSL_CA: "/opt/rds-certs/global-bundle.pem",
373
+ },
374
+ },
375
+ low: {
376
+ app: {
377
+ DOMAIN_LINK: "<%= DOMAIN_LINK %>",
378
+ EMAIL_LINK: "mike.mellor@fishawack.com",
379
+ },
380
+ },
381
+ high: {},
382
+ wordpress: {
383
+ shared: {
384
+ app: {
385
+ AUTH_KEY: generateSafeKey({
386
+ length: 64,
387
+ numbers: true,
388
+ symbols: true,
389
+ }),
390
+ SECURE_AUTH_KEY: generateSafeKey({
391
+ length: 64,
392
+ numbers: true,
393
+ symbols: true,
394
+ }),
395
+ LOGGED_IN_KEY: generateSafeKey({
396
+ length: 64,
397
+ numbers: true,
398
+ symbols: true,
399
+ }),
400
+ NONCE_KEY: generateSafeKey({
401
+ length: 64,
402
+ numbers: true,
403
+ symbols: true,
404
+ }),
405
+ AUTH_SALT: generateSafeKey({
406
+ length: 64,
407
+ numbers: true,
408
+ symbols: true,
409
+ }),
410
+ SECURE_AUTH_SALT: generateSafeKey({
411
+ length: 64,
412
+ numbers: true,
413
+ symbols: true,
414
+ }),
415
+ LOGGED_IN_SALT: generateSafeKey({
416
+ length: 64,
417
+ numbers: true,
418
+ symbols: true,
419
+ }),
420
+ NONCE_SALT: generateSafeKey({
421
+ length: 64,
422
+ numbers: true,
423
+ symbols: true,
424
+ }),
425
+ },
426
+ storage: ({ storage }) =>
427
+ storage && {
428
+ S3_UPLOADS_BUCKET: "<%= s3Slug %>",
429
+ S3_UPLOADS_REGION: "<%= AWS_REGION %>",
430
+ S3_UPLOADS_KEY: "<%= AccessKeyId %>",
431
+ S3_UPLOADS_SECRET: "<%= SecretAccessKey %>",
432
+ },
433
+ },
434
+ },
435
+ laravel: {
436
+ shared: {
437
+ app: {
438
+ APP_ENV: "production",
439
+ APP_KEY: `base64:${Buffer.from(generator.generate({ length: 32, numbers: true, symbols: true })).toString("base64")}`,
440
+ APP_DEBUG: "false",
441
+ APP_URL: "https://<%= DOMAIN_LINK %>",
442
+ },
443
+ storage: ({ storage }) =>
444
+ storage && {
445
+ AWS_BUCKET: "<%= s3Slug %>",
446
+ AWS_DEFAULT_REGION: "<%= AWS_REGION %>",
447
+ AWS_ACCESS_KEY_ID: "<%= AccessKeyId %>",
448
+ AWS_SECRET_ACCESS_KEY: "<%= SecretAccessKey %>",
449
+ FILESYSTEM_DISK: "s3",
450
+ FILESYSTEM_DISK_PUBLIC: "s3-public",
451
+ },
452
+ },
453
+ high: {
454
+ app: {
455
+ SESSION_DRIVER: "database",
456
+ SESSION_SECURE_COOKIE: "true",
457
+ },
458
+ },
459
+ },
460
+ adonis: {
461
+ shared: {
462
+ app: {
463
+ NODE_ENV: "production",
464
+ APP_KEY: `base64:${Buffer.from(generator.generate({ length: 32, numbers: true, symbols: true })).toString("base64")}`,
465
+ APP_URL: "https://<%= DOMAIN_LINK %>",
466
+ SESSION_DRIVER: "cookie",
467
+ PORT: "3333",
468
+ LOG_LEVEL: "info",
469
+ },
470
+ storage: ({ storage }) =>
471
+ storage && {
472
+ AWS_BUCKET: "<%= s3Slug %>",
473
+ AWS_DEFAULT_REGION: "<%= AWS_REGION %>",
474
+ AWS_ACCESS_KEY_ID: "<%= AccessKeyId %>",
475
+ AWS_SECRET_ACCESS_KEY: "<%= SecretAccessKey %>",
476
+ FILESYSTEM_DISK: "s3",
477
+ FILESYSTEM_DISK_PUBLIC: "s3-public",
478
+ },
479
+ },
480
+ },
481
+ python: {
482
+ high: {
483
+ app: {
484
+ APP_ENV: "production",
485
+ },
486
+ },
487
+ },
488
+ },
489
+ buildSecretPayloads(config, data = {}) {
490
+ const { framework, availability = "low", platform, language } = config;
491
+ const result = { app: {}, storage: {}, database: {} };
492
+
493
+ const sources = [
494
+ this.secretPayloads.shared,
495
+ this.secretPayloads[availability],
496
+ this.secretPayloads[platform]?.shared,
497
+ this.secretPayloads[platform]?.[availability],
498
+ this.secretPayloads[language]?.shared,
499
+ this.secretPayloads[language]?.[availability],
500
+ this.secretPayloads[framework]?.shared,
501
+ this.secretPayloads[framework]?.[availability],
502
+ ];
503
+
504
+ for (const source of sources) {
505
+ if (!source) continue;
506
+ for (const group of ["app", "storage", "database"]) {
507
+ let values = source[group];
508
+ if (typeof values === "function") {
509
+ values = values(config, data);
510
+ }
511
+ if (values) {
512
+ Object.assign(result[group], values);
513
+ }
514
+ }
515
+ }
516
+
517
+ // Apply lodash template interpolation
518
+ const templateData = { ...process.env, ...data };
519
+ for (const group of ["app", "storage", "database"]) {
520
+ if (Object.keys(result[group]).length) {
521
+ result[group] = JSON.parse(
522
+ template(JSON.stringify(result[group]))(templateData),
523
+ );
524
+ }
525
+ }
526
+
527
+ return result;
528
+ },
615
529
  configurations: {
616
530
  php: {
617
531
  shared: [".ebextensions/php/ini.config"],
@@ -680,6 +594,7 @@ module.exports.eb = {
680
594
  ".platform/nginx/conf.d/elasticbeanstalk/laravel.conf",
681
595
  ".ebextensions/laravel/post-deploy.config",
682
596
  ".ebextensions/laravel/software.config",
597
+ ".ebextensions/laravel/rds-ssl.config",
683
598
  ],
684
599
  low: [],
685
600
  high: [],
@@ -1,4 +1,12 @@
1
- const { EC2Client, DescribeKeyPairsCommand } = require("@aws-sdk/client-ec2");
1
+ const {
2
+ EC2Client,
3
+ DescribeKeyPairsCommand,
4
+ CreateSecurityGroupCommand,
5
+ AuthorizeSecurityGroupIngressCommand,
6
+ RevokeSecurityGroupIngressCommand,
7
+ DeleteSecurityGroupCommand,
8
+ DescribeSecurityGroupsCommand,
9
+ } = require("@aws-sdk/client-ec2");
2
10
  const { Spinner } = require("../../libs/utilities");
3
11
 
4
12
  module.exports.getKeyPair = async (KeyName) => {
@@ -15,3 +23,144 @@ module.exports.getKeyPair = async (KeyName) => {
15
23
 
16
24
  return res;
17
25
  };
26
+
27
+ module.exports.createRDSSecurityGroup = async (name, tags = []) => {
28
+ const client = new EC2Client({});
29
+
30
+ const groupName = `${name}-rds`;
31
+
32
+ const sg = await Spinner.prototype.simple(
33
+ `Creating security group ${groupName}`,
34
+ () => {
35
+ return client.send(
36
+ new CreateSecurityGroupCommand({
37
+ GroupName: groupName,
38
+ Description: `RDS access for ${name}`,
39
+ TagSpecifications: [
40
+ {
41
+ ResourceType: "security-group",
42
+ Tags: [
43
+ {
44
+ Key: "Name",
45
+ Value: groupName,
46
+ },
47
+ {
48
+ Key: "client",
49
+ Value: process.env.AWS_PROFILE,
50
+ },
51
+ ].concat(tags),
52
+ },
53
+ ],
54
+ }),
55
+ );
56
+ },
57
+ );
58
+
59
+ return sg.GroupId;
60
+ };
61
+
62
+ module.exports.authorizeRDSIngress = async (
63
+ rdsSecurityGroupId,
64
+ sourceSecurityGroupId,
65
+ ) => {
66
+ const client = new EC2Client({});
67
+
68
+ await Spinner.prototype.simple(
69
+ `Adding MySQL inbound rule from EB security group`,
70
+ () => {
71
+ return client.send(
72
+ new AuthorizeSecurityGroupIngressCommand({
73
+ GroupId: rdsSecurityGroupId,
74
+ IpPermissions: [
75
+ {
76
+ IpProtocol: "tcp",
77
+ FromPort: 3306,
78
+ ToPort: 3306,
79
+ UserIdGroupPairs: [
80
+ {
81
+ GroupId: sourceSecurityGroupId,
82
+ Description:
83
+ "MySQL access for EB instances",
84
+ },
85
+ ],
86
+ },
87
+ ],
88
+ }),
89
+ );
90
+ },
91
+ );
92
+ };
93
+
94
+ module.exports.revokeRDSIngress = async (
95
+ rdsSecurityGroupId,
96
+ sourceSecurityGroupId,
97
+ ) => {
98
+ const client = new EC2Client({});
99
+
100
+ await Spinner.prototype.simple(
101
+ `Removing MySQL inbound rule from RDS security group`,
102
+ () => {
103
+ return client.send(
104
+ new RevokeSecurityGroupIngressCommand({
105
+ GroupId: rdsSecurityGroupId,
106
+ IpPermissions: [
107
+ {
108
+ IpProtocol: "tcp",
109
+ FromPort: 3306,
110
+ ToPort: 3306,
111
+ UserIdGroupPairs: [
112
+ {
113
+ GroupId: sourceSecurityGroupId,
114
+ },
115
+ ],
116
+ },
117
+ ],
118
+ }),
119
+ );
120
+ },
121
+ );
122
+ };
123
+
124
+ module.exports.findSecurityGroupByTag = async (filters = []) => {
125
+ const client = new EC2Client({});
126
+
127
+ const res = await Spinner.prototype.simple(
128
+ `Looking up security group by filters`,
129
+ () => {
130
+ return client.send(
131
+ new DescribeSecurityGroupsCommand({
132
+ Filters: filters,
133
+ }),
134
+ );
135
+ },
136
+ );
137
+
138
+ return res.SecurityGroups[0] || null;
139
+ };
140
+
141
+ module.exports.findSecurityGroupByName = async (name) => {
142
+ const client = new EC2Client({});
143
+
144
+ const res = await Spinner.prototype.simple(
145
+ `Looking up security group ${name}`,
146
+ () => {
147
+ return client.send(
148
+ new DescribeSecurityGroupsCommand({
149
+ Filters: [{ Name: "group-name", Values: [name] }],
150
+ }),
151
+ );
152
+ },
153
+ );
154
+
155
+ return res.SecurityGroups[0] || null;
156
+ };
157
+
158
+ module.exports.deleteSecurityGroup = async (groupId) => {
159
+ const client = new EC2Client({});
160
+
161
+ await Spinner.prototype.simple(`Deleting security group ${groupId}`, () => {
162
+ return client.send(
163
+ new DeleteSecurityGroupCommand({ GroupId: groupId }),
164
+ );
165
+ });
166
+ };
@@ -10,6 +10,8 @@ const {
10
10
  DescribeEnvironmentsCommand,
11
11
  DescribeApplicationsCommand,
12
12
  DescribeApplicationVersionsCommand,
13
+ DescribeConfigurationSettingsCommand,
14
+ UpdateEnvironmentCommand,
13
15
  CreateApplicationVersionCommand,
14
16
  ListAvailableSolutionStacksCommand,
15
17
  } = require("@aws-sdk/client-elastic-beanstalk");
@@ -31,6 +33,16 @@ module.exports.createElasticBeanstalkApplication = async (name) => {
31
33
  return res;
32
34
  };
33
35
 
36
+ module.exports.describeEnvironment = async (name) => {
37
+ const client = new ElasticBeanstalkClient({});
38
+
39
+ return client.send(
40
+ new DescribeEnvironmentsCommand({
41
+ EnvironmentNames: [name],
42
+ }),
43
+ );
44
+ };
45
+
34
46
  module.exports.createElasticBeanstalkEnvironment = async (
35
47
  name,
36
48
  { language },
@@ -230,3 +242,45 @@ module.exports.deleteApplicationVersion = async (
230
242
  }),
231
243
  );
232
244
  };
245
+
246
+ module.exports.describeConfigurationSettings = async (
247
+ applicationName,
248
+ environmentName,
249
+ ) => {
250
+ const client = new ElasticBeanstalkClient({});
251
+
252
+ const res = await Spinner.prototype.simple(
253
+ `Retrieving configuration for ${environmentName}`,
254
+ () => {
255
+ return client.send(
256
+ new DescribeConfigurationSettingsCommand({
257
+ ApplicationName: applicationName,
258
+ EnvironmentName: environmentName,
259
+ }),
260
+ );
261
+ },
262
+ );
263
+
264
+ return res.ConfigurationSettings[0]?.OptionSettings || [];
265
+ };
266
+
267
+ module.exports.updateEnvironmentSettings = async (
268
+ environmentName,
269
+ optionSettings = [],
270
+ optionsToRemove = [],
271
+ ) => {
272
+ const client = new ElasticBeanstalkClient({});
273
+
274
+ await Spinner.prototype.simple(
275
+ `Updating environment ${environmentName}`,
276
+ () => {
277
+ return client.send(
278
+ new UpdateEnvironmentCommand({
279
+ EnvironmentName: environmentName,
280
+ OptionSettings: optionSettings,
281
+ OptionsToRemove: optionsToRemove,
282
+ }),
283
+ );
284
+ },
285
+ );
286
+ };