콘텐츠로 이동

Terraform

외부 리소스(Cloudflare DNS/Workers/D1, GitHub, healthchecks.io), Authentik 애플리케이션 정책, Headscale ACL policy를 코드로 관리합니다.

백엔드

비공개 Cloudflare R2 bucket sjanglab-terraform-state를 Terraform state 백엔드로 사용합니다. terraform/.envrc가 terraform/secrets.yaml의 bucket-scoped S3 credential을 환경 변수로 로드하고, OpenTofu native S3 lock file이 동시 쓰기를 막습니다.

cd terraform/<module>
direnv allow ..
terragrunt init
terragrunt plan
terragrunt apply

관리 리소스

Cloudflare DNS (sjanglab.org)

terraform/dns는 공개 ingress가 필요한 레코드만 관리합니다. Tailnet 전용 서비스 이름은 Headscale split DNS로 관리합니다.

Cloudflare R2

terraform/r2는 R2 bucket과 custom domain을 관리합니다. niks3 push endpoint는 niks3.sjanglab.org, 공개 cache read endpoint는 R2 custom domain cache.sjanglab.org를 사용합니다.

Authentik

terraform/authentik은 사용자, 그룹, nginx forward auth에 필요한 Authentik proxy provider, application, embedded outpost attachment, access policy binding을 관리합니다. Terraform token은 terraform/authentik/secrets.yaml의 AUTHENTIK_TOKEN으로 전달합니다. 사람 계정 목록은 SOPS로 암호화한 terraform/authentik/users.yaml에 둡니다.

기존 UI 객체를 Terraform으로 전환할 때는 먼저 import helper를 실행한 뒤 plan을 확인합니다.

cd terraform/authentik
terragrunt init
./import-existing.sh
terragrunt plan

학생 계정은 users.yaml에서 expires_on을 설정합니다. 만료된 학생 계정은 active: false로 바꿔 Authentik 로그인과 Headscale ACL group membership을 함께 제거합니다.

관리 대상:

애플리케이션 관리 내용
cloud.sjanglab.org Nextcloud OIDC provider/client + group/quota claim mapping
n8n.sjanglab.org sjanglab-admins, sjanglab-researchers
status.sjanglab.org 인증 없음 (Authentik dashboard tile만 관리)
logging.sjanglab.org sjanglab-admins

Nextcloud 연동은 양쪽으로 나뉩니다. Authentik의 OAuth2 provider/application과 claim mapping은 terraform/authentik/oidc.tf가 관리하고, Nextcloud 내부 user_oidc provider 설정은 modules/nextcloud/default.nix의 nextcloud-oidc-authentik.service가 occ user_oidc:provider로 관리합니다.

Headscale

terraform/headscale은 Headscale database ACL policy를 관리합니다. Headscale API key는 terraform/headscale/secrets.yaml의 HEADSCALE_API_KEY로 전달합니다. 사용자 membership은 terraform/authentik/users.yaml을 함께 읽어 Authentik과 같은 source of truth를 사용합니다.

Headscale 사용자 계정은 Terraform에서 사전 생성하지 않습니다. Authentik 그룹 membership이 OIDC allowed_groups 인가 경계이고, Headscale은 인가된 사용자의 첫 VPN 로그인 때 OIDC iss/sub 기준 user를 생성합니다. Headscale module은 services.headscale.settings.policy.mode = "database" 배포 후 apply합니다. headscale_policy는 provider가 import를 지원하지 않아 첫 apply가 singleton database policy를 설정하면서 Terraform state를 만듭니다.

cd terraform/headscale
terragrunt init
terragrunt plan
terragrunt apply

healthchecks.io

terraform/healthchecksio는 dead-man switch check를 관리하고 healthchecks.io Slack integration을 check에 연결합니다. healthchecks.io API key는 terraform/healthchecksio/secrets.yaml의 HEALTHCHECKSIO_API_KEY로 전달합니다. Slack integration 자체는 healthchecks.io UI에서 #infra-alerts로 먼저 생성합니다.

Check 용도 Ping URL 저장 위치
rho-alertmanager-watchdog Alertmanager Watchdog alert 수신 확인 modules/monitoring/secrets.yaml의 alertmanager-healthchecks-ping-url
infra-alert-bridge-heartbeat Cloudflare Worker bridge cron heartbeat terraform/alert-bridge/secrets.yaml의 BRIDGE_HEARTBEAT_PING_URL
cd terraform/healthchecksio
direnv allow ..
terragrunt init
terragrunt plan
terragrunt apply
terragrunt output -raw rho_alertmanager_watchdog_ping_url
terragrunt output -raw infra_alert_bridge_heartbeat_ping_url

ping_url은 secret입니다. Terraform output을 확인한 뒤 대상 SOPS 파일에 수동으로 저장합니다. Terraform apply가 SOPS 파일을 수정하지 않습니다.

Alert bridge (Cloudflare Worker/D1)

terraform/alert-bridge는 Slack alert bridge Cloudflare Worker, D1 database, Worker secrets, cron trigger를 관리합니다. Worker bundle은 Terragrunt hook이 .#infra-alert-bridge Nix package로 빌드한 결과를 업로드합니다.

cd terraform/alert-bridge
direnv allow ..
terragrunt init
terragrunt plan
terragrunt apply

Terraform provider는 D1 database를 생성하지만 SQL migration은 적용하지 않습니다. apply 후 packages/infra-alert-bridge에서 D1 migration을 실행합니다. Alertmanager는 bridge endpoint를 사용하고, healthchecks.io webhook은 별도 cutover 전까지 Slack integration을 유지합니다.

GitHub

  • 리포지토리 설정: Pages, 브랜치 보호 규칙
  • 라벨: bug, enhancement, documentation, expired-user, auto-merge
  • 자동 병합: 체크 통과 시 활성화