diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index e6020ef..18c0033 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -2,24 +2,24 @@ name: Terraform Apply on: push: - branches: [main] + branches: [main] # main 브랜치에 push될 때 실행 permissions: - contents: read - id-token: write + contents: read # 코드 리포지토리 읽기 권한 + id-token: write # OIDC 인증을 위한 ID 토큰 발급 권한 jobs: detect-changes: runs-on: ubuntu-latest outputs: - matrix: ${{ steps.set.outputs.matrix }} + matrix: ${{ steps.set.outputs.matrix }} # 다음 job에 전달할 matrix 출력 steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v3 # 현재 리포지토리 코드 체크아웃 - name: Filter Paths id: filter - uses: dorny/paths-filter@v3 + uses: dorny/paths-filter@v3 # 어떤 디렉토리에 변경이 있는지 필터링 with: filters: | operation: @@ -30,36 +30,33 @@ jobs: - 'prod-team-account/**' dev: - 'dev-team-account/**' - security: - - 'security-team-account/**' stage: - 'stage-team-account/**' - management: - - 'management-team-account/**' + - name: Build Matrix from Filter (with subdirs) id: set env: + # 필터링된 결과를 환경변수로 받아옴 FILTER_OUTPUTS_operation: ${{ steps.filter.outputs.operation }} FILTER_OUTPUTS_identity: ${{ steps.filter.outputs.identity }} FILTER_OUTPUTS_prod: ${{ steps.filter.outputs.prod }} FILTER_OUTPUTS_dev: ${{ steps.filter.outputs.dev }} - FILTER_OUTPUTS_security: ${{ steps.filter.outputs.security }} FILTER_OUTPUTS_stage: ${{ steps.filter.outputs.stage }} - FILTER_OUTPUTS_management: ${{ steps.filter.outputs.management }} run: | + # 계정 별 IAM Role Key 매핑 declare -A ROLE_MAP=( ["operation"]="ROLE_ARN_OPERATION" ["identity"]="ROLE_ARN_IDENTITY" ["prod"]="ROLE_ARN_PROD" ["dev"]="ROLE_ARN_DEV" - ["security"]="ROLE_ARN_SECURITY" ["stage"]="ROLE_ARN_STAGE" - ["management"]="ROLE_ARN_MANAGEMENT" + ) MATRIX_ITEMS=() + # 변경된 경로에 따라 matrix 구성 for KEY in "${!ROLE_MAP[@]}"; do VAR_NAME="FILTER_OUTPUTS_${KEY}" VALUE="${!VAR_NAME}" @@ -85,6 +82,7 @@ jobs: fi done + # 최종 matrix JSON 출력 if [ ${#MATRIX_ITEMS[@]} -eq 0 ]; then echo "matrix=[]" >> $GITHUB_OUTPUT else @@ -93,14 +91,14 @@ jobs: fi terraform-apply: - needs: detect-changes - if: ${{ needs.detect-changes.outputs.matrix != '[]' }} + needs: detect-changes # detect-changes job 이후 실행 + if: ${{ needs.detect-changes.outputs.matrix != '[]' }} # 변경사항이 있을 경우에만 실행 runs-on: ubuntu-latest strategy: - matrix: + matrix: # matrix 기반 반복 실행 include: ${{ fromJson(needs.detect-changes.outputs.matrix) }} - fail-fast: false + fail-fast: false # 하나 실패해도 나머지 job은 계속 진행 steps: - name: Checkout repository @@ -110,17 +108,17 @@ jobs: uses: aws-actions/configure-aws-credentials@v4 with: aws-region: ap-northeast-2 - role-to-assume: ${{ secrets[matrix.role_key] }} + role-to-assume: ${{ secrets[matrix.role_key] }} # OIDC 기반으로 계정별 IAM Role Assume - name: Setup Terraform uses: hashicorp/setup-terraform@v1 with: - terraform_version: 1.4.0 + terraform_version: 1.4.0 # Terraform 버전 명시 - name: Terraform Init - run: terraform init - working-directory: ${{ matrix.dir }} + run: terraform init # Terraform 초기화: 백엔드 설정 및 provider 다운로드 + working-directory: ${{ matrix.dir }} # matrix로 전달된 디렉토리에서 실행 - name: Terraform Apply - run: terraform apply -auto-approve + run: terraform apply -auto-approve # 사용자 승인 없이 자동 적용 working-directory: ${{ matrix.dir }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 01c5818..1b53d82 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,6 @@ on: - "dev-team-account/**" - "security-team-account/**" - "stage-team-account/**" - - "management-team-account/**" permissions: contents: read @@ -38,7 +37,7 @@ jobs: echo "Changed files:" echo "$FILES" - declare -A ROLE_MAP=( + declare -A ROLE_MAP=( ["operation-team-account"]="ROLE_ARN_OPERATION" ["identity-team-account"]="ROLE_ARN_IDENTITY" ["prod-team-account"]="ROLE_ARN_PROD" @@ -56,14 +55,12 @@ jobs: ROLE_KEY="${ROLE_MAP[$TOP_DIR]}" if [ -n "$ROLE_KEY" ]; then - # 루트 디렉터리 if [ "$DIR" == "$TOP_DIR" ]; then TF_COUNT=$(find "$DIR" -maxdepth 1 -name '*.tf' | wc -l) if [ "$TF_COUNT" -gt 0 ]; then echo "$DIR|$ROLE_KEY" >> $TMP_FILE fi else - # 하위 디렉터리 TF_COUNT=$(find "$DIR" -maxdepth 1 -name '*.tf' | wc -l) if [ "$TF_COUNT" -gt 0 ]; then echo "$DIR|$ROLE_KEY" >> $TMP_FILE @@ -72,9 +69,7 @@ jobs: fi done - # 중복 제거 UNIQUE_LINES=$(sort $TMP_FILE | uniq) - MATRIX_JSON="[" FIRST=1 @@ -116,6 +111,8 @@ jobs: steps: - name: Checkout Code uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 @@ -123,6 +120,12 @@ jobs: aws-region: ap-northeast-2 role-to-assume: ${{ secrets[matrix.role_key] }} + - name: Install Terraform + run: | + curl -LO https://releases.hashicorp.com/terraform/1.4.0/terraform_1.4.0_linux_amd64.zip + unzip terraform_1.4.0_linux_amd64.zip + sudo mv terraform /usr/local/bin/ + - name: Install tfsec run: | curl -sSL https://raw.githubusercontent.com/aquasecurity/tfsec/master/scripts/install_linux.sh | bash @@ -130,11 +133,6 @@ jobs: - name: Run tfsec (fail on HIGH+) run: tfsec --minimum-severity HIGH --no-color ${{ matrix.dir }} - - name: Setup Terraform - uses: hashicorp/setup-terraform@v1 - with: - terraform_version: 1.4.0 - - name: Terraform Init run: terraform init working-directory: ${{ matrix.dir }} @@ -150,12 +148,37 @@ jobs: - name: Terraform Plan id: plan run: | - terraform plan -no-color -out=tfplan.binary - terraform show -no-color tfplan.binary > plan.txt - terraform show -json tfplan.binary > plan.json - echo 'PLAN<> $GITHUB_OUTPUT - cat plan.txt >> $GITHUB_OUTPUT - echo 'EOF' >> $GITHUB_OUTPUT + START_TIME=$(date -u +"%Y-%m-%d %H:%M:%S UTC") + echo "START_TIME=$START_TIME" >> $GITHUB_ENV + + PLAN_FILE=tfplan.binary + PLAN_TXT=plan.txt + PLAN_JSON=plan.json + + # Run terraform plan + terraform plan -no-color -out=$PLAN_FILE > /dev/null 2> plan_error.txt || echo "PLAN_FAILED=true" >> $GITHUB_ENV + + # Show plan text output + terraform show -no-color $PLAN_FILE > $PLAN_TXT 2>/dev/null || echo "Plan failed" > $PLAN_TXT + + # Remove ANSI color codes + cat $PLAN_TXT | \ + sed 's/`/\\`/g' | \ + tr -d '\r' | \ + sed -r "s/\x1B\[[0-9;]*[JKmsu]//g" \ + > cleaned_plan.txt + + PLAN_CONTENT=$(cat cleaned_plan.txt) + + # Save JSON plan for infracost + terraform show -json $PLAN_FILE > $PLAN_JSON || true + + # Output plan content for PR comment + { + echo "PLAN_CONTENT<> $GITHUB_OUTPUT working-directory: ${{ matrix.dir }} - name: Comment Terraform Plan on PR @@ -164,9 +187,18 @@ jobs: with: issue-number: ${{ github.event.pull_request.number }} body: | - ### Terraform Plan Output for `${{ matrix.dir }}` + ## [Terraform Plan Summary] + | 항목 | 값 | + |-----------------|-----| + | **Status** | `${{ steps.plan.outcome }}` | + | **Directory** | `${{ matrix.dir }}` | + | **Executed At** | `${{ env.START_TIME }}` | + + --- + + ### Plan Output ```hcl - ${{ steps.plan.outputs.PLAN }} + ${{ steps.plan.outputs.PLAN_CONTENT }} ``` - name: Setup Infracost diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1668f42 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +.DS_Store +.idea + +# tfstate files +*.tfstate +*.tfstate.* +.terraform +.terraform/ +*.tfvars +*.tfvars.json +*.tfplan +*.tfplan.json +*.tfignore +*.tfbackup +*.tfstate.backup +*.tfstate.backup.* +*.tfstate.backup.json +*.tfstate.backup.json.* +.terraform.lock.hcl \ No newline at end of file diff --git a/dev-team-account/OIDC/iam/backend.tf b/dev-team-account/OIDC/iam/backend.tf new file mode 100644 index 0000000..d0d6476 --- /dev/null +++ b/dev-team-account/OIDC/iam/backend.tf @@ -0,0 +1,9 @@ +terraform { + backend "s3" { + bucket = "cloudfence-dev-state" + key = "OIDC/iam.tfstate" + region = "ap-northeast-2" + encrypt = true + dynamodb_table = "s3-dev-lock" + } +} \ No newline at end of file diff --git a/dev-team-account/OIDC/iam/main.tf b/dev-team-account/OIDC/iam/main.tf new file mode 100644 index 0000000..818f749 --- /dev/null +++ b/dev-team-account/OIDC/iam/main.tf @@ -0,0 +1,43 @@ +# modules/github_oidc를 불러와 해당account별 OIDC역할을 자동으로 생성하는 구조 +# +module "github_oidc" { + source = "../../../modules/iam_OIDC" + + role_name = "application-deployment-role1" + + # GitHub Actions에서 이 role을 사용할 수 있도록 허용하는 sub조건 + sub_condition = ["repo:WHS-DevSecOps-infra/Organization:*", + "repo:WHS-DevSecOps-infra/Application-Deployment:*"] + + thumbprint_list = [ + "d89e3bd43d5d909b47a18977aa9d5ce36cee184c" + ] + + # 이 role에 연결할 정책들(IAM 정책 ARN) + policy_arns = [] +} + +#tfsec:ignore:aws-iam-no-policy-wildcards +resource "aws_iam_role_policy" "custom_inline_policy" { + name = "dev-role" + role = module.github_oidc.oidc_role_name # 모듈에서 출력된 role이름 참조 + + policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Sid" : "VisualEditor0", + "Effect" : "Allow", + "Action" : [ + "rds:*", + "s3:*", + "ec2:*", + "kms:*", + "dynamodb:*", + "iam:*" + ], + "Resource" : "*" + } + ] + }) +} diff --git a/identity-team-account/OIDC/iam/backend.tf b/identity-team-account/OIDC/iam/backend.tf new file mode 100644 index 0000000..7f4b07a --- /dev/null +++ b/identity-team-account/OIDC/iam/backend.tf @@ -0,0 +1,9 @@ +terraform { + backend "s3" { + bucket = "cloudfence-identity-state" + key = "OIDC/iam.tfstate" + region = "ap-northeast-2" + encrypt = true + dynamodb_table = "s3-identity-lock" + } +} \ No newline at end of file diff --git a/identity-team-account/OIDC/iam/main.tf b/identity-team-account/OIDC/iam/main.tf new file mode 100644 index 0000000..ab27c6e --- /dev/null +++ b/identity-team-account/OIDC/iam/main.tf @@ -0,0 +1,95 @@ +# identity-team-account의 main.tf +# modules/github_oidc를 불러와 해당account별 OIDC역할을 자동으로 생성하는 구조 + +module "github_oidc" { + source = "../../../modules/iam_OIDC" + + role_name = "Organization-role" + + # GitHub Actions에서 이 role을 사용할 수 있도록 허용하는 sub조건 + sub_condition = ["repo:WHS-DevSecOps-infra/Organization:*", + "repo:WHS-DevSecOps-infra/Application-Deployment:*", + "repo:WHS-DevSecOps-infra/Monitoring:*"] + + + # 이 role에 연결할 정책들(IAM 정책 ARN) + policy_arns = [ + + ] + thumbprint_list = [ + "d89e3bd43d5d909b47a18977aa9d5ce36cee184c" + ] +} + +#tfsec:ignore:aws-iam-no-policy-wildcards +resource "aws_iam_role_policy" "custom_inline_policy" { + name = "org-role" + role = module.github_oidc.oidc_role_name # 모듈에서 출력된 role이름 참조 + + policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Sid" : "SSOAccess", + "Effect" : "Allow", + "Action" : [ + "sso:*", + "sso:CreateAccountAssignment" + ], + "Resource" : "*" + }, + { + "Sid" : "S3Access", + "Effect" : "Allow", + "Action" : [ + "s3:*" + ], + "Resource" : [ + "*" + ] + }, + { + "Sid" : "KMSAccess", + "Effect" : "Allow", + "Action" : [ + "kms:*" + ], + "Resource" : "*" + }, + { + "Sid" : "DynamoDBAccess", + "Effect" : "Allow", + "Action" : [ + "dynamodb:*" + ], + "Resource" : "*" + }, + { + "Sid" : "Statement1", + "Effect" : "Allow", + "Action" : [ + "organizations:*" + ], + "Resource" : "*" + }, + { + "Sid" : "Statement2", + "Effect" : "Allow", + "Action" : [ + "identitystore:*" + ], + "Resource" : "*" + }, + { + "Sid" : "Statement3", + "Effect" : "Allow", + "Action" : [ + "iam:*" + ], + "Resource" : [ + "*" + ] + } + ] + }) +} diff --git a/main.tf b/main.tf index e0031a5..a1b16b7 100644 --- a/main.tf +++ b/main.tf @@ -12,7 +12,7 @@ provider "aws" { # S3 버킷 생성 resource "aws_s3_bucket" "tfstate_app" { - bucket = "cloudfence-tfstate-app" + bucket = "cloudfence-tfstate-app" lifecycle { prevent_destroy = true @@ -64,7 +64,7 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "encryption" { # DynamoDB 테이블 생성 resource "aws_dynamodb_table" "lock_app" { - name = "tfstate-lock-app" + name = "tfstate-lock-app" billing_mode = "PAY_PER_REQUEST" hash_key = "LockID" @@ -81,8 +81,4 @@ resource "aws_dynamodb_table" "lock_app" { Name = "Terraform Lock Table" Environment = "application-deployment" } -<<<<<<< HEAD } -======= -} ->>>>>>> origin/main diff --git a/modules/iam_OIDC/main.tf b/modules/iam_OIDC/main.tf new file mode 100644 index 0000000..1e5482f --- /dev/null +++ b/modules/iam_OIDC/main.tf @@ -0,0 +1,52 @@ + +provider "aws" { + region = "ap-northeast-2" + +} +resource "aws_iam_openid_connect_provider" "github" { + url = "https://token.actions.githubusercontent.com" + + client_id_list = [ + "sts.amazonaws.com" # OIDC에서 사용할 클라이언트 ID + ] + + thumbprint_list = var.thumbprint_list +} + +resource "aws_iam_role" "oidc_role" { + name = var.role_name + description = "cicd" + + assume_role_policy = jsonencode({ + Version = "2012-10-17", + Statement = concat( + [ + { + Effect = "Allow", + Principal = { + Federated = aws_iam_openid_connect_provider.github.arn + }, + Action = "sts:AssumeRoleWithWebIdentity", + Condition = { + StringEquals = { + "token.actions.githubusercontent.com:aud" = "sts.amazonaws.com" + }, + StringLike = { + "token.actions.githubusercontent.com:sub" = var.sub_condition + } + } + } + ], + var.add_root_trust ? [ + { + Effect = "Allow", + Principal = { + AWS = "arn:aws:iam::${var.account_id}:root" + }, + Action = "sts:AssumeRole" + } + ] : [] + ) + + }) +} diff --git a/modules/iam_OIDC/outputs.tf b/modules/iam_OIDC/outputs.tf new file mode 100644 index 0000000..56e363e --- /dev/null +++ b/modules/iam_OIDC/outputs.tf @@ -0,0 +1,4 @@ +output "oidc_role_name" { + description = "OIDC로 생성된 IAM Role 이름" + value = aws_iam_role.oidc_role.name +} \ No newline at end of file diff --git a/modules/iam_OIDC/variables.tf b/modules/iam_OIDC/variables.tf new file mode 100644 index 0000000..d2f17a5 --- /dev/null +++ b/modules/iam_OIDC/variables.tf @@ -0,0 +1,38 @@ +variable "role_name" { + type = string + description = "OIDC 역할 이름" +} + +variable "sub_condition" { + type = list(string) + description = "OIDC Subject (sub) 조건" +} + +variable "policy_arns" { + type = list(string) + description = "Attach할 IAM 정책 목록" +} + +resource "aws_iam_role_policy_attachment" "attach_policy" { + for_each = toset(var.policy_arns) + role = aws_iam_role.oidc_role.name + policy_arn = each.value +} + +variable "thumbprint_list" { + description = "OIDC provider thumbprint list" + type = list(string) + default = ["6938fd4d98bab03faadb97b34396831e3780aea1"] +} + +variable "add_root_trust" { + description = "Whether to add root account trust" + type = bool + default = false +} + +variable "account_id" { + description = "AWS account ID for root trust" + type = string + default = "" +} diff --git a/operation-team-account/OIDC/iam/backend.tf b/operation-team-account/OIDC/iam/backend.tf new file mode 100644 index 0000000..2b14d75 --- /dev/null +++ b/operation-team-account/OIDC/iam/backend.tf @@ -0,0 +1,9 @@ +terraform { + backend "s3" { + bucket = "cloudfence-operation-state" + key = "OIDC/iam.tfstate" + region = "ap-northeast-2" + encrypt = true + dynamodb_table = "s3-operation-lock" + } +} \ No newline at end of file diff --git a/operation-team-account/OIDC/iam/main.tf b/operation-team-account/OIDC/iam/main.tf new file mode 100644 index 0000000..c8d9493 --- /dev/null +++ b/operation-team-account/OIDC/iam/main.tf @@ -0,0 +1,116 @@ +# modules/github_oidc를 불러와 해당account별 OIDC역할을 자동으로 생성하는 구조 + + + + +module "github_oidc" { + source = "../../../modules/iam_OIDC" + + role_name = "operation-cicd" + account_id = "502676416967" + add_root_trust = true + + + # GitHub Actions에서 이 role을 사용할 수 있도록 허용하는 sub조건 + sub_condition = ["repo:WHS-DevSecOps-infra/Organization:*", + "repo:WHS-DevSecOps-infra/Monitoring:*", + "repo:WHS-DevSecOps-infra/Application-Deployment:*", + "repo:yunhoch0i/Application-Deployment:*"] + thumbprint_list = ["d89e3bd43d5d909b47a18977aa9d5ce36cee184c"] + + # 이 role에 연결할 정책들(IAM 정책 ARN) + policy_arns = [] + + + +} + +#tfsec:ignore:aws-iam-no-policy-wildcards +resource "aws_iam_role_policy" "custom_inline_policy" { + name = "operation-cicd" + role = module.github_oidc.oidc_role_name # 모듈에서 출력된 role이름 참조 + + policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Effect" : "Allow", + "Action" : [ + "s3:ListBucket", + "s3:GetObject", + "s3:PutObject", + "s3:*", + "sts:AssumeRole" + ], + "Resource" : ["*"] + }, + { + "Effect" : "Allow", + "Action" : [ + "cloudwatch:*", + "cloudtrail:*" + ], + "Resource" : "*" + }, + { + "Sid" : "KMSAccess", + "Effect" : "Allow", + "Action" : [ + "kms:*" + ], + "Resource" : "*" + }, + { + "Sid" : "DynamoDBAccess", + "Effect" : "Allow", + "Action" : [ + "dynamodb:*" + ], + "Resource" : "*" + }, + { + "Sid" : "TerraformBackendOperationState", + "Effect" : "Allow", + "Action" : [ + "s3:GetObject", + "s3:PutObject", + "s3:ListBucket" + ], + "Resource" : [ + "arn:aws:s3:::cloudfence-operation-state", + "arn:aws:s3:::cloudfence-operation-state/*" + ] + }, + { + "Sid" : "TerraformDynamoDBLock", + "Effect" : "Allow", + "Action" : [ + "dynamodb:GetItem", + "dynamodb:PutItem", + "dynamodb:DeleteItem" + ], + "Resource" : "arn:aws:dynamodb:*:*:table/s3-operation-lock" + }, + { + "Sid" : "KMSAccessForState", + "Effect" : "Allow", + "Action" : [ + "kms:Decrypt", + "kms:Encrypt", + "kms:GenerateDataKey" + ], + "Resource" : "arn:aws:kms:ap-northeast-2:502676416967:key/9901c9d1-8b00-47a9-bd7a-53cfc1f70d25" + }, + { + "Sid" : "ECRAndIAMManagement", + "Effect" : "Allow", + "Action" : [ + "ecr:*", + "iam:CreateServiceLinkedRole" + ], + "Resource" : "*" + } + ] + } + ) +} diff --git a/prod-team-account/OIDC/iam/backend.tf b/prod-team-account/OIDC/iam/backend.tf new file mode 100644 index 0000000..006fcd1 --- /dev/null +++ b/prod-team-account/OIDC/iam/backend.tf @@ -0,0 +1,11 @@ + +terraform { + backend "s3" { + bucket = "cloudfence-prod-state" + key = "OIDC/iam.tfstate" + region = "ap-northeast-2" + encrypt = true + dynamodb_table = "s3-prod-lock" + + } +} \ No newline at end of file diff --git a/prod-team-account/OIDC/iam/main.tf b/prod-team-account/OIDC/iam/main.tf new file mode 100644 index 0000000..efcc1ff --- /dev/null +++ b/prod-team-account/OIDC/iam/main.tf @@ -0,0 +1,134 @@ +# prod-team-account의 main.tf +# modules/github_oidc를 불러와 해당account별 OIDC역할을 자동으로 생성하는 구조 + +module "github_oidc" { + source = "../../../modules/iam_OIDC" + + role_name = "Application-Deployment-role2" + add_root_trust = false + # GitHub Actions에서 이 role을 사용할 수 있도록 허용하는 sub조건 + sub_condition = ["repo:WHS-DevSecOps-infra/Organization:*", + "repo:WHS-DevSecOps-infra/Application-Deployment:*"] + + thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"] + # 이 role에 연결할 정책들(IAM 정책 ARN) + policy_arns = [] +} + +data "aws_caller_identity" "current" {} + + +#tfsec:ignore:aws-iam-no-policy-wildcards +resource "aws_iam_role_policy" "custom_inline_policy" { + name = "prod-role" + role = module.github_oidc.oidc_role_name # 모듈에서 출력된 role이름 참조 + + policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Sid" : "VisualEditor0", + "Effect" : "Allow", + "Action" : [ + "rds:*", + "s3:*", + "ec2:*", + "dynamodb:*", + "kms:*" + ], + "Resource" : "*" + }, + { + "Sid" : "TerraformBackendProdState", + "Effect" : "Allow", + "Action" : [ + "s3:GetObject", + "s3:PutObject", + "s3:ListBucket" + ], + "Resource" : [ + "arn:aws:s3:::cloudfence-prod-state", + "arn:aws:s3:::cloudfence-prod-state/*" + ] + }, + { + "Sid" : "TerraformBackendOperationState", + "Effect" : "Allow", + "Action" : [ + "s3:GetObject", + "s3:ListBucket" + ], + "Resource" : [ + "arn:aws:s3:::cloudfence-operation-state", + "arn:aws:s3:::cloudfence-operation-state/*" + ] + }, + { + "Sid" : "TerraformDynamoDBLock", + "Effect" : "Allow", + "Action" : [ + "dynamodb:GetItem", + "dynamodb:PutItem", + "dynamodb:DeleteItem" + ], + "Resource" : "arn:aws:dynamodb:*:*:table/s3-operation-lock" + }, + { + "Sid" : "KMSDecryptForStateFiles", + "Effect" : "Allow", + "Action" : [ + "kms:Decrypt", + "kms:Encrypt", + "kms:GenerateDataKey" + ], + "Resource" : "arn:aws:kms:ap-northeast-2:243359234795:key/c2c5da76-b55b-4bcc-a240-10cc6d6e9940" + }, + { + "Sid" : "AllProdResourceManagement", + "Effect" : "Allow", + "Action" : [ + "ec2:*", + "ecs:*", + "iam:*", + "elasticloadbalancing:*", + "codedeploy:*", + "autoscaling:*", + "cloudwatch:*", + "wafv2:*" + ], + "Resource" : "*" + }, + { + "Sid" : "AllowACMCertificateManagement", + "Effect" : "Allow", + "Action" : [ + "acm:RequestCertificate", + "acm:DescribeCertificate", + "acm:DeleteCertificate", + "acm:ListTagsForCertificate", + "acm:AddTagsToCertificate", + "acm:RemoveTagsFromCertificate" + ], + "Resource" : "*" + }, + { + "Sid" : "AllowRoute53DNSValidation", + "Effect" : "Allow", + "Action" : [ + "route53:GetChange", + "route53:ChangeResourceRecordSets", + "route53:ListHostedZonesByName", + "route53:GetHostedZone", + "route53:ListResourceRecordSets" + ], + "Resource" : "arn:aws:route53:::hostedzone/*" + }, + { + "Sid" : "AllowRoute53GetChange", + "Effect" : "Allow", + "Action" : "route53:GetChange", + "Resource" : "arn:aws:route53:::change/*" + } + ] + }) +} \ No newline at end of file diff --git a/stage-team-account/OIDC/iam/backend.tf b/stage-team-account/OIDC/iam/backend.tf new file mode 100644 index 0000000..1b3bf8a --- /dev/null +++ b/stage-team-account/OIDC/iam/backend.tf @@ -0,0 +1,9 @@ +terraform { + backend "s3" { + bucket = "cloudfence-stage-state" + key = "OIDC/iam.tfstate" + region = "ap-northeast-2" + encrypt = true + dynamodb_table = "s3-stage-lock" + } +} \ No newline at end of file diff --git a/stage-team-account/OIDC/iam/main.tf b/stage-team-account/OIDC/iam/main.tf new file mode 100644 index 0000000..d9c0edd --- /dev/null +++ b/stage-team-account/OIDC/iam/main.tf @@ -0,0 +1,45 @@ +# stage-team-account의 main.tf +# modules/github_oidc를 불러와 해당account별 OIDC역할을 자동으로 생성하는 구조 + +module "github_oidc" { + source = "../../../modules/iam_OIDC" + + role_name = "Application-deployment-role3" + + thumbprint_list = ["d89e3bd43d5d909b47a18977aa9d5ce36cee184c"] + # GitHub Actions에서 이 role을 사용할 수 있도록 허용하는 sub조건 + sub_condition = ["repo:WHS-DevSecOps-infra/Organization:*", + "repo:WHS-DevSecOps-infra/Application-Deployment:*"] + + + # 이 role에 연결할 정책들(IAM 정책 ARN) + policy_arns = [] + +} + + + +#tfsec:ignore:aws-iam-no-policy-wildcards +resource "aws_iam_role_policy" "custom_inline_policy" { + name = "stage-role" + role = module.github_oidc.oidc_role_name # 모듈에서 출력된 role이름 참조 + + policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Sid" : "VisualEditor0", + "Effect" : "Allow", + "Action" : [ + "s3:*", + "ec2:*", + "rds:*", + "dynamodb:*", + "kms:*", + "iam:*" + ], + "Resource" : "*" + } + ] + }) +} \ No newline at end of file