Hướng dẫn sử dụng Tailscale ACLs để triển khai mô hình Zero Trust: Phân quyền truy cập chi tiết cho từng User và thiết bị

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Câu chuyện quen thuộc: VPN truyền thống và cái bẫy “tin tưởng nội mạng”

Mình từng setup mạng nội bộ theo kiểu cổ điển: cài OpenVPN, ai cần truy cập server thì cấp tài khoản VPN. Đơn giản, nhanh, hiệu quả. Ít nhất là mình nghĩ vậy, cho đến khi một nhân viên part-time vô tình “khám phá” được database server production — vì anh ấy kết nối cùng mạng VPN với team backend.

Không phải anh ấy cố ý. Không ai cài backdoor gì cả. Nhưng khi mọi người đều ở trong cùng một “mạng tin cậy”, ranh giới giữa “được phép” và “không được phép” trở nên mờ nhạt. Khi bạn đã “vào mạng”, VPN truyền thống gần như bỏ qua mọi câu hỏi tiếp theo.

Đó chính xác là vấn đề mà Zero Trust ra đời để giải quyết. Và Tailscale ACLs là cách mình đang áp dụng triết lý đó vào thực tế, mà không cần cả đội phải học thêm gì phức tạp.

Zero Trust và Tailscale ACLs là gì?

Zero Trust — Không tin ai, dù đang ở “trong nhà”

Zero Trust là triết lý bảo mật với nguyên tắc cực kỳ đơn giản: không tự động tin tưởng bất kỳ thiết bị hay user nào, dù họ đang ở trong mạng nội bộ. Mỗi kết nối đều phải được xác thực và phân quyền rõ ràng.

Thay vì hỏi “ai cần bị chặn?”, Zero Trust đảo ngược câu hỏi thành “ai thực sự được phép?”. Sự đảo ngược đơn giản đó thay đổi hoàn toàn cách bạn thiết kế mạng nội bộ.

Tailscale ACLs — Bộ lọc kết nối cực kỳ linh hoạt

Tailscale tạo ra một mesh network riêng tư (overlay network) dựa trên WireGuard. Mọi thiết bị trong tailnet đều có địa chỉ IP 100.x.x.x cố định, nhận diện rõ ràng theo danh tính — không phải theo vị trí mạng.

ACLs trong Tailscale được viết bằng HuJSON (JSON có hỗ trợ comment), cho phép bạn định nghĩa:

  • Groups: nhóm user theo vai trò (dev, ops, intern…)
  • Tags: nhóm thiết bị theo loại (server, database, staging…)
  • ACL rules: ai được kết nối đến đâu, port nào
  • SSH rules: phân quyền SSH chi tiết đến từng Linux user

Quan trọng nhất: Tailscale hoạt động theo kiểu deny-by-default. Nếu không có rule nào khớp, kết nối bị chặn. Bạn chỉ cần lo viết đúng rule — không cần lo bị “hở”.

Thực hành: Cấu hình Tailscale ACLs từ đầu

Bước 1: Hiểu cấu trúc file ACL cơ bản

File ACL được quản lý tại Tailscale Admin Console → Access Controls. Đây là bộ khung mình dùng làm điểm xuất phát:

{
  // Định nghĩa nhóm user theo email
  "groups": {
    "group:dev": ["[email protected]", "[email protected]"],
    "group:ops": ["[email protected]"],
    "group:intern": ["[email protected]"]
  },

  // Ai có quyền gán tag cho thiết bị
  "tagOwners": {
    "tag:prod-server": ["group:ops"],
    "tag:prod-db": ["group:ops"],
    "tag:staging": ["group:ops"],
    "tag:dev-tools": ["group:ops", "group:dev"]
  },

  // ACL rules: src → dst:port
  "acls": [
    // Ops: full access
    {
      "action": "accept",
      "src": ["group:ops"],
      "dst": ["*:*"]
    },
    // Dev: SSH vào prod server (không phải DB) + full staging
    {
      "action": "accept",
      "src": ["group:dev"],
      "dst": [
        "tag:prod-server:22",
        "tag:prod-server:8080",
        "tag:staging:*",
        "tag:dev-tools:*"
      ]
    },
    // Intern: chỉ staging web ports
    {
      "action": "accept",
      "src": ["group:intern"],
      "dst": ["tag:staging:80", "tag:staging:443", "tag:staging:3000"]
    }
  ]
}

Lưu ý: tag:prod-db không xuất hiện trong rules của group:dev hay group:intern. Điều đó có nghĩa là họ không thể chạm vào database, dù cùng tailnet.

Bước 2: Tag thiết bị — Gắn nhãn server theo vai trò

Khi thêm server vào tailnet, bạn cần gán tag. Tag thay thế địa chỉ IP trong rules — khi IP server thay đổi, rules vẫn đúng.

# Khởi động Tailscale trên server production với tag
tailscale up --advertise-tags="tag:prod-server"

# Trên database server
tailscale up --advertise-tags="tag:prod-db"

# Trên staging server
tailscale up --advertise-tags="tag:staging"

# Kiểm tra thiết bị đang có tag gì
tailscale status --json | jq '.Self.Tags'

# Xem toàn bộ thiết bị trong tailnet
tailscale status

Nếu server dùng systemd, bạn cần ghi tag vào file cấu hình để persistent qua reboot:

# Tạo file override cho tailscaled
sudo mkdir -p /etc/systemd/system/tailscaled.service.d/
sudo nano /etc/systemd/system/tailscaled.service.d/override.conf

