간단한 웹페이지가 이전에는 가상환경에서 구동되고 있었는데요
여기서는 SSL 인증도 꼬여 90일 단위로 수동 업데이트 해주는 사태가 발생했습니다.
이번에 크래딧 지원을 받아
Azure에서 GCP로 옮기게 되었는데요!
그 김에 다음과 같은 업데이트를 진행하고자 했습니다.
1) 이번에는 기존보다 더 낮은 비용으로
2) 커밋 시 자동 배포 되며
3) IaC 형태로 정의도 하여 이후에 유지 보수도 쉽도록
변경해보고자 합니다.
인프라 구성
- Cloud Storage
- 빌드 완료된 정적 파일 업로드
- 버킷에 website 호스팅 모드 적용
- Cloud CDN (Content Delivery Network)
- 전세계 PoP(Point of Presence)에 캐싱
- 사용자 → 가장 가까운 캐시에서 받아서 속도 향상
- Cloud Load Balancing (HTTP(S) LB)
- 엔드포인트에 커스텀 도메인 연결
- SSL 인증서(Google-managed SSL) 자동 발급
- WAF, 보안 정책, 로깅 연동 가능
버킷생성
버킷을 만들어보고자 합니다
버킷 만들기 | Cloud Storage | Google Cloud
의견 보내기 버킷 만들기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지에서는 Cloud Storage 버킷을 만드는 방법을 보여줍니다. 요청에 달리 지정되
cloud.google.com
버킷을 만들기 위해서는 다음과 같은 권한이 필요합니다.
저는 이 권한들을 일단 복사해놓고 나중에 IAM으로 만들어 GitHub Action에 제공하고자 합니다.

이 역할은 버킷에 대한 권한이 아닌,
버킷 내부의 폴더에 대해 권한을 주고 싶다면 이용하면 되는 권한입니다.
저에겐 해당 사항 없는 권한이네요
권한의 굴레는 참으로 재미납니다.

사실 이곳을 참조하면 훨씬 쉽습니다.
Terraform Registry
registry.terraform.io
terraform-google-static-assets/modules/cloud-storage-static-website at v0.6.0 · gruntwork-io/terraform-google-static-assets
Modules for managing static assets (CSS, JS, images) in GCP - gruntwork-io/terraform-google-static-assets
github.com
여기 코드를 참조해서
이렇게 구성을 만들었습니다

그 중, project나 domain_name 같은 속성은
커밋해서 기록이 남으면 기분이 좋지 않습니다.
variable "project" {
description = "The project ID to host the site in."
type = string
}
variable "website_domain_name" {
description = "The name of the website and the Cloud Storage bucket to create (e.g. static.foo.com)."
type = string
}
이러한 값 들은 ` terraform.tfvars ` 파일에 기록한 뒤 커밋하지 않는 것을 추천합니다.
project = "프로젝트 ID"
website_domain_name = "도메인 이름"
혹여나 배포시와 테스트 시의 환경 변수가 다르다면, 이 파일로 구분할 수 있습니다.
이렇게 개발용, 배포용 등으로 이름을 나누면 되는거죠!
` dev.tfvars `, ` stage.tfvars ` , ` prod.tfvars `
아래는 저는 쓰진 않았지만 이런 예를 들 수 있습니다.
project = "project_id 값"
website_domain_name = "jinju.dev"
website_location = "asia-northeast3"
enable_cors = true # 기본 false인데 활성화 하고 싶을 때
cors_origins = ["https://jinju.dev", "https://app.jinju.dev", "https://api.jinju.dev"]
create_dns_entry = true
dns_managed_zone_name = "jinju-zone"
custom_labels = {
environment = "prod"
owner = "jinju"
}
` terraform.tfvars `이름을 쓰면 자동으로 환경변수가 적용되나,
` dev.tfvars `, ` stage.tfvars ` , ` prod.tfvars ` 과 같은 이름을 쓴다면
다음과 같이 적용할 수 있습니다.
terraform apply -var-file="dev.tfvars"
terraform apply -var-file="prod.tfvars"
이제 IAM 권한을 만들러 가봅니다!
전에!! 이상적인 구조라면 아래를 따릅니다

