diff --git a/.github/workflows/backend.yaml b/.github/workflows/backend.yaml index ea63340a..d0071c4c 100644 --- a/.github/workflows/backend.yaml +++ b/.github/workflows/backend.yaml @@ -11,6 +11,10 @@ on: - .github/** - backend/** +defaults: + run: + working-directory: ./backend + env: REGISTRY: ghcr.io IMAGE_NAME: backend @@ -30,7 +34,7 @@ jobs: - name: Run unit tests run: | - cd ./backend && go test ./... -v -race -cover + go test ./... -v -race -cover - name: Provide image name and version run: | @@ -41,7 +45,7 @@ jobs: - name: Build image run: | - cd ./backend && docker build . --file Dockerfile --target production --tag $IMAGE_ID:$IMAGE_VERSION --tag $IMAGE_ID:latest + docker build . --file Dockerfile --target production --tag $IMAGE_ID:$IMAGE_VERSION --tag $IMAGE_ID:latest cd: runs-on: ubuntu-latest @@ -69,7 +73,7 @@ jobs: - name: Build image run: | - cd ./backend && docker build . --file Dockerfile --target production --tag $IMAGE_ID:$IMAGE_VERSION --tag $IMAGE_ID:latest + docker build . --file Dockerfile --target production --tag $IMAGE_ID:$IMAGE_VERSION --tag $IMAGE_ID:latest - name: Log in to registry run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index dfff995a..8bc68104 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -11,6 +11,10 @@ on: - .github/** - frontend/** +defaults: + run: + working-directory: ./frontend + env: REGISTRY: ghcr.io IMAGE_NAME: frontend @@ -36,7 +40,7 @@ jobs: - name: Build image run: | - cd ./frontend && docker build . --file Dockerfile --target production --tag $IMAGE_ID:$IMAGE_VERSION --tag $IMAGE_ID:latest + docker build . --file Dockerfile --target production --tag $IMAGE_ID:$IMAGE_VERSION --tag $IMAGE_ID:latest cd: runs-on: ubuntu-latest @@ -64,7 +68,7 @@ jobs: - name: Build image run: | - cd ./frontend && docker build . --file Dockerfile --target production --tag $IMAGE_ID:$IMAGE_VERSION --tag $IMAGE_ID:latest + docker build . --file Dockerfile --target production --tag $IMAGE_ID:$IMAGE_VERSION --tag $IMAGE_ID:latest - name: Log in to registry run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin diff --git a/.github/workflows/infrastructure.yaml b/.github/workflows/infrastructure.yaml new file mode 100644 index 00000000..1f8b252c --- /dev/null +++ b/.github/workflows/infrastructure.yaml @@ -0,0 +1,82 @@ +name: Infrastructure CI and CD +on: + push: + branches: + - main + paths: + - .github/** + - infrastructure/** + pull_request: + paths: + - .github/** + - infrastructure/** + +defaults: + run: + working-directory: ./infrastructure + +env: + TF_VAR_project_name: tarhche + TF_VAR_instance_name: backend + TF_VAR_ssh_public_key: $(shell cat ssh-public-key.pub) + +jobs: + ci: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + + - name: Terraform Format + id: fmt + run: terraform fmt -check + + - name: Terraform Init + id: init + run: terraform init + + - name: Terraform Validate + id: validate + run: terraform validate -no-color + + - name: Terraform Plan + run: terraform plan -no-color -input=false + continue-on-error: true + + cd: + runs-on: ubuntu-latest + + # This job will be invoked only on default branch + if: ${{ always() && format('refs/heads/{0}', github.event.repository.default_branch) == github.ref }} + + needs: + - ci + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + + - name: Terraform Apply + run: terraform apply -auto-approve -input=false + continue-on-error: true diff --git a/infrastructure/.gitignore b/infrastructure/.gitignore new file mode 100644 index 00000000..b084d720 --- /dev/null +++ b/infrastructure/.gitignore @@ -0,0 +1,10 @@ +/.idea + +# SSH keys +/*.pem +/*.pub + +# Terraform files +*.tfstate +*.tfstate.backup +.terraform/ diff --git a/infrastructure/.terraform.lock.hcl b/infrastructure/.terraform.lock.hcl new file mode 100644 index 00000000..d3e4f5ce --- /dev/null +++ b/infrastructure/.terraform.lock.hcl @@ -0,0 +1,24 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.82.1" + hashes = [ + "h1:QTOtDMehUfiD3wDbbDuXYuTqGgLDkKK9Agkd5NCUEic=", + "zh:0fde8533282973f1f5d33b2c4f82d962a2c78860d39b42ac20a9ce399f06f62c", + "zh:1fd1a252bffe91668f35be8eac4e0a980f022120254eae1674c3c05049aff88a", + "zh:31bbd380cd7d74bf9a8c961fc64da4222bed40ffbdb27b011e637fa8b2d33641", + "zh:333ee400cf6f62fa199dc1270bf8efac6ffe56659f86918070b8351b8636e03b", + "zh:42ea9fee0a152d344d548eab43583299a13bcd73fae9e53e7e1a708720ac1315", + "zh:4b78f25a8cda3316eb56aa01909a403ec2f325a2eb0512c9a73966068c26cf29", + "zh:5e9cf9a275eda8f7940a41e32abe0b92ba76b5744def4af5124b343b5f33eb94", + "zh:6a46c8630c16b9e1338c2daed6006118db951420108b58b8b886403c69317439", + "zh:6efe11cf1a01f98a8d8043cdcd8c0ee5fe93a0e582c2b69ebb73ea073f5068c3", + "zh:88ab5c768c7d8133dab94eff48071e764424ad2b7cfeee5abe6d5bb16e4b85c6", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:a614beb312574342b27dbc34d65b450997f63fa3e948d0d30f441e4f69337380", + "zh:c1f486e27130610a9b64cacb0bd928009c433d62b3be515488185e6467b4aa1f", + "zh:dccd166e89e1a02e7ce658df3c42d040edec4b09c6f7906aa5743938518148b1", + "zh:e75a3ae0fb42b7ea5a0bb5dffd8f8468004c9700fcc934eb04c264fda2ba9984", + ] +} diff --git a/infrastructure/Makefile b/infrastructure/Makefile new file mode 100644 index 00000000..4bf4ba25 --- /dev/null +++ b/infrastructure/Makefile @@ -0,0 +1,25 @@ +export TF_VAR_project_name = tarhche +export TF_VAR_instance_name = backend +export TF_VAR_ssh_public_key = $(shell cat ssh-public-key.pub) +export EC2_SSH_ADDRESS = + +validate: + terraform validate + +init: + terraform init + +state: + terraform state list + +plan: + terraform plan + +apply: + terraform apply + +public_key: + ssh-keygen -y -f ssh-private-key.pem > ssh-public-key.pub + +ssh: + ssh -i "ssh-private-key.pem" ${EC2_SSH_ADDRESS} diff --git a/infrastructure/backend.tf b/infrastructure/backend.tf new file mode 100644 index 00000000..841585bd --- /dev/null +++ b/infrastructure/backend.tf @@ -0,0 +1,102 @@ +provider "aws" { + region = "eu-central-1" +} + +variable "project_name" { + description = "Project tag given to each deployed Instance" + type = string +} + +variable "instance_name" { + description = "instance_name" + type = string +} + +variable "ssh_public_key" { + description = "SSH public key" + type = string +} + +resource "aws_security_group" "backend" { + name = var.instance_name + description = "Allow HTTP, HTTPS, and SSH inbound traffic" + + tags = { + project_name = var.project_name + } + + # Allow SSH (port 22) from any IP address + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + # Allow HTTP (port 80) from any IP address + ingress { + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] # Allow HTTP from anywhere + } + + # Allow HTTPS (port 443) from any IP address + ingress { + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + # Allow all outbound traffic + egress { + from_port = 0 + to_port = 0 + protocol = "-1" # all protocols + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_key_pair" "ssh_public_key" { + key_name = var.instance_name + public_key = var.ssh_public_key + + tags = { + project_name = var.project_name + } +} + +resource "aws_instance" "backend" { + ami = "ami-0e54671bdf3c8ed8d" # Amazon linux 2023 + instance_type = "t2.micro" + key_name = aws_key_pair.ssh_public_key.key_name + + root_block_device { + delete_on_termination = true + encrypted = false + volume_size = 15 + volume_type = "gp3" + + tags = { + project_name = var.project_name + } + } + + security_groups = [ + aws_security_group.backend.name + ] + + tags = { + project_name = var.project_name + } +} + +resource "aws_eip" "backend" { + instance = aws_instance.backend.id + domain = "vpc" + + tags = { + project_name = var.project_name + } +}