클릭은 그만: Terraform으로 Cloudflare 엣지 인프라(CDN, WAF) 코드로 관리하기

곽태욱·2026년 1월 29일

안녕하세요! 오늘은 프론트엔드 개발자라면 누구나 한 번쯤 겪어봤을 "Cloudflare 콘솔 클릭 지옥"에서 탈출하는 방법에 대해 이야기해보려고 해요.

Cloudflare는 정말 강력한 CDN이자 보안 도구지만, 웹 콘솔에서 수많은 규칙(Page Rules, Cache Rules, WAF 등)을 일일이 설정하다 보면 실수가 생기기 마련이죠. "어? 내가 아까 이걸 켰던가?" 하고 헷갈리기도 하고요.

이번 글에서는 Terraform을 사용해 Cloudflare의 모든 설정을 코드(Infrastructure as Code)로 관리하여, 더 이상 클릭하지 않고 안전하게 인프라를 배포하는 방법을 소개할게요.

1. 왜 코드로 관리해야 할까요?

GUI 콘솔은 직관적이지만, 팀 단위로 일하거나 프로젝트 규모가 커지면 한계가 명확해요.

  1. 히스토리 관리 불가: "누가 언제 캐시 설정을 바꿨지?"를 추적하기 힘들어요.
  2. 재현 불가능: 개발 환경(Staging) 설정을 운영 환경(Production)에 똑같이 적용하려면 다시 클릭 노동을 해야 해요.
  3. 리뷰 없는 변경: 인프라 변경은 서비스에 큰 영향을 주는데, 코드 리뷰 없이 누군가가 "딸깍" 적용해버릴 수 있어요.

Terraform을 쓰면 이 모든 설정을 Git에 커밋하고, PR로 리뷰받을 수 있어요.

2. Terraform 설정 시작하기

가장 먼저 main.tf에서 Cloudflare 프로바이더를 설정해요. API 토큰은 보안을 위해 코드에 넣지 않고 환경 변수(CLOUDFLARE_API_TOKEN)로 주입받는 것이 좋아요.

terraform {
  required_providers {
    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = "~> 5"
    }
  }
  required_version = ">= 1.0"
}

provider "cloudflare" {
  # API token will be read from CLOUDFLARE_API_TOKEN environment variable
}

3. 정교한 Cache Rules 작성하기

Cloudflare의 강력한 기능인 'Cache Rules'를 코드로 정의해볼까요?
cache-rules.tf 파일을 보면, 경로별로 다른 TTL(Time To Live)을 적용하고 있어요.

먼저 locals 블록을 사용해 캐시할 경로들을 변수처럼 관리하면 가독성이 훨씬 좋아져요.

locals {
  respect_origin_prefixes = [
    "/api/",
  ]

  ttl_30d_path_prefixes = [
    "/auth/",
    "/image/",
    "/manga",
    "/static/",
    # ...
  ]
  
  # ... (중략)
  
  ttl_30d_expression = "${local.exact_path_conditions} or ${local.prefix_path_conditions} or (http.request.uri.path.extension in {${local.exact_extension_conditions}})"
}

그리고 실제 규칙을 정의합니다. 예를 들어, 정적 자원은 30일 동안 엣지에 캐시하도록 설정할 수 있어요.

resource "cloudflare_ruleset" "cache_rules" {
  zone_id = var.zone_id
  name    = "Cache Rules"
  kind    = "zone"
  phase   = "http_request_cache_settings"

  rules = [
    {
      ref         = "manga_pages_html"
      enabled     = true
      description = "Cache with 30 days TTL"
      expression  = local.ttl_30d_expression
      action      = "set_cache_settings"

      action_parameters = {
        cache = true
        edge_ttl = {
          mode    = "override_origin"
          default = 2592000 # 30 days
        }
        browser_ttl = {
          mode = "respect_origin"
        }
        cache_key = {
          cache_deception_armor      = true
          ignore_query_strings_order = true
        }
      }
    },
    # ...
  ]
}

이렇게 하면 mode = "override_origin"을 통해 서버 설정과 무관하게 Cloudflare 엣지에서 강제로 캐시 시간을 제어할 수 있어요.

4. DDoS 공격 방어와 보안 헤더

보안 설정도 빼놓을 수 없죠. rate-limiting.tf에서는 특정 IP에서 요청이 폭주할 때 자동으로 차단하는 규칙을 정의합니다.

resource "cloudflare_ruleset" "rate_limiting" {
  # ...
  rules = [
    {
      action = "block"
      ratelimit = {
        characteristics     = ["cf.colo.id", "ip.src"]
        period              = var.rate_limit_period
        requests_per_period = var.rate_limit_requests
        mitigation_timeout  = var.rate_limit_timeout
      }
    }
  ]
}

또한, managed-transforms.tf를 통해 보안 헤더를 자동으로 주입하거나 불필요한 헤더를 제거할 수 있어요. 예를 들어 X-Powered-By 헤더를 제거하여 서버 정보를 숨기는 것은 보안의 기본이죠!

locals {
  managed_response_headers_overrides = {
    remove_x-powered-by_header = true
  }
  # ...
}

resource "cloudflare_managed_transforms" "managed_transforms" {
  zone_id = var.zone_id
  managed_response_headers = local.managed_response_headers
  # ...
}

5. 마치며: 인프라도 이제 코드입니다

이제 Cloudflare 콘솔에 로그인해서 버튼을 클릭하는 대신, 터미널에서 terraform apply 한 번으로 모든 인프라를 배포할 수 있게 되었어요.

# 변경 사항 확인
$ terraform plan

# 변경 사항 적용
$ terraform apply

이렇게 관리하면 누가 언제 어떤 보안 규칙을 추가했는지 Git 로그로 투명하게 남고, 실수로 규칙을 지우더라도 언제든 복구할 수 있답니다. 프론트엔드 개발자 여러분도 이제 엣지 인프라를 코드로 우아하게 관리해 보세요!

profile
이유와 방법을 알려주는 메모장 겸 블로그 (Frontend, AI, 경제, 책)

0개의 댓글