Skip to content

Commit 17db1e1

Browse files
committed
Commit fixes, changes for things noticed during video
1 parent ed7bc56 commit 17db1e1

File tree

10 files changed

+82
-38
lines changed

10 files changed

+82
-38
lines changed

README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ A lot of `ci.yml` is self-explanatory but here are some notes to help clarify so
123123

124124
![Infrastructure Diagram](images/Interview-Prep-Infrastructure-v2.drawio.png)
125125

126-
The diagram above illustrates the major parts of the application infrastructure:
126+
The diagram above illustrates the major parts of the application infrastructure. Here are some descriptions and notes:
127127

128128
* **Interview Prep VPC**: "The Virtual Private Cloud (VPC) is a logically isolated network within the AWS cloud where we can launch and manage AWS resources. It provides a secure environment to group and connect related resources and services, such as EC2 instances, RDS databases, and ECS clusters. The VPC allows us to define our own IP address range, create subnets, and configure route tables and network gateways, ensuring that our infrastructure is both secure and scalable." (GitHub Copilot came up with such a great explanation here that I'm just going to use it as-is.)
129129
* **Availability zones A and B**: `us-east-1a` and `us-east-1b`. These zones, along with their corresponding public and private subnets, enhance the app's resilience. Currently, one task each for the ECS frontend and backend is deployed, but this can be scaled to distribute tasks across both availability zones.
@@ -142,6 +142,13 @@ The diagram above illustrates the major parts of the application infrastructure:
142142
* **RDS-hosted Postgres database instance**: The application uses an instance of Postgres hosted by the AWS Relational Database Service. It runs in the private subnets.
143143
* **Migrate Lambda function**: This is a function run by the GitHub workflow. A workflow step packages up the migration files with the Lambda function itself and then invokes the function.
144144
* **Route 53-hosted domains**: `dev.interviewprep.onyxdevtutorials.com` and `api.dev.interviewprep.onyxdevtutorials.com`. The DNS configuration in Route 53 connects the frontend and backend domains to the load balancer. This is achieved using alias records that point to the load balancer's DNS name and zone ID.
145+
* **CIDR Blocks**: CIDR (Classless Inter-Domain Routing) blocks are used to define IP address ranges within the VPC.
146+
* **VPC CIDR Block**: This is set to `10.0.0.0/16`, allowing for 65,536 possible IP addresses -- which is plenty for this project.
147+
* **Subnet CIDR Blocks**: Each subnet gets 256 IP addresses:
148+
* **Public Subnet A**: 10.0.1.0/24 provides 256 IP addresses.
149+
* **Public Subnet B**: 10.0.2.0/24 provides 256 IP addresses.
150+
* **Private Subnet A**: 10.0.3.0/24 provides 256 IP addresses.
151+
* **Private Subnet B**: 10.0.4.0/24 provides 256 IP addresses.
145152

146153
## Costs
147154

@@ -261,6 +268,16 @@ Once you're connected to the bastion host, you can directly access the database:
261268

262269
`psql -h <db-endpoint> -U <username> -d <db-name>`
263270

271+
Once connected to the database, you can type `\l` to list all the databases managed by the PostgreSQL server you are connected to.
272+
273+
Type `\dt` to list all the tables in the current database.
274+
275+
Type `\d products` or `\d users` to get information about each of these tables.
276+
277+
## Add New Migration File
278+
279+
Assuming CWD is `backend`, `npx knex migrate:make <migration-file-name> --knexfile ./src/knexFile.ts --migrations-directory ../migrations`.
280+
264281
## Version History
265282

266283
### 0.1.0

terraform/environments/development/main.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ module "rds" {
4343
db_username = var.db_username
4444
db_password = var.db_password
4545
db_sg_id = module.security_groups.db_sg_id
46-
lambda_sg_id = module.security_groups.lambda_sg_id
4746
environment = var.environment
4847
}
4948

terraform/environments/development/outputs.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ output "ecs_task_execution_role_arn" {
4848
value = module.iam.ecs_task_execution_role_arn
4949
}
5050

51+
output "ecs_task_role_arn" {
52+
description = "The ARN of the ECS task role"
53+
value = module.iam.ecs_task_role_arn
54+
}
55+
5156
output "lambda_exec_role_arn" {
5257
description = "The ARN of the Lambda execution role"
5358
value = module.iam.lambda_exec_role_arn

terraform/modules/ecr/main.tf

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
resource "aws_ecr_repository" "frontend" {
22
name = "interview-prep-frontend"
3-
image_tag_mutability = "MUTABLE"
3+
image_tag_mutability = "MUTABLE" # Allows using a tag like "latest" to refer to the latest version of the image.
4+
# Allows you to enable or disable automatic scanning of container images for vulnerabilities when they are pushed to the repository.
45
image_scanning_configuration {
5-
scan_on_push = true
6+
scan_on_push = true # Images are automatically scanned for vulnerabilities when they are pushed to the repository.
67
}
78

89
tags = {
@@ -14,8 +15,9 @@ resource "aws_ecr_repository" "frontend" {
1415
resource "aws_ecr_repository" "backend" {
1516
name = "interview-prep-backend"
1617
image_tag_mutability = "MUTABLE"
18+
# Allows you to enable or disable automatic scanning of container images for vulnerabilities when they are pushed to the repository.
1719
image_scanning_configuration {
18-
scan_on_push = true
20+
scan_on_push = true # Images are automatically scanned for vulnerabilities when they are pushed to the repository.
1921
}
2022

2123
tags = {

terraform/modules/ecs/main.tf

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,23 @@ resource "aws_ecs_cluster" "main" {
44

55
resource "aws_ecs_task_definition" "frontend" {
66
family = "${var.environment}-frontend-ecs-task"
7+
// "awsvpc" mode provides each task with its own elastic network interface (ENI)
8+
// and a primary private IP address, allowing tasks to have full networking features
79
network_mode = "awsvpc"
10+
// Specifies that the task requires Fargate launch type
11+
// Fargate is a serverless compute engine for containers that works with ECS
812
requires_compatibilities = ["FARGATE"]
913
cpu = "256"
1014
memory = "512"
1115
execution_role_arn = var.ecs_task_execution_role
16+
# task_role_arn is used for task-level permissions, e.g., AmazonS3ReadOnlyAccess, AmazonSSMReadOnlyAccess. It allows the ECS tasks to interact with other AWS services.
1217
task_role_arn = var.ecs_task_role_arn
1318

1419
container_definitions = jsonencode([
1520
{
1621
name = "frontend"
1722
image = "${var.frontend_repository_url}:latest"
23+
# If this container stops or fails, the entire task is considered to have failed, and ECS will stop all other containers in the task.
1824
essential = true
1925
portMappings = [
2026
{
@@ -38,6 +44,9 @@ resource "aws_ecs_task_definition" "frontend" {
3844
}
3945
],
4046
linuxParameters = {
47+
# An init process is run inside the container.
48+
# The init process handles reaping zombie processes, which are child processes that have completed execution but still have an entry in the process table.
49+
# This can help prevent resource leaks and ensure that the container environment remains clean and efficient.
4150
initProcessEnabled = true
4251
}
4352
}
@@ -46,17 +55,23 @@ resource "aws_ecs_task_definition" "frontend" {
4655

4756
resource "aws_ecs_task_definition" "backend" {
4857
family = "${var.environment}-backend-ecs-task"
58+
// "awsvpc" mode provides each task with its own elastic network interface (ENI)
59+
// and a primary private IP address, allowing tasks to have full networking features
4960
network_mode = "awsvpc"
61+
// Specifies that the task requires Fargate launch type
62+
// Fargate is a serverless compute engine for containers that works with ECS
5063
requires_compatibilities = ["FARGATE"]
5164
cpu = "256"
5265
memory = "512"
5366
execution_role_arn = var.ecs_task_execution_role
67+
# task_role_arn is used for task-level permissions, e.g., AmazonS3ReadOnlyAccess, AmazonSSMReadOnlyAccess. It allows the ECS tasks to interact with other AWS services.
5468
task_role_arn = var.ecs_task_role_arn
5569

5670
container_definitions = jsonencode([
5771
{
5872
name = "backend"
5973
image = "${var.backend_repository_url}"
74+
# If this container stops or fails, the entire task is considered to have failed, and ECS will stop all other containers in the task.
6075
essential = true
6176
portMappings = [
6277
{
@@ -84,6 +99,9 @@ resource "aws_ecs_task_definition" "backend" {
8499
}
85100
},
86101
linuxParameters = {
102+
# An init process is run inside the container.
103+
# The init process handles reaping zombie processes, which are child processes that have completed execution but still have an entry in the process table.
104+
# This can help prevent resource leaks and ensure that the container environment remains clean and efficient.
87105
initProcessEnabled = true
88106
}
89107
}
@@ -109,6 +127,8 @@ resource "aws_ecs_service" "frontend" {
109127
container_port = 80
110128
}
111129

130+
# You can use the ecs execute-command feature to run commands inside your containers.
131+
# This is useful for debugging, troubleshooting, and managing your containers without needing SSH access or exposing additional ports.
112132
enable_execute_command = true
113133
}
114134

@@ -131,6 +151,8 @@ resource "aws_ecs_service" "backend" {
131151
container_port = 3000
132152
}
133153

154+
# You can use the ecs execute-command feature to run commands inside your containers.
155+
# This is useful for debugging, troubleshooting, and managing your containers without needing SSH access or exposing additional ports.
134156
enable_execute_command = true
135157
}
136158

terraform/modules/iam/main.tf

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# Role used by ECS agent to perform actions on your behalf when launching and managing tasks. Common actions: Pulling images from ECR, writing logs to CloudWatch, etc.
12
resource "aws_iam_role" "ecs_task_execution_role" {
23
name = "${var.environment}-ecs-task-execution-role"
34
assume_role_policy = jsonencode({
@@ -18,16 +19,18 @@ resource "aws_iam_role" "ecs_task_execution_role" {
1819
}
1920
}
2021

22+
# Policies attached are AmazonEC2ContainerRegistryReadOnly and AmazonECSTaskExecutionRolePolicy
2123
resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" {
2224
role = aws_iam_role.ecs_task_execution_role.name
2325
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
2426
}
2527

26-
resource "aws_iam_role_policy_attachment" "ecr_pull_policy" {
27-
role = aws_iam_role.ecs_task_execution_role.name
28-
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
29-
}
28+
# resource "aws_iam_role_policy_attachment" "ecr_pull_policy" {
29+
# role = aws_iam_role.ecs_task_execution_role.name
30+
# policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
31+
# }
3032

33+
# Role is assumed by the ECS tasks themselves. It allows the containers running within the tasks to interact with other AWS services. Common actions: reading from or writing to S3 buckets; accessing secrets from SSM Parameter Store; interacting with DynamoDB tables, etc. Here, because we don't attach any policies, the role does not grant any permissions to perform actions on AWS resources.
3134
resource "aws_iam_role" "ecs_task_role" {
3235
name = "${var.environment}-ecs-task-role"
3336
assume_role_policy = jsonencode({
@@ -48,16 +51,6 @@ resource "aws_iam_role" "ecs_task_role" {
4851
}
4952
}
5053

51-
resource "aws_iam_role_policy_attachment" "ecs_task_role_policy" {
52-
role = aws_iam_role.ecs_task_role.name
53-
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
54-
}
55-
56-
# resource "aws_iam_role_policy_attachment" "ecs_task_role_ssm_policy" {
57-
# role = aws_iam_role.ecs_task_role.name
58-
# policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
59-
# }
60-
6154
resource "aws_iam_role" "lambda_exec" {
6255
name = "${var.environment}-interview-prep-lambda-exec"
6356
assume_role_policy = jsonencode({
@@ -116,13 +109,13 @@ resource "aws_iam_policy" "lambda_exec_policy" {
116109
"arn:aws:ssm:${var.region}:${var.account_id}:parameter/interview-prep/${var.environment}/*"
117110
]
118111
},
119-
{
120-
Effect = "Allow",
121-
Action = [
122-
"kms:Decrypt"
123-
],
124-
Resource = "arn:aws:kms:${var.region}:${var.account_id}:key/169ce983-7b59-4ff6-9c74-533af48cf478"
125-
},
112+
# {
113+
# Effect = "Allow",
114+
# Action = [
115+
# "kms:Decrypt"
116+
# ],
117+
# Resource = "arn:aws:kms:${var.region}:${var.account_id}:key/169ce983-7b59-4ff6-9c74-533af48cf478"
118+
# },
126119
]
127120
})
128121
}

terraform/modules/rds/main.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ resource "aws_db_instance" "postgres" {
1818
password = var.db_password
1919
vpc_security_group_ids = [var.db_sg_id]
2020
db_subnet_group_name = aws_db_subnet_group.postgres.name
21-
skip_final_snapshot = true
22-
apply_immediately = false
21+
skip_final_snapshot = true # Because I don't need a backup before deletion.
22+
apply_immediately = false # This parameter determines whether modifications to the RDS instance are applied immediately or during the next maintenance window.
2323
tags = {
2424
Name = "${var.environment}-interview-prep-db"
2525
Environment = var.environment

terraform/modules/rds/variables.tf

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@ variable "db_sg_id" {
2525
type = string
2626
}
2727

28-
variable "lambda_sg_id" {
29-
description = "The ID of the security group for the Lambda function"
30-
type = string
31-
}
32-
3328
variable "environment" {
3429
description = "The environment for the resources (e.g., development, staging, production)"
3530
type = string

terraform/modules/security_groups/main.tf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,4 +181,14 @@ resource "aws_security_group_rule" "allow_bastion_to_db" {
181181
protocol = "tcp"
182182
source_security_group_id = aws_security_group.bastion_sg.id
183183
security_group_id = aws_security_group.db_sg.id
184+
}
185+
186+
resource "aws_security_group_rule" "allow_backend_to_db" {
187+
type = "ingress"
188+
from_port = 5432
189+
to_port = 5432
190+
protocol = "tcp"
191+
source_security_group_id = aws_security_group.backend_sg.id
192+
security_group_id = aws_security_group.db_sg.id
193+
description = "Allow backend to access the db"
184194
}

terraform/modules/vpc/main.tf

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
resource "aws_vpc" "interview_prep_vpc" {
22
cidr_block = var.vpc_cidr
3-
enable_dns_support = true
4-
enable_dns_hostnames = true
3+
enable_dns_support = true # Allows instances within the VPC to resolve domain names to IP addresses using the Amazon-provided DNS server.
4+
enable_dns_hostnames = true # Allows instances to receive DNS hostnames that can be resolved to their private IP addresses.
55
tags = {
66
Name = "interview-prep-vpc"
77
Environment = var.environment
@@ -17,14 +17,15 @@ resource "aws_internet_gateway" "igw" {
1717
}
1818

1919
resource "aws_nat_gateway" "nat_gw" {
20-
allocation_id = aws_eip.nat_eip.id
20+
allocation_id = aws_eip.nat_eip.id # An identifier for an Elastic IP (EIP) that has been allocated in your AWS account. Used to associate the Elastic IP with a NAT Gateway, ensuring that the NAT Gateway has a static public IP address.
2121
subnet_id = var.public_subnet_a_id
2222
tags = {
2323
Name = "interview-prep-nat-gw"
2424
Environment = var.environment
2525
}
2626
}
2727

28+
# Allocate an Elastic IP address for the NAT Gateway.
2829
resource "aws_eip" "nat_eip" {
2930
tags = {
3031
Name = "interview-prep-nat-eip"
@@ -35,7 +36,7 @@ resource "aws_eip" "nat_eip" {
3536
resource "aws_route_table" "public" {
3637
vpc_id = aws_vpc.interview_prep_vpc.id
3738
route {
38-
cidr_block = "0.0.0.0/0"
39+
cidr_block = "0.0.0.0/0" # Direct all outbound traffic to the internet gateway.
3940
gateway_id = aws_internet_gateway.igw.id
4041
}
4142
tags = {
@@ -57,7 +58,7 @@ resource "aws_route_table_association" "public_b" {
5758
resource "aws_route_table" "private" {
5859
vpc_id = aws_vpc.interview_prep_vpc.id
5960
route {
60-
cidr_block = "0.0.0.0/0"
61+
cidr_block = "0.0.0.0/0" # Direct all outbound traffic to the NAT Gateway.
6162
nat_gateway_id = aws_nat_gateway.nat_gw.id
6263
}
6364
tags = {

0 commit comments

Comments
 (0)