675 คำ
3 นาที
เมื่อผมอยากทำซอฟต์แวร์ใช้เอง ภาค 2 ตอนที่ 5: agent ไม่ใช่ตัวเรา
สารบัญ

ตอนที่แล้ว กฎของบ้านที่ระบบคุม เราได้กฎที่ระบบบังคับเอง

ตอนนี้เราจะให้ agent มีตัวตนของตัวเอง ออกมาเป็นตารางตัวตนและสิทธิ์

ตอนหน้าลูกค้าจริงเริ่มส่งงานมา ตารางนี้จะบอกว่าใครหยิบงานไหนได้

ทุกบทความในซีรีส์นี้มาจากการที่ผมคุยกับ AI แล้วค้นข้อมูลเพิ่มเติม ผมเป็นคนกำหนดทิศทาง ให้ AI ช่วยสรุป วิเคราะห์ และเรียบเรียงออกมาเป็นบทความครับ

เราอยู่ตรงไหนของแผนที่#

ยังอยู่ขั้นที่ 3 จาก 5 คือ Build

ตัวตนเป็นพื้นที่ทุกอย่างใน Build ยืนอยู่

ชิ้นจิ๊กซอว์ของตอนนี้คือเรื่องที่ 9 เครื่อง บัญชี และตัวตน กับเรื่องที่ 10 secret และสิทธิ์ บวกพื้นฐานของเรื่องที่ 22 ความปลอดภัย รวมถึงของ agent

ตอนนี้ปิดช่วงที่ 1 ช่วงก่อนมีลูกค้า

หัวใจของตอนนี้#

ประโยคเดียวพอครับ

ถ้า agent ใช้ตัวตนของเรา มันก็คือเรา

ทำไมเรื่องนี้สำคัญ?#

ตอน 4 เรามีสามอย่าง กฎที่เขียนไว้ ระบบที่บังคับ และ log

ทั้งสามอย่างใช้ได้ก็ต่อเมื่อรู้ว่าใครเป็นคนทำ

ถ้า agent ถือกุญแจของเจ้าของ branch protection ก็กันอะไรไม่ได้มาก

ถ้า log ทุกบรรทัดเขียนว่า “ต้น” log ก็ตอบไม่ได้ว่าใครทำ

ทางแก้คือ agent ทุกตัวมีชื่อ กุญแจ และวันหมดอายุของตัวเอง กับสิทธิ์เท่าที่งานต้องใช้

หลัก 6 ข้อข้างล่างคือวิธีไปให้ถึงตรงนั้น

คืนที่ log บอกว่าต้นทำ#

agent ของต้นใช้ GitHub login ของต้น กับ personal token ของต้น

API key อยู่ใน .env และเคยแปะ key ลงใน chat ไปครั้งหนึ่ง (ตัวอย่าง)

คืนหนึ่งมี commit ลบไฟล์ migration ทิ้ง

log เขียนว่า “ต้น”

แต่ต้นหลับอยู่

log สองแบบ ฝั่งซ้ายบอกไม่ได้ว่าใครทำ ทุกบรรทัดเขียนว่าต้น ทั้ง commit ลบ migration และ deploy ใครทำจริง ฝั่งขวาบอกได้ เหตุการณ์เดียวกันขึ้นชื่อ agent-build agent-deploy ที่ขออนุมัติ และต้นอนุมัติ

เรื่องแบบนี้เกิดจริง

@adriaandotcom โพสต์ไว้ว่า “Codex pushed to “main” without my permission, triggering a deploy to production.”

และ “It was able to reuse my existing GitHub credentials, giving it the same publishing access I have.”

agent ใช้ตัวตนเขา มันก็คือเขา

และถ้า key ตัวเดียวหลุด มันเปิดได้ทุกอย่าง

หลัก 1: agent มีตัวตนของตัวเอง#

ข้อนี้ตอบหัวใจตรงที่สุด ถ้า agent ไม่ใช้ตัวตนเรา มันก็ไม่ใช่เรา

GitHub เรียกบัญชีที่สร้างไว้ “to automate activity” ว่า machine user

ส่วน GitHub App “can act independently of a user” และ “indicate that the action was performed by the app on behalf of the user”

หน้า personal access token เขียนว่า token แบบนี้ “intended to access GitHub resources on behalf of yourself”

ถ้าเป็นงานยาวๆ “you should use a GitHub App”

แปลว่า personal token ของต้นที่ agent ใช้อยู่ คือตัวตนของต้นจริงๆ

หลัก 2: สิทธิ์น้อยที่สุด กุญแจห้อง ไม่ใช่กุญแจผี#

ต่อให้ agent มีชื่อของตัวเอง ถ้าได้สิทธิ์ทุกอย่างเท่าเรา มันก็ทำได้ทุกอย่างที่เราทำ เกือบเป็นเราอยู่ดี

NIST นิยาม least privilege ว่าจำกัดสิทธิ์ “to the minimum necessary to accomplish assigned tasks”

