การหมุนเวียนซีเคร็ตและการจัดเก็บอย่างปลอดภัย
สำหรับผู้ดูแลระบบที่ต้องการอัปเดต (หมุนเวียน) ซีเคร็ตของแอปที่ใช้งานจริงในโปรดักชันเป็นระยะ
ซีเคร็ตมีธรรมชาติที่ว่า "ยิ่งใช้ตัวเดิมนานเท่าไหร่ ความเสี่ยงที่จะรั่วไหลก็ยิ่งสะสมมากขึ้น" สมาชิกที่ลาออกไปเคยดูค่านั้นในอดีต, ปนไปกับล็อกที่พิมพ์ออกมา, หรือถูกนำออกไปพร้อมกับข้อมูลสำรอง — ล้วนเป็นช่องทางที่เป็นไปได้ทั้งสิ้น กลยุทธ์พื้นฐานคือการหมุนเวียนเป็นระยะเพื่อจำกัดขอบเขตผลกระทบจากการรั่วไหลด้วยเวลา
เกณฑ์ความถี่ในการหมุนเวียน
| เป้าหมาย | ความถี่ที่แนะนำ | สถานการณ์ที่ต้องอัปเดตทันที |
|---|---|---|
| ไคลเอนต์ซีเคร็ต | ปีละ 1 ครั้ง | สงสัยว่ารั่วไหล, มีคนลาออก, เหตุการณ์การรั่วไหล |
| Webhook ซีเคร็ต | ปีละ 1 ครั้ง | เช่นเดียวกับข้างต้น |
| แอ็กเซสโทเคน | อัตโนมัติ(1 ชั่วโมง) | ― |
| รีเฟรชโทเคน | อัตโนมัติ(90 วัน) | ― |
ขั้นตอนการหมุนเวียนไคลเอนต์ซีเคร็ต
ReceiptRoller รองรับ "ช่วงคู่ขนานระหว่างซีเคร็ตเก่ากับใหม่" จึงสามารถหมุนเวียนได้โดยไม่ต้องหยุดให้บริการ
- พอร์ทัลนักพัฒนา → แอป → ข้อมูลรับรอง (Credentials) → "ออกซีเคร็ตเพิ่ม"
- จัดเก็บซีเคร็ตใหม่อย่างปลอดภัย
- อัปเดตค่าในบริการจัดการซีเคร็ต(เช่น AWS Secrets Manager)ให้เป็นซีเคร็ตใหม่
- ดีพลอยสภาพแวดล้อมโปรดักชันตามลำดับ(หรือรีสตาร์ท rolling เพื่อให้ environment variable มีผล)
- ยืนยันจากล็อกว่าทุกสภาพแวดล้อมกำลังทำงานด้วยซีเคร็ตใหม่
- "เพิกถอน" ซีเคร็ตเก่าในพอร์ทัลนักพัฒนา
ในช่วงคู่ขนาน ซีเคร็ตทั้งสองตัวจะใช้งานได้ แม้ในระหว่างดีพลอยจะมีริเควสต์ที่ใช้ซีเคร็ตเก่าเข้ามา การยืนยันตัวตนก็จะยังผ่าน จึงสลับเปลี่ยนได้โดยไม่ต้องหยุดให้บริการ
การหมุนเวียน Webhook ซีเคร็ต
Webhook ซีเคร็ตก็สามารถใช้งานแบบช่วงคู่ขนานได้เช่นกัน หากฝั่งรับออกแบบให้ "ลองตรวจสอบลายเซ็นด้วยซีเคร็ตทั้งเก่าและใหม่" ช่วงสลับเปลี่ยนก็จะปลอดภัย
function verify(body, signature, ts) {
return verifyWith(body, signature, ts, NEW_SECRET)
|| verifyWith(body, signature, ts, OLD_SECRET);
}
หลังสลับเปลี่ยนเสร็จแล้ว ให้ลบการอ้างอิง OLD_SECRET ออกจากโค้ด
แนวปฏิบัติที่ดีในการจัดเก็บ
- ใช้บริการจัดการซีเคร็ต:AWS Secrets Manager / Azure Key Vault / GCP Secret Manager / HashiCorp Vault
- เข้ารหัส environment variable:เมื่อลงทะเบียนใน CI ให้ใช้ฟีเจอร์เข้ารหัส(GitHub Secrets, GitLab CI Variables เป็นต้น)
- ตรวจสอบการเข้าถึง:ทำให้อยู่ในสถานะที่ติดตามได้ว่าใครดึงซีเคร็ตเมื่อไหร่
- สิทธิ์ขั้นต่ำ:ซีเคร็ตโปรดักชันให้เฉพาะ service account ของโปรดักชันเท่านั้นที่ดึงได้
- ไม่รวมอยู่ในข้อมูลสำรอง:ไม่รวมซีเคร็ตไว้ในข้อมูลสำรอง DB หรือ log archive
- เพิกถอนเมื่อมีคนลาออก:ซีเคร็ตที่ผู้ลาออกเคยเข้าถึงให้หมุนเวียนทันที
สิ่งที่ไม่ควรทำ
| แอนตี้แพตเทิร์น | วิธีแก้ไข |
|---|---|
| คอมมิตไฟล์ .env เข้า git | เพิ่มใน .gitignore, ลบการปนเปื้อนในอดีตทั้งประวัติ พร้อมสร้างซีเคร็ตใหม่ |
| แชร์ซีเคร็ตทาง Slack หรืออีเมล | แชร์ผ่านบริการจัดการซีเคร็ต |
| ฝังไว้ในโค้ดฝั่งไคลเอนต์ | ย้ายไปฝั่งเซิร์ฟเวอร์, สร้างใหม่ทันที |
| พิมพ์ซีเคร็ตออกในเออเรอร์ล็อก | มาสก์ค่า, ลบล็อก, สร้างใหม่ |
| ใช้ซีเคร็ตตัวเดิมต่อเนื่องหลายปี | ตั้งการหมุนเวียนประจำปีไว้ในปฏิทิน |