@studion/infra-code-blocks 0.0.1 → 0.0.3
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 +364 -2
- package/dist/components/acm-certificate.d.ts +10 -0
- package/dist/components/acm-certificate.js +29 -0
- package/dist/components/database.d.ts +48 -0
- package/dist/components/database.js +64 -0
- package/dist/components/ec2-ssm-connect.d.ts +16 -0
- package/dist/components/ec2-ssm-connect.js +92 -0
- package/dist/components/project.d.ts +24 -15
- package/dist/components/project.js +42 -111
- package/dist/components/redis.d.ts +7 -2
- package/dist/components/redis.js +7 -3
- package/dist/components/static-site.d.ts +20 -0
- package/dist/components/static-site.js +108 -0
- package/dist/components/web-server.d.ts +86 -0
- package/dist/components/web-server.js +304 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -2
- package/package.json +3 -3
- package/dist/components/ecs.d.ts +0 -33
- package/dist/components/ecs.js +0 -154
- package/dist/components/rds.d.ts +0 -20
- package/dist/components/rds.js +0 -42
package/README.md
CHANGED
|
@@ -1,11 +1,373 @@
|
|
|
1
1
|
# `@studion/infra-code-blocks`
|
|
2
2
|
|
|
3
|
-
Studion common infra components.
|
|
3
|
+
Studion Platform common infra components.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [Installation](#installation)
|
|
8
|
+
2. [Usage](#usage)
|
|
9
|
+
3. [API](#api)
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
6
12
|
|
|
7
13
|
- Run the command:
|
|
8
14
|
|
|
9
15
|
```bash
|
|
10
16
|
$ npm i @studion/infra-code-blocks
|
|
11
17
|
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
- Import Studion infra components in your project
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import * as studion from '@studion/infra-code-blocks';
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- Use Studion components
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import * as studion from '@studion/infra-code-blocks';
|
|
31
|
+
|
|
32
|
+
const project = new studion.Project('demo-project', {
|
|
33
|
+
environment: 'DEVELOPMENT',
|
|
34
|
+
services: [
|
|
35
|
+
{
|
|
36
|
+
type: 'REDIS',
|
|
37
|
+
serviceName: 'redis',
|
|
38
|
+
dbName: 'test-db',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export const projectName = project.name;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## API
|
|
47
|
+
|
|
48
|
+
1. [Project](#project)
|
|
49
|
+
2. [Database](#database)
|
|
50
|
+
3. [Redis](#redis)
|
|
51
|
+
4. [StaticSite](#static-site)
|
|
52
|
+
5. [WebServer](#web-server)
|
|
53
|
+
|
|
54
|
+
### Project
|
|
55
|
+
|
|
56
|
+
Project component makes it really easy to spin up project infrastructure,
|
|
57
|
+
hiding infrastructure complexity.
|
|
58
|
+
<br>
|
|
59
|
+
The component creates its own VPC which is used for resources within the project.
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
new Project(name: string, args: ProjectArgs, opts?: pulumi.CustomResourceOptions);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
| Argument | Description |
|
|
66
|
+
| :------- | :--------------------------------------------: |
|
|
67
|
+
| name \* | The unique name of the resource. |
|
|
68
|
+
| args \* | The arguments to resource properties. |
|
|
69
|
+
| opts | Bag of options to control resource's behavior. |
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
type ProjectArgs = {
|
|
73
|
+
services: (
|
|
74
|
+
| DatabaseService
|
|
75
|
+
| RedisService
|
|
76
|
+
| StaticSiteService
|
|
77
|
+
| WebServerService
|
|
78
|
+
)[];
|
|
79
|
+
environment: Environment;
|
|
80
|
+
hostedZoneId?: pulumi.Input<string>;
|
|
81
|
+
enableSSMConnect?: pulumi.Input<boolean>;
|
|
82
|
+
};
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
| Argument | Description |
|
|
86
|
+
| :--------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
|
87
|
+
| services \* | Service list. |
|
|
88
|
+
| environment \* | Environment name. |
|
|
89
|
+
| hostedZoneId | Route53 hosted zone ID responsible for managing records for the domain. |
|
|
90
|
+
| enableSSMConnect | Setup ec2 instance and SSM in order to connect to the database in the private subnet. Please refer to the [SSM Connect](#ssm-connect) section for more info. |
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
type DatabaseService = {
|
|
94
|
+
type: 'DATABASE';
|
|
95
|
+
serviceName: string;
|
|
96
|
+
dbName: pulumi.Input<string>;
|
|
97
|
+
username: pulumi.Input<string>;
|
|
98
|
+
password: pulumi.Input<string>;
|
|
99
|
+
applyImmediately?: pulumi.Input<boolean>;
|
|
100
|
+
skipFinalSnapshot?: pulumi.Input<boolean>;
|
|
101
|
+
allocatedStorage?: pulumi.Input<number>;
|
|
102
|
+
maxAllocatedStorage?: pulumi.Input<number>;
|
|
103
|
+
instanceClass?: pulumi.Input<string>;
|
|
104
|
+
};
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
export type RedisService = {
|
|
109
|
+
type: 'REDIS';
|
|
110
|
+
serviceName: string;
|
|
111
|
+
dbName: pulumi.Input<string>;
|
|
112
|
+
region?: pulumi.Input<string>;
|
|
113
|
+
};
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
export type StaticSiteService = {
|
|
118
|
+
type: 'STATIC_SITE';
|
|
119
|
+
serviceName: string;
|
|
120
|
+
domain: pulumi.Input<string>;
|
|
121
|
+
};
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
export type WebServerService = {
|
|
126
|
+
type: 'WEB_SERVER';
|
|
127
|
+
serviceName: string;
|
|
128
|
+
environment?:
|
|
129
|
+
| aws.ecs.KeyValuePair[]
|
|
130
|
+
| ((services: Services) => aws.ecs.KeyValuePair[]);
|
|
131
|
+
image: pulumi.Input<string>;
|
|
132
|
+
port: pulumi.Input<number>;
|
|
133
|
+
domain: pulumi.Input<string>;
|
|
134
|
+
desiredCount?: pulumi.Input<number>;
|
|
135
|
+
minCount?: pulumi.Input<number>;
|
|
136
|
+
maxCount?: pulumi.Input<number>;
|
|
137
|
+
size?: pulumi.Input<Size>;
|
|
138
|
+
healtCheckPath?: pulumi.Input<string>;
|
|
139
|
+
taskExecutionRoleInlinePolicies?: pulumi.Input<
|
|
140
|
+
pulumi.Input<RoleInlinePolicy>[]
|
|
141
|
+
>;
|
|
142
|
+
taskRoleInlinePolicies?: pulumi.Input<pulumi.Input<RoleInlinePolicy>[]>;
|
|
143
|
+
};
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Often, web server depends on other services such as database, Redis, etc.
|
|
147
|
+
For that purpose, environment factory can be used. The factory function
|
|
148
|
+
recieves services bag as argument.
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
const project = new studion.Project('demo-project', {
|
|
152
|
+
environment: 'DEVELOPMENT',
|
|
153
|
+
services: [
|
|
154
|
+
{
|
|
155
|
+
type: 'REDIS',
|
|
156
|
+
serviceName: 'redis',
|
|
157
|
+
dbName: 'test-db',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
type: 'WEB_SERVER',
|
|
161
|
+
serviceName: 'api',
|
|
162
|
+
image: imageUri,
|
|
163
|
+
port: 3000,
|
|
164
|
+
domain: 'api.my-domain.com',
|
|
165
|
+
environment: (services: Services) => {
|
|
166
|
+
const redisServiceName = 'redis';
|
|
167
|
+
const redis = services[redisServiceName];
|
|
168
|
+
return [
|
|
169
|
+
{ name: 'REDIS_HOST', value: redis.endpoint },
|
|
170
|
+
{ name: 'REDIS_PORT', value: redis.port.apply(port => String(port)) },
|
|
171
|
+
];
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Database
|
|
179
|
+
|
|
180
|
+
RDS Postgres instance.
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
new Database(name: string, args: DatabaseArgs, opts?: pulumi.CustomResourceOptions);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
| Argument | Description |
|
|
187
|
+
| :------- | :--------------------------------------------: |
|
|
188
|
+
| name \* | The unique name of the resource. |
|
|
189
|
+
| args \* | The arguments to resource properties. |
|
|
190
|
+
| opts | Bag of options to control resource's behavior. |
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
type DatabaseArgs = {
|
|
194
|
+
dbName: pulumi.Input<string>;
|
|
195
|
+
username: pulumi.Input<string>;
|
|
196
|
+
password: pulumi.Input<string>;
|
|
197
|
+
vpc: awsx.ec2.Vpc;
|
|
198
|
+
applyImmediately?: pulumi.Input<boolean>;
|
|
199
|
+
skipFinalSnapshot?: pulumi.Input<boolean>;
|
|
200
|
+
allocatedStorage?: pulumi.Input<number>;
|
|
201
|
+
maxAllocatedStorage?: pulumi.Input<number>;
|
|
202
|
+
instanceClass?: pulumi.Input<string>;
|
|
203
|
+
};
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Redis
|
|
207
|
+
|
|
208
|
+
Upstash Redis instance.
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
new Redis(name: string, args: RedisArgs, opts: RedisOptions);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
| Argument | Description |
|
|
215
|
+
| :------- | :--------------------------------------------: |
|
|
216
|
+
| name \* | The unique name of the resource. |
|
|
217
|
+
| args \* | The arguments to resource properties. |
|
|
218
|
+
| opts | Bag of options to control resource's behavior. |
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
type RedisArgs = {
|
|
222
|
+
dbName: pulumi.Input<string>;
|
|
223
|
+
region?: pulumi.Input<string>;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
interface RedisOptions extends pulumi.ComponentResourceOptions {
|
|
227
|
+
provider: upstash.Provider;
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Static Site
|
|
232
|
+
|
|
233
|
+
A static site that will be deployed using S3 + Cloudfront.
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
new StaticSite(name: string, args: StaticSiteArgs, opts?: pulumi.ComponentResourceOptions );
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
| Argument | Description |
|
|
240
|
+
| :------- | :--------------------------------------------: |
|
|
241
|
+
| name \* | The unique name of the resource. |
|
|
242
|
+
| args \* | The arguments to resource properties. |
|
|
243
|
+
| opts | Bag of options to control resource's behavior. |
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
type StaticSiteArgs = {
|
|
247
|
+
domain: pulumi.Input<string>;
|
|
248
|
+
hostedZoneId: pulumi.Input<string>;
|
|
249
|
+
};
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Web Server
|
|
253
|
+
|
|
254
|
+
A web server that will be deployed to ECS Fargate service with autoscaling enabled.
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
new WebServer(name: string, args: WebServerArgs, opts?: pulumi.ComponentResourceOptions );
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
| Argument | Description |
|
|
261
|
+
| :------- | :--------------------------------------------: |
|
|
262
|
+
| name \* | The unique name of the resource. |
|
|
263
|
+
| args \* | The arguments to resource properties. |
|
|
264
|
+
| opts | Bag of options to control resource's behavior. |
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
export type WebServerArgs = {
|
|
268
|
+
image: pulumi.Input<string>;
|
|
269
|
+
port: pulumi.Input<number>;
|
|
270
|
+
domain: pulumi.Input<string>;
|
|
271
|
+
cluster: aws.ecs.Cluster;
|
|
272
|
+
hostedZoneId: pulumi.Input<string>;
|
|
273
|
+
vpc: awsx.ec2.Vpc;
|
|
274
|
+
desiredCount?: pulumi.Input<number>;
|
|
275
|
+
minCount?: pulumi.Input<number>;
|
|
276
|
+
maxCount?: pulumi.Input<number>;
|
|
277
|
+
size?: pulumi.Input<Size>;
|
|
278
|
+
environment?: aws.ecs.KeyValuePair[];
|
|
279
|
+
healtCheckPath?: pulumi.Input<string>;
|
|
280
|
+
taskExecutionRoleInlinePolicies?: pulumi.Input<
|
|
281
|
+
pulumi.Input<RoleInlinePolicy>[]
|
|
282
|
+
>;
|
|
283
|
+
taskRoleInlinePolicies?: pulumi.Input<pulumi.Input<RoleInlinePolicy>[]>;
|
|
284
|
+
};
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## SSM Connect
|
|
288
|
+
|
|
289
|
+
The [Database](#database) component deploys a database instance inside a private subnet,
|
|
290
|
+
and it's not publicly accessible from outside of VPC.
|
|
291
|
+
<br>
|
|
292
|
+
In order to connect to the database we need to deploy the ec2 instance which will be used
|
|
293
|
+
to open an SSH tunnel to the database instance.
|
|
294
|
+
<br>
|
|
295
|
+
Because of security reasons, ec2 instance is also deployed inside private subnet
|
|
296
|
+
which means we can't directly connect to it. For that purpose, we use AWS System Manager
|
|
297
|
+
which enables us to connect to the ec2 instance even though it's inside private subnet.
|
|
298
|
+
|
|
299
|
+

|
|
300
|
+
|
|
301
|
+
**Prerequisites**
|
|
302
|
+
|
|
303
|
+
1. Install the [Session Manager plugin](https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-macos-overview.html#install-plugin-macos)
|
|
304
|
+
2. Generate a new ssh key pair or use the existing one.
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
$ ssh-keygen -f my_rsa
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
3. Set stack config property by running:
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
$ pulumi config set ssh:publicKey "ssh-rsa Z...9= mymac@Studions-MBP.localdomain"
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
SSM Connect can be enabled by setting `enableSSMConnect` property to `true`.
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
const project = new studion.Project('demo-project', {
|
|
320
|
+
enableSSMConnect: true,
|
|
321
|
+
...
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
export const ec2InstanceId = project.ec2SSMConnect?.ec2.id;
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Open up your terminal and run the following command:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
$ aws ssm start-session --target EC2_INSTANCE_ID --document-name AWS-StartPortForwardingSession --parameters '{"portNumber":["22"], "localPortNumber":["9999"]}'
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Where `EC2_INSTANCE_ID` is an ID of the EC2 instance that is created for you. ID can be
|
|
334
|
+
obtained by exporting it from the stack.
|
|
335
|
+
|
|
336
|
+
Next, open another terminal window and run the following command:
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
$ ssh ec2-user@localhost -p 9999 -N -L 5555:DATABASE_ADDRESS:DATABASE_PORT -i SSH_PRIVATE_KEY
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Where `DATABASE_ADDRESS` and `DATABASE_PORT` are the address and port of the database instance,
|
|
343
|
+
and `SSH_PRIVATE_KEY` is the path to the SSH private key.
|
|
344
|
+
|
|
345
|
+
And that is it! 🥳
|
|
346
|
+
Now you can use your favorite database client to connect to the database.
|
|
347
|
+
|
|
348
|
+

|
|
349
|
+
|
|
350
|
+
It is important that for the host you set `localhost` and for the port you set `5555`
|
|
351
|
+
because we have an SSH tunnel open that forwards traffic from localhost:5555 to the
|
|
352
|
+
DATABASE_ADDRESS:DATABASE_PORT. For the user, password, and database field, set values
|
|
353
|
+
which are set in the `Project`.
|
|
354
|
+
|
|
355
|
+
```ts
|
|
356
|
+
const project = new studion.Project('demo-project', {
|
|
357
|
+
enableSSMConnect: true,
|
|
358
|
+
services: [
|
|
359
|
+
{
|
|
360
|
+
type: 'DATABASE',
|
|
361
|
+
dbName: 'database_name',
|
|
362
|
+
username: 'username',
|
|
363
|
+
password: 'password',
|
|
364
|
+
...
|
|
365
|
+
}
|
|
366
|
+
]
|
|
367
|
+
});
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## 🚧 TODO
|
|
371
|
+
|
|
372
|
+
- [ ] Add worker service for executing tasks
|
|
373
|
+
- [ ] Update docs, describe each service, describe required stack configs...
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as pulumi from '@pulumi/pulumi';
|
|
2
|
+
import * as aws from '@pulumi/aws';
|
|
3
|
+
export type AcmCertificateArgs = {
|
|
4
|
+
domain: pulumi.Input<string>;
|
|
5
|
+
hostedZoneId: pulumi.Input<string>;
|
|
6
|
+
};
|
|
7
|
+
export declare class AcmCertificate extends pulumi.ComponentResource {
|
|
8
|
+
certificate: aws.acm.Certificate;
|
|
9
|
+
constructor(name: string, args: AcmCertificateArgs, opts?: pulumi.ComponentResourceOptions);
|
|
10
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AcmCertificate = void 0;
|
|
4
|
+
const pulumi = require("@pulumi/pulumi");
|
|
5
|
+
const aws = require("@pulumi/aws");
|
|
6
|
+
class AcmCertificate extends pulumi.ComponentResource {
|
|
7
|
+
constructor(name, args, opts = {}) {
|
|
8
|
+
super('studion:acm:Certificate', name, {}, opts);
|
|
9
|
+
this.certificate = new aws.acm.Certificate(`${args.domain}-certificate`, { domainName: args.domain, validationMethod: 'DNS' }, { parent: this });
|
|
10
|
+
const certificateValidationDomain = new aws.route53.Record(`${args.domain}-cert-validation-domain`, {
|
|
11
|
+
name: this.certificate.domainValidationOptions[0].resourceRecordName,
|
|
12
|
+
type: this.certificate.domainValidationOptions[0].resourceRecordType,
|
|
13
|
+
zoneId: args.hostedZoneId,
|
|
14
|
+
records: [
|
|
15
|
+
this.certificate.domainValidationOptions[0].resourceRecordValue,
|
|
16
|
+
],
|
|
17
|
+
ttl: 600,
|
|
18
|
+
}, {
|
|
19
|
+
parent: this,
|
|
20
|
+
deleteBeforeReplace: true,
|
|
21
|
+
});
|
|
22
|
+
const certificateValidation = new aws.acm.CertificateValidation(`${args.domain}-cert-validation`, {
|
|
23
|
+
certificateArn: this.certificate.arn,
|
|
24
|
+
validationRecordFqdns: [certificateValidationDomain.fqdn],
|
|
25
|
+
}, { parent: this });
|
|
26
|
+
this.registerOutputs();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.AcmCertificate = AcmCertificate;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as aws from '@pulumi/aws';
|
|
2
|
+
import * as awsx from '@pulumi/awsx';
|
|
3
|
+
import * as pulumi from '@pulumi/pulumi';
|
|
4
|
+
export type DatabaseArgs = {
|
|
5
|
+
/**
|
|
6
|
+
* The name of the database to create when the DB instance is created.
|
|
7
|
+
*/
|
|
8
|
+
dbName: pulumi.Input<string>;
|
|
9
|
+
/**
|
|
10
|
+
* Username for the master DB user.
|
|
11
|
+
*/
|
|
12
|
+
username: pulumi.Input<string>;
|
|
13
|
+
/**
|
|
14
|
+
* Password for the master DB user.
|
|
15
|
+
*/
|
|
16
|
+
password: pulumi.Input<string>;
|
|
17
|
+
/**
|
|
18
|
+
* The awsx.ec2.Vpc resource.
|
|
19
|
+
*/
|
|
20
|
+
vpc: awsx.ec2.Vpc;
|
|
21
|
+
/**
|
|
22
|
+
* Specifies whether any database modifications are applied immediately, or during the next maintenance window. Default is false.
|
|
23
|
+
*/
|
|
24
|
+
applyImmediately?: pulumi.Input<boolean>;
|
|
25
|
+
/**
|
|
26
|
+
* Determines whether a final DB snapshot is created before the DB instance is deleted.
|
|
27
|
+
*/
|
|
28
|
+
skipFinalSnapshot?: pulumi.Input<boolean>;
|
|
29
|
+
/**
|
|
30
|
+
* The allocated storage in gibibytes.
|
|
31
|
+
*/
|
|
32
|
+
allocatedStorage?: pulumi.Input<number>;
|
|
33
|
+
/**
|
|
34
|
+
* The upper limit to which Amazon RDS can automatically scale the storage of the DB instance.
|
|
35
|
+
*/
|
|
36
|
+
maxAllocatedStorage?: pulumi.Input<number>;
|
|
37
|
+
/**
|
|
38
|
+
* The instance type of the RDS instance.
|
|
39
|
+
*/
|
|
40
|
+
instanceClass?: pulumi.Input<string>;
|
|
41
|
+
};
|
|
42
|
+
export declare class Database extends pulumi.ComponentResource {
|
|
43
|
+
instance: aws.rds.Instance;
|
|
44
|
+
kms: aws.kms.Key;
|
|
45
|
+
dbSubnetGroup: aws.rds.SubnetGroup;
|
|
46
|
+
dbSecurityGroup: aws.ec2.SecurityGroup;
|
|
47
|
+
constructor(name: string, args: DatabaseArgs, opts?: pulumi.ComponentResourceOptions);
|
|
48
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Database = void 0;
|
|
4
|
+
const aws = require("@pulumi/aws");
|
|
5
|
+
const pulumi = require("@pulumi/pulumi");
|
|
6
|
+
const defaults = {
|
|
7
|
+
applyImmediately: false,
|
|
8
|
+
skipFinalSnapshot: false,
|
|
9
|
+
allocatedStorage: 20,
|
|
10
|
+
maxAllocatedStorage: 100,
|
|
11
|
+
instanceClass: 'db.t3.micro',
|
|
12
|
+
};
|
|
13
|
+
class Database extends pulumi.ComponentResource {
|
|
14
|
+
constructor(name, args, opts = {}) {
|
|
15
|
+
super('studion:Database', name, {}, opts);
|
|
16
|
+
const argsWithDefaults = Object.assign({}, defaults, args);
|
|
17
|
+
this.dbSubnetGroup = new aws.rds.SubnetGroup(`${name}-subnet-group`, {
|
|
18
|
+
subnetIds: argsWithDefaults.vpc.privateSubnetIds,
|
|
19
|
+
}, { parent: this });
|
|
20
|
+
this.dbSecurityGroup = new aws.ec2.SecurityGroup(`${name}-security-group`, {
|
|
21
|
+
vpcId: argsWithDefaults.vpc.vpcId,
|
|
22
|
+
ingress: [
|
|
23
|
+
{
|
|
24
|
+
protocol: 'tcp',
|
|
25
|
+
fromPort: 5432,
|
|
26
|
+
toPort: 5432,
|
|
27
|
+
cidrBlocks: [argsWithDefaults.vpc.vpc.cidrBlock],
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
}, { parent: this });
|
|
31
|
+
this.kms = new aws.kms.Key(`${name}-rds-key`, {
|
|
32
|
+
customerMasterKeySpec: 'SYMMETRIC_DEFAULT',
|
|
33
|
+
isEnabled: true,
|
|
34
|
+
keyUsage: 'ENCRYPT_DECRYPT',
|
|
35
|
+
multiRegion: false,
|
|
36
|
+
enableKeyRotation: true,
|
|
37
|
+
}, { parent: this });
|
|
38
|
+
this.instance = new aws.rds.Instance(`${name}-rds`, {
|
|
39
|
+
identifier: name,
|
|
40
|
+
engine: 'postgres',
|
|
41
|
+
engineVersion: '14.9',
|
|
42
|
+
allocatedStorage: argsWithDefaults.allocatedStorage,
|
|
43
|
+
maxAllocatedStorage: argsWithDefaults.maxAllocatedStorage,
|
|
44
|
+
instanceClass: argsWithDefaults.instanceClass,
|
|
45
|
+
dbName: argsWithDefaults.dbName,
|
|
46
|
+
username: argsWithDefaults.username,
|
|
47
|
+
password: argsWithDefaults.password,
|
|
48
|
+
dbSubnetGroupName: this.dbSubnetGroup.name,
|
|
49
|
+
vpcSecurityGroupIds: [this.dbSecurityGroup.id],
|
|
50
|
+
storageEncrypted: true,
|
|
51
|
+
kmsKeyId: this.kms.arn,
|
|
52
|
+
publiclyAccessible: false,
|
|
53
|
+
skipFinalSnapshot: argsWithDefaults.skipFinalSnapshot,
|
|
54
|
+
applyImmediately: argsWithDefaults.applyImmediately,
|
|
55
|
+
autoMinorVersionUpgrade: true,
|
|
56
|
+
maintenanceWindow: 'Mon:07:00-Mon:07:30',
|
|
57
|
+
finalSnapshotIdentifier: `${name}-final-snapshot`,
|
|
58
|
+
backupWindow: '06:00-06:30',
|
|
59
|
+
backupRetentionPeriod: 14,
|
|
60
|
+
}, { parent: this });
|
|
61
|
+
this.registerOutputs();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.Database = Database;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as pulumi from '@pulumi/pulumi';
|
|
2
|
+
import * as aws from '@pulumi/aws';
|
|
3
|
+
import * as awsx from '@pulumi/awsx';
|
|
4
|
+
export type Ec2SSMConnectArgs = {
|
|
5
|
+
vpc: awsx.ec2.Vpc;
|
|
6
|
+
sshPublicKey: pulumi.Input<string>;
|
|
7
|
+
};
|
|
8
|
+
export declare class Ec2SSMConnect extends pulumi.ComponentResource {
|
|
9
|
+
ec2SecurityGroup: aws.ec2.SecurityGroup;
|
|
10
|
+
ssmVpcEndpoint: aws.ec2.VpcEndpoint;
|
|
11
|
+
ec2MessagesVpcEndpoint: aws.ec2.VpcEndpoint;
|
|
12
|
+
ssmMessagesVpcEndpoint: aws.ec2.VpcEndpoint;
|
|
13
|
+
ec2: aws.ec2.Instance;
|
|
14
|
+
sshKeyPair: aws.ec2.KeyPair;
|
|
15
|
+
constructor(name: string, args: Ec2SSMConnectArgs, opts?: pulumi.ComponentResourceOptions);
|
|
16
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Ec2SSMConnect = void 0;
|
|
4
|
+
const pulumi = require("@pulumi/pulumi");
|
|
5
|
+
const aws = require("@pulumi/aws");
|
|
6
|
+
const config = new pulumi.Config('aws');
|
|
7
|
+
const awsRegion = config.require('region');
|
|
8
|
+
class Ec2SSMConnect extends pulumi.ComponentResource {
|
|
9
|
+
constructor(name, args, opts = {}) {
|
|
10
|
+
super('studion:Ec2BastionSSMConnect', name, {}, opts);
|
|
11
|
+
const subnetId = args.vpc.privateSubnetIds.apply(ids => ids[0]);
|
|
12
|
+
this.ec2SecurityGroup = new aws.ec2.SecurityGroup(`${name}-ec2-security-group`, {
|
|
13
|
+
ingress: [
|
|
14
|
+
{
|
|
15
|
+
protocol: 'tcp',
|
|
16
|
+
fromPort: 22,
|
|
17
|
+
toPort: 22,
|
|
18
|
+
cidrBlocks: ['0.0.0.0/0'],
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
egress: [
|
|
22
|
+
{ protocol: '-1', fromPort: 0, toPort: 0, cidrBlocks: ['0.0.0.0/0'] },
|
|
23
|
+
],
|
|
24
|
+
vpcId: args.vpc.vpcId,
|
|
25
|
+
}, { parent: this });
|
|
26
|
+
const role = new aws.iam.Role(`${name}-ec2-role`, {
|
|
27
|
+
assumeRolePolicy: {
|
|
28
|
+
Version: '2012-10-17',
|
|
29
|
+
Statement: [
|
|
30
|
+
{
|
|
31
|
+
Effect: 'Allow',
|
|
32
|
+
Principal: {
|
|
33
|
+
Service: 'ec2.amazonaws.com',
|
|
34
|
+
},
|
|
35
|
+
Action: 'sts:AssumeRole',
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
}, { parent: this });
|
|
40
|
+
const ssmPolicyAttachment = new aws.iam.RolePolicyAttachment(`${name}-ssm-policy-attachment`, {
|
|
41
|
+
role: role.name,
|
|
42
|
+
policyArn: 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore',
|
|
43
|
+
}, { parent: this });
|
|
44
|
+
const ssmProfile = new aws.iam.InstanceProfile(`${name}-ssm-profile`, {
|
|
45
|
+
role: role.name,
|
|
46
|
+
}, { parent: this, dependsOn: [ssmPolicyAttachment] });
|
|
47
|
+
this.ssmVpcEndpoint = new aws.ec2.VpcEndpoint(`${name}-ssm-vpc-endpoint`, {
|
|
48
|
+
vpcId: args.vpc.vpcId,
|
|
49
|
+
ipAddressType: 'ipv4',
|
|
50
|
+
serviceName: `com.amazonaws.${awsRegion}.ssm`,
|
|
51
|
+
vpcEndpointType: 'Interface',
|
|
52
|
+
subnetIds: [subnetId],
|
|
53
|
+
securityGroupIds: [this.ec2SecurityGroup.id],
|
|
54
|
+
privateDnsEnabled: true,
|
|
55
|
+
}, { parent: this });
|
|
56
|
+
this.ec2MessagesVpcEndpoint = new aws.ec2.VpcEndpoint(`${name}-ec2messages-vpc-endpoint`, {
|
|
57
|
+
vpcId: args.vpc.vpcId,
|
|
58
|
+
ipAddressType: 'ipv4',
|
|
59
|
+
serviceName: `com.amazonaws.${awsRegion}.ec2messages`,
|
|
60
|
+
vpcEndpointType: 'Interface',
|
|
61
|
+
subnetIds: [subnetId],
|
|
62
|
+
securityGroupIds: [this.ec2SecurityGroup.id],
|
|
63
|
+
privateDnsEnabled: true,
|
|
64
|
+
}, { parent: this });
|
|
65
|
+
this.ssmMessagesVpcEndpoint = new aws.ec2.VpcEndpoint(`${name}-ssmmessages-vpc-endpoint`, {
|
|
66
|
+
vpcId: args.vpc.vpcId,
|
|
67
|
+
ipAddressType: 'ipv4',
|
|
68
|
+
serviceName: `com.amazonaws.${awsRegion}.ssmmessages`,
|
|
69
|
+
vpcEndpointType: 'Interface',
|
|
70
|
+
subnetIds: [subnetId],
|
|
71
|
+
securityGroupIds: [this.ec2SecurityGroup.id],
|
|
72
|
+
privateDnsEnabled: true,
|
|
73
|
+
}, { parent: this });
|
|
74
|
+
this.sshKeyPair = new aws.ec2.KeyPair(`${name}-ec2-keypair`, {
|
|
75
|
+
publicKey: args.sshPublicKey,
|
|
76
|
+
}, { parent: this });
|
|
77
|
+
this.ec2 = new aws.ec2.Instance(`${name}-ec2`, {
|
|
78
|
+
ami: 'ami-067d1e60475437da2',
|
|
79
|
+
associatePublicIpAddress: false,
|
|
80
|
+
instanceType: 't2.micro',
|
|
81
|
+
keyName: this.sshKeyPair.keyName,
|
|
82
|
+
iamInstanceProfile: ssmProfile.name,
|
|
83
|
+
subnetId,
|
|
84
|
+
vpcSecurityGroupIds: [this.ec2SecurityGroup.id],
|
|
85
|
+
tags: {
|
|
86
|
+
Name: `${name}-ec2`,
|
|
87
|
+
},
|
|
88
|
+
}, { parent: this });
|
|
89
|
+
this.registerOutputs();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.Ec2SSMConnect = Ec2SSMConnect;
|