OWASP เรื่อง Excessive Agency บอกว่าต้นเหตุคือ “excessive functionality; excessive permissions; excessive autonomy”

ภาค 1 เราเห็นแล้วว่ากฎใน prompt ถูกลืมได้

สิทธิ์ที่ไม่มี ใช้ไม่ได้

กุญแจผีดอกเดียวเปิดได้ทุกประตู เทียบกับกุญแจห้องละดอกของ agent-build agent-review และ CI พร้อมวันหมดอายุ ข้างล่างเป็นวงจร สร้าง จำกัด ใช้ หมุน เพิกถอน วนกลับผ่านทะเบียนกุญแจ

หลัก 3: กุญแจอายุสั้น ขอบเขตแคบ#

กุญแจที่ไม่มีวันหมดอายุ ใครได้ไปก็เป็นเราได้ตลอดไป

GitHub มี fine-grained token จำกัดได้ทีละ repo ทีละสิทธิ์ ตั้งวันหมดอายุได้ ตัวอย่างในหน้า docs ของ GitHub เองใช้ 45 วัน

ใน API ตั้งวันหมดอายุได้ “between 1 and 366, or none”

ฝั่ง OAuth app ในหน้า GitHub Apps เขียนว่า token “do not expire until the person who authorized the OAuth app revokes the token”

ต้นเลยทำทะเบียนกุญแจ (ตัวอย่าง) มีช่อง key, agent, scope, วันหมดอายุ และใช้ที่ไหน

สงสัยเมื่อไหร่ หมุนหรือเพิกถอนเลย

หลัก 4: secret ไม่อยู่ใน chat ไม่อยู่ใน code#

secret ที่ agent อ่านได้ ก็หลุดออกไปพร้อมตัวตนเราได้

ให้ agent ใช้ secret ได้ แต่ไม่ต้องเห็น

Kent C. Dodds โพสต์ว่าเขาเก็บ secret ไว้ “somewhere agents can use them, but can’t get them”

ตัวอย่างวิธี เช่น secret store ของ platform ที่ใส่ให้ตอน runtime, OAuth connector, .env อยู่ใน .gitignore และไม่แปะ key ลง chat

secret scanning ใน pre-commit หรือ CI ก็ต่อกับกฎของตอน 4 ได้เลย

หลัก 5: agent เสนอ คนอนุมัติ เมื่อเสี่ยงสูง#

งานที่เสี่ยงสูงต้องมีคนจริงกดยืนยัน ไม่ใช่ให้ agent กดแทนในนามเรา

OWASP แนะนำให้ “require a human to approve high-impact actions before they are taken”

EU AI Act มาตรา 14 ให้คนต้องดู ขัด ย้อน และหยุดระบบได้ ข้อนี้เขียนไว้สำหรับ AI ความเสี่ยงสูง ผมยืมมาใช้เป็นหลักคิดเท่านั้น

รายการที่ต้องรอต้นเสมอ (ตัวอย่าง) ลบข้อมูล จ่ายเงิน ส่งอะไรถึงลูกค้า และแตะ secret ของ prod

แต่ถ้ามีคนเดียว ใครอนุมัติงานของคนเขียนเอง? เก็บไว้ตอน 7 กับตอน 10

หลัก 6: log บอกว่า agent ตัวไหนทำอะไร#

ข้อนี้คือผลของหัวใจ พอ agent ไม่ใช่เรา log ก็แยกได้ว่าใครทำ

พอแยกตัวตน log ของ GitHub จะขึ้นว่า app ตัวไหนทำ

คืนที่ migration หายไป ถ้าแยกตัวตนไว้แล้ว บรรทัดนั้นจะขึ้นว่า agent-build ไม่ใช่ต้น

AuditBadger เขียนว่า audit trail ที่ดี “records the token, the change set and the approver”

log ของ agent แบบเต็มๆ เก็บไว้ตอน 10

ตารางตัวตนและสิทธิ์ของต้นหน้าตาเป็นยังไง?#

ตารางตัวตนและสิทธิ์แบบย่อ สามคอลัมน์ ใคร ทำอะไรได้ ต้องอนุมัติ ต้นเจ้าของทำได้ทุกอย่าง งานเสี่ยงสูงรอตอน 7 agent-build เปิด PR ใน app repo ต้น merge agent-review อ่านและ comment ไม่ต้อง agent-deploy deploy preview prod ต้องรอต้น CI รัน check ไม่ต้อง หัวตารางรับมาจากกฎของบ้านตอน 4 ท้ายตารางส่งต่อให้ตอน 6 7 และ 10 ตารางเต็มอยู่ด้านล่างในบทความ

ตารางของต้น (ตัวอย่าง)

