From a370826395e5051ad2e0cd98142cc26c59bac6fd Mon Sep 17 00:00:00 2001 From: grand7070 Date: Tue, 11 Jun 2024 20:07:15 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20stage=20=ED=99=98=EA=B2=BD=20=EA=B5=AC?= =?UTF-8?q?=EC=B6=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/image_resizer_stage_CD.yaml | 86 ++++++ .github/workflows/prod_initial_setting.yaml | 3 +- .github/workflows/stage_CD.yaml | 114 ++++++++ .github/workflows/stage_CI.yaml | 76 ++++++ .github/workflows/stage_initial_setting.yaml | 53 ++++ global/stage/backend.tf | 9 + global/stage/main.tf | 258 ++++++++++++++++++ global/stage/terraform.tfvars | 3 + global/stage/variables.tf | 9 + global/stage/version.tf | 12 + modules/terraform-aws-opensearch/main.tf | 2 +- modules/terraform-aws-route53/main.tf | 32 ++- modules/terraform-aws-route53/outputs.tf | 2 +- root/stage/backend.tf | 9 + root/stage/main.tf | 197 +++++++++++++ root/stage/stage.tfvars | 20 ++ root/stage/variables.tf | 67 +++++ root/stage/version.tf | 17 ++ 18 files changed, 956 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/image_resizer_stage_CD.yaml create mode 100644 .github/workflows/stage_CD.yaml create mode 100644 .github/workflows/stage_CI.yaml create mode 100644 .github/workflows/stage_initial_setting.yaml create mode 100644 global/stage/backend.tf create mode 100644 global/stage/main.tf create mode 100644 global/stage/terraform.tfvars create mode 100644 global/stage/variables.tf create mode 100644 global/stage/version.tf create mode 100644 root/stage/backend.tf create mode 100644 root/stage/main.tf create mode 100644 root/stage/stage.tfvars create mode 100644 root/stage/variables.tf create mode 100644 root/stage/version.tf diff --git a/.github/workflows/image_resizer_stage_CD.yaml b/.github/workflows/image_resizer_stage_CD.yaml new file mode 100644 index 0000000..f71c30a --- /dev/null +++ b/.github/workflows/image_resizer_stage_CD.yaml @@ -0,0 +1,86 @@ +name: image_resizer_stage_CD + +on: + pull_request: + branches: + - stage + types: + - closed + paths: + - 'lambda/image_resizer/**' + - '!lambda/image_resizer/README.md' + workflow_dispatch: + +permissions: + id-token: write + contents: read + +env: + LAMBDA: stage-image-resizer + STAGE_BUCKET_NAME: stage-daedong-image-637423658689 + +jobs: + upload_zip_to_lambda: + runs-on: ubuntu-latest + defaults: + run: + working-directory: lambda/image_resizer + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Make zip + run: | + sed -i "s/BUCKET_NAME/${{ env.STGAGE_BUCKET_NAME }}/gi" index.js + docker build --tag sharp_on_lambda:nodejs20 . + docker run --name sharp_on_lambda_container sharp_on_lambda:nodejs20 + docker cp sharp_on_lambda_container:/image_resizer.zip . + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ secrets.STG_AWS_GITHUB_ACTION_ROLE }} + aws-region: ap-northeast-2 + + - name: Upload and Publish Lambda + id: upload-lambda + run: | + aws lambda update-function-code \ + --region us-east-1 \ + --function-name ${{ env.LAMBDA }} \ + --zip-file fileb://image_resizer.zip + + while [[ "$(aws lambda get-function --region us-east-1 --function-name ${{ env.LAMBDA }} --query 'Configuration.LastUpdateStatus')" != "\"Successful\"" ]]; do + echo "Waiting for function update to complete..." + sleep 10 + done + + echo "Function update completed." + + echo "LAMBDA_ARN=$( + aws lambda publish-version \ + --region us-east-1 \ + --function-name ${{ env.LAMBDA }} \ + --query 'FunctionArn'\ + --output text + )" >> $GITHUB_OUTPUT + + - name: Distribute Lambda@Edge + env: + LAMBDA_ARN: ${{ steps.upload-lambda.outputs.LAMBDA_ARN }} + run: | + aws cloudfront get-distribution-config \ + --id ${{ secrets.STG_IMAGE_CLOUDFRONT_ID }} \ + --output json > distribution-config-with-etag.json + + ETag=$(jq -r '.ETag' distribution-config-with-etag.json) + jq -r '.DistributionConfig' distribution-config-with-etag.json > distribution-config.json + + jq --arg lambda_arn $LAMBDA_ARN \ + '.DefaultCacheBehavior.LambdaFunctionAssociations.Items[0].LambdaFunctionARN = $lambda_arn' \ + distribution-config.json > modified-config.json + + aws cloudfront update-distribution \ + --id ${{ secrets.STG_IMAGE_CLOUDFRONT_ID }} \ + --if-match $ETag \ + --distribution-config file://modified-config.json diff --git a/.github/workflows/prod_initial_setting.yaml b/.github/workflows/prod_initial_setting.yaml index 31eb546..7309f75 100644 --- a/.github/workflows/prod_initial_setting.yaml +++ b/.github/workflows/prod_initial_setting.yaml @@ -23,8 +23,7 @@ jobs: - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v2 with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: ${{ secrets.PRD_AWS_GITHUB_ACTION_ROLE }} aws-region: ${{ env.AWS_REGION }} - name: Setup Terraform diff --git a/.github/workflows/stage_CD.yaml b/.github/workflows/stage_CD.yaml new file mode 100644 index 0000000..6cd6cb9 --- /dev/null +++ b/.github/workflows/stage_CD.yaml @@ -0,0 +1,114 @@ +name: stage_CD + +on: + pull_request: + branches: + - stage + types: + - closed + paths: + - 'modules/**' + - 'root/stage/**' + - '!modules/READMD.md' + - '!root/stage/READMD.md' + workflow_dispatch: + +env: + AWS_REGION: ap-northeast-2 + +permissions: + id-token: write + contents: read + actions: read + +jobs: + terraform-apply: + if: ${{ (github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.merged == true)) && github.ref == 'refs/heads/stage' }} + runs-on: ubuntu-latest + defaults: + run: + working-directory: root/stage + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ secrets.STG_AWS_GITHUB_ACTION_ROLE }} + aws-region: ${{ env.AWS_REGION }} + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + with: + terraform_version: 1.7.3 + + - name: Terraform init + id: init + run: terraform init + + - name: Terraform plan + env: + RDS_PASSWORD: ${{ secrets.STG_RDS_PASSWORD }} + JWT_KEY: ${{ secrets.STG_JWT_KEY }} + JWT_ADMIN_KEY: ${{ secrets.STG_JWT_ADMIN_KEY }} + OPEN_SEARCH_USERNAME: ${{ secrets.STG_OPEN_SEARCH_USERNAME }} + OPEN_SEARCH_PASSWORD: ${{ secrets.STG_OPEN_SEARCH_PASSWORD }} + SGIS_KEY: ${{ secrets.SGIS_KEY }} + SGIS_SECRET: ${{ secrets.SGIS_SECRET }} + FIREBASE_PROJECTID: ${{ secrets.STG_FIREBASE_PROJECTID }} + FIREBASE_CREDENTIALS: ${{ secrets.STG_FIREBASE_CREDENTIALS }} + run: | + terraform plan -lock-timeout=3m --var-file=prod.tfvars -no-color \ + -var rds_password=$RDS_PASSWORD \ + -var jwt_key=$JWT_KEY \ + -var jwt_admin_key=$JWT_ADMIN_KEY \ + -var search_master_user_name=$OPEN_SEARCH_USERNAME \ + -var search_master_user_password=$OPEN_SEARCH_PASSWORD \ + -var sgis_key=$SGIS_KEY \ + -var sgis_secret=$SGIS_SECRET \ + -var firebase_projectid=$FIREBASE_PROJECTID \ + -var firebase_credentials="$FIREBASE_CREDENTIALS" \ + -out tfplan + + - name: Terraform apply + run: | + terraform apply tfplan + + - name: CD notification to Slack + uses: 8398a7/action-slack@v3 + with: + status: custom + fields: repo,workflow,job + custom_payload: | + { + text: '*[개발 환경]* Terraform Apply', + attachments: [{ + color: '${{ job.status }}' === 'success' ? 'good' : 'danger', + fields: [ + { + title: 'Result', + value: '${{ job.status }}' === 'success' ? 'Success' : 'Fail', + short: false + }, + { + "title": 'Resource', + "value": '${{ contains(github.event.pull_request.body, '[API]') && 'API' || 'Infra' }}', + "short": false + }, + { + title: 'Repository', + value: `${process.env.AS_REPO}`, + short: false + }, + { + title: 'Action', + value: `${process.env.AS_WORKFLOW}`, + short: false + } + ] + }] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + if: always() diff --git a/.github/workflows/stage_CI.yaml b/.github/workflows/stage_CI.yaml new file mode 100644 index 0000000..bfb25fa --- /dev/null +++ b/.github/workflows/stage_CI.yaml @@ -0,0 +1,76 @@ +name: stage_CI + +on: + pull_request: + branches: + - stage + paths: + - 'modules/**' + - 'root/stage/**' + - '!modules/READMD.md' + - '!root/stage/READMD.md' + workflow_dispatch: + +env: + AWS_REGION: ap-northeast-2 + +permissions: + id-token: write + contents: read + +jobs: + terraform-validate: + runs-on: ubuntu-latest + defaults: + run: + working-directory: root/stage + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ secrets.STG_AWS_GITHUB_ACTION_ROLE }} + aws-region: ${{ env.AWS_REGION }} + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + with: + terraform_version: 1.7.3 + + - name: Terraform fmt + id: fmt + run: terraform fmt -recursive -check + continue-on-error: true + + - name: Terraform init + id: init + run: terraform init + + - name: Terraform Validate + id: validate + run: terraform validate -no-color + + - name: Terraform plan + env: + RDS_PASSWORD: ${{ secrets.STG_RDS_PASSWORD }} + JWT_KEY: ${{ secrets.STG_JWT_KEY }} + JWT_ADMIN_KEY: ${{ secrets.STG_JWT_ADMIN_KEY }} + OPEN_SEARCH_USERNAME: ${{ secrets.STG_OPEN_SEARCH_USERNAME }} + OPEN_SEARCH_PASSWORD: ${{ secrets.STG_OPEN_SEARCH_PASSWORD }} + SGIS_KEY: ${{ secrets.SGIS_KEY }} + SGIS_SECRET: ${{ secrets.SGIS_SECRET }} + FIREBASE_PROJECTID: ${{ secrets.STG_FIREBASE_PROJECTID }} + FIREBASE_CREDENTIALS: ${{ secrets.STG_FIREBASE_CREDENTIALS }} + run: | + terraform plan -lock-timeout=3m --var-file=stage.tfvars -no-color \ + -var rds_password=$RDS_PASSWORD \ + -var jwt_key=$JWT_KEY \ + -var jwt_admin_key=$JWT_ADMIN_KEY \ + -var search_master_user_name=$OPEN_SEARCH_USERNAME \ + -var search_master_user_password=$OPEN_SEARCH_PASSWORD \ + -var sgis_key=$SGIS_KEY \ + -var sgis_secret=$SGIS_SECRET \ + -var firebase_projectid=$FIREBASE_PROJECTID \ + -var firebase_credentials="$FIREBASE_CREDENTIALS" diff --git a/.github/workflows/stage_initial_setting.yaml b/.github/workflows/stage_initial_setting.yaml new file mode 100644 index 0000000..eec9237 --- /dev/null +++ b/.github/workflows/stage_initial_setting.yaml @@ -0,0 +1,53 @@ +name: stage_initial_setting + +on: + workflow_dispatch: + +env: + AWS_REGION: ap-northeast-2 + +permissions: + id-token: write + contents: read + +jobs: + terraform-apply: + runs-on: ubuntu-latest + defaults: + run: + working-directory: global/stage + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ secrets.STG_AWS_GITHUB_ACTION_ROLE }} + aws-region: ${{ env.AWS_REGION }} + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + with: + terraform_version: 1.7.3 + + - name: Terraform fmt + id: fmt + run: terraform fmt -recursive -check + continue-on-error: true + + - 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 -out planfile + + - name: Terraform apply + run: | + terraform apply planfile diff --git a/global/stage/backend.tf b/global/stage/backend.tf new file mode 100644 index 0000000..501bec3 --- /dev/null +++ b/global/stage/backend.tf @@ -0,0 +1,9 @@ +terraform { + backend "s3" { + bucket = "stage-daedong-terraform-remote-state-637423658689" // TODO + key = "global/stage/terraform.tfstate" // TODO + region = "ap-northeast-2" + dynamodb_table = "stage-daedong-terraform-state-lock-637423658689" // TODO + encrypt = true + } +} diff --git a/global/stage/main.tf b/global/stage/main.tf new file mode 100644 index 0000000..16848e8 --- /dev/null +++ b/global/stage/main.tf @@ -0,0 +1,258 @@ +data "aws_caller_identity" "current" {} + +# Terraform Backend +resource "aws_s3_bucket" "tfstate" { + bucket = "${var.env}-daedong-terraform-remote-state-${data.aws_caller_identity.current.account_id}" + + force_destroy = true + lifecycle { + prevent_destroy = true + } +} + +resource "aws_s3_bucket_versioning" "tfstate_versioning" { + bucket = aws_s3_bucket.tfstate.id + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_dynamodb_table" "terraform_state_lock" { + name = "${var.env}-daedong-terraform-state-lock-${data.aws_caller_identity.current.account_id}" + hash_key = "LockID" + billing_mode = "PAY_PER_REQUEST" + deletion_protection_enabled = true + + attribute { + name = "LockID" + type = "S" + } +} + +# IAM +## GitHub Actions +data "aws_iam_openid_connect_provider" "github_actions" { + url = "https://token.actions.githubusercontent.com" +} + +data "aws_iam_policy_document" "github_actions_policy" { + statement { + actions = ["sts:AssumeRoleWithWebIdentity"] + + condition { + test = "StringEquals" + variable = "token.actions.githubusercontent.com:aud" + values = ["sts.amazonaws.com"] + } + + condition { + test = "StringLike" + variable = "token.actions.githubusercontent.com:sub" + values = ["repo:${var.github_organization}/*:*"] # TODO + } + + effect = "Allow" + + principals { + type = "Federated" + identifiers = [data.aws_iam_openid_connect_provider.github_actions.arn] + } + } +} + +resource "aws_iam_role" "github_actions" { + name = "${var.env}-GithubActionsRole" + assume_role_policy = data.aws_iam_policy_document.github_actions_policy.json +} + +resource "aws_iam_role_policy_attachment" "github_actions_full_access" { + role = aws_iam_role.github_actions.name + policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess" # TODO +} + +# Lambda +data "aws_iam_policy_document" "lambda_trust_policy" { + statement { + actions = ["sts:AssumeRole"] + effect = "Allow" + principals { + type = "Service" + identifiers = ["lambda.amazonaws.com"] + } + } +} + +resource "aws_iam_role" "api_cloudwatch_to_slack" { + name = "${var.env}-ApiCloudwatchToSlackRole" + assume_role_policy = data.aws_iam_policy_document.lambda_trust_policy.json + managed_policy_arns = ["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"] +} + +resource "aws_iam_role" "ip_update_to_slack" { + name = "${var.env}-IpUpdateToSlackRole" + assume_role_policy = data.aws_iam_policy_document.lambda_trust_policy.json + managed_policy_arns = [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess", + ] +} + +resource "aws_iam_role" "rds_slowquery_to_slack" { + name = "${var.env}-RdsSlowqueryToSlackRole" + assume_role_policy = data.aws_iam_policy_document.lambda_trust_policy.json + managed_policy_arns = ["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"] +} + +resource "aws_iam_role" "image_resizer" { + name = "${var.env}-ImageResizerRole" + assume_role_policy = data.aws_iam_policy_document.lambda_edge_trust_policy.json + managed_policy_arns = [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess", + aws_iam_policy.image_resizer.arn + ] +} + +data "aws_iam_policy_document" "lambda_edge_trust_policy" { + statement { + actions = ["sts:AssumeRole"] + effect = "Allow" + principals { + type = "Service" + identifiers = [ + "lambda.amazonaws.com", + "edgelambda.amazonaws.com" + ] + } + } +} + +resource "aws_iam_policy" "image_resizer" { + name = "${var.env}-ResizeLambdaPolicy" + policy = data.aws_iam_policy_document.image_resize.json +} + +data "aws_iam_policy_document" "image_resize" { + statement { + effect = "Allow" + + actions = [ + "iam:CreateServiceLinkedRole", + "lambda:GetFunction", + "lambda:EnableReplication", + "cloudfront:UpdateDistribution", + "s3:GetObject", + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + "logs:DescribeLogStreams" + ] + resources = ["*"] + } +} + +# resource "aws_iam_role_policy_attachment" "github_actions_ecs_full_access" { +# role = aws_iam_role.github_actions.name +# policy_arn = "arn:aws:iam::aws:policy/AmazonECS_FullAccess" +# } + +# resource "aws_iam_role_policy_attachment" "github_actions_ec2_container_registry_full_access" { +# role = aws_iam_role.github_actions.name +# policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess" +# } + +# resource "aws_iam_role_policy_attachment" "github_actions_terraform_state_s3_access" { +# role = aws_iam_role.github_actions.name +# policy_arn = aws_iam_policy.terraform_state_s3_access_policy.arn +# } + +# resource "aws_iam_policy" "terraform_state_s3_access_policy" { +# name = "${var.env}-TerraformStateS3AccessPolicy" +# policy = data.aws_iam_policy_document.terraform_state_s3_access.json +# } + +# data "aws_iam_policy_document" "terraform_state_s3_access" { +# statement { +# effect = "Allow" + +# actions = [ +# "s3:ListBucket" +# ] +# resources = [ +# "${aws_s3_bucket.tfstate.arn}", +# ] +# } + +# statement { +# effect = "Allow" + +# actions = [ +# "s3:GetObject", +# "s3:PutObject" +# ] +# resources = [ +# "${aws_s3_bucket.tfstate.arn}/*" # TODO +# ] +# } +# } + +# resource "aws_iam_role_policy_attachment" "github_actions_terraform_state_dynamodb_access" { +# role = aws_iam_role.github_actions.name +# policy_arn = aws_iam_policy.terraform_state_dynamodb_policy.arn +# } + +# resource "aws_iam_policy" "terraform_state_dynamodb_policy" { +# name = "${var.env}-TerraformStateDynamoDBPolicy" +# policy = data.aws_iam_policy_document.terraform_state_dynamodb_access.json +# } + +# data "aws_iam_policy_document" "terraform_state_dynamodb_access" { +# statement { +# effect = "Allow" + +# actions = [ +# "dynamodb:DescribeTable", +# "dynamodb:GetItem", +# "dynamodb:PutItem", +# "dynamodb:DeleteItem" +# ] +# resources = [ +# "${aws_dynamodb_table.terraform_state_lock.arn}", +# ] +# } +# } + +# ECR +resource "aws_ecr_repository" "api" { + name = "${var.env}-daedong-api" + force_delete = true +} + +resource "aws_ecr_lifecycle_policy" "api" { + repository = aws_ecr_repository.api.name + policy = < { + for_each = var.env == "prod" ? { + for dvo in aws_acm_certificate.daedong[0].domain_validation_options : dvo.domain_name => { name = dvo.resource_record_name record = dvo.resource_record_value type = dvo.resource_record_type } - } + } : {} allow_overwrite = true name = each.value.name records = [each.value.record] ttl = 172800 type = each.value.type - zone_id = aws_route53_zone.daedong.zone_id + # zone_id = aws_route53_zone.daedong[0].zone_id + zone_id = var.env == "prod" ? aws_route53_zone.daedong[0].zone_id : data.aws_route53_zone.daedong[0].zone_id } resource "aws_acm_certificate_validation" "acm_certificate" { // TODO - certificate_arn = aws_acm_certificate.daedong.arn + count = var.env == "prod" ? 1 : 0 + certificate_arn = aws_acm_certificate.daedong[0].arn validation_record_fqdns = [for record in aws_route53_record.acm_certificate : record.fqdn] } diff --git a/modules/terraform-aws-route53/outputs.tf b/modules/terraform-aws-route53/outputs.tf index 9d19c94..e7ca786 100644 --- a/modules/terraform-aws-route53/outputs.tf +++ b/modules/terraform-aws-route53/outputs.tf @@ -1,5 +1,5 @@ output "domain_acm_certificate_arn" { - value = aws_acm_certificate.daedong.arn + value = var.env == "prod" ? aws_acm_certificate.daedong[0].arn : data.aws_acm_certificate.daedong[0].arn } # output "admin_acm_certificate_arn" { # value = aws_acm_certificate.admin_daedong.arn diff --git a/root/stage/backend.tf b/root/stage/backend.tf new file mode 100644 index 0000000..6e5cba6 --- /dev/null +++ b/root/stage/backend.tf @@ -0,0 +1,9 @@ +terraform { + backend "s3" { + bucket = "stage-daedong-terraform-remote-state-637423658689" // TODO + key = "root/stage/terraform.tfstate" // TODO + region = "ap-northeast-2" + dynamodb_table = "stage-daedong-terraform-state-lock-637423658689" // TODO + encrypt = true + } +} diff --git a/root/stage/main.tf b/root/stage/main.tf new file mode 100644 index 0000000..be40865 --- /dev/null +++ b/root/stage/main.tf @@ -0,0 +1,197 @@ +module "iam" { + source = "../../modules/terraform-aws-iam" + + env = var.env + image_bucket_arn = module.s3.image_bucket_arn + image_resizer_lambda_arn = module.lambda.image_resizer_arn + # admin_codebuild_log_group_arn = module.cloudwatch.admin_codebuild_log_group_arn + # admin_codebuild_name = module.codeseries.admin_codebuild_name +} + +# module "codeseries" { +# source = "../../modules/terraform-aws-codeseries" + +# env = var.env +# github_organization = var.github_organization +# domain = var.domain +# admin_bucket_name = module.s3.admin_bucket_name +# admin_cloudfront_id = module.cloudfront.admin_cloudfront_id +# admin_codebuild_role_arn = module.iam.admin_codebuild_role_arn +# admin_codepipeline_role_arn = module.iam.admin_codepipeline_role_arn +# admin_codepipeline_bucket = module.s3.admin_codepipeline_bucket +# } + +module "cloudwatch" { + source = "../../modules/terraform-aws-cloudwatch" + + env = var.env + api_cloudwatch_to_slack_lambda_name = module.lambda.api_cloudwatch_to_slack_name + ip_update_to_slack_lambda_name = module.lambda.ip_update_to_slack_name + rds_slowquery_to_slack_lambda_name = module.lambda.rds_slowquery_to_slack_name + image_resizer_lambda_name = module.lambda.image_resizer_name + rds_identifier = module.rds.rds_identifier +} + +module "lambda" { + source = "../../modules/terraform-aws-lambda" + + providers = { + aws.virginia = aws.virginia + } + + env = var.env + image_resizer_role_arn = module.iam.image_resizer_role_arn + api_log_group_arn = module.cloudwatch.api_log_group_arn + api_log_group_name = module.cloudwatch.api_log_group_name + rds_slowquery_log_group_name = module.cloudwatch.rds_slowquery_log_group_name + rds_slowquery_log_group_arn = module.cloudwatch.rds_slowquery_log_group_arn +} + +module "cloudfront" { + source = "../../modules/terraform-aws-cloudfront" + + image_bucket_domain_name = module.s3.image_bucket_domain_name + image_resizer_lambda_qualified_arn = module.lambda.image_resizer_qualified_arn + # admin_bucket_domain_name = module.s3.admin_bucket_domain_name + # domain = var.domain + # admin_acm_arn = module.route53.admin_acm_certificate_arn +} + +module "s3" { + source = "../../modules/terraform-aws-s3" + + env = var.env + domain = var.domain + image_cloudfront_domain = module.cloudfront.image_cloudfront_domain + image_cloudfront_arn = module.cloudfront.image_cloudfront_arn + image_resizer_role_arn = module.iam.image_resizer_role_arn + # admin_cloudfront_arn = module.cloudfront.admin_cloudfront_arn +} + +module "vpc" { + source = "../../modules/terraform-aws-vpc" + + env = var.env + availability_zones = var.availability_zones + vpc_cidr = var.vpc_cidr + image_bucket_arn = module.s3.image_bucket_arn + ecs_task_role_arn = module.iam.ecs_task_role_arn +} + +module "security_group" { + source = "../../modules/terraform-aws-security-group" + + env = var.env + vpc_id = module.vpc.vpc_id +} + +module "lb" { + source = "../../modules/terraform-aws-lb" + + env = var.env + vpc_id = module.vpc.vpc_id + lb_pub_subnet_ids = module.vpc.lb_pub_subnet_ids + pub_alb_security_group_id = module.security_group.pub_alb_security_group_id + domain_acm_certificate_arn = module.route53.domain_acm_certificate_arn +} + +module "route53" { + source = "../../modules/terraform-aws-route53" + + env = var.env + domain = var.domain + pub_alb_dns_name = module.lb.pub_alb_dns_name + pub_alb_zone_id = module.lb.pub_alb_zone_id + # admin_cloudfront_domain = module.cloudfront.admin_cloudfront_domain + # admin_cloudfront_zone_id = module.cloudfront.admin_cloudfront_zone_id +} + +module "rds" { + source = "../../modules/terraform-aws-rds" + + env = var.env + rds_security_group_id = module.security_group.rds_security_group_id + db_prv_subnet_ids = module.vpc.db_prv_subnet_ids + rds_password = var.rds_password +} + +module "elasticache" { + source = "../../modules/terraform-aws-elasticache" + + env = var.env + redis_security_group_id = module.security_group.redis_security_group_id + db_prv_subnet_ids = module.vpc.db_prv_subnet_ids +} + +module "ec2" { + source = "../../modules/terraform-aws-ec2" + + env = var.env + instance_type = var.instance_type + ecs_security_group_id = module.security_group.ecs_security_group_id + ecs_instance_profile_arn = module.iam.ecs_instance_profile_arn + ecs_cluster_name = module.ecs.cluster_name + svc_pub_subnet_ids = module.vpc.svc_pub_subnet_ids + min_size = var.min_size + max_size = var.max_size + desired_capacity = var.desired_capacity + key_pair_name = var.key_pair_name +} + +module "ecr" { + source = "../../modules/terraform-aws-ecr" + + env = var.env +} + +module "ecs" { + source = "../../modules/terraform-aws-ecs" + + env = var.env + api_target_group_arn = module.lb.api_target_group_arn + ecs_task_role_arn = module.iam.ecs_task_role_arn + ecs_task_execution_role_arn = module.iam.ecs_task_execution_role_arn + api_repository_url = module.ecr.api_repository_url + api_log_group_name = module.cloudwatch.api_log_group_name + rds_endpoint = module.rds.rds_address + rds_db_name = module.rds.rds_db_name + rds_username = module.rds.rds_username + rds_password = module.rds.rds_password + image_cloudfront_domain = module.cloudfront.image_cloudfront_domain + elasticache_host = module.elasticache.elasticache_host + image_bucket_name = module.s3.image_bucket_name + api_image_tag = var.api_image_tag + api_cpu = var.api_cpu + api_memory = var.api_memory + search_opensearch_endpoint = module.opensearch.search_opensearch_endpoint + search_opensearch_id = var.search_master_user_name + search_opensearch_password = var.search_master_user_password + sgis_key = var.sgis_key + sgis_secret = var.sgis_secret + jwt_key = var.jwt_key + jwt_admin_key = var.jwt_admin_key + firebase_projectid = var.firebase_projectid + firebase_credentials = var.firebase_credentials +} + +module "eventbridge" { + source = "../../modules/terraform-aws-eventbridge" + + ecs_asg_name = module.ec2.ecs_asg_name + ip_update_to_slack_lambda_arn = module.lambda.ip_update_to_slack_arn + ecs_security_group_id = module.security_group.ecs_security_group_id + svc_pub_subnet_ids = module.vpc.svc_pub_subnet_ids + ecs_event_role_arn = module.iam.ecs_event_role_arn +} + +module "opensearch" { + source = "../../modules/terraform-aws-opensearch" + + env = var.env + search_master_user_name = var.search_master_user_name + search_master_user_password = var.search_master_user_password +} + +module "sqs" { + source = "../../modules/terraform-aws-sqs" +} diff --git a/root/stage/stage.tfvars b/root/stage/stage.tfvars new file mode 100644 index 0000000..5d88bd6 --- /dev/null +++ b/root/stage/stage.tfvars @@ -0,0 +1,20 @@ +env = "stage" +github_organization = "daedongbread" +domain = "stage.daedongbread.com" + +# vpc +availability_zones = ["ap-northeast-2a", "ap-northeast-2c"] +vpc_cidr = "172.31.0.0/16" + +# ec2 +instance_type = "t2.micro" +min_size = 1 +max_size = 1 +desired_capacity = 1 +key_pair_name = "daedong" + +# ecs +api_image_tag = "76c1ca444645ab3dd9509b0f62249fbdc93d1099" + +api_cpu = 256 # 0.25 vCPU +api_memory = 410 # 0.4 GB diff --git a/root/stage/variables.tf b/root/stage/variables.tf new file mode 100644 index 0000000..664804d --- /dev/null +++ b/root/stage/variables.tf @@ -0,0 +1,67 @@ +variable "env" { + type = string +} +variable "github_organization" { + type = string +} +variable "availability_zones" { + type = list(string) +} +variable "vpc_cidr" { + type = string +} +variable "domain" { + type = string +} +variable "rds_password" { + type = string + sensitive = true +} +variable "instance_type" { + type = string +} +variable "min_size" { + type = number +} +variable "max_size" { + type = number +} +variable "desired_capacity" { + type = number +} +variable "key_pair_name" { + type = string +} +variable "api_image_tag" { + type = string +} +variable "api_cpu" { + type = number +} +variable "api_memory" { + type = number +} +variable "search_master_user_name" { + type = string +} +variable "search_master_user_password" { + type = string +} +variable "sgis_key" { + type = string +} +variable "sgis_secret" { + type = string +} +variable "jwt_key" { + type = string +} +variable "jwt_admin_key" { + type = string +} +variable "firebase_projectid" { + type = string +} +variable "firebase_credentials" { + type = string +} diff --git a/root/stage/version.tf b/root/stage/version.tf new file mode 100644 index 0000000..3fb12cf --- /dev/null +++ b/root/stage/version.tf @@ -0,0 +1,17 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.0" + } + } +} + +provider "aws" { + region = "ap-northeast-2" +} + +provider "aws" { + alias = "virginia" + region = "us-east-1" +}