
Phân quyền Claude Code cho team: settings.json an toàn mặc định
Gom permission Claude Code của cả team vào một file settings.json commit trong repo: thứ tự deny-ask-allow, pattern matching và giới hạn thật sự.
Mỗi dev trong team có một bộ permission Claude Code khác nhau, và không ai biết agent của đồng nghiệp được phép chạy gì. Người mới vào bấm "yes" suốt ngày đầu mà không hiểu prompt nào đáng quan tâm. Cách sửa: gom luật vào một file settings commit thẳng vào repo, để mọi session khởi động từ cùng một baseline.
Ba file settings, chỉ một file thuộc về team
Với một team, ba file sau là đủ:
| File | Áp dụng cho | Commit? |
|---|---|---|
.claude/settings.json | Mọi người làm việc trong repo | Có |
.claude/settings.local.json | Một dev, repo này | Không |
~/.claude/settings.json | Một dev, mọi project | Không |
File chia sẻ là nơi đặt luật của team; file local dành cho ngoại lệ cá nhân, để một dev muốn duyệt thêm một lệnh không phải sửa file chung. Khi Claude Code tự tạo file local, nó giữ file đó ngoài git; nếu ai tạo tay thì phải thêm vào .gitignore. Tổ chức cần luật không ai override được có thể dùng managed settings, nằm trên cả ba file.
Nội dung tối thiểu cho file chia sẻ
Điểm xuất phát tốt thì ngắn (ví dụ minh hoạ, thay bằng lệnh của project bạn):
{
"permissions": {
"allow": ["Bash(npm run lint)", "Bash(npm run test *)", "Bash(git status)", "Bash(git diff *)"],
"ask": ["Bash(git push *)"],
"deny": ["Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)"]
}
}
Pattern mới là thứ quan trọng. allow cho lệnh chạy hàng chục lần mỗi ngày và không gây hại: test, lint, type check, git read-only. ask cho hành động đáng để người nhìn qua: push, publish, migration local. deny cho việc đọc secret.
Các list từ nhiều file được gộp lại chứ không thay thế nhau: luật allow cá nhân cộng thêm vào list của team, nhưng không gỡ được deny của team.
deny thắng — và đó là lý do file chia sẻ đáng tin
Claude Code kiểm tra deny trước, rồi ask, rồi allow. Match đầu tiên theo thứ tự đó quyết định, và luật cụ thể hơn không đổi được thứ tự — allow không khoét được ngoại lệ ra khỏi deny. Nếu file team deny Bash(aws *), dev thêm Bash(aws s3 ls) vào allow local vẫn bị chặn.
Viết pattern đúng với ý mình
- Dấu
*khớp mọi text ở vị trí đó:Bash(npm run test *)khớpnpm run testvới mọi argument. - Khoảng trắng trước dấu
*cuối có ý nghĩa.Bash(ls *)khớplsvàls -lanhưng không khớplsof;Bash(ls*)thì khớp cảlsof. - Lệnh ghép bị tách ra: allow
Bash(npm run test *)không duyệtnpm run test && rm -rf build. Mỗi phần phải được allow riêng, và deny áp dụng nếu bất kỳ phần nào match. - Luật file dùng path:
Read(./.env)phủ một file,Read(./secrets/**)phủ mọi thứ dưới thư mục đó.
Permission rules không phải security boundary
Luật permission định hình việc agent làm gì, nhưng tự chúng không phải một lớp bảo mật. Luật Bash match theo text của lệnh mà agent viết ra; cùng chương trình đó chạy qua biến, qua script hay qua sh -c có thể không match. Tài liệu Claude Code nói thẳng: những luật cố giới hạn argument, kiểu ép curl về đúng một domain, là mong manh.
Với thứ không bao giờ được phép xảy ra, thêm lớp thứ hai. Sandboxing enforce giới hạn filesystem và network, không phụ thuộc cách viết lệnh. PreToolUse hook chạy check của bạn trước mỗi lệnh và có thể block; hook nằm trong cùng file settings chia sẻ nên cả team cùng nhận. Access control thật vẫn áp dụng: nếu agent không được chạm production, máy dev không nên giữ credential production.
Triển khai trong một PR
- Commit deny cho secret và allow cho test/lint trước — riêng hai nhóm đó đã gỡ phần lớn prompt và chặn những lần đọc rủi ro nhất.
- Đưa file vào một PR bình thường, để team review như review code.
- Nhờ dev ghi lại prompt nào họ approve quá hai lần một tuần; đó là ứng viên cho allow list chung.
- Chạy
/statusđể xác nhận file đã load — nó liệt kê các settings source đang dùng. - Review thay đổi
.claude/settings.jsoncẩn thận như review CI config — nó quyết định agent của từng dev được làm gì mà không cần hỏi.
Không spam, hủy đăng ký bất kỳ lúc nào.