ใครทำอะไรได้กุญแจ / scopeหมดอายุต้องอนุมัติ
ต้นเจ้าของ ทำได้ทุกอย่างpasskeyไม่มีงานเสี่ยงสูงรอตอน 7
agent-buildเปิด PR ใน app repotoken เฉพาะ repo30 วันต้น merge
agent-reviewอ่านและ commentread only30 วันไม่ต้อง
agent-deploydeploy previewpreview เท่านั้น30 วันprod ต้องรอต้น
CIรัน checksecret ใส่ตอน runtime ไม่มี login คนตาม runไม่ต้อง

ทุกแถวตอบได้ว่าใครทำ และใครอนุมัติงานเสี่ยงสูง

มาตรฐานว่ายังไง

29110 Basic มี Annex D เพิ่มงานด้านความปลอดภัย

12207 มี Infrastructure Management อยู่ในกลุ่ม Organizational project-enabling processes

ISO 27001 กับ SOC 2 มีหมวดเรื่อง access control ทั้งคู่

ข้อนี้ผมเทียบเอง ตารางของต้นก็คือบันทึก access control ที่บริษัทใหญ่เก็บไว้นั่นแหละครับ

จิ๊กซอว์ชิ้นที่เติมแล้ว#

ชิ้นที่ 4 ตัวตนและสิทธิ์ เติมแล้ว ช่วงที่ 1 จบ

ตอนนี้ต้นมีหน้า requirement แผนออกแบบ กฎของบ้าน และตารางตัวตน

ต้นพร้อมแล้ว แต่ยังไม่มีลูกค้า

ชิ้นถัดไปคือรับงานจากลูกค้า

สิ่งที่ผมได้จากตอนนี้#

ลองทำเอง#

ใช้ test repo ทิ้งได้เท่านั้น สร้าง fine-grained token (หรือบัญชีแยก หรือ GitHub App) ให้ agent ใช้กับ repo เดียว สิทธิ์ contents กับ pull requests หมดอายุ 30 วัน เปิด 2FA หรือ passkey ในบัญชีตัวเอง สั่ง agent เปิด PR (ควรได้) แล้วสั่ง push ไป repo อื่น (ควรพัง) จากนั้นเพิกถอน token

ผมลองแล้ว: __ นาที ฿0 ใช้แบบ __ แตะ repo อื่นได้ข้อความ ’__’ เพิกถอนแล้วมีผลทันที __

เก็บศัพท์#

คำความหมายสั้นๆ
identityตัวตนที่ระบบใช้บอกว่าใครทำ
machine userบัญชีที่สร้างไว้ให้งานอัตโนมัติ
GitHub Appตัวตนของ app ที่ทำงานแยกจากคน
least privilegeให้สิทธิ์น้อยที่สุดเท่าที่งานต้องใช้
fine-grained tokentoken ที่จำกัด repo และสิทธิ์ได้ละเอียด
scopeขอบเขตที่กุญแจเปิดได้
expiryวันหมดอายุของกุญแจ
secretข้อมูลลับ เช่น key และ password
rotateเปลี่ยนกุญแจใหม่
revokeเพิกถอนกุญแจ
excessive agencyagent ทำได้มากเกินกว่างาน
human-in-the-loopให้คนอนุมัติก่อนงานสำคัญ

จดบันทึก#

agent ทุกตัวมีชื่อ กุญแจ และวันหมดอายุของตัวเอง

ถ้าต้นเริ่มใหม่ เขาจะทำเรื่องนี้ตั้งแต่วันแรกไหม?

ทำ ข้อนี้แก้ทีหลังแพงที่สุด ตัวตนแยกของ agent กุญแจที่จำกัดขอบเขตและหมดอายุ และ secret store ตั้งแต่วันแรก ใช้ราว 1 ถึง 2 ชั่วโมง ฿0 (ตัวอย่าง) ถ้ามาแก้ทีหลัง ต้องหมุนกุญแจทุกดอก และ log เก่าก็ยังตอบไม่ได้ว่าใครทำ

ตอนต่อไป#

เพื่อนสามคนกลายเป็นลูกค้า

วันเดียวส่งงานมาทาง LINE, email และ X (ตัวอย่าง)

ใครหยิบงานไหน ตารางตอนนี้จะได้ใช้

ลูกค้าส่งงานมาท่วม

คำถามที่พบบ่อย#

bot account หรือ GitHub App ดีกว่า?

agent ที่ใช้ยาวๆ ใช้ GitHub App ส่วน bot account ง่ายกว่า แต่เป็นบัญชีเต็มที่ต้องดูแลเอง

ใช้ token เดียวกับทุก agent ได้ไหม?

ไม่ควร จะแยกไม่ได้ว่าใครทำ และเพิกถอนทีละตัวไม่ได้

agent ต้องเห็นไฟล์ .env ไหม?

ไม่ต้อง ให้ใช้ secret ได้โดยไม่เห็นค่า

ทำคนเดียวต้องมีขั้นอนุมัติไหม?

ต้องมีสำหรับงานเสี่ยงสูง วิธีทำเก็บไว้ตอน 7

Next → ภาค 2 ตอนที่ 6: ลูกค้าส่งงานมาท่วม