1.Bootstrap IAM: 사람이 Terraform이 쓸 초기 열쇠(서비스 계정 + 권한)를 줌
2.Terraform IAM 관리: Terraform이 IAM 권한 자체를 코드로 관리 시작
3.Resource IAM 관리: 리소스별 IAM 권한(버킷 접근, VM 접근 등)을 Terraform이 설정
4.Resource 생성: 최종적으로 Terraform이 실제 리소스를 생성
하지만
마감 시간에 쫒기는 삶을 사는 저는 간략화하여

다음과 같이 구현한 뒤 발전시키는 모습으로 돌아오고자 합니다 ㅎㅎ...
이것이 해당 역할입니다.
위에서 보셨던 그 권한 4개를 포함하였습니다.
서비스용 계정을 만들어 저장소 관리자 역할을 넣었습니다!

그리고 접근 키를 만들려고 했죠


역시 쉬운길로 가고자 하면 모든 것이 막혀 있지요

Workload Identity Pool 생성
인증 구조가 변했습니다...
환경에 따라가야지요
🌱 WIF (Workload Identity Federation)
- 뜻: 워크로드(=CI/CD, 외부 시스템 등)가 Google Cloud에 접근할 때, 서비스 계정 키 파일 없이 안전하게 임시 자격증명으로 인증하는 방식
- 왜 쓰는가!?
- JSON 키는 유출 위험이 크기 때문에 차단.
- 대신 WIF를 쓰면 외부에서 온 요청(GitHub Actions OIDC 토큰)을 GCP가 검증해서 짧은 수명(1시간짜리) 권한을 줌.
- 보안 + 자동화 둘 다 챙길 수 있음.

현재 진행할 건 OIDC(OpenID Connect) 속성을 만들어 주는 겁니다.
"이 토큰은 누구(어떤 주체)에게서 발급된 것이고, 어떤 속성을 가지고 있다"
를 증명하기 위함이지요
요청 예제 입니다!
{
"iss": "https://token.actions.githubusercontent.com",
"sub": "repo:OWNER/REPO:ref:refs/heads/main",
"repository": "OWNER/REPO",
"ref": "refs/heads/main"
}
` iss `는 발급자
` sub `는 주체(subject, 어떤 레포/브랜치에서 발급했는지)
` repository, ref `는 부가 속성입니다
이 값을 기반해서 아하 줘야징 하고 IAM 권한을 내려줍니다.

가장 간단하고 범용적인 OIDC를 선택했습니다.
인증이 GitHub Action 과정에 포함될 예정이라 action 선택했습니다.


providers.tf 수정
앞 날을 몰랐던 저는 json 파일을 이용해서 하고자 했는데요
이번에 방식이 변하며 이 코드도 변경되어야 합니다.
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
required_version = ">= 1.6.0"
}
provider "google" {
project = var.project
region = var.website_location
credentials = file("terraform-key.json")
}
credentials를 쿨하게 삭제해주었습니다.
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
required_version = ">= 1.6.0"
}
provider "google" {
project = var.project
region = var.website_location
}
따라서 다음 과정으로 인증이 진행됩니다!!
- GitHub Actions에서 google-github-actions/auth@v2 실행 → OIDC 토큰을 받아 GCP WIF로 교환 → 임시 ADC 발급.
- terraform init / apply → providers.tf의 google 블록이 ADC를 자동으로 사용.
- 버킷 생성 및 DNS 레코드 생성 완료.
으앙 이제 GitHub Action
필요 정보
1) 프로젝트 ID
현재 작업 중인 프로젝트 ID
(이거 문자면 안됨니다...!)
모르시면 클라우드 쉘 키셔서 아래 명령어 입력하세요

