Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ECS backend deployment #9

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
# Fight.Me Infrastructure

Yep

## aws-vault

Account ID: `470096912115`
User: `tom`

1. Install aws-vault (using homebrew, works for both mac and wsl linux)

```bash
brew install aws-vault
```

2. Add IAM credentials. This is where you'll need to enter your access key and secret (access) key. Replace `my_iam_name` with your account name.

```bash
aws-vault add my_iam_name
```

3. Initialise Terraform backend

```bash
aws-vault exec my_iam_name -- terraform init
```

4. To deploy infrastructure

```bash
aws-vault exec my_iam_name -- terraform apply
```

5. To remove infrastructure

```bash
aws-vault exec my_iam_name -- terraform destroy
```
273 changes: 228 additions & 45 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,85 +12,268 @@ provider "aws" {
region = "eu-west-2"
}

resource "aws_security_group" "fight_me_backend_sg" {
name = "fight_me_backend_sg"
description = "Allow inbound traffic for Socket.IO server"
resource "aws_ecs_cluster" "fight_me_backend_cluster" {
name = "fight-me-backend-cluster"
}

# tfsec:ignore:aws-ec2-no-public-ingress-sgr
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow inbound http/websocket traffic to server on port 80"
resource "aws_ecs_task_definition" "fight_me_backend_task" {
family = "fight-me-backened-task"
container_definitions = <<DEFINITION
[
{
"name": "my-first-task",
"image": "terminalhavok97/fight-me-backend:latest",
"essential": true,
"portMappings": [
{
"containerPort": 5000,
"hostPort": 5000
}
],
"memory": 512,
"cpu": 256,
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/my-first-task",
"awslogs-region": "eu-west-2",
"awslogs-stream-prefix": "ecs"
}
},
"healthCheck": {
"command": ["CMD-SHELL","curl -f http://0.0.0.0:5000/health || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3,
"startPeriod": 0
}
}
]
DEFINITION
requires_compatibilities = ["EC2"]
network_mode = "bridge" # Change from awsvpc to bridge
memory = 512
cpu = 256
execution_role_arn = aws_iam_role.ecsTaskExecutionRole.arn
}

resource "aws_iam_role" "ecsTaskExecutionRole" {
name = "ecsTaskExecutionRole"
assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json
}

data "aws_iam_policy_document" "assume_role_policy" {
statement {
actions = ["sts:AssumeRole"]

principals {
type = "Service"
identifiers = ["ecs-tasks.amazonaws.com"]
}
}
}

resource "aws_iam_role_policy_attachment" "ecsTaskExecutionRole_policy" {
role = aws_iam_role.ecsTaskExecutionRole.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

resource "aws_lb" "fight_me_backend_lb" {
name = "fight-me-backend-lb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.lb_sg.id]
subnets = ["${aws_default_subnet.default_subnet_a.id}", "${aws_default_subnet.default_subnet_b.id}", "${aws_default_subnet.default_subnet_c.id}"]
}

resource "aws_lb_target_group" "fight_me_backend_tg" {
name = "fight-me-backend-tg"
port = 5000
protocol = "HTTP"
vpc_id = aws_default_vpc.default_vpc.id

health_check {
interval = 30
path = "/health"
protocol = "HTTP"
timeout = 5
healthy_threshold = 2
unhealthy_threshold = 2
matcher = "200"
}
}

resource "aws_lb_listener" "fight_me_backend_listener" {
load_balancer_arn = aws_lb.fight_me_backend_lb.arn
port = "80"
protocol = "HTTP"

default_action {
type = "forward"
target_group_arn = aws_lb_target_group.fight_me_backend_tg.arn
}
}

resource "aws_ecs_service" "fight_me_backend_service" {
name = "fight-me-backend-service"
cluster = aws_ecs_cluster.fight_me_backend_cluster.id
task_definition = aws_ecs_task_definition.fight_me_backend_task.arn
launch_type = "EC2"
desired_count = 1

load_balancer {
target_group_arn = aws_lb_target_group.fight_me_backend_tg.arn
container_name = "my-first-task"
container_port = 5000
}
}

resource "aws_security_group" "lb_sg" {
name = "lb_sg"
description = "Allow inbound traffic"
vpc_id = aws_default_vpc.default_vpc.id

# tfsec:ignore:aws-ec2-no-public-ingress-sgr
ingress {
from_port = 8080
to_port = 8080
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow inbound http/websocket traffic to server on port 8080"
}

# tfsec:ignore:aws-ec2-no-public-ingress-sgr
# New rule to allow inbound traffic on port 5000
ingress {
from_port = 5000
to_port = 5000
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow inbound http/websocket traffic to server on port 8080"
}

# tfsec:ignore:aws-ec2-no-public-egress-sgr
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow outbound http/websocket traffic from server"
}
}

