@studion/infra-code-blocks 0.0.7 → 0.0.9

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 CHANGED
@@ -131,6 +131,7 @@ export type WebServerService = {
131
131
  environment?:
132
132
  | aws.ecs.KeyValuePair[]
133
133
  | ((services: Services) => aws.ecs.KeyValuePair[]);
134
+ secrets?: aws.ecs.Secret[];
134
135
  image: pulumi.Input<string>;
135
136
  port: pulumi.Input<number>;
136
137
  domain: pulumi.Input<string>;
@@ -181,6 +182,27 @@ const project = new studion.Project('demo-project', {
181
182
  });
182
183
  ```
183
184
 
185
+ In order to pass sensitive information to the container use `secrets` instead of `environment`. AWS will fetch values from
186
+ Secret Manager based on arn that is provided for the `valueFrom` field.
187
+
188
+ ```ts
189
+ const project = new studion.Project('demo-project', {
190
+ environment: 'DEVELOPMENT',
191
+ services: [
192
+ {
193
+ type: 'WEB_SERVER',
194
+ serviceName: 'api',
195
+ image: imageUri,
196
+ port: 3000,
197
+ domain: 'api.my-domain.com',
198
+ secrets: [
199
+ { name: 'DB_PASSWORD', valueFrom: 'arn-of-the-secret-manager-secret' },
200
+ ],
201
+ },
202
+ ],
203
+ });
204
+ ```
205
+
184
206
  ### Database
185
207
 
186
208
  AWS RDS Postgres instance.
@@ -331,6 +353,7 @@ export type WebServerArgs = {
331
353
  maxCount?: pulumi.Input<number>;
332
354
  size?: pulumi.Input<Size>;
333
355
  environment?: aws.ecs.KeyValuePair[];
356
+ secrets?: aws.ecs.Secret[];
334
357
  healtCheckPath?: pulumi.Input<string>;
335
358
  taskExecutionRoleInlinePolicies?: pulumi.Input<
336
359
  pulumi.Input<RoleInlinePolicy>[]
@@ -376,11 +399,12 @@ The [Database](#database) component deploys a database instance inside a private
376
399
  and it's not publicly accessible from outside of VPC.
377
400
  <br>
378
401
  In order to connect to the database we need to deploy the ec2 instance which will be used
379
- to open an SSH tunnel to the database instance.
402
+ to forward traffic to the database instance.
380
403
  <br>
381
- Because of security reasons, ec2 instance is also deployed inside private subnet
404
+ Because of security reasons, the ec2 instance is also deployed inside a private subnet
382
405
  which means we can't directly connect to it. For that purpose, we use AWS System Manager
383
- which enables us to connect to the ec2 instance even though it's inside private subnet.
406
+ which enables us to connect to the ec2 instance even though it's inside a private subnet.
407
+ The benefit of using AWS SSM is that we don't need a ssh key pair.
384
408
 
385
409
  ![AWS RDS connection schema](/assets/images/ssm-rds.png)
386
410
 
@@ -392,18 +416,6 @@ which enables us to connect to the ec2 instance even though it's inside private
392
416
  $ brew install --cask session-manager-plugin
393
417
  ```
394
418
 
395
- 2. Generate a new ssh key pair or use the existing one.
396
-
397
- ```bash
398
- $ ssh-keygen -f my_rsa
399
- ```
400
-
401
- 3. Set stack config property by running:
402
-
403
- ```bash
404
- $ pulumi config set ssh:publicKey "ssh-rsa Z...9= mymac@Studions-MBP.localdomain"
405
- ```
406
-
407
419
  SSM Connect can be enabled by setting `enableSSMConnect` property to `true`.
408
420
 
409
421
  ```ts
@@ -418,20 +430,13 @@ export const ec2InstanceId = project.ec2SSMConnect?.ec2.id;
418
430
  Open up your terminal and run the following command:
419
431
 
420
432
  ```bash
421
- $ aws ssm start-session --target EC2_INSTANCE_ID --document-name AWS-StartPortForwardingSession --parameters '{"portNumber":["22"], "localPortNumber":["9999"]}'
422
- ```
423
-
424
- Where `EC2_INSTANCE_ID` is an ID of the EC2 instance that is created for you. ID can be
425
- obtained by exporting it from the stack.
426
-
427
- Next, open another terminal window and run the following command:
428
-
429
- ```bash
430
- $ ssh ec2-user@localhost -p 9999 -N -L 5555:DATABASE_ADDRESS:DATABASE_PORT -i SSH_PRIVATE_KEY
433
+ $ aws ssm start-session --target EC2_INSTANCE_ID --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters '{"host": ["DATABASE_ADDRESS"], "portNumber":["DATABASE_PORT"], "localPortNumber":["5555"]}'
431
434
  ```
432
435
 
433
- Where `DATABASE_ADDRESS` and `DATABASE_PORT` are the address and port of the database instance,
434
- and `SSH_PRIVATE_KEY` is the path to the SSH private key.
436
+ Where `EC2_INSTANCE_ID` is an ID of the EC2 instance that is created for you
437
+ (ID can be obtained by exporting it from the stack), and
438
+ `DATABASE_ADDRESS` and `DATABASE_PORT` are the address and port of the
439
+ database instance.
435
440
 
436
441
  And that is it! 🥳
437
442
  Now you can use your favorite database client to connect to the database.
@@ -439,9 +444,9 @@ Now you can use your favorite database client to connect to the database.
439
444
  ![RDS connection](/assets/images/rds-connection.png)
440
445
 
441
446
  It is important that for the host you set `localhost` and for the port you set `5555`
442
- because we have an SSH tunnel open that forwards traffic from localhost:5555 to the
443
- DATABASE_ADDRESS:DATABASE_PORT. For the user, password, and database field, set values
444
- which are set in the `Project`.
447
+ because we are port forwarding traffic from
448
+ localhost:5555 to DATABASE_ADDRESS:DATABASE_PORT.
449
+ For the user, password, and database field, set values which are set in the `Project`.
445
450
 
446
451
  ```ts
447
452
  const project = new studion.Project('demo-project', {
@@ -462,3 +467,4 @@ const project = new studion.Project('demo-project', {
462
467
 
463
468
  - [ ] Add worker service for executing tasks
464
469
  - [ ] Add MongoDB service
470
+ - [ ] Make db username & password fields optional and autogenerate db username & password if they are not provided
@@ -3,7 +3,6 @@ import * as aws from '@pulumi/aws';
3
3
  import * as awsx from '@pulumi/awsx';
4
4
  export type Ec2SSMConnectArgs = {
5
5
  vpc: awsx.ec2.Vpc;
6
- sshPublicKey: pulumi.Input<string>;
7
6
  tags?: pulumi.Input<{
8
7
  [key: string]: pulumi.Input<string>;
9
8
  }>;
@@ -14,6 +13,5 @@ export declare class Ec2SSMConnect extends pulumi.ComponentResource {
14
13
  ec2MessagesVpcEndpoint: aws.ec2.VpcEndpoint;
15
14
  ssmMessagesVpcEndpoint: aws.ec2.VpcEndpoint;
16
15
  ec2: aws.ec2.Instance;
17
- sshKeyPair: aws.ec2.KeyPair;
18
16
  constructor(name: string, args: Ec2SSMConnectArgs, opts?: pulumi.ComponentResourceOptions);
19
17
  }
@@ -56,14 +56,10 @@ class Ec2SSMConnect extends pulumi.ComponentResource {
56
56
  const ssmProfile = new aws.iam.InstanceProfile(`${name}-ssm-profile`, {
57
57
  role: role.name,
58
58
  }, { parent: this, dependsOn: [ssmPolicyAttachment] });
59
- this.sshKeyPair = new aws.ec2.KeyPair(`${name}-ec2-keypair`, {
60
- publicKey: args.sshPublicKey,
61
- }, { parent: this });
62
59
  this.ec2 = new aws.ec2.Instance(`${name}-ec2`, {
63
60
  ami: 'ami-067d1e60475437da2',
64
61
  associatePublicIpAddress: false,
65
62
  instanceType: 't2.micro',
66
- keyName: this.sshKeyPair.keyName,
67
63
  iamInstanceProfile: ssmProfile.name,
68
64
  subnetId,
69
65
  vpcSecurityGroupIds: [this.ec2SecurityGroup.id],
@@ -39,10 +39,8 @@ class Project extends pulumi.ComponentResource {
39
39
  this.vpc = this.createVpc();
40
40
  this.createServices(services);
41
41
  if (args.enableSSMConnect) {
42
- const sshConfig = new pulumi.Config('ssh');
43
42
  this.ec2SSMConnect = new ec2_ssm_connect_1.Ec2SSMConnect(`${name}-ssm-connect`, {
44
43
  vpc: this.vpc,
45
- sshPublicKey: sshConfig.require('publicKey'),
46
44
  });
47
45
  }
48
46
  this.registerOutputs();
@@ -61,9 +61,16 @@ export type WebServerArgs = {
61
61
  */
62
62
  size?: pulumi.Input<Size>;
63
63
  /**
64
- * The environment variables to pass to a container. Defaults to [].
64
+ * The environment variables to pass to a container. Don't use this field for
65
+ * sensitive information such as passwords, API keys, etc. For that purpose,
66
+ * please use the `secrets` property.
67
+ * Defaults to [].
65
68
  */
66
69
  environment?: aws.ecs.KeyValuePair[];
70
+ /**
71
+ * The secrets to pass to the container. Defaults to [].
72
+ */
73
+ secrets?: aws.ecs.Secret[];
67
74
  /**
68
75
  * Path for the health check request. Defaults to "/healtcheck".
69
76
  */
@@ -26,6 +26,7 @@ const defaults = {
26
26
  maxCount: 10,
27
27
  size: 'small',
28
28
  environment: [],
29
+ secrets: [],
29
30
  healtCheckPath: '/healtcheck',
30
31
  taskExecutionRoleInlinePolicies: [],
31
32
  taskRoleInlinePolicies: [],
@@ -128,6 +129,20 @@ class WebServer extends pulumi.ComponentResource {
128
129
  },
129
130
  ],
130
131
  }, { parent: this });
132
+ const secretManagerSecretsInlinePolicy = {
133
+ name: `${name}-secret-manager-access`,
134
+ policy: JSON.stringify({
135
+ Version: '2012-10-17',
136
+ Statement: [
137
+ {
138
+ Sid: 'AllowContainerToGetSecretManagerSecrets',
139
+ Effect: 'Allow',
140
+ Action: ['secretsmanager:GetSecretValue'],
141
+ Resource: '*',
142
+ },
143
+ ],
144
+ }),
145
+ };
131
146
  const taskExecutionRole = new aws.iam.Role(`${name}-ecs-task-exec-role`, {
132
147
  name: `${name}-ecs-task-exec-role`,
133
148
  assumeRolePolicy,
@@ -135,7 +150,10 @@ class WebServer extends pulumi.ComponentResource {
135
150
  'arn:aws:iam::aws:policy/CloudWatchFullAccess',
136
151
  'arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess',
137
152
  ],
138
- inlinePolicies: argsWithDefaults.taskExecutionRoleInlinePolicies,
153
+ inlinePolicies: [
154
+ secretManagerSecretsInlinePolicy,
155
+ ...argsWithDefaults.taskExecutionRoleInlinePolicies,
156
+ ],
139
157
  }, { parent: this });
140
158
  const execCmdInlinePolicy = {
141
159
  name: `${name}-ecs-exec`,
@@ -191,10 +209,11 @@ class WebServer extends pulumi.ComponentResource {
191
209
  argsWithDefaults.image,
192
210
  argsWithDefaults.port,
193
211
  argsWithDefaults.environment,
212
+ argsWithDefaults.secrets,
194
213
  this.logGroup.name,
195
214
  awsRegion,
196
215
  ])
197
- .apply(([containerName, image, port, environment, logGroup, region]) => {
216
+ .apply(([containerName, image, port, environment, secrets, logGroup, region,]) => {
198
217
  return JSON.stringify([
199
218
  {
200
219
  readonlyRootFilesystem: false,
@@ -216,6 +235,7 @@ class WebServer extends pulumi.ComponentResource {
216
235
  },
217
236
  },
218
237
  environment,
238
+ secrets,
219
239
  },
220
240
  ]);
221
241
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studion/infra-code-blocks",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "Studion common infra components",
5
5
  "keywords": [
6
6
  "infrastructure",