Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 21 additions & 23 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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}"
Expand All @@ -85,6 +82,7 @@ jobs:
fi
done

# 최종 matrix JSON 출력
if [ ${#MATRIX_ITEMS[@]} -eq 0 ]; then
echo "matrix=[]" >> $GITHUB_OUTPUT
else
Expand All @@ -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
Expand All @@ -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 }}
70 changes: 51 additions & 19 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ on:
- "dev-team-account/**"
- "security-team-account/**"
- "stage-team-account/**"
- "management-team-account/**"

permissions:
contents: read
Expand Down Expand Up @@ -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"
Expand All @@ -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
Expand All @@ -72,9 +69,7 @@ jobs:
fi
done

# 중복 제거
UNIQUE_LINES=$(sort $TMP_FILE | uniq)

MATRIX_JSON="["
FIRST=1

Expand Down Expand Up @@ -116,25 +111,28 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
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

- 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 }}
Expand All @@ -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<<EOF' >> $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<<EOF"
echo "$PLAN_CONTENT"
echo "EOF"
} >> $GITHUB_OUTPUT
working-directory: ${{ matrix.dir }}

- name: Comment Terraform Plan on PR
Expand All @@ -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
Expand Down
19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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
9 changes: 9 additions & 0 deletions dev-team-account/OIDC/iam/backend.tf
Original file line number Diff line number Diff line change
@@ -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"
}
}
43 changes: 43 additions & 0 deletions dev-team-account/OIDC/iam/main.tf
Original file line number Diff line number Diff line change
@@ -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" : "*"
}
]
})
}
9 changes: 9 additions & 0 deletions identity-team-account/OIDC/iam/backend.tf
Original file line number Diff line number Diff line change
@@ -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"
}
}
Loading