@studion/infra-code-blocks 0.0.11 → 0.1.0
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/README.md +14 -9
- package/dist/components/database.d.ts +11 -5
- package/dist/components/database.js +43 -25
- package/dist/components/ec2-ssm-connect.js +5 -10
- package/dist/components/project.js +5 -0
- package/dist/components/redis.js +1 -1
- package/dist/components/static-site.d.ts +5 -0
- package/dist/components/static-site.js +39 -23
- package/dist/components/web-server.d.ts +9 -2
- package/dist/components/web-server.js +90 -49
- package/dist/constants.d.ts +5 -0
- package/dist/constants.js +6 -1
- package/package.json +1 -1
- /package/dist/{components/types.d.ts → types/size.d.ts} +0 -0
- /package/dist/{components/types.js → types/size.js} +0 -0
package/README.md
CHANGED
|
@@ -92,7 +92,7 @@ type DatabaseService = {
|
|
|
92
92
|
serviceName: string;
|
|
93
93
|
dbName: pulumi.Input<string>;
|
|
94
94
|
username: pulumi.Input<string>;
|
|
95
|
-
password
|
|
95
|
+
password: pulumi.Input<string>;
|
|
96
96
|
applyImmediately?: pulumi.Input<boolean>;
|
|
97
97
|
skipFinalSnapshot?: pulumi.Input<boolean>;
|
|
98
98
|
allocatedStorage?: pulumi.Input<number>;
|
|
@@ -237,7 +237,7 @@ AWS RDS Postgres instance.
|
|
|
237
237
|
Features:
|
|
238
238
|
|
|
239
239
|
- enabled encryption with a symmetric encryption key
|
|
240
|
-
- deployed inside
|
|
240
|
+
- deployed inside an isolated subnet
|
|
241
241
|
- backup enabled with retention period set to 14 days
|
|
242
242
|
|
|
243
243
|
<br>
|
|
@@ -256,8 +256,8 @@ new Database(name: string, args: DatabaseArgs, opts?: pulumi.CustomResourceOptio
|
|
|
256
256
|
type DatabaseArgs = {
|
|
257
257
|
dbName: pulumi.Input<string>;
|
|
258
258
|
username: pulumi.Input<string>;
|
|
259
|
+
password: pulumi.Input<string>;
|
|
259
260
|
vpc: awsx.ec2.Vpc;
|
|
260
|
-
password?: pulumi.Input<string>;
|
|
261
261
|
applyImmediately?: pulumi.Input<boolean>;
|
|
262
262
|
skipFinalSnapshot?: pulumi.Input<boolean>;
|
|
263
263
|
allocatedStorage?: pulumi.Input<number>;
|
|
@@ -269,9 +269,8 @@ type DatabaseArgs = {
|
|
|
269
269
|
};
|
|
270
270
|
```
|
|
271
271
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
as `passwordSecret`.
|
|
272
|
+
The database password is stored as a secret inside AWS Secret Manager.
|
|
273
|
+
The secret will be available on the `Database` resource as `passwordSecret`.
|
|
275
274
|
|
|
276
275
|
### Redis
|
|
277
276
|
|
|
@@ -429,16 +428,16 @@ Where `CLUSTER_NAME` is the name of the ECS cluster and `TASK_FAMILY_NAME` is th
|
|
|
429
428
|
|
|
430
429
|
## SSM Connect
|
|
431
430
|
|
|
432
|
-
The [Database](#database) component deploys a database instance inside a
|
|
431
|
+
The [Database](#database) component deploys a database instance inside a isolated subnet,
|
|
433
432
|
and it's not publicly accessible from outside of VPC.
|
|
434
433
|
<br>
|
|
435
434
|
In order to connect to the database we need to deploy the ec2 instance which will be used
|
|
436
435
|
to forward traffic to the database instance.
|
|
437
436
|
<br>
|
|
438
|
-
Because of security reasons, the ec2 instance is
|
|
437
|
+
Because of security reasons, the ec2 instance is deployed inside a private subnet
|
|
439
438
|
which means we can't directly connect to it. For that purpose, we use AWS System Manager
|
|
440
439
|
which enables us to connect to the ec2 instance even though it's inside a private subnet.
|
|
441
|
-
|
|
440
|
+
Another benefit of using AWS SSM is that we don't need a ssh key pair.
|
|
442
441
|
|
|
443
442
|

|
|
444
443
|
|
|
@@ -501,3 +500,9 @@ const project = new studion.Project('demo-project', {
|
|
|
501
500
|
|
|
502
501
|
- [ ] Add worker service for executing tasks
|
|
503
502
|
- [ ] Add MongoDB service
|
|
503
|
+
- [x] reduce ec2 security group rules and change cidr block to be within VPC
|
|
504
|
+
- [x] change db private subnet ids to isolated subnet ids
|
|
505
|
+
- [x] change default instance classes to t4g
|
|
506
|
+
- [x] extract ami images/ instance classes, etc...
|
|
507
|
+
- [x] remove duplicated types
|
|
508
|
+
- [ ] extract constructor code to private methods...
|
|
@@ -11,14 +11,14 @@ export type DatabaseArgs = {
|
|
|
11
11
|
*/
|
|
12
12
|
username: pulumi.Input<string>;
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* Password for the master DB user.
|
|
15
|
+
* The value will be stored as a secret in AWS Secret Manager.
|
|
15
16
|
*/
|
|
16
|
-
|
|
17
|
+
password: pulumi.Input<string>;
|
|
17
18
|
/**
|
|
18
|
-
*
|
|
19
|
-
* The value will be stored as a secret in AWS Secret Manager.
|
|
19
|
+
* The awsx.ec2.Vpc resource.
|
|
20
20
|
*/
|
|
21
|
-
|
|
21
|
+
vpc: awsx.ec2.Vpc;
|
|
22
22
|
/**
|
|
23
23
|
* Specifies whether any database modifications are applied immediately, or during the next maintenance window. Default is false.
|
|
24
24
|
*/
|
|
@@ -47,10 +47,16 @@ export type DatabaseArgs = {
|
|
|
47
47
|
}>;
|
|
48
48
|
};
|
|
49
49
|
export declare class Database extends pulumi.ComponentResource {
|
|
50
|
+
name: string;
|
|
50
51
|
instance: aws.rds.Instance;
|
|
51
52
|
kms: aws.kms.Key;
|
|
52
53
|
dbSubnetGroup: aws.rds.SubnetGroup;
|
|
53
54
|
dbSecurityGroup: aws.ec2.SecurityGroup;
|
|
54
55
|
passwordSecret: aws.secretsmanager.Secret;
|
|
55
56
|
constructor(name: string, args: DatabaseArgs, opts?: pulumi.ComponentResourceOptions);
|
|
57
|
+
private createSubnetGroup;
|
|
58
|
+
private createSecurityGroup;
|
|
59
|
+
private createEncryptionKey;
|
|
60
|
+
private createPasswordSecret;
|
|
61
|
+
private createDatabaseInstance;
|
|
56
62
|
}
|
|
@@ -8,49 +8,67 @@ const defaults = {
|
|
|
8
8
|
skipFinalSnapshot: false,
|
|
9
9
|
allocatedStorage: 20,
|
|
10
10
|
maxAllocatedStorage: 100,
|
|
11
|
-
instanceClass: 'db.
|
|
11
|
+
instanceClass: 'db.t4g.micro',
|
|
12
12
|
};
|
|
13
13
|
class Database extends pulumi.ComponentResource {
|
|
14
14
|
constructor(name, args, opts = {}) {
|
|
15
15
|
super('studion:Database', name, {}, opts);
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
this.
|
|
20
|
-
|
|
16
|
+
this.name = name;
|
|
17
|
+
const { vpc, password } = args;
|
|
18
|
+
this.dbSubnetGroup = this.createSubnetGroup({ vpc });
|
|
19
|
+
this.dbSecurityGroup = this.createSecurityGroup({ vpc });
|
|
20
|
+
this.kms = this.createEncryptionKey();
|
|
21
|
+
this.passwordSecret = this.createPasswordSecret({ password });
|
|
22
|
+
this.instance = this.createDatabaseInstance(args);
|
|
23
|
+
this.registerOutputs();
|
|
24
|
+
}
|
|
25
|
+
createSubnetGroup({ vpc }) {
|
|
26
|
+
const dbSubnetGroup = new aws.rds.SubnetGroup(`${this.name}-subnet-group`, {
|
|
27
|
+
subnetIds: vpc.isolatedSubnetIds,
|
|
21
28
|
}, { parent: this });
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
return dbSubnetGroup;
|
|
30
|
+
}
|
|
31
|
+
createSecurityGroup({ vpc }) {
|
|
32
|
+
const dbSecurityGroup = new aws.ec2.SecurityGroup(`${this.name}-security-group`, {
|
|
33
|
+
vpcId: vpc.vpcId,
|
|
24
34
|
ingress: [
|
|
25
35
|
{
|
|
26
36
|
protocol: 'tcp',
|
|
27
37
|
fromPort: 5432,
|
|
28
38
|
toPort: 5432,
|
|
29
|
-
cidrBlocks: [
|
|
39
|
+
cidrBlocks: [vpc.vpc.cidrBlock],
|
|
30
40
|
},
|
|
31
41
|
],
|
|
32
42
|
}, { parent: this });
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
return dbSecurityGroup;
|
|
44
|
+
}
|
|
45
|
+
createEncryptionKey() {
|
|
46
|
+
const kms = new aws.kms.Key(`${this.name}-rds-key`, {
|
|
47
|
+
description: `${this.name} RDS encryption key`,
|
|
35
48
|
customerMasterKeySpec: 'SYMMETRIC_DEFAULT',
|
|
36
49
|
isEnabled: true,
|
|
37
50
|
keyUsage: 'ENCRYPT_DECRYPT',
|
|
38
51
|
multiRegion: false,
|
|
39
52
|
enableKeyRotation: true,
|
|
40
53
|
}, { parent: this });
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
54
|
+
return kms;
|
|
55
|
+
}
|
|
56
|
+
createPasswordSecret({ password }) {
|
|
57
|
+
const project = pulumi.getProject();
|
|
58
|
+
const stack = pulumi.getStack();
|
|
59
|
+
const passwordSecret = new aws.secretsmanager.Secret(`${this.name}-password-secret`, {
|
|
60
|
+
namePrefix: `${stack}/${project}/DatabasePassword-`,
|
|
47
61
|
}, { parent: this });
|
|
48
|
-
const passwordSecretValue = new aws.secretsmanager.SecretVersion(`${name}-password-secret-value`, {
|
|
49
|
-
secretId:
|
|
62
|
+
const passwordSecretValue = new aws.secretsmanager.SecretVersion(`${this.name}-password-secret-value`, {
|
|
63
|
+
secretId: passwordSecret.id,
|
|
50
64
|
secretString: password,
|
|
51
|
-
}, { parent: this, dependsOn: [
|
|
52
|
-
|
|
53
|
-
|
|
65
|
+
}, { parent: this, dependsOn: [passwordSecret] });
|
|
66
|
+
return passwordSecret;
|
|
67
|
+
}
|
|
68
|
+
createDatabaseInstance(args) {
|
|
69
|
+
const argsWithDefaults = Object.assign({}, defaults, args);
|
|
70
|
+
const instance = new aws.rds.Instance(`${this.name}-rds`, {
|
|
71
|
+
identifierPrefix: `${this.name}-`,
|
|
54
72
|
engine: 'postgres',
|
|
55
73
|
engineVersion: '14.9',
|
|
56
74
|
allocatedStorage: argsWithDefaults.allocatedStorage,
|
|
@@ -58,7 +76,7 @@ class Database extends pulumi.ComponentResource {
|
|
|
58
76
|
instanceClass: argsWithDefaults.instanceClass,
|
|
59
77
|
dbName: argsWithDefaults.dbName,
|
|
60
78
|
username: argsWithDefaults.username,
|
|
61
|
-
password,
|
|
79
|
+
password: argsWithDefaults.password,
|
|
62
80
|
dbSubnetGroupName: this.dbSubnetGroup.name,
|
|
63
81
|
vpcSecurityGroupIds: [this.dbSecurityGroup.id],
|
|
64
82
|
storageEncrypted: true,
|
|
@@ -68,12 +86,12 @@ class Database extends pulumi.ComponentResource {
|
|
|
68
86
|
applyImmediately: argsWithDefaults.applyImmediately,
|
|
69
87
|
autoMinorVersionUpgrade: true,
|
|
70
88
|
maintenanceWindow: 'Mon:07:00-Mon:07:30',
|
|
71
|
-
finalSnapshotIdentifier: `${name}-final-snapshot`,
|
|
89
|
+
finalSnapshotIdentifier: `${this.name}-final-snapshot`,
|
|
72
90
|
backupWindow: '06:00-06:30',
|
|
73
91
|
backupRetentionPeriod: 14,
|
|
74
92
|
tags: argsWithDefaults.tags,
|
|
75
93
|
}, { parent: this });
|
|
76
|
-
|
|
94
|
+
return instance;
|
|
77
95
|
}
|
|
78
96
|
}
|
|
79
97
|
exports.Database = Database;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Ec2SSMConnect = void 0;
|
|
4
4
|
const pulumi = require("@pulumi/pulumi");
|
|
5
5
|
const aws = require("@pulumi/aws");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
6
7
|
const config = new pulumi.Config('aws');
|
|
7
8
|
const awsRegion = config.require('region');
|
|
8
9
|
class Ec2SSMConnect extends pulumi.ComponentResource {
|
|
@@ -15,19 +16,13 @@ class Ec2SSMConnect extends pulumi.ComponentResource {
|
|
|
15
16
|
protocol: 'tcp',
|
|
16
17
|
fromPort: 22,
|
|
17
18
|
toPort: 22,
|
|
18
|
-
cidrBlocks: [
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
protocol: 'tcp',
|
|
22
|
-
fromPort: 80,
|
|
23
|
-
toPort: 80,
|
|
24
|
-
cidrBlocks: ['0.0.0.0/0'],
|
|
19
|
+
cidrBlocks: [args.vpc.vpc.cidrBlock],
|
|
25
20
|
},
|
|
26
21
|
{
|
|
27
22
|
protocol: 'tcp',
|
|
28
23
|
fromPort: 443,
|
|
29
24
|
toPort: 443,
|
|
30
|
-
cidrBlocks: [
|
|
25
|
+
cidrBlocks: [args.vpc.vpc.cidrBlock],
|
|
31
26
|
},
|
|
32
27
|
],
|
|
33
28
|
egress: [
|
|
@@ -57,9 +52,9 @@ class Ec2SSMConnect extends pulumi.ComponentResource {
|
|
|
57
52
|
role: role.name,
|
|
58
53
|
}, { parent: this, dependsOn: [ssmPolicyAttachment] });
|
|
59
54
|
this.ec2 = new aws.ec2.Instance(`${name}-ec2`, {
|
|
60
|
-
ami:
|
|
55
|
+
ami: constants_1.Ec2AMI.AmazonLinux2023.ARM,
|
|
61
56
|
associatePublicIpAddress: false,
|
|
62
|
-
instanceType: '
|
|
57
|
+
instanceType: 't4g.nano',
|
|
63
58
|
iamInstanceProfile: ssmProfile.name,
|
|
64
59
|
subnetId,
|
|
65
60
|
vpcSecurityGroupIds: [this.ec2SecurityGroup.id],
|
|
@@ -50,6 +50,11 @@ class Project extends pulumi.ComponentResource {
|
|
|
50
50
|
numberOfAvailabilityZones: 2,
|
|
51
51
|
enableDnsHostnames: true,
|
|
52
52
|
enableDnsSupport: true,
|
|
53
|
+
subnetSpecs: [
|
|
54
|
+
{ type: awsx.ec2.SubnetType.Public, cidrMask: 24 },
|
|
55
|
+
{ type: awsx.ec2.SubnetType.Private, cidrMask: 24 },
|
|
56
|
+
{ type: awsx.ec2.SubnetType.Isolated, cidrMask: 24 },
|
|
57
|
+
],
|
|
53
58
|
}, { parent: this });
|
|
54
59
|
return vpc;
|
|
55
60
|
}
|
package/dist/components/redis.js
CHANGED
|
@@ -21,7 +21,7 @@ class Redis extends pulumi.ComponentResource {
|
|
|
21
21
|
tls: true,
|
|
22
22
|
}, { provider: opts.provider, parent: this });
|
|
23
23
|
this.passwordSecret = new aws.secretsmanager.Secret(`${name}-password-secret`, {
|
|
24
|
-
|
|
24
|
+
namePrefix: `${stack}/${project}/RedisPassword-`,
|
|
25
25
|
}, { parent: this, dependsOn: [this.instance] });
|
|
26
26
|
const passwordSecretValue = new aws.secretsmanager.SecretVersion(`${name}-password-secret-value`, {
|
|
27
27
|
secretId: this.passwordSecret.id,
|
|
@@ -19,8 +19,13 @@ export type StaticSiteArgs = {
|
|
|
19
19
|
}>;
|
|
20
20
|
};
|
|
21
21
|
export declare class StaticSite extends pulumi.ComponentResource {
|
|
22
|
+
name: string;
|
|
22
23
|
certificate: AcmCertificate;
|
|
23
24
|
bucket: aws.s3.Bucket;
|
|
24
25
|
cloudfront: aws.cloudfront.Distribution;
|
|
25
26
|
constructor(name: string, args: StaticSiteArgs, opts?: pulumi.ComponentResourceOptions);
|
|
27
|
+
private createTlsCertificate;
|
|
28
|
+
private createPublicBucket;
|
|
29
|
+
private createCloudfrontDistribution;
|
|
30
|
+
private createDnsRecord;
|
|
26
31
|
}
|
|
@@ -7,25 +7,38 @@ const acm_certificate_1 = require("./acm-certificate");
|
|
|
7
7
|
class StaticSite extends pulumi.ComponentResource {
|
|
8
8
|
constructor(name, args, opts = {}) {
|
|
9
9
|
super('studion:StaticSite', name, {}, opts);
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
this.name = name;
|
|
11
|
+
const { domain, hostedZoneId, tags } = args;
|
|
12
|
+
this.certificate = this.createTlsCertificate({ domain, hostedZoneId });
|
|
13
|
+
this.bucket = this.createPublicBucket({ tags });
|
|
14
|
+
this.cloudfront = this.createCloudfrontDistribution({ domain, tags });
|
|
15
|
+
this.createDnsRecord({ domain, hostedZoneId });
|
|
16
|
+
this.registerOutputs();
|
|
17
|
+
}
|
|
18
|
+
createTlsCertificate({ domain, hostedZoneId, }) {
|
|
19
|
+
const certificate = new acm_certificate_1.AcmCertificate(`${domain}-acm-certificate`, {
|
|
20
|
+
domain,
|
|
21
|
+
hostedZoneId,
|
|
13
22
|
}, { parent: this });
|
|
14
|
-
|
|
23
|
+
return certificate;
|
|
24
|
+
}
|
|
25
|
+
createPublicBucket({ tags }) {
|
|
26
|
+
const bucket = new aws.s3.Bucket(`${this.name}-bucket`, {
|
|
27
|
+
bucketPrefix: `${this.name}-`,
|
|
15
28
|
website: {
|
|
16
29
|
indexDocument: 'index.html',
|
|
17
30
|
errorDocument: 'index.html',
|
|
18
31
|
},
|
|
19
|
-
tags
|
|
32
|
+
tags,
|
|
20
33
|
}, { parent: this });
|
|
21
|
-
const bucketPublicAccessBlock = new aws.s3.BucketPublicAccessBlock(`${name}-bucket-access-block`, {
|
|
34
|
+
const bucketPublicAccessBlock = new aws.s3.BucketPublicAccessBlock(`${this.name}-bucket-access-block`, {
|
|
22
35
|
bucket: bucket.id,
|
|
23
36
|
blockPublicAcls: false,
|
|
24
37
|
blockPublicPolicy: false,
|
|
25
38
|
ignorePublicAcls: false,
|
|
26
39
|
restrictPublicBuckets: false,
|
|
27
40
|
}, { parent: this });
|
|
28
|
-
const siteBucketPolicy = new aws.s3.BucketPolicy(`${name}-bucket-policy`, {
|
|
41
|
+
const siteBucketPolicy = new aws.s3.BucketPolicy(`${this.name}-bucket-policy`, {
|
|
29
42
|
bucket: bucket.bucket,
|
|
30
43
|
policy: bucket.bucket.apply(publicReadPolicy),
|
|
31
44
|
}, { parent: this, dependsOn: [bucketPublicAccessBlock] });
|
|
@@ -42,22 +55,25 @@ class StaticSite extends pulumi.ComponentResource {
|
|
|
42
55
|
],
|
|
43
56
|
};
|
|
44
57
|
}
|
|
45
|
-
|
|
58
|
+
return bucket;
|
|
59
|
+
}
|
|
60
|
+
createCloudfrontDistribution({ domain, tags, }) {
|
|
61
|
+
const cloudfront = new aws.cloudfront.Distribution(`${this.name}-cloudfront`, {
|
|
46
62
|
enabled: true,
|
|
47
63
|
defaultRootObject: 'index.html',
|
|
48
|
-
aliases: [
|
|
64
|
+
aliases: [domain],
|
|
49
65
|
isIpv6Enabled: true,
|
|
50
66
|
waitForDeployment: true,
|
|
51
67
|
httpVersion: 'http2and3',
|
|
52
68
|
viewerCertificate: {
|
|
53
|
-
acmCertificateArn: certificate.certificate.arn,
|
|
69
|
+
acmCertificateArn: this.certificate.certificate.arn,
|
|
54
70
|
sslSupportMethod: 'sni-only',
|
|
55
71
|
minimumProtocolVersion: 'TLSv1.2_2021',
|
|
56
72
|
},
|
|
57
73
|
origins: [
|
|
58
74
|
{
|
|
59
|
-
originId: bucket.arn,
|
|
60
|
-
domainName: bucket.websiteEndpoint,
|
|
75
|
+
originId: this.bucket.arn,
|
|
76
|
+
domainName: this.bucket.websiteEndpoint,
|
|
61
77
|
connectionAttempts: 3,
|
|
62
78
|
connectionTimeout: 10,
|
|
63
79
|
customOriginConfig: {
|
|
@@ -69,7 +85,7 @@ class StaticSite extends pulumi.ComponentResource {
|
|
|
69
85
|
},
|
|
70
86
|
],
|
|
71
87
|
defaultCacheBehavior: {
|
|
72
|
-
targetOriginId: bucket.arn,
|
|
88
|
+
targetOriginId: this.bucket.arn,
|
|
73
89
|
viewerProtocolPolicy: 'redirect-to-https',
|
|
74
90
|
allowedMethods: ['GET', 'HEAD', 'OPTIONS'],
|
|
75
91
|
cachedMethods: ['GET', 'HEAD', 'OPTIONS'],
|
|
@@ -86,24 +102,24 @@ class StaticSite extends pulumi.ComponentResource {
|
|
|
86
102
|
restrictions: {
|
|
87
103
|
geoRestriction: { restrictionType: 'none' },
|
|
88
104
|
},
|
|
89
|
-
tags
|
|
105
|
+
tags,
|
|
90
106
|
}, { parent: this });
|
|
91
|
-
|
|
107
|
+
return cloudfront;
|
|
108
|
+
}
|
|
109
|
+
createDnsRecord({ domain, hostedZoneId, }) {
|
|
110
|
+
const cdnAliasRecord = new aws.route53.Record(`${this.name}-cdn-route53-record`, {
|
|
92
111
|
type: 'A',
|
|
93
|
-
name:
|
|
94
|
-
zoneId:
|
|
112
|
+
name: domain,
|
|
113
|
+
zoneId: hostedZoneId,
|
|
95
114
|
aliases: [
|
|
96
115
|
{
|
|
97
|
-
name: cloudfront.domainName,
|
|
98
|
-
zoneId: cloudfront.hostedZoneId,
|
|
116
|
+
name: this.cloudfront.domainName,
|
|
117
|
+
zoneId: this.cloudfront.hostedZoneId,
|
|
99
118
|
evaluateTargetHealth: true,
|
|
100
119
|
},
|
|
101
120
|
],
|
|
102
121
|
}, { parent: this });
|
|
103
|
-
|
|
104
|
-
this.bucket = bucket;
|
|
105
|
-
this.cloudfront = cloudfront;
|
|
106
|
-
this.registerOutputs();
|
|
122
|
+
return cdnAliasRecord;
|
|
107
123
|
}
|
|
108
124
|
}
|
|
109
125
|
exports.StaticSite = StaticSite;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as pulumi from '@pulumi/pulumi';
|
|
2
2
|
import * as aws from '@pulumi/aws';
|
|
3
3
|
import * as awsx from '@pulumi/awsx';
|
|
4
|
-
import { Size } from '
|
|
4
|
+
import { Size } from '../types/size';
|
|
5
5
|
import { AcmCertificate } from './acm-certificate';
|
|
6
6
|
export type RoleInlinePolicy = {
|
|
7
7
|
/**
|
|
@@ -85,6 +85,7 @@ export type WebServerArgs = {
|
|
|
85
85
|
}>;
|
|
86
86
|
};
|
|
87
87
|
export declare class WebServer extends pulumi.ComponentResource {
|
|
88
|
+
name: string;
|
|
88
89
|
certificate: AcmCertificate;
|
|
89
90
|
logGroup: aws.cloudwatch.LogGroup;
|
|
90
91
|
lbSecurityGroup: aws.ec2.SecurityGroup;
|
|
@@ -92,8 +93,14 @@ export declare class WebServer extends pulumi.ComponentResource {
|
|
|
92
93
|
lbTargetGroup: aws.lb.TargetGroup;
|
|
93
94
|
lbHttpListener: aws.lb.Listener;
|
|
94
95
|
lbTlsListener: aws.lb.Listener;
|
|
95
|
-
serviceSecurityGroup: aws.ec2.SecurityGroup;
|
|
96
96
|
taskDefinition: aws.ecs.TaskDefinition;
|
|
97
97
|
service: aws.ecs.Service;
|
|
98
98
|
constructor(name: string, args: WebServerArgs, opts?: pulumi.ComponentResourceOptions);
|
|
99
|
+
private createTlsCertificate;
|
|
100
|
+
private createLogGroup;
|
|
101
|
+
private createLoadBalancer;
|
|
102
|
+
private createTaskDefinition;
|
|
103
|
+
private createEcsService;
|
|
104
|
+
private createDnsRecord;
|
|
105
|
+
private enableAutoscaling;
|
|
99
106
|
}
|
|
@@ -34,17 +34,39 @@ const defaults = {
|
|
|
34
34
|
class WebServer extends pulumi.ComponentResource {
|
|
35
35
|
constructor(name, args, opts = {}) {
|
|
36
36
|
super('studion:WebServer', name, {}, opts);
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
this.name = name;
|
|
38
|
+
const { domain, hostedZoneId, vpc, port, healtCheckPath } = args;
|
|
39
|
+
this.certificate = this.createTlsCertificate({ domain, hostedZoneId });
|
|
40
|
+
this.logGroup = this.createLogGroup();
|
|
41
|
+
const { lb, lbTargetGroup, lbHttpListener, lbTlsListener, lbSecurityGroup, } = this.createLoadBalancer({ vpc, port, healtCheckPath });
|
|
42
|
+
this.lb = lb;
|
|
43
|
+
this.lbTargetGroup = lbTargetGroup;
|
|
44
|
+
this.lbHttpListener = lbHttpListener;
|
|
45
|
+
this.lbTlsListener = lbTlsListener;
|
|
46
|
+
this.lbSecurityGroup = lbSecurityGroup;
|
|
47
|
+
this.taskDefinition = this.createTaskDefinition(args);
|
|
48
|
+
this.service = this.createEcsService(args);
|
|
49
|
+
this.createDnsRecord({ domain, hostedZoneId });
|
|
50
|
+
this.enableAutoscaling(args);
|
|
51
|
+
this.registerOutputs();
|
|
52
|
+
}
|
|
53
|
+
createTlsCertificate({ domain, hostedZoneId, }) {
|
|
54
|
+
const certificate = new acm_certificate_1.AcmCertificate(`${domain}-acm-certificate`, {
|
|
55
|
+
domain,
|
|
56
|
+
hostedZoneId,
|
|
41
57
|
}, { parent: this });
|
|
42
|
-
|
|
58
|
+
return certificate;
|
|
59
|
+
}
|
|
60
|
+
createLogGroup() {
|
|
61
|
+
const logGroup = new aws.cloudwatch.LogGroup(`${this.name}-log-group`, {
|
|
43
62
|
retentionInDays: 14,
|
|
44
|
-
|
|
63
|
+
namePrefix: `/ecs/${this.name}-`,
|
|
45
64
|
}, { parent: this });
|
|
46
|
-
|
|
47
|
-
|
|
65
|
+
return logGroup;
|
|
66
|
+
}
|
|
67
|
+
createLoadBalancer({ vpc, port, healtCheckPath, }) {
|
|
68
|
+
const lbSecurityGroup = new aws.ec2.SecurityGroup(`${this.name}-lb-security-group`, {
|
|
69
|
+
vpcId: vpc.vpcId,
|
|
48
70
|
ingress: [
|
|
49
71
|
{
|
|
50
72
|
protocol: 'tcp',
|
|
@@ -68,29 +90,29 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
68
90
|
},
|
|
69
91
|
],
|
|
70
92
|
}, { parent: this });
|
|
71
|
-
|
|
72
|
-
|
|
93
|
+
const lb = new aws.lb.LoadBalancer(`${this.name}-lb`, {
|
|
94
|
+
namePrefix: `${this.name}-lb-`,
|
|
73
95
|
loadBalancerType: 'application',
|
|
74
|
-
subnets:
|
|
75
|
-
securityGroups: [
|
|
96
|
+
subnets: vpc.publicSubnetIds,
|
|
97
|
+
securityGroups: [lbSecurityGroup.id],
|
|
76
98
|
internal: false,
|
|
77
99
|
ipAddressType: 'ipv4',
|
|
78
100
|
}, { parent: this });
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
port
|
|
101
|
+
const lbTargetGroup = new aws.lb.TargetGroup(`${this.name}-lb-tg`, {
|
|
102
|
+
namePrefix: `${this.name}-lb-tg-`,
|
|
103
|
+
port,
|
|
82
104
|
protocol: 'HTTP',
|
|
83
105
|
targetType: 'ip',
|
|
84
|
-
vpcId:
|
|
106
|
+
vpcId: vpc.vpcId,
|
|
85
107
|
healthCheck: {
|
|
86
108
|
healthyThreshold: 3,
|
|
87
109
|
unhealthyThreshold: 2,
|
|
88
110
|
interval: 60,
|
|
89
111
|
timeout: 5,
|
|
90
|
-
path:
|
|
112
|
+
path: healtCheckPath || defaults.healtCheckPath,
|
|
91
113
|
},
|
|
92
114
|
}, { parent: this, dependsOn: [this.lb] });
|
|
93
|
-
|
|
115
|
+
const lbHttpListener = new aws.lb.Listener(`${this.name}-lb-listener-80`, {
|
|
94
116
|
loadBalancerArn: this.lb.arn,
|
|
95
117
|
port: 80,
|
|
96
118
|
defaultActions: [
|
|
@@ -104,7 +126,7 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
104
126
|
},
|
|
105
127
|
],
|
|
106
128
|
}, { parent: this });
|
|
107
|
-
|
|
129
|
+
const lbTlsListener = new aws.lb.Listener(`${this.name}-lb-listener-443`, {
|
|
108
130
|
loadBalancerArn: this.lb.arn,
|
|
109
131
|
port: 443,
|
|
110
132
|
protocol: 'HTTPS',
|
|
@@ -117,20 +139,18 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
117
139
|
},
|
|
118
140
|
],
|
|
119
141
|
}, { parent: this });
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
],
|
|
131
|
-
}, { parent: this });
|
|
142
|
+
return {
|
|
143
|
+
lb,
|
|
144
|
+
lbTargetGroup,
|
|
145
|
+
lbHttpListener,
|
|
146
|
+
lbTlsListener,
|
|
147
|
+
lbSecurityGroup,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
createTaskDefinition(args) {
|
|
151
|
+
const argsWithDefaults = Object.assign({}, defaults, args);
|
|
132
152
|
const secretManagerSecretsInlinePolicy = {
|
|
133
|
-
name: `${name}-secret-manager-access`,
|
|
153
|
+
name: `${this.name}-secret-manager-access`,
|
|
134
154
|
policy: JSON.stringify({
|
|
135
155
|
Version: '2012-10-17',
|
|
136
156
|
Statement: [
|
|
@@ -143,8 +163,8 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
143
163
|
],
|
|
144
164
|
}),
|
|
145
165
|
};
|
|
146
|
-
const taskExecutionRole = new aws.iam.Role(`${name}-ecs-task-exec-role`, {
|
|
147
|
-
|
|
166
|
+
const taskExecutionRole = new aws.iam.Role(`${this.name}-ecs-task-exec-role`, {
|
|
167
|
+
namePrefix: `${this.name}-ecs-task-exec-role-`,
|
|
148
168
|
assumeRolePolicy,
|
|
149
169
|
managedPolicyArns: [
|
|
150
170
|
'arn:aws:iam::aws:policy/CloudWatchFullAccess',
|
|
@@ -156,7 +176,7 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
156
176
|
],
|
|
157
177
|
}, { parent: this });
|
|
158
178
|
const execCmdInlinePolicy = {
|
|
159
|
-
name: `${name}-ecs-exec`,
|
|
179
|
+
name: `${this.name}-ecs-exec`,
|
|
160
180
|
policy: JSON.stringify({
|
|
161
181
|
Version: '2012-10-17',
|
|
162
182
|
Statement: [
|
|
@@ -174,8 +194,8 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
174
194
|
],
|
|
175
195
|
}),
|
|
176
196
|
};
|
|
177
|
-
const taskRole = new aws.iam.Role(`${name}-ecs-task-role`, {
|
|
178
|
-
|
|
197
|
+
const taskRole = new aws.iam.Role(`${this.name}-ecs-task-role`, {
|
|
198
|
+
namePrefix: `${this.name}-ecs-task-role-`,
|
|
179
199
|
assumeRolePolicy,
|
|
180
200
|
inlinePolicies: [
|
|
181
201
|
execCmdInlinePolicy,
|
|
@@ -195,8 +215,8 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
195
215
|
}
|
|
196
216
|
throw Error('Incorrect EcsService size argument');
|
|
197
217
|
});
|
|
198
|
-
|
|
199
|
-
family: `${name}-task-definition`,
|
|
218
|
+
const taskDefinition = new aws.ecs.TaskDefinition(`${this.name}-task-definition`, {
|
|
219
|
+
family: `${this.name}-task-definition`,
|
|
200
220
|
networkMode: 'awsvpc',
|
|
201
221
|
executionRoleArn: taskExecutionRole.arn,
|
|
202
222
|
taskRoleArn: taskRole.arn,
|
|
@@ -205,7 +225,7 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
205
225
|
requiresCompatibilities: ['FARGATE'],
|
|
206
226
|
containerDefinitions: pulumi
|
|
207
227
|
.all([
|
|
208
|
-
name,
|
|
228
|
+
this.name,
|
|
209
229
|
argsWithDefaults.image,
|
|
210
230
|
argsWithDefaults.port,
|
|
211
231
|
argsWithDefaults.environment,
|
|
@@ -241,7 +261,11 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
241
261
|
}),
|
|
242
262
|
tags: argsWithDefaults.tags,
|
|
243
263
|
}, { parent: this });
|
|
244
|
-
|
|
264
|
+
return taskDefinition;
|
|
265
|
+
}
|
|
266
|
+
createEcsService(args) {
|
|
267
|
+
const argsWithDefaults = Object.assign({}, defaults, args);
|
|
268
|
+
const serviceSecurityGroup = new aws.ec2.SecurityGroup(`${this.name}-security-group`, {
|
|
245
269
|
vpcId: argsWithDefaults.vpc.vpcId,
|
|
246
270
|
ingress: [
|
|
247
271
|
{
|
|
@@ -260,8 +284,8 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
260
284
|
},
|
|
261
285
|
],
|
|
262
286
|
}, { parent: this });
|
|
263
|
-
|
|
264
|
-
name,
|
|
287
|
+
const service = new aws.ecs.Service(`${this.name}-service`, {
|
|
288
|
+
name: this.name,
|
|
265
289
|
cluster: argsWithDefaults.cluster.id,
|
|
266
290
|
launchType: 'FARGATE',
|
|
267
291
|
desiredCount: argsWithDefaults.desiredCount,
|
|
@@ -269,7 +293,7 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
269
293
|
enableExecuteCommand: true,
|
|
270
294
|
loadBalancers: [
|
|
271
295
|
{
|
|
272
|
-
containerName: name,
|
|
296
|
+
containerName: this.name,
|
|
273
297
|
containerPort: argsWithDefaults.port,
|
|
274
298
|
targetGroupArn: this.lbTargetGroup.arn,
|
|
275
299
|
},
|
|
@@ -277,7 +301,7 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
277
301
|
networkConfiguration: {
|
|
278
302
|
assignPublicIp: true,
|
|
279
303
|
subnets: argsWithDefaults.vpc.publicSubnetIds,
|
|
280
|
-
securityGroups: [
|
|
304
|
+
securityGroups: [serviceSecurityGroup.id],
|
|
281
305
|
},
|
|
282
306
|
tags: argsWithDefaults.tags,
|
|
283
307
|
}, {
|
|
@@ -289,14 +313,32 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
289
313
|
this.lbTlsListener,
|
|
290
314
|
],
|
|
291
315
|
});
|
|
292
|
-
|
|
316
|
+
return service;
|
|
317
|
+
}
|
|
318
|
+
createDnsRecord({ domain, hostedZoneId, }) {
|
|
319
|
+
const albAliasRecord = new aws.route53.Record(`${this.name}-route53-record`, {
|
|
320
|
+
type: 'A',
|
|
321
|
+
name: domain,
|
|
322
|
+
zoneId: hostedZoneId,
|
|
323
|
+
aliases: [
|
|
324
|
+
{
|
|
325
|
+
name: this.lb.dnsName,
|
|
326
|
+
zoneId: this.lb.zoneId,
|
|
327
|
+
evaluateTargetHealth: true,
|
|
328
|
+
},
|
|
329
|
+
],
|
|
330
|
+
}, { parent: this });
|
|
331
|
+
}
|
|
332
|
+
enableAutoscaling(args) {
|
|
333
|
+
const argsWithDefaults = Object.assign({}, defaults, args);
|
|
334
|
+
const autoscalingTarget = new aws.appautoscaling.Target(`${this.name}-autoscale-target`, {
|
|
293
335
|
minCapacity: argsWithDefaults.minCount,
|
|
294
336
|
maxCapacity: argsWithDefaults.maxCount,
|
|
295
337
|
resourceId: pulumi.interpolate `service/${argsWithDefaults.cluster.name}/${this.service.name}`,
|
|
296
338
|
serviceNamespace: 'ecs',
|
|
297
339
|
scalableDimension: 'ecs:service:DesiredCount',
|
|
298
340
|
}, { parent: this });
|
|
299
|
-
const memoryAutoscalingPolicy = new aws.appautoscaling.Policy(`${name}-memory-autoscale-policy`, {
|
|
341
|
+
const memoryAutoscalingPolicy = new aws.appautoscaling.Policy(`${this.name}-memory-autoscale-policy`, {
|
|
300
342
|
policyType: 'TargetTrackingScaling',
|
|
301
343
|
resourceId: autoscalingTarget.resourceId,
|
|
302
344
|
scalableDimension: autoscalingTarget.scalableDimension,
|
|
@@ -308,7 +350,7 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
308
350
|
targetValue: 80,
|
|
309
351
|
},
|
|
310
352
|
}, { parent: this });
|
|
311
|
-
const cpuAutoscalingPolicy = new aws.appautoscaling.Policy(`${name}-cpu-autoscale-policy`, {
|
|
353
|
+
const cpuAutoscalingPolicy = new aws.appautoscaling.Policy(`${this.name}-cpu-autoscale-policy`, {
|
|
312
354
|
policyType: 'TargetTrackingScaling',
|
|
313
355
|
resourceId: autoscalingTarget.resourceId,
|
|
314
356
|
scalableDimension: autoscalingTarget.scalableDimension,
|
|
@@ -320,7 +362,6 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
320
362
|
targetValue: 60,
|
|
321
363
|
},
|
|
322
364
|
}, { parent: this });
|
|
323
|
-
this.registerOutputs();
|
|
324
365
|
}
|
|
325
366
|
}
|
|
326
367
|
exports.WebServer = WebServer;
|
package/dist/constants.d.ts
CHANGED
package/dist/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PredefinedSize = void 0;
|
|
3
|
+
exports.Ec2AMI = exports.PredefinedSize = void 0;
|
|
4
4
|
const CPU_1_VCPU = 1024;
|
|
5
5
|
const MEMORY_1GB = 1024;
|
|
6
6
|
exports.PredefinedSize = {
|
|
@@ -21,3 +21,8 @@ exports.PredefinedSize = {
|
|
|
21
21
|
memory: MEMORY_1GB * 4, // 4 GB memory
|
|
22
22
|
},
|
|
23
23
|
};
|
|
24
|
+
exports.Ec2AMI = {
|
|
25
|
+
AmazonLinux2023: {
|
|
26
|
+
ARM: 'ami-0b40baa8c6b882e6c',
|
|
27
|
+
},
|
|
28
|
+
};
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|