Bước 3: Ví dụ ACL hoàn chỉnh cho team nhỏ

Mình có setup thực tế với 3 nhóm user và 4 loại server. Đây là ACL đang chạy (đã thay email thật):

{
  "groups": {
    "group:backend-dev": [
      "[email protected]",
      "[email protected]"
    ],
    "group:frontend-dev": [
      "[email protected]"
    ],
    "group:sysops": [
      "[email protected]"
    ]
  },

  "tagOwners": {
    "tag:prod-server": ["group:sysops"],
    "tag:prod-db":     ["group:sysops"],
    "tag:staging":     ["group:sysops"],
    "tag:dev-tools":   ["group:sysops", "group:backend-dev"]
  },

  "acls": [
    // SysOps: full access không giới hạn
    {
      "action": "accept",
      "src": ["group:sysops"],
      "dst": ["*:*"]
    },
    // Backend dev: staging full + prod server SSH port 2222 + API 8080
    {
      "action": "accept",
      "src": ["group:backend-dev"],
      "dst": [
        "tag:staging:*",
        "tag:prod-server:2222",
        "tag:prod-server:8080",
        "tag:dev-tools:*"
      ]
    },
    // Frontend dev: chỉ web ports của staging và dev-tools
    {
      "action": "accept",
      "src": ["group:frontend-dev"],
      "dst": [
        "tag:staging:80",
        "tag:staging:443",
        "tag:staging:3000",
        "tag:dev-tools:80",
        "tag:dev-tools:443"
      ]
    }
  ],

  // SSH rules: kiểm soát Linux user được phép đăng nhập
  "ssh": [
    {
      "action": "accept",
      "src": ["group:sysops"],
      "dst": ["tag:prod-server", "tag:staging"],
      "users": ["root", "ubuntu", "deploy"]
    },
    {
      "action": "accept",
      "src": ["group:backend-dev"],
      "dst": ["tag:staging"],
      "users": ["deploy"]
    }
  ]
}

Bước 4: Phân biệt thiết bị công ty và thiết bị cá nhân

Khi team làm remote, nhân viên hay dùng máy cá nhân. Tailscale giải quyết bằng cách dùng tag để đánh dấu thiết bị công ty — và chỉ sysops mới gán được tag đó:

{
  "tagOwners": {
    // Chỉ sysops gán được tag này → chỉ thiết bị công ty mới có
    "tag:company-device": ["group:sysops"]
  },

  "acls": [
    // Production chỉ dành cho company device
    {
      "action": "accept",
      "src": ["tag:company-device"],
      "dst": ["tag:prod-server:*", "tag:prod-db:5432"]
    },
    // Personal device (máy cá nhân của dev) chỉ vào staging
    {
      "action": "accept",
      "src": ["group:backend-dev"],
      "dst": ["tag:staging:*"]
    }
  ]
}

Bước 5: Kiểm tra ACL trước khi apply

Tailscale Admin Console có tính năng “Preview rules” để simulate — hãy dùng trước khi save. Sau khi apply, test thực tế:

# Từ máy của backend dev — thử ping vào prod-db (phải timeout/fail)
ping 100.x.x.x   # IP của prod-db

# Thử SSH vào staging với user deploy (phải thành công)
ssh [email protected]

# Debug: kiểm tra kết nối có được phép không
tailscale debug access \
  [email protected] \
  --dst=100.x.x.x:5432

# Xem log Tailscale để debug nếu cần
journalctl -u tailscaled -f

Khi thiết lập các service account trên server production, mình tạo password mạnh ngẫu nhiên bằng password generator tại toolcraft.app — công cụ chạy 100% trên trình duyệt nên không lo mật khẩu bị gửi đi đâu qua mạng. Nhỏ nhưng quan trọng khi bạn đang cố xây một hệ thống Zero Trust thật sự.

Một số lưu ý khi vận hành thực tế

  • Không dùng wildcard cho production DB: "tag:prod-db:*" mở toàn bộ port. Hãy khai báo rõ tag:prod-db:5432 (PostgreSQL) hoặc tag:prod-db:3306 (MySQL).
  • Review ACL định kỳ: Nhân viên off-board hay bị quên xóa khỏi group. Đặt reminder mỗi quý để audit lại danh sách user.
  • Version control ACL bằng Git: Admin Console không lưu lịch sử đầy đủ. Copy ACL JSON vào private repo, commit mỗi lần thay đổi.
  • Test trước khi save: Dùng tính năng Preview trong Admin Console — một rule sai có thể block toàn bộ team khỏi server production.
  • Đặt tên group rõ nghĩa: group:backend-dev tốt hơn group:team-a. Khi audit 6 tháng sau, bạn sẽ biết ơn chính mình.

Kết luận

Tailscale ACLs biến VPN từ công cụ “mở cửa vào nhà” thành hệ thống phân quyền chi tiết đến từng cửa phòng, từng ổ khóa. Setup ban đầu mất khoảng 1-2 giờ, nhưng đổi lại bạn có một mô hình bảo mật rõ ràng, dễ audit, và quan trọng hơn — dễ giải thích cho cả team kể cả những người không làm kỹ thuật.

Điểm mạnh thực sự của cách tiếp cận này không nằm ở công nghệ mà ở tư duy: buộc bạn phải trả lời câu hỏi “ai thực sự cần quyền này?” thay vì “ai cần bị chặn?”. Và câu hỏi đó, theo kinh nghiệm của mình, là nền tảng của mọi hệ thống bảo mật thật sự hoạt động được.

Share: