จัดการ Secret บน GCP ให้โปรด้วย Terraform & Cloud Run 🚀

KDBEER
January 28, 2026
จัดการ-Secret-บน-GCP-ให้โปรด้วย-Terraform-&-Cloud-Run-🚀-697a6eed1bb5dac428cbcb5f

ในโลกของ Cloud Native การเก็บรหัสผ่านหรือ API Key ไว้ในโค้ดแบบ Hardcoded หรือแม้แต่ใส่ตรง ๆ เป็น Environment Variables บน Console เริ่มไม่ปลอดภัยและจัดการยากขึ้นเรื่อย ๆ
วันนี้ผมจะมาแชร์วิธีจัดการ Secret ด้วย GCP Secret Manager โดยใช้ Terraform เป็นตัวควบคุมจากจุดเดียว ช่วยลดเวลาการตั้งค่าผ่านหน้า Console ทำซ้ำได้ง่าย และเหมาะกับการทำงานเป็นทีมมากขึ้นครับ

🏗️ 3 ผสานการสร้าง Secret ด้วย Terraform

การจัดการ Secret ที่ดี ไม่ใช่แค่เอาค่าไปเก็บ แต่ต้องคำนึงถึง Lifecycle และ สิทธิ์การเข้าถึง ให้ถูกต้อง โดยสามารถแบ่งออกเป็น 3 ส่วนหลักดังนี้

1. The Container (การสร้างกล่องเก็บ Secret)

เริ่มจากการสร้าง “กล่องเก็บ Secret” หรือชื่อของตัวแปรใน Secret Manager ก่อน โดยใช้ resource google_secret_manager_secret

resource "google_secret_manager_secret" "app_secret" {
  secret_id = "my-service-secrets" # ชื่อที่จะปรากฏบน GCP Console
  project   = var.project_id       # Project ID ของคุณ

  replication {
    auto {} # ให้ GCP ช่วยสำรองข้อมูล (Replication) อัตโนมัติ
  }
}

2. The Permission (การแจกสิทธิ์)

มีกล่องแล้ว แต่คำถามคือ ใครมีสิทธิ์เปิดดูได้บ้าง? สำหรับ Cloud Run เราจำเป็นต้องให้ Service Account ของแอป มี Role เป็น
Secret Manager Secret Accessor

resource "google_secret_manager_secret_iam_member" "app_accessor" {
  project   = var.project_id
  secret_id = google_secret_manager_secret.app_secret.secret_id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${var.app_service_account_email}"
}

3. The Data (การใส่ข้อมูล)

เมื่อมีกล่องและสิทธิ์พร้อมแล้ว ขั้นต่อไปคือการใส่ Value ของ Secret เข้าไป ซึ่งตรงนี้ถือเป็น จุดตัดสินใจที่สำคัญ เพราะเรามี 2 แนวทางให้เลือก

3.1 Fully Terraform 

ให้ Terraform เป็นคนอัปโหลดค่า Secret จากเครื่องเราเข้าไปเลย เหมาะกับค่าที่ไม่สำคัญมาก หรือเป็นค่า Demo / Test

# 1. สร้างตัว Secret (กล่อง)
resource "google_secret_manager_secret" "app_secret" {
  secret_id = "my-app-env"
  project   = "my-project-id"
  replication {
    auto {}
  }
}

# 2. ใส่ข้อมูล (Version) โดยอ่านจากไฟล์ .env ตรงๆ
resource "google_secret_manager_secret_version" "app_secret_version" {
  secret      = google_secret_manager_secret.app_secret.id
  
  # ใช้ฟังก์ชัน file() เพื่ออ่านเนื้อหาในไฟล์ส่งเข้าไปเป็นข้อมูลลับ
  secret_data = file("${path.module}/secrets/.env") 
}

⚠️ ข้อควรระวัง

Security Risk: ข้อมูลในไฟล์ .env จะถูกเก็บไว้ในไฟล์ terraform.tfstate เป็นแบบ Plain Text (ตัวอักษรอ่านออก) หากใครเข้าถึงไฟล์ state ได้ ก็จะเห็นรหัสผ่านทั้งหมดทันที

Sensitive Suppression: ใน Terraform เวอร์ชันใหม่ๆ มักจะแนะนำให้กำหนดค่าตัวแปรเป็น sensitive = true เพื่อไม่ให้รหัสผ่านโชว์ขึ้นมาบนหน้าจอตอนรัน terraform plan ครับ

3.2 Hybrid Approach (แนะนำ ✅)

ใช้ Terraform สร้างเฉพาะ กล่อง และ สิทธิ์
ส่วน Value ของ Secret ใส่ผ่าน gcloud CLI หรือ Cloud Console เอง
เพื่อป้องกันไม่ให้ข้อมูลลับไปค้างอยู่ในไฟล์ terraform.tfstate

วิธีใส่ข้อมูลผ่าน Cloud Console (หน้าเว็บ)

หากต้องการอัปเดตค่า Secret ด้วยตัวเองผ่านหน้าเว็บ สามารถทำได้ตามขั้นตอนนี้

  1. ไปที่ GCP Console
  2. ค้นหาคำว่า Secret Manager หรือเลือกจากเมนู Security
  3. เลือก Secret ที่ Terraform สร้างไว้ (เช่น backoffice-service-dev)
  4. คลิกปุ่ม + CREATE VERSION
  5. วางค่า Secret (เช่น จากไฟล์ .env หรือรหัสผ่าน)
  6. กด CREATE เป็นอันเสร็จสิ้น

ระบบจะใช้ค่าใน Version ล่าสุด (Latest) เสมอ หาก Cloud Run ถูกตั้งค่าให้ดึงแบบนั้น

💻 วิธีใช้ gcloud CLI (สำหรับสาย Command Line)

ถ้าไม่อยากเปิดเว็บ แต่ยังต้องการความปลอดภัย สามารถใช้ gcloud รันจากเครื่องได้โดยตรง (ค่าที่อ่านมาจากไฟล์ไม่ค้างใน history)

gcloud secrets versions add [ชื่อ-SECRET-ของคุณ] \
    --data-file=".env" \
    --project=[PROJECT-ID]

🔥 ทำไมวิธี 3.2 ถึงเป็นที่นิยม?

  • Separation of Concerns
    ทีม Infra ดูแล Terraform
    ทีม Dev ถือและจัดการรหัสผ่าน
  • No State Leak
    Secret จะไม่ไปโผล่ใน terraform.tfstate หรือ Git Repository
  • Audit Log
    GCP บันทึกครบว่า ใคร แก้ เมื่อไหร่
    ตอบโจทย์เรื่อง Security และ Compliance มาก

🎯 เทคนิคเด็ด: Mount Secret เป็นไฟล์ใน Cloud Run

วิธีที่ปลอดภัยที่สุดไม่ใช่การดึง Secret มาเป็น Environment Variable (เพราะอาจหลุดไปใน Log ได้)

แต่คือการ Mount Secret เป็นไฟล์ เข้าไปใน Container โดยตรง แอปอ่านค่าจากไฟล์แทน

ตัวอย่างการตั้งค่าใน Terraform:

template {
  volumes {
    name = "conf-volume"
    secret {
      secret = "my-service-secrets"
      items {
        version = "latest"
        path    = ".env" # ชื่อไฟล์ที่จะไปปรากฏในเครื่อง
      }
    }
  }
  containers {
    volume_mounts {
      name       = "conf-volume"
      mount_path = "/app/configs" # โฟลเดอร์ปลายทาง
    }
  }
}

ถ้าต้องจัดการแค่ไม่กี่ service การทำผ่าน Console ก็อาจเพียงพอ แต่เมื่อจำนวน service เพิ่มขึ้น และต้องทำซ้ำบ่อย ๆ วิธีนี้จะกลายเป็นตัวช่วยที่ทรงพลังมาก
หวังว่าเทคนิคนี้จะช่วยให้การทำงานของคุณง่ายขึ้น เป็นระบบขึ้น และขอให้มีความสุขกับการทำงานครับ 🚀