Sổ tay kỹ thuật

An toàn khi cho AI agent thao tác trên mạng thật

concept#agents#security#networking· cập nhật 2026-11-06

Lộ trình và các lớp bảo vệ (read-only trước, dry-run, approval gate, commit confirmed, audit log, giới hạn blast radius) trước khi cho agent đẩy cấu hình lên router production.

Sửa trang này
Mục lục

Agent có thể hiểu sai yêu cầu, bị prompt injection qua dữ liệu (description interface, syslog, ticket), hoặc tự tin đề xuất một lệnh sai. Trên mạng thật, một lệnh sai có thể làm mất kết nối cả site, kể cả kết nối quản trị dùng để sửa lại. Nguyên tắc: model không phải ranh giới an toàn. Mọi giới hạn phải nằm ở tầng tool, tài khoản thiết bị và quy trình, những nơi model không thể vượt qua.

Đường đi của một thay đổi

flowchart LR A["Agent đề xuất intent"] --> B["Tool sinh config + diff"] B --> C["Dry-run: commit check / check mode"] C --> D{"Người duyệt xem diff"} D -->|"từ chối"| X[Dừng] D -->|"duyệt"| E["Commit confirmed (timer)"] E --> F["Verify: BGP, interface, ping"] F -->|"OK"| G["Confirm commit"] F -->|"lỗi / hết giờ"| H["Tự rollback"] G --> I["Audit log"] H --> I

Lộ trình mở quyền

Giai đoạn Agent được làm Điều kiện để lên giai đoạn tiếp
0. Chỉ đọc show/get, NetBox, ClickHouse, log Bộ eval ổn định, không bịa số liệu
1. Đề xuất Sinh config + diff, người tự áp Diff đề xuất đúng ở đa số case, người duyệt ít phải sửa
2. Ghi trong lab Commit trên containerlab/lab Không có safety violation qua nhiều lần chạy
3. Ghi production có duyệt Đẩy thay đổi phạm vi hẹp sau approval Có rollback tự động, audit đầy đủ
4. Tự động có giới hạn Thao tác lặp lại, rủi ro thấp (description, shut port access theo ticket) Chỉ với các loại thay đổi đã whitelist

Phần lớn team chỉ nên dừng ở giai đoạn 1-3.

Các lớp bảo vệ

Lớp Cách làm cụ thể
Tool Không có tool "chạy lệnh tuỳ ý". Tool ghi nhận intent có cấu trúc (set_interface_description(device, ifname, text)), code sinh config từ template
Tách đọc / ghi Hai MCP server hoặc hai bộ credential khác nhau. Server chỉ đọc dùng user AAA read-only (task-group / login class)
Dry-run IOS XR: commit sau show commit changes diff. Junos: commit check + show | compare. Ansible: --check --diff (ví dụ)
Approval gate Người duyệt xem diff thật trên thiết bị, không xem lời mô tả của model. Ghi rõ ai duyệt
Tự rollback IOS XR commit confirmed 300 / Junos commit confirmed 5, chỉ confirm khi bước verify pass (PyEZ)
Verify sau thay đổi Script so trạng thái trước/sau: số BGP Established, interface up, prefix nhận, ping đích quan trọng
Blast radius Mỗi lần chỉ một thiết bị, giới hạn số dòng diff, cấm đụng vào interface/VRF quản trị, rollout theo canary
Thời gian Chỉ cho ghi trong maintenance window, chặn ngoài giờ ở tầng tool
Rate limit Tối đa N thay đổi mỗi giờ, quá thì dừng agent và báo người
Audit Log mọi tool call: user, phiên, input, diff, người duyệt, kết quả verify. Đẩy về syslog/SIEM tập trung
Kill switch Một flag (file, biến môi trường, feature flag) tắt toàn bộ tool ghi ngay lập tức
Host agent Claude Code: permissions.deny + hook PreToolUse chặn lệnh đẩy config (settings và hooks)

Không dùng --dangerously-skip-permissions / bypassPermissions trên máy có SSH key hoặc credential tới thiết bị production.

Prompt injection từ dữ liệu mạng

Bất kỳ trường văn bản nào có thể bị người khác sửa đều là đầu vào không tin cậy: interface description, BGP neighbor description, SNMP sysContact, syslog message, nội dung ticket, trang wiki.

  • Coi output của tool là dữ liệu, không phải lệnh. Nhắc điều này trong system prompt, nhưng không chỉ dựa vào đó.
  • Tool ghi luôn đi qua approval: dù model bị lừa thì vẫn có người chặn.
  • Phiên đọc dữ liệu không tin cậy thì không cấp tool ghi trong cùng phiên đó.
  • Lọc và cắt ngắn trường văn bản tự do trước khi trả cho model.

Mẫu tool ghi an toàn

tools/write.py
MAX_DIFF_LINES = 40
PROTECTED = ("MgmtEth0/RP0/CPU0/0", "fxp0", "em0")
 
 
def propose_change(device: str, intent: dict) -> dict:
    """Chỉ sinh config + diff, không commit. Trả change_id để người duyệt."""
    config = render_template(intent)                 # template, không nhận config tự do từ model
    if any(p in config for p in PROTECTED):
        raise PermissionError("Không được thay đổi interface quản trị")
    diff = device_dry_run(device, config)            # commit check / show commit changes diff
    if len(diff.splitlines()) > MAX_DIFF_LINES:
        raise ValueError(f"Diff {len(diff.splitlines())} dòng, vượt giới hạn {MAX_DIFF_LINES}")
    change_id = save_pending(device, config, diff)   # lưu, chờ duyệt
    audit("propose", device=device, change_id=change_id, diff=diff)
    return {"change_id": change_id, "diff": diff, "status": "pending_approval"}
 
 
def apply_change(change_id: str, approver: str) -> dict:
    """Chỉ gọi được từ UI/CLI của người duyệt, KHÔNG expose cho model."""
    change = load_pending(change_id)
    commit_confirmed(change.device, change.config, minutes=5)
    ok = verify(change.device)
    (confirm if ok else rollback)(change.device)
    audit("apply", change_id=change_id, approver=approver, verified=ok)
    return {"applied": ok}

Các hàm render_template, device_dry_run, commit_confirmed... là phần bạn tự hiện thực bằng NETCONF/PyEZ/Ansible. Điểm chính: apply_change không nằm trong danh sách tool của agent.

Khi nào dùng

  • Trước khi viết tool ghi đầu tiên cho agent: dùng bảng lộ trình để thống nhất với team đang ở giai đoạn nào.
  • Khi review một MCP server hoặc agent mới cho mạng: đối chiếu với bảng các lớp bảo vệ.
  • Kết hợp với thiết kế tool và pipeline network CI/CD: thay đổi do agent đề xuất nên đi qua cùng pipeline với thay đổi do người viết.