diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml new file mode 100644 index 0000000..43003e6 --- /dev/null +++ b/.github/workflows/develop.yml @@ -0,0 +1,24 @@ +name: 'Develop Flow' + +on: + push: + branches: [devel] + +permissions: + id-token: write + contents: read + +jobs: + integration: + uses: ./.github/workflows/integration.yml + secrets: inherit + + tf-plan: + needs: [integration] + uses: ./.github/workflows/tf-plan.yml + secrets: inherit + + tf-apply: + needs: [ integration, tf-plan ] + uses: ./.github/workflows/tf-plan.yml + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/tf-apply.yml b/.github/workflows/tf-apply.yml new file mode 100644 index 0000000..c58ca04 --- /dev/null +++ b/.github/workflows/tf-apply.yml @@ -0,0 +1,48 @@ +name: 'Tf Apply Flow' + +on: + workflow_call: + inputs: + environment: + description: 'App Env' + required: false + type: string + default: devel + working_directory: + description: 'App Path' + required: false + type: string + default: infrastructure/aws + + +permissions: + id-token: write + contents: read + +jobs: + tf-apply: + runs-on: ubuntu-latest + environment: ${{ inputs.environment }} + steps: + - name: Configure AWS + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_TF_ROLE }} + aws-region: us-east-1 + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + + - name: TF init + working-directory: ${{ inputs.working_directory }} + run: | + terraform init + + - name: TF plan + working-directory: ${{ inputs.working_directory }} + run: | + terraform apply --auto-approve + diff --git a/.github/workflows/tf-plan.yml b/.github/workflows/tf-plan.yml new file mode 100644 index 0000000..c64d27d --- /dev/null +++ b/.github/workflows/tf-plan.yml @@ -0,0 +1,48 @@ +name: 'Tf Plan Flow' + +on: + workflow_call: + inputs: + environment: + description: 'App Env' + required: false + type: string + default: devel + working_directory: + description: 'App Path' + required: false + type: string + default: infrastructure/aws + + +permissions: + id-token: write + contents: read + +jobs: + tf-plan: + runs-on: ubuntu-latest + environment: ${{ inputs.environment }} + steps: + - name: Configure AWS + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_TF_ROLE }} + aws-region: us-east-1 + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + + - name: TF init + working-directory: ${{ inputs.working_directory }} + run: | + terraform init + + - name: TF plan + working-directory: ${{ inputs.working_directory }} + run: | + terraform plan + diff --git a/infrastructure/aws/backend.tf b/infrastructure/aws/backend.tf new file mode 100644 index 0000000..21c6264 --- /dev/null +++ b/infrastructure/aws/backend.tf @@ -0,0 +1,8 @@ +terraform { + backend "s3" { + bucket = "fsl-challenge-tfstate" + key = "terraform.tfstate" + region = "us-east-1" + dynamodb_table = "fsl-challenge-tfstate" + } +} \ No newline at end of file diff --git a/infrastructure/aws/main.tf b/infrastructure/aws/main.tf new file mode 100644 index 0000000..c055ee7 --- /dev/null +++ b/infrastructure/aws/main.tf @@ -0,0 +1,10 @@ +module "s3_bucket" { + source = "./modules/s3-bucket" +} + +module "cloudfront" { + source = "./modules/cloudfront" + domain_name = module.s3_bucket.bucket_regional_domain_name + target_origin_id = module.s3_bucket.target_origin_id + origin_access_identity = module.s3_bucket.cloudfront_access_identity_path +} \ No newline at end of file diff --git a/infrastructure/aws/modules/cloudfront/main.tf b/infrastructure/aws/modules/cloudfront/main.tf new file mode 100644 index 0000000..9e429d7 --- /dev/null +++ b/infrastructure/aws/modules/cloudfront/main.tf @@ -0,0 +1,46 @@ +resource "aws_cloudfront_distribution" "s3_distribution" { + origin { + domain_name = var.domain_name + origin_id = var.target_origin_id + + s3_origin_config { + origin_access_identity = var.origin_access_identity + } + } + + enabled = true + is_ipv6_enabled = true + comment = "Clodfront distribution for fsl-challenge" + default_root_object = "index.html" + + default_cache_behavior { + allowed_methods = ["GET", "HEAD"] + cached_methods = ["GET", "HEAD"] + target_origin_id = var.target_origin_id + + forwarded_values { + query_string = false + + cookies { + forward = "none" + } + } + + viewer_protocol_policy = "allow-all" + min_ttl = 0 + default_ttl = 3600 + max_ttl = 86400 + } + + price_class = "PriceClass_200" + + restrictions { + geo_restriction { + restriction_type = "none" + } + } + + viewer_certificate { + cloudfront_default_certificate = true + } +} \ No newline at end of file diff --git a/infrastructure/aws/modules/cloudfront/variables.tf b/infrastructure/aws/modules/cloudfront/variables.tf new file mode 100644 index 0000000..93837ab --- /dev/null +++ b/infrastructure/aws/modules/cloudfront/variables.tf @@ -0,0 +1,11 @@ +variable "domain_name" { + type = string +} + +variable "target_origin_id" { + type = string +} + +variable "origin_access_identity" { + type = string +} \ No newline at end of file diff --git a/infrastructure/aws/modules/s3-bucket/main.tf b/infrastructure/aws/modules/s3-bucket/main.tf new file mode 100644 index 0000000..47e6c7c --- /dev/null +++ b/infrastructure/aws/modules/s3-bucket/main.tf @@ -0,0 +1,64 @@ +resource "aws_s3_bucket" "this" { + bucket = "fsl-challenge-bucket" + + tags = { + Name = "fsl-challenge-bucket" + } +} + +resource "aws_s3_bucket_ownership_controls" "this" { + bucket = aws_s3_bucket.this.id + + rule { + object_ownership = "BucketOwnerPreferred" + } +} + +resource "aws_s3_bucket_acl" "this" { + depends_on = [aws_s3_bucket_ownership_controls.this] + + bucket = aws_s3_bucket.this.id + acl = "private" +} + +resource "aws_s3_bucket_public_access_block" "this" { + bucket = aws_s3_bucket.this.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_s3_bucket_website_configuration" "this" { + bucket = aws_s3_bucket.this.id + + index_document { + suffix = "index.html" + } + + error_document { + key = "index.html" + } +} + +resource "aws_cloudfront_origin_access_identity" "this" { + comment = "Cloudfront OAI for bucket ${aws_s3_bucket.this.bucket}" +} + +data "aws_iam_policy_document" "s3_policy" { + statement { + actions = ["s3:GetObject"] + resources = ["${aws_s3_bucket.this.arn}/*"] + + principals { + type = "AWS" + identifiers = [aws_cloudfront_origin_access_identity.this.iam_arn] + } + } +} + +resource "aws_s3_bucket_policy" "this" { + bucket = aws_s3_bucket.this.id + policy = data.aws_iam_policy_document.s3_policy.json +} \ No newline at end of file diff --git a/infrastructure/aws/modules/s3-bucket/outputs.tf b/infrastructure/aws/modules/s3-bucket/outputs.tf new file mode 100644 index 0000000..50abf52 --- /dev/null +++ b/infrastructure/aws/modules/s3-bucket/outputs.tf @@ -0,0 +1,11 @@ +output "bucket_regional_domain_name" { + value = aws_s3_bucket.this.bucket_regional_domain_name +} + +output "cloudfront_access_identity_path" { + value = aws_cloudfront_origin_access_identity.this.cloudfront_access_identity_path +} + +output "target_origin_id" { + value = aws_cloudfront_origin_access_identity.this.id +} \ No newline at end of file diff --git a/infrastructure/aws/providers.tf b/infrastructure/aws/providers.tf new file mode 100644 index 0000000..3e3bddb --- /dev/null +++ b/infrastructure/aws/providers.tf @@ -0,0 +1,12 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} + +provider "aws" { + region = "us-east-1" +} \ No newline at end of file