resource "aws_instance" "fight_me_backend" {
ami = "ami-0cd8ad123effa531a" # Amazon Linux 3 for eu-west-2
instance_type = "t2.micro" # Free tier eligible instance type
resource "aws_default_vpc" "default_vpc" {
}

vpc_security_group_ids = [aws_security_group.fight_me_backend_sg.id]
resource "aws_default_subnet" "default_subnet_a" {
availability_zone = "eu-west-2a"
}

root_block_device {
encrypted = true
}
resource "aws_default_subnet" "default_subnet_b" {
availability_zone = "eu-west-2b"
}

resource "aws_default_subnet" "default_subnet_c" {
availability_zone = "eu-west-2c"
}

resource "aws_cloudwatch_log_group" "ecs_log_group" {
name = "/ecs/my-first-task"
retention_in_days = 14
}

metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
resource "aws_iam_role_policy_attachment" "ecsTaskExecutionRole_cloudwatch" {
role = aws_iam_role.ecsTaskExecutionRole.name
policy_arn = "arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"
}

data "aws_ami" "latest_ecs_optimized" {
most_recent = true

filter {
name = "name"
values = ["amzn2-ami-ecs-hvm-*-x86_64-ebs"]
}

user_data = <<EOF
#!/bin/bash
yum update -y
yum install -y python3 python3-pip git
owners = ["amazon"]
}

# Install Poetry
curl -sSL https://install.python-poetry.org | python3 -
# ECS Instance Security Group
resource "aws_security_group" "ecs_instance_sg" {
name = "ecs_instance_sg"
description = "Allow inbound traffic from ALB"
vpc_id = aws_default_vpc.default_vpc.id

# Clone your project repository
git clone --depth=1 https://github.com/tomvaughan77/fight-me-backend /home/ec2-user/fight-me-backend
ingress {
from_port = 5000
to_port = 5000
protocol = "tcp"
security_groups = [aws_security_group.lb_sg.id] # Allows traffic from the ALB to the EC2 instance
}

# Set environment variables
export PATH=$PATH:/root/.local/bin
# This will allow all outbound traffic. Modify to meet your needs.
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}

# ECS Instance
resource "aws_instance" "ecs_instance" {
ami = data.aws_ami.latest_ecs_optimized.id
instance_type = "t2.micro"
iam_instance_profile = aws_iam_instance_profile.ecs_instance_profile.name

# Navigate to the project directory and install dependencies
cd /home/ec2-user/fight-me-backend
poetry install
vpc_security_group_ids = [aws_security_group.ecs_instance_sg.id] # Associates the new security group with the EC2 instance

# Run your Socket.IO server (Replace <your_main_file> with the name of your main Python file)
nohup python fight_me_backend/main.py &
EOF
user_data = <<-EOF
#!/bin/bash
echo ECS_CLUSTER=${aws_ecs_cluster.fight_me_backend_cluster.name} >> /etc/ecs/ecs.config
EOF

tags = {
Name = "fight-me-backend"
Name = "ECS Instance - ${aws_ecs_cluster.fight_me_backend_cluster.name}"
}
}

resource "aws_iam_instance_profile" "ecs_instance_profile" {
name = "ecs-instance-profile"
role = aws_iam_role.ecs_instance_role.name
}

resource "aws_iam_role" "ecs_instance_role" {
name = "ecs-instance-role"

assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}

resource "aws_iam_role_policy_attachment" "ecs_instance_role_policy_attach" {
role = aws_iam_role.ecs_instance_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"
}

resource "aws_lb_listener_rule" "health_check" {
listener_arn = aws_lb_listener.fight_me_backend_listener.arn
priority = 100

action {
type = "forward"
target_group_arn = aws_lb_target_group.fight_me_backend_tg.arn
}

condition {
path_pattern {
values = ["/health"]
}
}
}