From a9c6124e1125c81dc8614e7300502dfc6b94acd3 Mon Sep 17 00:00:00 2001 From: sh1un Date: Mon, 10 Jun 2024 18:45:04 +0800 Subject: [PATCH 1/4] refactor: add Terraform configuration for dev, poc, and prod environments The code changes include adding Terraform configuration files for the dev, poc, and prod environments. This allows for separate infrastructure provisioning and management for each environment. SCRUM-22 --- src/file_service/terraform/main.tf | 508 +++++++++--------- src/file_service/terraform/output.tf | 8 +- terraform/dev/backend.tf | 0 terraform/dev/backend_setting/dynamodb.tf | 14 + terraform/dev/backend_setting/output.tf | 7 + terraform/dev/backend_setting/s3.tf | 33 ++ terraform/dev/cloudfront.tf | 88 +++ terraform/dev/main.tf | 8 + terraform/dev/output.tf | 7 + terraform/dev/provider.tf | 6 + terraform/dev/route53.tf | 11 + terraform/dev/terraform.tf | 9 + terraform/dev/variables.tf | 52 ++ terraform/poc/.terraform.lock.hcl | 43 ++ terraform/poc/backend.tf | 0 .../poc/backend_setting/.terraform.lock.hcl | 24 + terraform/poc/backend_setting/dynamodb.tf | 14 + terraform/poc/backend_setting/output.tf | 7 + terraform/poc/backend_setting/s3.tf | 33 ++ terraform/poc/cloudfront.tf | 58 ++ terraform/poc/main.tf | 8 + terraform/poc/output.tf | 1 + terraform/poc/provider.tf | 6 + terraform/poc/route53.tf | 34 ++ terraform/poc/s3.tf | 8 + terraform/poc/terraform.tf | 9 + terraform/poc/variables.tf | 52 ++ terraform/prod/backend.tf | 0 terraform/prod/backend_setting/dynamodb.tf | 14 + terraform/prod/backend_setting/output.tf | 7 + terraform/prod/backend_setting/s3.tf | 33 ++ terraform/prod/cloudfront.tf | 88 +++ terraform/prod/main.tf | 8 + terraform/prod/output.tf | 7 + terraform/prod/provider.tf | 6 + terraform/prod/route53.tf | 11 + terraform/prod/terraform.tf | 9 + terraform/prod/variables.tf | 52 ++ 38 files changed, 1028 insertions(+), 255 deletions(-) create mode 100644 terraform/dev/backend.tf create mode 100644 terraform/dev/backend_setting/dynamodb.tf create mode 100644 terraform/dev/backend_setting/output.tf create mode 100644 terraform/dev/backend_setting/s3.tf create mode 100644 terraform/dev/cloudfront.tf create mode 100644 terraform/dev/main.tf create mode 100644 terraform/dev/output.tf create mode 100644 terraform/dev/provider.tf create mode 100644 terraform/dev/route53.tf create mode 100644 terraform/dev/terraform.tf create mode 100644 terraform/dev/variables.tf create mode 100644 terraform/poc/.terraform.lock.hcl create mode 100644 terraform/poc/backend.tf create mode 100644 terraform/poc/backend_setting/.terraform.lock.hcl create mode 100644 terraform/poc/backend_setting/dynamodb.tf create mode 100644 terraform/poc/backend_setting/output.tf create mode 100644 terraform/poc/backend_setting/s3.tf create mode 100644 terraform/poc/cloudfront.tf create mode 100644 terraform/poc/main.tf create mode 100644 terraform/poc/output.tf create mode 100644 terraform/poc/provider.tf create mode 100644 terraform/poc/route53.tf create mode 100644 terraform/poc/s3.tf create mode 100644 terraform/poc/terraform.tf create mode 100644 terraform/poc/variables.tf create mode 100644 terraform/prod/backend.tf create mode 100644 terraform/prod/backend_setting/dynamodb.tf create mode 100644 terraform/prod/backend_setting/output.tf create mode 100644 terraform/prod/backend_setting/s3.tf create mode 100644 terraform/prod/cloudfront.tf create mode 100644 terraform/prod/main.tf create mode 100644 terraform/prod/output.tf create mode 100644 terraform/prod/provider.tf create mode 100644 terraform/prod/route53.tf create mode 100644 terraform/prod/terraform.tf create mode 100644 terraform/prod/variables.tf diff --git a/src/file_service/terraform/main.tf b/src/file_service/terraform/main.tf index 749846d..64ae3a1 100644 --- a/src/file_service/terraform/main.tf +++ b/src/file_service/terraform/main.tf @@ -1,254 +1,254 @@ -provider "aws" { - region = "ap-northeast-1" -} - -data "aws_region" "current" {} - -resource "aws_iam_role" "lambda_exec_role" { - name = "lambda_exec_role" - assume_role_policy = jsonencode({ - Version = "2012-10-17" - Statement = [{ - Action = "sts:AssumeRole" - Effect = "Allow" - Principal = { - Service = "lambda.amazonaws.com" - } - }] - }) - - managed_policy_arns = [ - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", - "arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess" - ] -} - -data "archive_file" "lambda_zip" { - type = "zip" - source_dir = "${path.module}/../list_files" - output_path = "${path.module}/list_files_function.zip" -} - -data "archive_file" "get_file_lambda_zip" { - type = "zip" - source_dir = "${path.module}/../get_file" - output_path = "${path.module}/get_file_function.zip" -} - -resource "aws_lambda_function" "list_files" { - filename = data.archive_file.lambda_zip.output_path - function_name = "list_files" - role = aws_iam_role.lambda_exec_role.arn - handler = "list_files_function.lambda_handler" - source_code_hash = filebase64sha256(data.archive_file.lambda_zip.output_path) - runtime = "python3.11" - - environment { - variables = { - TABLE_NAME = "file" - } - } -} - -resource "aws_lambda_function" "get_file" { - filename = data.archive_file.get_file_lambda_zip.output_path - function_name = "get_file_by_id" - role = aws_iam_role.lambda_exec_role.arn - handler = "get_file_by_id.lambda_handler" - source_code_hash = filebase64sha256(data.archive_file.lambda_zip.output_path) - runtime = "python3.11" - - environment { - variables = { - TABLE_NAME = "file" - } - } -} - -resource "aws_api_gateway_rest_api" "files_api" { - name = "Files API" - description = "API for listing files with pagination and filtering" -} - -resource "aws_api_gateway_resource" "files_resource" { - rest_api_id = aws_api_gateway_rest_api.files_api.id - parent_id = aws_api_gateway_rest_api.files_api.root_resource_id - path_part = "files" -} - -resource "aws_api_gateway_resource" "file_resource" { - rest_api_id = aws_api_gateway_rest_api.files_api.id - parent_id = aws_api_gateway_resource.files_resource.id - path_part = "{file_id}" -} - -# GET Method for listing files -resource "aws_api_gateway_method" "list_files_method" { - rest_api_id = aws_api_gateway_rest_api.files_api.id - resource_id = aws_api_gateway_resource.files_resource.id - http_method = "GET" - authorization = "NONE" -} - -resource "aws_api_gateway_integration" "list_files_integration" { - rest_api_id = aws_api_gateway_rest_api.files_api.id - resource_id = aws_api_gateway_resource.files_resource.id - http_method = aws_api_gateway_method.list_files_method.http_method - type = "AWS_PROXY" - integration_http_method = "POST" - uri = aws_lambda_function.list_files.invoke_arn -} - -resource "aws_api_gateway_method_response" "list_files_response_200" { - rest_api_id = aws_api_gateway_rest_api.files_api.id - resource_id = aws_api_gateway_resource.files_resource.id - http_method = aws_api_gateway_method.list_files_method.http_method - status_code = "200" - - response_parameters = { - "method.response.header.Access-Control-Allow-Origin" = true, - "method.response.header.Access-Control-Allow-Headers" = true, - "method.response.header.Access-Control-Allow-Methods" = true - } -} - -resource "aws_api_gateway_integration_response" "list_files_integration_response_200" { - rest_api_id = aws_api_gateway_rest_api.files_api.id - resource_id = aws_api_gateway_resource.files_resource.id - http_method = aws_api_gateway_method.list_files_method.http_method - status_code = "200" - - response_parameters = { - "method.response.header.Access-Control-Allow-Origin" = "'*'", - "method.response.header.Access-Control-Allow-Headers" = "'*'", - "method.response.header.Access-Control-Allow-Methods" = "'GET,OPTIONS,POST,PUT'" - } -} - -# GET Method for getting a specific file -resource "aws_api_gateway_method" "get_file_method" { - rest_api_id = aws_api_gateway_rest_api.files_api.id - resource_id = aws_api_gateway_resource.file_resource.id - http_method = "GET" - authorization = "NONE" -} - -resource "aws_api_gateway_integration" "get_file_integration" { - rest_api_id = aws_api_gateway_rest_api.files_api.id - resource_id = aws_api_gateway_resource.file_resource.id - http_method = aws_api_gateway_method.get_file_method.http_method - type = "AWS_PROXY" - integration_http_method = "POST" - uri = aws_lambda_function.get_file.invoke_arn -} - -resource "aws_api_gateway_method_response" "get_file_response_200" { - rest_api_id = aws_api_gateway_rest_api.files_api.id - resource_id = aws_api_gateway_resource.file_resource.id - http_method = aws_api_gateway_method.get_file_method.http_method - status_code = "200" - - response_parameters = { - "method.response.header.Access-Control-Allow-Origin" = true, - "method.response.header.Access-Control-Allow-Headers" = true, - "method.response.header.Access-Control-Allow-Methods" = true - } -} - -resource "aws_api_gateway_integration_response" "get_file_integration_response_200" { - rest_api_id = aws_api_gateway_rest_api.files_api.id - resource_id = aws_api_gateway_resource.file_resource.id - http_method = aws_api_gateway_method.get_file_method.http_method - status_code = "200" - - response_parameters = { - "method.response.header.Access-Control-Allow-Origin" = "'*'", - "method.response.header.Access-Control-Allow-Headers" = "'*'", - "method.response.header.Access-Control-Allow-Methods" = "'GET,OPTIONS,POST,PUT'" - } -} - -# OPTIONS Method -resource "aws_api_gateway_method" "options_method" { - rest_api_id = aws_api_gateway_rest_api.files_api.id - resource_id = aws_api_gateway_resource.files_resource.id - http_method = "OPTIONS" - authorization = "NONE" -} - -resource "aws_api_gateway_integration" "options_integration" { - rest_api_id = aws_api_gateway_rest_api.files_api.id - resource_id = aws_api_gateway_resource.files_resource.id - http_method = aws_api_gateway_method.options_method.http_method - type = "MOCK" - request_templates = { - "application/json" = "{\"statusCode\": 200}" - } -} - -resource "aws_api_gateway_method_response" "options_response_200" { - rest_api_id = aws_api_gateway_rest_api.files_api.id - resource_id = aws_api_gateway_resource.files_resource.id - http_method = aws_api_gateway_method.options_method.http_method - status_code = "200" - - response_parameters = { - "method.response.header.Access-Control-Allow-Headers" = true, - "method.response.header.Access-Control-Allow-Methods" = true, - "method.response.header.Access-Control-Allow-Origin" = true - } - - response_models = { - "application/json" = "Empty" - } -} - -resource "aws_api_gateway_integration_response" "options_integration_response" { - rest_api_id = aws_api_gateway_rest_api.files_api.id - resource_id = aws_api_gateway_resource.files_resource.id - http_method = aws_api_gateway_method.options_method.http_method - status_code = aws_api_gateway_method_response.options_response_200.status_code - - response_parameters = { - "method.response.header.Access-Control-Allow-Headers" = "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'", - "method.response.header.Access-Control-Allow-Methods" = "'GET,OPTIONS,POST,PUT'", - "method.response.header.Access-Control-Allow-Origin" = "'*'" - } -} - -resource "aws_api_gateway_deployment" "files_api_deployment" { - depends_on = [ - aws_api_gateway_integration.list_files_integration, - aws_api_gateway_method_response.list_files_response_200, - aws_api_gateway_integration_response.list_files_integration_response_200, - aws_api_gateway_integration.get_file_integration, - aws_api_gateway_method_response.get_file_response_200, - aws_api_gateway_integration_response.get_file_integration_response_200, - aws_api_gateway_method.options_method, - aws_api_gateway_method_response.options_response_200, - aws_api_gateway_integration.options_integration, - aws_api_gateway_integration_response.options_integration_response - ] - rest_api_id = aws_api_gateway_rest_api.files_api.id - stage_name = "dev" -} - -resource "aws_lambda_permission" "api_gateway_permission" { - statement_id = "AllowAPIGatewayInvoke" - action = "lambda:InvokeFunction" - function_name = aws_lambda_function.list_files.function_name - principal = "apigateway.amazonaws.com" - source_arn = "${aws_api_gateway_rest_api.files_api.execution_arn}/*/*" -} - -resource "aws_lambda_permission" "api_gateway_permission_get_file" { - statement_id = "AllowAPIGatewayInvokeGetFile" - action = "lambda:InvokeFunction" - function_name = aws_lambda_function.get_file.function_name - principal = "apigateway.amazonaws.com" - source_arn = "${aws_api_gateway_rest_api.files_api.execution_arn}/*/*" -} - -output "api_url" { - value = "https://${aws_api_gateway_rest_api.files_api.id}.execute-api.${data.aws_region.current.name}.amazonaws.com/dev/files" -} +# provider "aws" { +# region = "ap-northeast-1" +# } + +# data "aws_region" "current" {} + +# resource "aws_iam_role" "lambda_exec_role" { +# name = "lambda_exec_role" +# assume_role_policy = jsonencode({ +# Version = "2012-10-17" +# Statement = [{ +# Action = "sts:AssumeRole" +# Effect = "Allow" +# Principal = { +# Service = "lambda.amazonaws.com" +# } +# }] +# }) + +# managed_policy_arns = [ +# "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", +# "arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess" +# ] +# } + +# data "archive_file" "lambda_zip" { +# type = "zip" +# source_dir = "${path.module}/../list_files" +# output_path = "${path.module}/list_files_function.zip" +# } + +# data "archive_file" "get_file_lambda_zip" { +# type = "zip" +# source_dir = "${path.module}/../get_file" +# output_path = "${path.module}/get_file_function.zip" +# } + +# resource "aws_lambda_function" "list_files" { +# filename = data.archive_file.lambda_zip.output_path +# function_name = "list_files" +# role = aws_iam_role.lambda_exec_role.arn +# handler = "list_files_function.lambda_handler" +# source_code_hash = filebase64sha256(data.archive_file.lambda_zip.output_path) +# runtime = "python3.11" + +# environment { +# variables = { +# TABLE_NAME = "file" +# } +# } +# } + +# resource "aws_lambda_function" "get_file" { +# filename = data.archive_file.get_file_lambda_zip.output_path +# function_name = "get_file_by_id" +# role = aws_iam_role.lambda_exec_role.arn +# handler = "get_file_by_id.lambda_handler" +# source_code_hash = filebase64sha256(data.archive_file.lambda_zip.output_path) +# runtime = "python3.11" + +# environment { +# variables = { +# TABLE_NAME = "file" +# } +# } +# } + +# resource "aws_api_gateway_rest_api" "files_api" { +# name = "Files API" +# description = "API for listing files with pagination and filtering" +# } + +# resource "aws_api_gateway_resource" "files_resource" { +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# parent_id = aws_api_gateway_rest_api.files_api.root_resource_id +# path_part = "files" +# } + +# resource "aws_api_gateway_resource" "file_resource" { +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# parent_id = aws_api_gateway_resource.files_resource.id +# path_part = "{file_id}" +# } + +# # GET Method for listing files +# resource "aws_api_gateway_method" "list_files_method" { +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# resource_id = aws_api_gateway_resource.files_resource.id +# http_method = "GET" +# authorization = "NONE" +# } + +# resource "aws_api_gateway_integration" "list_files_integration" { +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# resource_id = aws_api_gateway_resource.files_resource.id +# http_method = aws_api_gateway_method.list_files_method.http_method +# type = "AWS_PROXY" +# integration_http_method = "POST" +# uri = aws_lambda_function.list_files.invoke_arn +# } + +# resource "aws_api_gateway_method_response" "list_files_response_200" { +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# resource_id = aws_api_gateway_resource.files_resource.id +# http_method = aws_api_gateway_method.list_files_method.http_method +# status_code = "200" + +# response_parameters = { +# "method.response.header.Access-Control-Allow-Origin" = true, +# "method.response.header.Access-Control-Allow-Headers" = true, +# "method.response.header.Access-Control-Allow-Methods" = true +# } +# } + +# resource "aws_api_gateway_integration_response" "list_files_integration_response_200" { +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# resource_id = aws_api_gateway_resource.files_resource.id +# http_method = aws_api_gateway_method.list_files_method.http_method +# status_code = "200" + +# response_parameters = { +# "method.response.header.Access-Control-Allow-Origin" = "'*'", +# "method.response.header.Access-Control-Allow-Headers" = "'*'", +# "method.response.header.Access-Control-Allow-Methods" = "'GET,OPTIONS,POST,PUT'" +# } +# } + +# # GET Method for getting a specific file +# resource "aws_api_gateway_method" "get_file_method" { +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# resource_id = aws_api_gateway_resource.file_resource.id +# http_method = "GET" +# authorization = "NONE" +# } + +# resource "aws_api_gateway_integration" "get_file_integration" { +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# resource_id = aws_api_gateway_resource.file_resource.id +# http_method = aws_api_gateway_method.get_file_method.http_method +# type = "AWS_PROXY" +# integration_http_method = "POST" +# uri = aws_lambda_function.get_file.invoke_arn +# } + +# resource "aws_api_gateway_method_response" "get_file_response_200" { +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# resource_id = aws_api_gateway_resource.file_resource.id +# http_method = aws_api_gateway_method.get_file_method.http_method +# status_code = "200" + +# response_parameters = { +# "method.response.header.Access-Control-Allow-Origin" = true, +# "method.response.header.Access-Control-Allow-Headers" = true, +# "method.response.header.Access-Control-Allow-Methods" = true +# } +# } + +# resource "aws_api_gateway_integration_response" "get_file_integration_response_200" { +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# resource_id = aws_api_gateway_resource.file_resource.id +# http_method = aws_api_gateway_method.get_file_method.http_method +# status_code = "200" + +# response_parameters = { +# "method.response.header.Access-Control-Allow-Origin" = "'*'", +# "method.response.header.Access-Control-Allow-Headers" = "'*'", +# "method.response.header.Access-Control-Allow-Methods" = "'GET,OPTIONS,POST,PUT'" +# } +# } + +# # OPTIONS Method +# resource "aws_api_gateway_method" "options_method" { +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# resource_id = aws_api_gateway_resource.files_resource.id +# http_method = "OPTIONS" +# authorization = "NONE" +# } + +# resource "aws_api_gateway_integration" "options_integration" { +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# resource_id = aws_api_gateway_resource.files_resource.id +# http_method = aws_api_gateway_method.options_method.http_method +# type = "MOCK" +# request_templates = { +# "application/json" = "{\"statusCode\": 200}" +# } +# } + +# resource "aws_api_gateway_method_response" "options_response_200" { +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# resource_id = aws_api_gateway_resource.files_resource.id +# http_method = aws_api_gateway_method.options_method.http_method +# status_code = "200" + +# response_parameters = { +# "method.response.header.Access-Control-Allow-Headers" = true, +# "method.response.header.Access-Control-Allow-Methods" = true, +# "method.response.header.Access-Control-Allow-Origin" = true +# } + +# response_models = { +# "application/json" = "Empty" +# } +# } + +# resource "aws_api_gateway_integration_response" "options_integration_response" { +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# resource_id = aws_api_gateway_resource.files_resource.id +# http_method = aws_api_gateway_method.options_method.http_method +# status_code = aws_api_gateway_method_response.options_response_200.status_code + +# response_parameters = { +# "method.response.header.Access-Control-Allow-Headers" = "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'", +# "method.response.header.Access-Control-Allow-Methods" = "'GET,OPTIONS,POST,PUT'", +# "method.response.header.Access-Control-Allow-Origin" = "'*'" +# } +# } + +# resource "aws_api_gateway_deployment" "files_api_deployment" { +# depends_on = [ +# aws_api_gateway_integration.list_files_integration, +# aws_api_gateway_method_response.list_files_response_200, +# aws_api_gateway_integration_response.list_files_integration_response_200, +# aws_api_gateway_integration.get_file_integration, +# aws_api_gateway_method_response.get_file_response_200, +# aws_api_gateway_integration_response.get_file_integration_response_200, +# aws_api_gateway_method.options_method, +# aws_api_gateway_method_response.options_response_200, +# aws_api_gateway_integration.options_integration, +# aws_api_gateway_integration_response.options_integration_response +# ] +# rest_api_id = aws_api_gateway_rest_api.files_api.id +# stage_name = "dev" +# } + +# resource "aws_lambda_permission" "api_gateway_permission" { +# statement_id = "AllowAPIGatewayInvoke" +# action = "lambda:InvokeFunction" +# function_name = aws_lambda_function.list_files.function_name +# principal = "apigateway.amazonaws.com" +# source_arn = "${aws_api_gateway_rest_api.files_api.execution_arn}/*/*" +# } + +# resource "aws_lambda_permission" "api_gateway_permission_get_file" { +# statement_id = "AllowAPIGatewayInvokeGetFile" +# action = "lambda:InvokeFunction" +# function_name = aws_lambda_function.get_file.function_name +# principal = "apigateway.amazonaws.com" +# source_arn = "${aws_api_gateway_rest_api.files_api.execution_arn}/*/*" +# } + +# output "api_url" { +# value = "https://${aws_api_gateway_rest_api.files_api.id}.execute-api.${data.aws_region.current.name}.amazonaws.com/dev/files" +# } diff --git a/src/file_service/terraform/output.tf b/src/file_service/terraform/output.tf index d60c555..0980c0a 100644 --- a/src/file_service/terraform/output.tf +++ b/src/file_service/terraform/output.tf @@ -1,3 +1,9 @@ output "api_url" { - value = "https://${aws_api_gateway_rest_api.files_api.id}.execute-api.${data.aws_region.current.name}.amazonaws.com/dev/files" + description = "The URL of the API Gateway" + value = "https://${aws_api_gateway_rest_api.files_api.id}.execute-api.${data.aws_region.current.name}.amazonaws.com/dev/files" +} + +output "api_gateway_domain_name" { + description = "The domain name of the API Gateway" + value = aws_api_gateway_rest_api.files_api.execution_arn } diff --git a/terraform/dev/backend.tf b/terraform/dev/backend.tf new file mode 100644 index 0000000..e69de29 diff --git a/terraform/dev/backend_setting/dynamodb.tf b/terraform/dev/backend_setting/dynamodb.tf new file mode 100644 index 0000000..3f5de03 --- /dev/null +++ b/terraform/dev/backend_setting/dynamodb.tf @@ -0,0 +1,14 @@ +resource "aws_dynamodb_table" "state_locks" { + name = "terraform-locks" + billing_mode = "PAY_PER_REQUEST" + hash_key = "LockID" + + attribute { + name = "LockID" + type = "S" + } + + tags = { + Terraform = true + } +} diff --git a/terraform/dev/backend_setting/output.tf b/terraform/dev/backend_setting/output.tf new file mode 100644 index 0000000..f2fa6d6 --- /dev/null +++ b/terraform/dev/backend_setting/output.tf @@ -0,0 +1,7 @@ +output "bucket_name" { + value = aws_s3_bucket.state.bucket +} + +output "dynamodb_table_name" { + value = aws_dynamodb_table.state_locks.name +} diff --git a/terraform/dev/backend_setting/s3.tf b/terraform/dev/backend_setting/s3.tf new file mode 100644 index 0000000..b66d317 --- /dev/null +++ b/terraform/dev/backend_setting/s3.tf @@ -0,0 +1,33 @@ +resource "aws_s3_bucket" "state" { + bucket_prefix = "dev-terraform-state-" + + tags = { + Terraform = "true" + } +} + +resource "aws_s3_bucket_versioning" "state" { + bucket = aws_s3_bucket.state.bucket + + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "state" { + bucket = aws_s3_bucket.state.bucket + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +resource "aws_s3_bucket_ownership_controls" "state" { + bucket = aws_s3_bucket.state.bucket + + rule { + object_ownership = "BucketOwnerPreferred" + } +} diff --git a/terraform/dev/cloudfront.tf b/terraform/dev/cloudfront.tf new file mode 100644 index 0000000..1f88cef --- /dev/null +++ b/terraform/dev/cloudfront.tf @@ -0,0 +1,88 @@ +resource "aws_cloudfront_distribution" "api_distribution" { + enabled = true + is_ipv6_enabled = true + comment = "CloudFront distribution for multiple API Gateways" + default_root_object = "" + + aliases = [var.domain_name] + + viewer_certificate { + acm_certificate_arn = var.acm_certificate_arn + ssl_support_method = "sni-only" + minimum_protocol_version = "TLSv1.2_2021" + } + + restrictions { + geo_restriction { + restriction_type = "none" + } + } + + dynamic "origin" { + for_each = var.api_gateway_origins + content { + domain_name = origin.value.domain_name + origin_id = origin.value.domain_name + + custom_origin_config { + http_port = 80 + https_port = 443 + origin_protocol_policy = "https-only" + origin_ssl_protocols = ["TLSv1.2"] + } + } + } + + dynamic "cache_behavior" { + for_each = var.api_gateway_origins + content { + path_pattern = cache_behavior.value.path_pattern + target_origin_id = cache_behavior.value.domain_name + viewer_protocol_policy = "redirect-to-https" + + allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"] + cached_methods = ["GET", "HEAD"] + + forwarded_values { + query_string = true + headers = ["Origin", "Access-Control-Request-Headers", "Access-Control-Request-Method"] + } + + min_ttl = 0 + default_ttl = 3600 + max_ttl = 86400 + + lambda_function_association { + event_type = "origin-response" + lambda_arn = var.simple_cors_lambda_arn + } + } + } + + default_cache_behavior { + target_origin_id = var.api_gateway_origins[0].domain_name + viewer_protocol_policy = "redirect-to-https" + + allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"] + cached_methods = ["GET", "HEAD"] + + forwarded_values { + cookies { + forward = "none" + } + query_string = true + headers = ["Origin", "Access-Control-Request-Headers", "Access-Control-Request-Method"] + } + + min_ttl = 0 + default_ttl = 3600 + max_ttl = 86400 + + } + + logging_config { + include_cookies = false + bucket = "aws-eudcate-tpet-cloudfront-logging-bucket.s3.amazonaws.com" + prefix = "cloudfront/" + } +} diff --git a/terraform/dev/main.tf b/terraform/dev/main.tf new file mode 100644 index 0000000..0f3c43e --- /dev/null +++ b/terraform/dev/main.tf @@ -0,0 +1,8 @@ +module "list_files" { + source = "./../src/file_service/terraform" + aws_region = var.aws_region + environment = var.environment +} + + + diff --git a/terraform/dev/output.tf b/terraform/dev/output.tf new file mode 100644 index 0000000..f2fa6d6 --- /dev/null +++ b/terraform/dev/output.tf @@ -0,0 +1,7 @@ +output "bucket_name" { + value = aws_s3_bucket.state.bucket +} + +output "dynamodb_table_name" { + value = aws_dynamodb_table.state_locks.name +} diff --git a/terraform/dev/provider.tf b/terraform/dev/provider.tf new file mode 100644 index 0000000..e9b7251 --- /dev/null +++ b/terraform/dev/provider.tf @@ -0,0 +1,6 @@ +provider "aws" { + region = var.aws_region +} + + + diff --git a/terraform/dev/route53.tf b/terraform/dev/route53.tf new file mode 100644 index 0000000..6015717 --- /dev/null +++ b/terraform/dev/route53.tf @@ -0,0 +1,11 @@ +resource "aws_route53_record" "api_alias" { + zone_id = var.zone_id + name = var.domain_name + type = "A" + + alias { + name = aws_cloudfront_distribution.api_distribution.domain_name + zone_id = aws_cloudfront_distribution.api_distribution.hosted_zone_id + evaluate_target_health = false + } +} diff --git a/terraform/dev/terraform.tf b/terraform/dev/terraform.tf new file mode 100644 index 0000000..2cc4414 --- /dev/null +++ b/terraform/dev/terraform.tf @@ -0,0 +1,9 @@ +terraform { + backend "s3" { + bucket = "terraform-state-20240610095057872800000001" + key = "dev/terraform.tfstate" + region = "ap-northeast-1" + dynamodb_table = "terraform-locks" + encrypt = true + } +} diff --git a/terraform/dev/variables.tf b/terraform/dev/variables.tf new file mode 100644 index 0000000..d69b07a --- /dev/null +++ b/terraform/dev/variables.tf @@ -0,0 +1,52 @@ +variable "domain_name" { + description = "The custom domain name for CloudFront" + type = string + default = "api.tpet.awseducate.systems" +} + + +variable "acm_certificate_arn" { + description = "The ARN of the ACM certificate for the custom domain" + type = string + default = "arn:aws:acm:us-east-1:070576557102:certificate/6ef7979c-596b-42fd-a6ed-fceccc2efc0b" +} + +variable "zone_id" { + description = "The Route 53 Hosted Zone ID for the domain" + type = string + default = "Z00402303DMA4KDX72AUO" +} + +variable "api_gateway_origins" { + description = "List of API Gateway domain names and their corresponding path patterns" + type = list(object({ + domain_name = string + path_pattern = string + })) + default = [ + { + # Campaign Service + domain_name = "pihjp3tc7f.execute-api.ap-northeast-1.amazonaws.com" + path_pattern = "/dev/campaigns*" + }, + { + # Files Service + domain_name = "8um2zizr80.execute-api.ap-northeast-1.amazonaws.com" + path_pattern = "/dev/files*" + } + ] +} + + +variable "aws_region" { + description = "The AWS region to deploy the service to" + type = string + default = "us-east-1" +} + +variable "environment" { + description = "The environment to deploy the service to" + type = string + default = "dev" + +} diff --git a/terraform/poc/.terraform.lock.hcl b/terraform/poc/.terraform.lock.hcl new file mode 100644 index 0000000..f70412e --- /dev/null +++ b/terraform/poc/.terraform.lock.hcl @@ -0,0 +1,43 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/archive" { + version = "2.4.2" + hashes = [ + "h1:sCJKfmlbxo4w+AxizeJ3i1rPEfoVarCajyJuIODVPTg=", + "zh:08faed7c9f42d82bc3d406d0d9d4971e2d1c2d34eae268ad211b8aca57b7f758", + "zh:3564112ed2d097d7e0672378044a69b06642c326f6f1584d81c7cdd32ebf3a08", + "zh:53cd9afd223c15828c1916e68cb728d2be1cbccb9545568d6c2b122d0bac5102", + "zh:5ae4e41e3a1ce9d40b6458218a85bbde44f21723943982bca4a3b8bb7c103670", + "zh:5b65499218b315b96e95c5d3463ea6d7c66245b59461217c99eaa1611891cd2c", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:7f45b35a8330bebd184c2545a41782ff58240ed6ba947274d9881dd5da44b02e", + "zh:87e67891033214e55cfead1391d68e6a3bf37993b7607753237e82aa3250bb71", + "zh:de3590d14037ad81fc5cedf7cfa44614a92452d7b39676289b704a962050bc5e", + "zh:e7e6f2ea567f2dbb3baa81c6203be69f9cd6aeeb01204fd93e3cf181e099b610", + "zh:fd24d03c89a7702628c2e5a3c732c0dede56fa75a08da4a1efe17b5f881c88e2", + "zh:febf4b7b5f3ff2adff0573ef6361f09b6638105111644bdebc0e4f575373935f", + ] +} + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.53.0" + hashes = [ + "h1:YCupEeam12IXAPo9j2wvnfJTqFFuaHjyzTgSj3GlOeg=", + "zh:2adad39412111d19a5195474d6b95577fc25ccf06d88a90019bee0efba33a1e3", + "zh:51226453a14f95b0d1163cfecafc9cf1a92ce5f66e42e6b4065d83a813836a2c", + "zh:62450fadb56db9c18d50bb8b7728a3d009be608d7ee0d4fe95c85ccb521dff83", + "zh:6f3ad977a9cc4800847c136690b1c0a0fd8437705062163d29dc4e9429598950", + "zh:71ca0a16b735b8d34b7127dd7d1e1e5d1eaac9c9f792e08abde291b5beb947d5", + "zh:7ae9cf4838eea80288305be0a3e69b39ffff86ede7b4319be421f06d32d04fb6", + "zh:93abc2db5ad995cfee014eb7446abc7caedc427e141d375a11993e6e199076b5", + "zh:9560b3424d97da804e98ee86b474b7370afefa09baf350cae7f33afb3f1aa209", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:9eb57a9b649c217ac4eeb27af2a1935c18bd9bc8fb1be07434e7de74729eff46", + "zh:b5f32dcbe71ea22c2090eeeaec9af3e098d7b8c3e4491f34ffdfdc6f1c1abf81", + "zh:c9fbd5417f266c773055178e87bb4091df7f0542b72bf5ad0a4ae27045a2b7ca", + "zh:d518b3c52c8a9f79769dbe1b3683d25b4cdc8bfc77a3b3cd9c85f74e6c7383e1", + "zh:db741be21f32404bb87d73d25b1b7fd9b813b00aeb20a130ed8806d44dc26680", + "zh:ed1a8bb4d08653d87265ae534d6fc33bbdabae1608692a1ee364fce03548d36c", + ] +} diff --git a/terraform/poc/backend.tf b/terraform/poc/backend.tf new file mode 100644 index 0000000..e69de29 diff --git a/terraform/poc/backend_setting/.terraform.lock.hcl b/terraform/poc/backend_setting/.terraform.lock.hcl new file mode 100644 index 0000000..dba1e54 --- /dev/null +++ b/terraform/poc/backend_setting/.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.53.0" + hashes = [ + "h1:YCupEeam12IXAPo9j2wvnfJTqFFuaHjyzTgSj3GlOeg=", + "zh:2adad39412111d19a5195474d6b95577fc25ccf06d88a90019bee0efba33a1e3", + "zh:51226453a14f95b0d1163cfecafc9cf1a92ce5f66e42e6b4065d83a813836a2c", + "zh:62450fadb56db9c18d50bb8b7728a3d009be608d7ee0d4fe95c85ccb521dff83", + "zh:6f3ad977a9cc4800847c136690b1c0a0fd8437705062163d29dc4e9429598950", + "zh:71ca0a16b735b8d34b7127dd7d1e1e5d1eaac9c9f792e08abde291b5beb947d5", + "zh:7ae9cf4838eea80288305be0a3e69b39ffff86ede7b4319be421f06d32d04fb6", + "zh:93abc2db5ad995cfee014eb7446abc7caedc427e141d375a11993e6e199076b5", + "zh:9560b3424d97da804e98ee86b474b7370afefa09baf350cae7f33afb3f1aa209", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:9eb57a9b649c217ac4eeb27af2a1935c18bd9bc8fb1be07434e7de74729eff46", + "zh:b5f32dcbe71ea22c2090eeeaec9af3e098d7b8c3e4491f34ffdfdc6f1c1abf81", + "zh:c9fbd5417f266c773055178e87bb4091df7f0542b72bf5ad0a4ae27045a2b7ca", + "zh:d518b3c52c8a9f79769dbe1b3683d25b4cdc8bfc77a3b3cd9c85f74e6c7383e1", + "zh:db741be21f32404bb87d73d25b1b7fd9b813b00aeb20a130ed8806d44dc26680", + "zh:ed1a8bb4d08653d87265ae534d6fc33bbdabae1608692a1ee364fce03548d36c", + ] +} diff --git a/terraform/poc/backend_setting/dynamodb.tf b/terraform/poc/backend_setting/dynamodb.tf new file mode 100644 index 0000000..3f5de03 --- /dev/null +++ b/terraform/poc/backend_setting/dynamodb.tf @@ -0,0 +1,14 @@ +resource "aws_dynamodb_table" "state_locks" { + name = "terraform-locks" + billing_mode = "PAY_PER_REQUEST" + hash_key = "LockID" + + attribute { + name = "LockID" + type = "S" + } + + tags = { + Terraform = true + } +} diff --git a/terraform/poc/backend_setting/output.tf b/terraform/poc/backend_setting/output.tf new file mode 100644 index 0000000..f2fa6d6 --- /dev/null +++ b/terraform/poc/backend_setting/output.tf @@ -0,0 +1,7 @@ +output "bucket_name" { + value = aws_s3_bucket.state.bucket +} + +output "dynamodb_table_name" { + value = aws_dynamodb_table.state_locks.name +} diff --git a/terraform/poc/backend_setting/s3.tf b/terraform/poc/backend_setting/s3.tf new file mode 100644 index 0000000..7d62536 --- /dev/null +++ b/terraform/poc/backend_setting/s3.tf @@ -0,0 +1,33 @@ +resource "aws_s3_bucket" "state" { + bucket_prefix = "poc-terraform-state-" + + tags = { + Terraform = "true" + } +} + +resource "aws_s3_bucket_versioning" "state" { + bucket = aws_s3_bucket.state.bucket + + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "state" { + bucket = aws_s3_bucket.state.bucket + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +resource "aws_s3_bucket_ownership_controls" "state" { + bucket = aws_s3_bucket.state.bucket + + rule { + object_ownership = "BucketOwnerPreferred" + } +} diff --git a/terraform/poc/cloudfront.tf b/terraform/poc/cloudfront.tf new file mode 100644 index 0000000..4e84a5d --- /dev/null +++ b/terraform/poc/cloudfront.tf @@ -0,0 +1,58 @@ +module "cloudfront" { + source = "terraform-aws-modules/cloudfront/aws" + version = "3.4.0" + + aliases = [var.domain_name] + + comment = "CloudFront distribution for multiple API Gateways" + enabled = true + is_ipv6_enabled = true + price_class = "PriceClass_All" + retain_on_delete = false + wait_for_deployment = false + + logging_config = { + bucket = aws_s3_bucket.cloudfront_logging.bucket + } + + origin = { + for o in var.api_gateway_origins : o.domain_name => { + domain_name = o.domain_name + custom_origin_config = { + http_port = 80 + https_port = 443 + origin_protocol_policy = "https-only" + origin_ssl_protocols = ["TLSv1.2"] + } + } + } + + default_cache_behavior = { + target_origin_id = var.api_gateway_origins[0].domain_name + viewer_protocol_policy = "redirect-to-https" + allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"] + cached_methods = ["GET", "HEAD"] + compress = true + query_string = true + headers = ["Origin", "Access-Control-Request-Headers", "Access-Control-Request-Method"] + } + + ordered_cache_behavior = [ + for o in var.api_gateway_origins : + { + path_pattern = o.path_pattern + target_origin_id = o.domain_name + viewer_protocol_policy = "redirect-to-https" + allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"] + cached_methods = ["GET", "HEAD"] + compress = true + query_string = true + headers = ["Origin", "Access-Control-Request-Headers", "Access-Control-Request-Method"] + } + ] + + viewer_certificate = { + acm_certificate_arn = var.acm_certificate_arn + ssl_support_method = "sni-only" + } +} diff --git a/terraform/poc/main.tf b/terraform/poc/main.tf new file mode 100644 index 0000000..63d6835 --- /dev/null +++ b/terraform/poc/main.tf @@ -0,0 +1,8 @@ +module "list_files" { + source = "./../../src/file_service/terraform" + aws_region = var.aws_region + environment = var.environment +} + + + diff --git a/terraform/poc/output.tf b/terraform/poc/output.tf new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/terraform/poc/output.tf @@ -0,0 +1 @@ + diff --git a/terraform/poc/provider.tf b/terraform/poc/provider.tf new file mode 100644 index 0000000..e9b7251 --- /dev/null +++ b/terraform/poc/provider.tf @@ -0,0 +1,6 @@ +provider "aws" { + region = var.aws_region +} + + + diff --git a/terraform/poc/route53.tf b/terraform/poc/route53.tf new file mode 100644 index 0000000..e371456 --- /dev/null +++ b/terraform/poc/route53.tf @@ -0,0 +1,34 @@ +module "zones" { + source = "terraform-aws-modules/route53/aws//modules/zones" + version = "3.1.0" + + zones = { + "${var.domain_name}" = { + comment = "Managed by Terraform" + } + } + + tags = { + ManagedBy = "Terraform" + } +} + +module "records" { + source = "terraform-aws-modules/route53/aws//modules/records" + version = "3.1.0" + + zone_name = var.domain_name + + records = [ + { + name = "" + type = "A" + alias = { + name = module.cloudfront.cloudfront_distribution_domain_name + zone_id = module.cloudfront.cloudfront_distribution_hosted_zone_id + } + } + ] + + depends_on = [module.zones] +} diff --git a/terraform/poc/s3.tf b/terraform/poc/s3.tf new file mode 100644 index 0000000..7e15a72 --- /dev/null +++ b/terraform/poc/s3.tf @@ -0,0 +1,8 @@ +resource "aws_s3_bucket" "cloudfront_logging" { + bucket = "aws-educate-tpet-cloudfront-logs" + + tags = { + Name = "cloudfront-logs" + Terraform = "true" + } +} diff --git a/terraform/poc/terraform.tf b/terraform/poc/terraform.tf new file mode 100644 index 0000000..d45330e --- /dev/null +++ b/terraform/poc/terraform.tf @@ -0,0 +1,9 @@ +terraform { + backend "s3" { + bucket = "poc-terraform-state-20240610102132009600000001" + key = "poc/terraform.tfstate" + region = "ap-northeast-1" + dynamodb_table = "terraform-locks" + encrypt = true + } +} diff --git a/terraform/poc/variables.tf b/terraform/poc/variables.tf new file mode 100644 index 0000000..d69b07a --- /dev/null +++ b/terraform/poc/variables.tf @@ -0,0 +1,52 @@ +variable "domain_name" { + description = "The custom domain name for CloudFront" + type = string + default = "api.tpet.awseducate.systems" +} + + +variable "acm_certificate_arn" { + description = "The ARN of the ACM certificate for the custom domain" + type = string + default = "arn:aws:acm:us-east-1:070576557102:certificate/6ef7979c-596b-42fd-a6ed-fceccc2efc0b" +} + +variable "zone_id" { + description = "The Route 53 Hosted Zone ID for the domain" + type = string + default = "Z00402303DMA4KDX72AUO" +} + +variable "api_gateway_origins" { + description = "List of API Gateway domain names and their corresponding path patterns" + type = list(object({ + domain_name = string + path_pattern = string + })) + default = [ + { + # Campaign Service + domain_name = "pihjp3tc7f.execute-api.ap-northeast-1.amazonaws.com" + path_pattern = "/dev/campaigns*" + }, + { + # Files Service + domain_name = "8um2zizr80.execute-api.ap-northeast-1.amazonaws.com" + path_pattern = "/dev/files*" + } + ] +} + + +variable "aws_region" { + description = "The AWS region to deploy the service to" + type = string + default = "us-east-1" +} + +variable "environment" { + description = "The environment to deploy the service to" + type = string + default = "dev" + +} diff --git a/terraform/prod/backend.tf b/terraform/prod/backend.tf new file mode 100644 index 0000000..e69de29 diff --git a/terraform/prod/backend_setting/dynamodb.tf b/terraform/prod/backend_setting/dynamodb.tf new file mode 100644 index 0000000..3f5de03 --- /dev/null +++ b/terraform/prod/backend_setting/dynamodb.tf @@ -0,0 +1,14 @@ +resource "aws_dynamodb_table" "state_locks" { + name = "terraform-locks" + billing_mode = "PAY_PER_REQUEST" + hash_key = "LockID" + + attribute { + name = "LockID" + type = "S" + } + + tags = { + Terraform = true + } +} diff --git a/terraform/prod/backend_setting/output.tf b/terraform/prod/backend_setting/output.tf new file mode 100644 index 0000000..f2fa6d6 --- /dev/null +++ b/terraform/prod/backend_setting/output.tf @@ -0,0 +1,7 @@ +output "bucket_name" { + value = aws_s3_bucket.state.bucket +} + +output "dynamodb_table_name" { + value = aws_dynamodb_table.state_locks.name +} diff --git a/terraform/prod/backend_setting/s3.tf b/terraform/prod/backend_setting/s3.tf new file mode 100644 index 0000000..0fc4ba5 --- /dev/null +++ b/terraform/prod/backend_setting/s3.tf @@ -0,0 +1,33 @@ +resource "aws_s3_bucket" "state" { + bucket_prefix = "prod-terraform-state-" + + tags = { + Terraform = "true" + } +} + +resource "aws_s3_bucket_versioning" "state" { + bucket = aws_s3_bucket.state.bucket + + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "state" { + bucket = aws_s3_bucket.state.bucket + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +resource "aws_s3_bucket_ownership_controls" "state" { + bucket = aws_s3_bucket.state.bucket + + rule { + object_ownership = "BucketOwnerPreferred" + } +} diff --git a/terraform/prod/cloudfront.tf b/terraform/prod/cloudfront.tf new file mode 100644 index 0000000..1f88cef --- /dev/null +++ b/terraform/prod/cloudfront.tf @@ -0,0 +1,88 @@ +resource "aws_cloudfront_distribution" "api_distribution" { + enabled = true + is_ipv6_enabled = true + comment = "CloudFront distribution for multiple API Gateways" + default_root_object = "" + + aliases = [var.domain_name] + + viewer_certificate { + acm_certificate_arn = var.acm_certificate_arn + ssl_support_method = "sni-only" + minimum_protocol_version = "TLSv1.2_2021" + } + + restrictions { + geo_restriction { + restriction_type = "none" + } + } + + dynamic "origin" { + for_each = var.api_gateway_origins + content { + domain_name = origin.value.domain_name + origin_id = origin.value.domain_name + + custom_origin_config { + http_port = 80 + https_port = 443 + origin_protocol_policy = "https-only" + origin_ssl_protocols = ["TLSv1.2"] + } + } + } + + dynamic "cache_behavior" { + for_each = var.api_gateway_origins + content { + path_pattern = cache_behavior.value.path_pattern + target_origin_id = cache_behavior.value.domain_name + viewer_protocol_policy = "redirect-to-https" + + allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"] + cached_methods = ["GET", "HEAD"] + + forwarded_values { + query_string = true + headers = ["Origin", "Access-Control-Request-Headers", "Access-Control-Request-Method"] + } + + min_ttl = 0 + default_ttl = 3600 + max_ttl = 86400 + + lambda_function_association { + event_type = "origin-response" + lambda_arn = var.simple_cors_lambda_arn + } + } + } + + default_cache_behavior { + target_origin_id = var.api_gateway_origins[0].domain_name + viewer_protocol_policy = "redirect-to-https" + + allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"] + cached_methods = ["GET", "HEAD"] + + forwarded_values { + cookies { + forward = "none" + } + query_string = true + headers = ["Origin", "Access-Control-Request-Headers", "Access-Control-Request-Method"] + } + + min_ttl = 0 + default_ttl = 3600 + max_ttl = 86400 + + } + + logging_config { + include_cookies = false + bucket = "aws-eudcate-tpet-cloudfront-logging-bucket.s3.amazonaws.com" + prefix = "cloudfront/" + } +} diff --git a/terraform/prod/main.tf b/terraform/prod/main.tf new file mode 100644 index 0000000..0f3c43e --- /dev/null +++ b/terraform/prod/main.tf @@ -0,0 +1,8 @@ +module "list_files" { + source = "./../src/file_service/terraform" + aws_region = var.aws_region + environment = var.environment +} + + + diff --git a/terraform/prod/output.tf b/terraform/prod/output.tf new file mode 100644 index 0000000..f2fa6d6 --- /dev/null +++ b/terraform/prod/output.tf @@ -0,0 +1,7 @@ +output "bucket_name" { + value = aws_s3_bucket.state.bucket +} + +output "dynamodb_table_name" { + value = aws_dynamodb_table.state_locks.name +} diff --git a/terraform/prod/provider.tf b/terraform/prod/provider.tf new file mode 100644 index 0000000..e9b7251 --- /dev/null +++ b/terraform/prod/provider.tf @@ -0,0 +1,6 @@ +provider "aws" { + region = var.aws_region +} + + + diff --git a/terraform/prod/route53.tf b/terraform/prod/route53.tf new file mode 100644 index 0000000..6015717 --- /dev/null +++ b/terraform/prod/route53.tf @@ -0,0 +1,11 @@ +resource "aws_route53_record" "api_alias" { + zone_id = var.zone_id + name = var.domain_name + type = "A" + + alias { + name = aws_cloudfront_distribution.api_distribution.domain_name + zone_id = aws_cloudfront_distribution.api_distribution.hosted_zone_id + evaluate_target_health = false + } +} diff --git a/terraform/prod/terraform.tf b/terraform/prod/terraform.tf new file mode 100644 index 0000000..2cc4414 --- /dev/null +++ b/terraform/prod/terraform.tf @@ -0,0 +1,9 @@ +terraform { + backend "s3" { + bucket = "terraform-state-20240610095057872800000001" + key = "dev/terraform.tfstate" + region = "ap-northeast-1" + dynamodb_table = "terraform-locks" + encrypt = true + } +} diff --git a/terraform/prod/variables.tf b/terraform/prod/variables.tf new file mode 100644 index 0000000..d69b07a --- /dev/null +++ b/terraform/prod/variables.tf @@ -0,0 +1,52 @@ +variable "domain_name" { + description = "The custom domain name for CloudFront" + type = string + default = "api.tpet.awseducate.systems" +} + + +variable "acm_certificate_arn" { + description = "The ARN of the ACM certificate for the custom domain" + type = string + default = "arn:aws:acm:us-east-1:070576557102:certificate/6ef7979c-596b-42fd-a6ed-fceccc2efc0b" +} + +variable "zone_id" { + description = "The Route 53 Hosted Zone ID for the domain" + type = string + default = "Z00402303DMA4KDX72AUO" +} + +variable "api_gateway_origins" { + description = "List of API Gateway domain names and their corresponding path patterns" + type = list(object({ + domain_name = string + path_pattern = string + })) + default = [ + { + # Campaign Service + domain_name = "pihjp3tc7f.execute-api.ap-northeast-1.amazonaws.com" + path_pattern = "/dev/campaigns*" + }, + { + # Files Service + domain_name = "8um2zizr80.execute-api.ap-northeast-1.amazonaws.com" + path_pattern = "/dev/files*" + } + ] +} + + +variable "aws_region" { + description = "The AWS region to deploy the service to" + type = string + default = "us-east-1" +} + +variable "environment" { + description = "The environment to deploy the service to" + type = string + default = "dev" + +} From cd8e4a4490cd7baf9e24a6913a3ae276b68028db Mon Sep 17 00:00:00 2001 From: sh1un Date: Mon, 10 Jun 2024 19:35:13 +0800 Subject: [PATCH 2/4] refactor: update IAM role and Lambda function names The code changes update the names of the IAM role and Lambda function in the Terraform configuration files for the file service. This ensures that the names are more descriptive and aligned with their purpose. SCRUM-22 --- .../{send-email => send_email}/Dockerfile | 0 .../lambda_function.py | 0 .../{send-email => send_email}/main.tf | 0 .../requirements.txt | 0 src/file_service/terraform/iam.tf | 7 +-- src/file_service/terraform/lambda.tf | 2 +- .../terraform/list_files_function.zip | Bin 0 -> 1590 bytes terraform/poc/cloudfront.tf | 3 -- terraform/poc/route53.tf | 21 +------- terraform/poc/s3.tf | 7 --- terraform/prod/backend_setting/s3.tf | 48 +++++++++--------- 11 files changed, 29 insertions(+), 59 deletions(-) rename src/email_service/{send-email => send_email}/Dockerfile (100%) rename src/email_service/{send-email => send_email}/lambda_function.py (100%) rename src/email_service/{send-email => send_email}/main.tf (100%) rename src/email_service/{send-email => send_email}/requirements.txt (100%) create mode 100644 src/file_service/terraform/list_files_function.zip diff --git a/src/email_service/send-email/Dockerfile b/src/email_service/send_email/Dockerfile similarity index 100% rename from src/email_service/send-email/Dockerfile rename to src/email_service/send_email/Dockerfile diff --git a/src/email_service/send-email/lambda_function.py b/src/email_service/send_email/lambda_function.py similarity index 100% rename from src/email_service/send-email/lambda_function.py rename to src/email_service/send_email/lambda_function.py diff --git a/src/email_service/send-email/main.tf b/src/email_service/send_email/main.tf similarity index 100% rename from src/email_service/send-email/main.tf rename to src/email_service/send_email/main.tf diff --git a/src/email_service/send-email/requirements.txt b/src/email_service/send_email/requirements.txt similarity index 100% rename from src/email_service/send-email/requirements.txt rename to src/email_service/send_email/requirements.txt diff --git a/src/file_service/terraform/iam.tf b/src/file_service/terraform/iam.tf index d62777a..e108add 100644 --- a/src/file_service/terraform/iam.tf +++ b/src/file_service/terraform/iam.tf @@ -1,5 +1,5 @@ -resource "aws_iam_role" "lambda_exec_role" { - name = "lambda_exec_role" +resource "aws_iam_role" "list_files_lambda_exec_role" { + name = "list_files_lambda_exec_role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ @@ -16,7 +16,4 @@ resource "aws_iam_role" "lambda_exec_role" { "arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess" ] - lifecycle { - prevent_destroy = true - } } diff --git a/src/file_service/terraform/lambda.tf b/src/file_service/terraform/lambda.tf index 27e63d2..bbe8f2a 100644 --- a/src/file_service/terraform/lambda.tf +++ b/src/file_service/terraform/lambda.tf @@ -7,7 +7,7 @@ data "archive_file" "lambda_zip" { resource "aws_lambda_function" "list_files" { filename = data.archive_file.lambda_zip.output_path function_name = "list_files" - role = aws_iam_role.lambda_exec_role.arn + role = aws_iam_role.list_files_lambda_exec_role.arn handler = "list_files_function.lambda_handler" source_code_hash = filebase64sha256(data.archive_file.lambda_zip.output_path) runtime = "python3.11" diff --git a/src/file_service/terraform/list_files_function.zip b/src/file_service/terraform/list_files_function.zip new file mode 100644 index 0000000000000000000000000000000000000000..812f4a1dc9c7ea01ecd47d7855a48148650a4030 GIT binary patch literal 1590 zcmZvcdpOez7{`C)Zn@=>+ew8u=h#qlJse7kxy-Gz!>O%yBC|``LPIlba^g8!?sMD8 zO4b$)%{oycq!cHSj8@7z)5=K5?C{6A{BgeD=Xu}n^L(G@egFHwVVl&90j+fd!1iC( z$3HS%PuN5v2^pV=Jx)Z%pT?s}i3B|Ohl*`Ih))ovWf$O+EazzUSE0!W{FP zODiLD5%bIam{vs*+1Cuyp?J2q)Zj{1u`@k(*KW@|p=)Mt=uqNUd7S>@w_!dJS7 z2jzP?kshoP+{l!e9v%L2FDLk6QjYiI1$~S1mfg!%qLNzJa0>LMgm;qWnn(j*pXvzj zkC&R*hi=v2@D+~3`bjNF3FnT3LW3$yQ zVJ{=KcL|IsHW^oku&Dmc$hv)KvA^Jpn@iKH8-bQj>k(R-Thh)v%OFZ+MYe)_a@lS? zN_8~$D8l|qsvxD|+a43hkGP3yH#Wp~F`i6p-v37Ja#BK?c!ip;GvR{=M!SSIPG5h_ zXGI2=j|xr&HY`Kppr$z^cz*{o*A;Qra4%|TfDbxS!#2E}V@aX6t`)tiE#A(U#9DNXU~v`xYBz)2IMaDt-B>wc7+0apiYLZ({^< zwwsJ5F@wb9OOrbM+~_{Wfi(YZ-=$t^H^Cx5U4Hq1(>d~%%48IZoytrdpNaJ5$w6u* zUG=zwenvtlR2G+!$2`ASRlzIM;9jS@R6}oD1QAymq?zHqmuRM^)^p3OcB!aBVg8Z* zStCCx^Ajy9^-eUB&~#DZvJ(oy4Ug6tT21puuLpmCzGH4b^ci+7Wkf7~pNoIRm|Oe}LVOW>5- zry%J}sOs5_;t4B+3)=BSHAuvb%sCml3~(WFih1C2?@_t z+AF~BSgRt4v`20r-=nvL(VUOF7&6)v#MEnrM5+j3JTr0__7a#r`zCjHIh>_eqI@?@lp>@iIqkZliSTCX-5wFCr}WVV1zYqc9G^WjD4O?b6oCSLJzH5ewCb*#6`yJ zQ(rh8r*(G>J&p?a-J%Dr%UfHy`Z34-wc(qOnz*&PM<4u|B<{)q#6`@;tKb#K!G)t4 zlm`p=PF=J{&YFtuMO<4Kae7#sok3X|Te7Za^9D_B;>UvxJOdt=S>mdCpVV>LeCHQ; zWGUA5Al?(iL`SzId-ZotOXukWFZzS*mJ66cX@A}$gQN!2gN{BTL}e>}m-XieiFg-{ zrRE`8q&N5pC_lo-sf}!qaLVgD4WbY&e{wQCa~stwV6HH%_EjxP88#BW4xYEBeqC+p zPj4{12k)ztHGIyik-TOVfb3oFgoRJvpKh!2W-dQ+*B)|kUjg3}i-2v-+V*NG%`~~VU_Mrd( literal 0 HcmV?d00001 diff --git a/terraform/poc/cloudfront.tf b/terraform/poc/cloudfront.tf index 4e84a5d..5039409 100644 --- a/terraform/poc/cloudfront.tf +++ b/terraform/poc/cloudfront.tf @@ -11,9 +11,6 @@ module "cloudfront" { retain_on_delete = false wait_for_deployment = false - logging_config = { - bucket = aws_s3_bucket.cloudfront_logging.bucket - } origin = { for o in var.api_gateway_origins : o.domain_name => { diff --git a/terraform/poc/route53.tf b/terraform/poc/route53.tf index e371456..ad0dbe1 100644 --- a/terraform/poc/route53.tf +++ b/terraform/poc/route53.tf @@ -1,27 +1,12 @@ -module "zones" { - source = "terraform-aws-modules/route53/aws//modules/zones" - version = "3.1.0" - - zones = { - "${var.domain_name}" = { - comment = "Managed by Terraform" - } - } - - tags = { - ManagedBy = "Terraform" - } -} - module "records" { source = "terraform-aws-modules/route53/aws//modules/records" version = "3.1.0" - zone_name = var.domain_name + zone_id = var.zone_id records = [ { - name = "" + name = "api.tpet" type = "A" alias = { name = module.cloudfront.cloudfront_distribution_domain_name @@ -29,6 +14,4 @@ module "records" { } } ] - - depends_on = [module.zones] } diff --git a/terraform/poc/s3.tf b/terraform/poc/s3.tf index 7e15a72..8b13789 100644 --- a/terraform/poc/s3.tf +++ b/terraform/poc/s3.tf @@ -1,8 +1 @@ -resource "aws_s3_bucket" "cloudfront_logging" { - bucket = "aws-educate-tpet-cloudfront-logs" - tags = { - Name = "cloudfront-logs" - Terraform = "true" - } -} diff --git a/terraform/prod/backend_setting/s3.tf b/terraform/prod/backend_setting/s3.tf index 0fc4ba5..e72227c 100644 --- a/terraform/prod/backend_setting/s3.tf +++ b/terraform/prod/backend_setting/s3.tf @@ -1,33 +1,33 @@ -resource "aws_s3_bucket" "state" { - bucket_prefix = "prod-terraform-state-" +resource "aws_s3_bucket" "cloudfront_logging" { + bucket = "aws-educate-tpet-cloudfront-logs" tags = { + Name = "cloudfront-logs" Terraform = "true" } } -resource "aws_s3_bucket_versioning" "state" { - bucket = aws_s3_bucket.state.bucket +resource "aws_s3_bucket_policy" "cloudfront_logging_policy" { + bucket = aws_s3_bucket.cloudfront_logging.id - versioning_configuration { - status = "Enabled" - } -} - -resource "aws_s3_bucket_server_side_encryption_configuration" "state" { - bucket = aws_s3_bucket.state.bucket - - rule { - apply_server_side_encryption_by_default { - sse_algorithm = "AES256" - } - } + policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Effect = "Allow", + Principal = { + Service = "cloudfront.amazonaws.com" + }, + Action = "s3:PutObject", + Resource = "${aws_s3_bucket.cloudfront_logging.arn}/*", + Condition = { + StringEquals = { + "AWS:SourceArn" = "arn:aws:cloudfront::${data.aws_caller_identity.current.account_id}:distribution/*" + } + } + } + ] + }) } -resource "aws_s3_bucket_ownership_controls" "state" { - bucket = aws_s3_bucket.state.bucket - - rule { - object_ownership = "BucketOwnerPreferred" - } -} +data "aws_caller_identity" "current" {} From a03540319f3da293d6e5dcd88907cc14f8870c9a Mon Sep 17 00:00:00 2001 From: sh1un Date: Mon, 10 Jun 2024 19:56:45 +0800 Subject: [PATCH 3/4] feat(terraform): update Terraform configuration for all of APIs The code changes in the `variables.tf` file update the Terraform configuration for the file service endpoints. This includes adding new endpoints for uploading files, uploading multiple files, and sending emails. The changes ensure that the endpoints are correctly configured and aligned with the file service functionality. SCRUM-22 --- terraform/poc/s3.tf | 1 - terraform/poc/variables.tf | 19 ++++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) delete mode 100644 terraform/poc/s3.tf diff --git a/terraform/poc/s3.tf b/terraform/poc/s3.tf deleted file mode 100644 index 8b13789..0000000 --- a/terraform/poc/s3.tf +++ /dev/null @@ -1 +0,0 @@ - diff --git a/terraform/poc/variables.tf b/terraform/poc/variables.tf index d69b07a..b46d275 100644 --- a/terraform/poc/variables.tf +++ b/terraform/poc/variables.tf @@ -30,10 +30,27 @@ variable "api_gateway_origins" { path_pattern = "/dev/campaigns*" }, { - # Files Service + # File Service - List files & Get file by ID domain_name = "8um2zizr80.execute-api.ap-northeast-1.amazonaws.com" path_pattern = "/dev/files*" + }, + { + # File Service - Upload file + domain_name = "ssckvgoo10.execute-api.ap-northeast-1.amazonaws.com" + path_pattern = "/dev/upload-file*" + }, + { + # File Service - Upload multiple files + domain_name = "sojek1stci.execute-api.ap-northeast-1.amazonaws.com" + path_pattern = "/dev/upload-multiple-file*" + }, + + { + # Email Service - Send Email + domain_name = "diyf4tafbl.execute-api.ap-northeast-1.amazonaws.com" + path_pattern = "/dev/send-email*" } + ] } From cc4dce0d0cac5acaf79ee64f05ce5b73a3869521 Mon Sep 17 00:00:00 2001 From: sh1un Date: Mon, 10 Jun 2024 20:22:01 +0800 Subject: [PATCH 4/4] build: add GitHub Actions workflow for Terraform infrastructure change management --- .github/workflows/terraform.yaml | 117 +++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 .github/workflows/terraform.yaml diff --git a/.github/workflows/terraform.yaml b/.github/workflows/terraform.yaml new file mode 100644 index 0000000..5267cb6 --- /dev/null +++ b/.github/workflows/terraform.yaml @@ -0,0 +1,117 @@ +name: "Terraform Infrastructure Change Management Pipeline with GitHub Actions" + +on: + push: + branches: + - main + - dev + - poc + paths: + - terraform/** + pull_request: + branches: + - main + - dev + - poc + paths: + - terraform/** + +env: + # verbosity setting for Terraform logs + TF_LOG: INFO + # Credentials for deployment to AWS + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + # S3 bucket for the Terraform state + +jobs: + terraform: + name: "Terraform Infrastructure Change Management" + runs-on: ubuntu-latest + defaults: + run: + shell: bash + + steps: + - name: Checkout the repository to the runner + uses: actions/checkout@v2 + + - name: Setup Terraform with specified version on the runner + uses: hashicorp/setup-terraform@v2 + with: + terraform_version: 1.8.3 + + - name: Set environment variables + id: set-env + run: | + if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then + echo "::set-output name=env::prod" + echo "::set-output name=dir::./terraform/prod" + echo "::set-output name=tfvars::variables_prod.tfvars" + elif [[ "${{ github.ref }}" == "refs/heads/dev" ]]; then + echo "::set-output name=env::dev" + echo "::set-output name=dir::./terraform/dev" + echo "::set-output name=tfvars::variables_dev.tfvars" + elif [[ "${{ github.ref }}" == "refs/heads/poc" ]]; then + echo "::set-output name=env::poc" + echo "::set-output name=dir::./terraform/poc" + echo "::set-output name=tfvars::variables_poc.tfvars" + fi + + - name: Terraform init + id: init + working-directory: ${{ steps.set-env.outputs.dir }} + run: terraform init" + + - name: Terraform format + id: fmt + working-directory: ${{ steps.set-env.outputs.dir }} + run: terraform fmt -check + + - name: Terraform validate + id: validate + working-directory: ${{ steps.set-env.outputs.dir }} + run: terraform validate + + - name: Terraform plan + id: plan + if: github.event_name == 'pull_request' + working-directory: ${{ steps.set-env.outputs.dir }} + run: terraform plan -no-color -input=false -var-file="${{ steps.set-env.outputs.tfvars }}" + continue-on-error: true + + - uses: actions/github-script@v6 + if: github.event_name == 'pull_request' + env: + PLAN: "terraform\n${{ steps.plan.outputs.stdout }}" + with: + script: | + const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\` + #### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\` + #### Terraform Validation 🤖\`${{ steps.validate.outcome }}\` + #### Terraform Plan 📖\`${{ steps.plan.outcome }}\` + +
Show Plan + + \`\`\`\n + ${process.env.PLAN} + \`\`\` + +
+ *Pushed by: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`; + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: output + }) + + - name: Terraform Plan Status + if: steps.plan.outcome == 'failure' + run: exit 1 + + - name: Terraform Apply + if: github.ref == 'refs/heads/main' && github.event_name == 'push' + working-directory: ${{ steps.set-env.outputs.dir }} + run: terraform apply -auto-approve -input=false -var-file="${{ steps.set-env.outputs.tfvars }}"