gcloud projects describe tih-web-new --format="value(projectNumber)"
2) 워크로드 아이덴티티풀 ID
함께 버킷을 위해 만든 워크로드 아이덴티티풀 ID
3) 프로바이더 ID
아이덴티티풀 ID 할 때 Github Action 적고 했을 때 그 이름
4) 서비스 계정 이메일
서비스 계정 만들고 나면 나오는 이메일
[Github Action] GCP 워크로드 아이덴티티 제휴 (Workload Identity Federation) 연결하기
GCP 워크로드 아이덴티티 제휴에 대해선 여기에서 설명하고 있습니다. Github Action에서 GCP 리소스를 접근하기 위해선 서비스계정의 key file 내용을 scret 에 등록하는 방법과 워크로드 아이덴티티 제
brownbears.tistory.com
위를 참조해 들고 왔는데 버전만 옛 버전이라 살짝 수정했습니다
name: git action test
on:
push:
branches:
- develop
jobs:
workload-identity-connection:
runs-on: ubuntu-latest
# Add "id-token" with the intended permissions.
permissions:
contents: 'read'
id-token: 'write'
steps:
- uses: actions/checkout@v3
- id: 'auth'
uses: 'google-github-actions/auth@v2'
with:
workload_identity_provider: '**projects/{프로젝트번호}/locations/global/workloadIdentityPools/{워크로드 아이덴티티 풀id}/providers/{워크로드 아이덴티티 공급업체 id}**'
service_account: '{서비스 계정 이메일}'
- name: 'Set up Cloud SDK'
uses: 'google-github-actions/setup-gcloud@v2'
- name: 'Use gcloud CLI'
run: 'gcloud info'
그럼 커밋 할 때마다 버킷 새로 만드나요?
라는 문제 방지를 위해 backend.tf에 아래 내용을 추가합니다.
terraform {
backend "gcs" {
bucket = "tih-ai-terraform-state"
prefix = "infra/state"
}
}
이렇게 state 저장용 GCS 버킷을 미리 만들어 두어야 한다!
(닭/달걀 문제 때문)
gcloud storage buckets create gs://{지을만한 프로젝트이름}-terraform-state \
--project=tih-web-new \
--location=us-central1 \
--uniform-bucket-level-access
- 버킷 권한
- Terraform 실행하는 서비스 계정(tih-ai-terraform-deployer@...)한테 roles/storage.admin 또는 최소 roles/storage.objectAdmin 붙여야 state 읽고 쓸 수 있어.
- terraform init -migrate-state
- backend 블록 추가 후 처음 init 할 때는:
-
terraform init -migrate-state
- 그래야 로컬에 있던 state가 GCS로 옮겨짐.
배포는 실전이야

iam.allowedPolicyMemberDomains
조직 허용을 받아 가볍게 했더니

왕 으앙이 된다.
현재 버킷에서 정적웹으로 호스팅하였는데, 이 경우 https를 지원하지 않는다.
이를 해결하기 위해서는 CDN + Load Balancer를 붙이면 된다.
이 말인 즉슨 다시 terraform과 싸움을 해야한다는 것이다.
놀랍게도 한 번에 챡 잘붙어버렸는데
인증서 문제가 오래지속되었다.
원인은 로드벨런서의 IP를 모두 A레코드에 등록하였어야 했는데
www.{사이트주소}는 등록하지 않았던게 원인이었다.
gcloud compute ssl-certificates list --project={프로젝트 이름}


'기술 단어장 > IaC' 카테고리의 다른 글
| [Terraform] 공식문서로 파해쳐본Terraform GCP 배포 (0) | 2025.03.26 |
|---|---|
| [Error] 나의 첫 테라폼 사용기 - Error: Backend initialization required, please run "terraform init" (0) | 2023.11.29 |
댓글