Bảo mật và cô lập tenant
Mô hình đe dọa của chính Access Hub Scanner: một công cụ bảo mật chạy đặc quyền trên hàng nghìn máy khách hàng, đọc cả nội dung tệp chứa bí mật và dữ liệu cá nhân, là mục tiêu hấp dẫn. Access Hub Scanner không đi qua Access Hub Agent hay Access Hub Collector (Q25, ADR 0001); mô hình đe dọa của hai sản phẩm đó (access-hub-collector/docs/07-security.md, access-hub-agent/docs/05-security.md) chỉ là tham khảo cho các phần Scanner chép mẫu (enroll, backoff). Tài liệu này nêu đủ phần của Scanner: bộ đọc, bộ gửi, vai trò ingest, matcher.
1. Tài sản
| Tài sản | Vì sao quan trọng |
|---|---|
| Máy chủ khách hàng | Scanner đọc được mọi tệp; nếu bị chiếm hoặc có lỗi, nó là cửa ngõ đặc quyền |
| Danh sách gói, kết quả kiểm tra, finding | Bản đồ điểm yếu của khách hàng: lộ ra là kẻ tấn công biết đánh vào đâu |
| DB lỗ hổng và khóa ký | DB bị đầu độc thì giấu lỗ hổng thật hoặc gây báo động giả hàng loạt |
| Ngoại lệ | Lạm dụng để giấu rủi ro khỏi lãnh đạo, kiểm toán |
| Bí mật và dữ liệu cá nhân trên máy | Scanner đọc chúng vào bộ nhớ khi quét nội dung; chúng không bao giờ được rời máy (ADR 0011) |
| Vị trí bí mật và dữ liệu cá nhân (finding nội dung) | Bản đồ cho kẻ tấn công: biết tệp nào trên máy nào chứa khóa cloud, tệp nào chứa danh sách khách hàng |
Khóa fingerprint K_host, K_company | Lộ khóa cho phép thử đoán giá trị có không gian nhỏ khi có fingerprint |
| Kênh cấu hình quét | Nếu cho phép quá nhiều, thành kênh điều khiển máy |
2. Quyền trên máy
2.1 Cần gì
| Dữ liệu | Quyền tối thiểu |
|---|---|
/var/lib/dpkg/status, /etc/os-release, /proc/net/*, /proc/sys/*, phần lớn /etc | Người dùng thường |
| rpmdb | Thường đọc được bởi mọi người, cần kiểm chứng theo distro (S4) |
/etc/shadow, /etc/gshadow, /etc/sudoers, /etc/sudoers.d/*, sshd_config trên một số distro, thư mục bị giới hạn khi duyệt tệp | Đọc tệp bỏ qua quyền: CAP_DAC_READ_SEARCH |
Nội dung tệp trong phạm vi quét nội dung, gồm thư mục nhà (/home, /root) | CAP_DAC_READ_SEARCH cộng ProtectHome=read-only chỉ ở unit nội dung (ADR 0009 mục 6) |
| Trạng thái dịch vụ (P6, nếu Q44 đồng ý) | Phương thức chỉ đọc của systemd qua D-Bus hệ thống (AF_UNIX), không cần capability thêm |
| Ánh xạ cổng sang tiến trình | Truy cập /proc/<pid>/fd của tiến trình khác: cần quyền kiểu ptrace (CAP_SYS_PTRACE), mạnh hơn nhiều. Mặc định không cấp (Q17) |
| Danh sách luật tường lửa | CAP_NET_ADMIN (cũng cho phép sửa luật). Mặc định không cấp (Q16) |
2.2 Phương án
| Phương án | Đánh giá |
|---|---|
| Chạy root đầy đủ | Đơn giản, nhưng lỗi parser thành chiếm máy với mọi quyền. Không chọn |
Tài khoản accesshub-scanner + ambient CAP_DAC_READ_SEARCH, bounding set chỉ gồm capability đó | Khuyến nghị. Đọc được mọi tệp, không ghi được tệp hệ thống, không đổi chủ sở hữu, không nạp module, không có mạng |
Root nhưng CapabilityBoundingSet=CAP_DAC_READ_SEARCH | Dự phòng cho kernel không hỗ trợ ambient capability. Vẫn là uid 0 (sở hữu nhiều tệp), phải dựa vào ProtectSystem=strict để chặn ghi. Cần kiểm chứng trên CentOS 7 (kernel 3.10, systemd 219 thiếu nhiều chỉ thị bảo vệ) ở spike S4 |
2.3 Unit đề xuất (accesshub-scanner.service, chạy bởi accesshub-scanner.timer)
[Service]
Type=oneshot
User=accesshub-scanner
Group=accesshub-scanner
AmbientCapabilities=CAP_DAC_READ_SEARCH
CapabilityBoundingSet=CAP_DAC_READ_SEARCH
NoNewPrivileges=yes
ExecStart=/usr/bin/accesshub-scanner scan
StateDirectory=accesshub-scanner
LogsDirectory=accesshub-scanner
ReadWritePaths=/var/lib/accesshub-scanner /var/log/accesshub-scanner
UMask=0027
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
ProtectClock=yes
ProtectHostname=yes
LockPersonality=yes
MemoryDenyWriteExecute=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_UNIX
IPAddressDeny=any
SystemCallArchitectures=native
SystemCallFilter=@system-service
MemoryMax=192M
CPUQuota=50%
Nice=19
IOSchedulingClass=idle
LimitCORE=0
TimeoutStartSec=15min2.3b Unit lượt nội dung (accesshub-scanner-content.service, chạy bởi accesshub-scanner-content.timer trong khung giờ yên tĩnh)
Giống unit trên, khác ở các dòng sau (ADR 0009):
[Service]
ExecStart=/usr/bin/accesshub-scanner scan --content
ProtectHome=read-only
MemoryMax=256M
CPUQuota=25%
LimitCORE=0
TimeoutStartSec=4h
# Giới hạn băng thông IO theo thiết bị (tùy chọn, cgroup v2), đo ở S9:
# IOReadBandwidthMax=/ 16MTimeoutStartSec là lưới an toàn; scanner tự dừng khi hết khung giờ, hết ngân sách CPU hoặc byte (SNFR-12, SNFR-14).
Ghi chú:
- Không dùng
PrivateNetwork=yes:/proc/net/tcphiển thị socket của network namespace của tiến trình đọc, namespace riêng sẽ làm danh sách cổng nghe rỗng. Chặn mạng bằngRestrictAddressFamilies=AF_UNIXcộngIPAddressDeny=any. ProtectHome=yesở unit siêu dữ liệu khớp với việc kiểm traAHS-FS-*không duyệt thư mục nhà (05mục 5). Chỉ unit nội dung được đọc thư mục nhà, và chỉ đọc.LimitCORE=0ở cả hai unit: tiến trình giữ bí mật trong bộ nhớ không để lại core dump.- Bộ chỉ thị tham khảo unit của Agent (chép, không phụ thuộc); bộ gửi
accesshub-scan-uploadercó unit riêng: không capability,RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX,ProtectSystem=strict,ProtectHome=yes, chỉ ghi/var/lib/accesshub-scan-uploader,MemoryMax=32M. systemd cũ bỏ qua chỉ thị không biết kèm cảnh báo, nên mức bảo vệ thực tế phải đo theo distro (S4).
2.4 Đầu vào không tin cậy ngay trên máy
Scanner đặc quyền đọc tệp mà người khác có thể ảnh hưởng. Biện pháp:
- Duyệt tệp chỉ
lstat, không theo symlink, không đọc nội dung. - Mở tệp cấu hình bằng
O_NOFOLLOWkhi đường dẫn không được là symlink; với tệp nhạy cảm (sshd, sudoers, PAM) kiểm tra chủ sở hữu là root trước khi phân tích; tệp do người khác sở hữu thì báofailở kiểm tra quyền thay vì tin nội dung. - Mọi parser (dpkg status, rpmdb, apk,
sshd_config,sudoers,login.defs, PAM,mountinfo) có giới hạn kích thước đọc, độ sâuInclude, số dòng, và được fuzz trong CI (11). - Cấu hình từ trung tâm (
config.pb) được kiểm tra lại ở bộ đọc dù ingest và bộ gửi đã kiểm tra. - Quét nội dung: chỉ mở tệp thường,
O_NOFOLLOW | O_NONBLOCK,fstatsau khi mở để chắc vẫn là tệp đãlstat(chống đổi tệp giữa chừng), không mở FIFO, socket, thiết bị; regex là RE2 (thời gian tuyến tính, không ReDoS); bộ phân tích PEM, OpenSSH, JSON, YAML, OOXML có giới hạn kích thước, độ sâu, số phần tử, tỷ lệ nén; tất cả được fuzz. - Kẻ tấn công cục bộ có thể cố tình rải chuỗi giống bí mật để làm nhiễu (gây dương tính giả) hoặc tạo cây thư mục rất lớn để tiêu hết ngân sách: trần số mục, điểm dừng, độ phủ được báo cáo; không ảnh hưởng an toàn của máy.
3. Mô hình đe dọa (STRIDE rút gọn)
| Đe dọa | Kịch bản | Biện pháp |
|---|---|---|
| Spoofing | Máy A gửi báo cáo nhận là máy B hoặc công ty khác | Danh tính chỉ từ chữ ký Ed25519 của máy Scanner tra trong registry (host_id); trường danh tính trong payload bị bỏ (07 mục 1, 3.0) |
| Spoofing | Lấy mã enroll để gắn máy lạ vào công ty | Mã một lần dùng, hết hạn 24 giờ, băm trong Access Hub, chỉ người có security.hosts.manage tạo; enroll đếm vào hạn mức và ghi audit; máy mới hiện trên trang máy Scanner để thu hồi |
| Elevation | Chiếm bộ gửi (có mạng) để đọc tệp của máy | Bộ gửi không capability, không đọc gì ngoài spool và thư mục của mình (systemd); khóa máy Scanner bị lộ chỉ cho gửi báo cáo giả của đúng máy đó, thu hồi trong Access Hub |
| Tampering | Kẻ có root trên máy sửa scanner hoặc báo cáo để giấu gói | Không ngăn được với kẻ đã có root. Phát hiện: inventory giảm đột ngột quá 50%, phiên bản scanner lùi, kernel_running khác kernel mà giám sát báo cho cùng Server (chỉ khi khách hàng có cả hai sản phẩm), chỉ gửi HASH_ONLY quá lâu trong khi kiểm kê Agent đổi. Finding hiển thị nhãn "tự báo cáo" |
| Tampering | Đầu độc DB lỗ hổng (CDN, nguồn upstream, pipeline dựng) | Chữ ký Ed25519 khóa riêng trong KMS hoặc HSM; kiểm tra hợp lý (số bản ghi không giảm quá 5%); bản cập nhật làm đóng hơn 1.000 finding vì advisory_changed trên toàn nền tảng bị giữ lại chờ người duyệt trước khi phát hành; dựng lại độc lập từ bản thô (30 ngày) để so băm |
| Tampering | Cấu hình quét độc hại từ trung tâm bị chiếm | Cấu hình chỉ bật, tắt mã có sẵn và ngưỡng số học; không đường dẫn tùy ý để đọc (loại trừ chỉ làm giảm phạm vi), không lệnh; kiểm tra ở ba nơi |
| Repudiation | Người dùng phủ nhận đã chấp nhận rủi ro | Ngoại lệ Auditable, người duyệt khác người yêu cầu, hạn bắt buộc |
| Information disclosure | Báo cáo chứa bí mật | Danh sách trắng bằng chứng trong mã, giới hạn ở ingest, kiểm thử "không lộ bí mật" với fixture chứa bí mật giả (11) |
| Information disclosure | Công ty A xem gói, finding của B | Mục 6 |
| Information disclosure | Dò bảng CVE toàn cục để biết có khách hàng dính CVE X | Không có endpoint liệt kê security_vulnerabilities cho tenant, chỉ join qua finding của mình (08 mục 2) |
| Information disclosure | Nhân viên nền tảng đọc dữ liệu quét | Không màn hình, không phiên truy cập; chỉ thống kê ẩn danh có ngưỡng k |
| DoS | Scanner làm chậm máy | CPUQuota, MemoryMax, Nice, IOSchedulingClass=idle, trần số inode, TimeoutStartSec |
| DoS | Báo cáo khổng lồ làm sập secmatch | Giới hạn 07 mục 3.2, tốc độ 6 mỗi giờ mỗi máy Scanner; ingest tách khỏi matcher |
| Elevation | Lỗi parser trong scanner đặc quyền | Không mạng, chỉ một capability, không ghi được tệp hệ thống, fuzz, Go an toàn bộ nhớ, không CGO |
| Elevation | Biến scanner thành kênh khắc phục từ xa | Không có mã thực thi (ADR 0003); thêm khắc phục tự động cần ADR mới thay thế ADR 0003 và ADR 0005 của Agent (Q7) |
| Information disclosure | Giá trị bí mật hoặc dữ liệu cá nhân rời máy qua báo cáo, log, lỗi, core dump | Kiểu kết quả detector không có trường giá trị; preview giới hạn, rỗng với dữ liệu cá nhân; log có kiểu, không chuỗi tự do từ nội dung tệp; LimitCORE=0; kiểm tra lớp hai ở Collector; bộ "không giá trị rời máy" là cổng phát hành (ADR 0011) |
| Information disclosure | Dò ngược fingerprint bằng cách thử mọi số điện thoại, CCCD | Dữ liệu cá nhân và bí mật entropy thấp dùng K_host không rời máy; K_company chỉ cho bí mật entropy cao (ADR 0011 mục 3) |
| Information disclosure | Bản build scanner bị chiếm giấu giá trị trong fingerprint hoặc đường dẫn | Chuỗi cung ứng (mục 4), review hai người cho mã trong ranh giới che giấu; giới hạn định dạng ở ingest chỉ làm hẹp kênh (R17) |
| Information disclosure | Tài khoản Access Hub bị chiếm dùng danh sách vị trí bí mật làm bản đồ tấn công | Quyền security.secrets.view, security.pii.view tách khỏi security.view; thông báo, webhook không đường dẫn; audit khi xem chi tiết và xuất; khuyến nghị 2FA (R21) |
| Tampering | Cấu hình trung tâm bị chiếm đặt gốc tùy chọn để dùng scanner như "máy dò" nội dung | Gốc chỉ trong giới hạn (16 mục, danh sách cấm cứng), detector biên dịch sẵn nên không hỏi được câu tùy ý về nội dung, kết quả chỉ là các trường ADR 0011; quản trị viên máy phủ quyết bằng allow_central_roots = false, deny_roots; audit ở Access Hub |
| DoS | Lượt nội dung làm chậm máy sản xuất | Khung giờ yên tĩnh, CPUQuota=25%, IO idle, giới hạn tốc độ, PSI, POSIX_FADV_DONTNEED, tăng dần (ADR 0009) |
4. Chuỗi cung ứng
- Binary tĩnh
CGO_ENABLED=0,-trimpath, Go ghim phiên bản,govulncheck,osv-scannertrên chính phụ thuộc, SBOM CycloneDX mỗi bản phát hành, gói.deb,.tar.gz(sau này.rpm) phát hành như artifact riêng (Q21); ký gói bằng khóa riêng của Scanner. - Gói
accesshub-scannerchứa bộ đọc và bộ gửi, không khai báo phụ thuộc góiaccesshub-agentvà ngược lại (Q25, ADR 0001). Mã mẫu từ repo Agent chỉ được chép, có ghi nguồn. - Phụ thuộc mới (thư viện rpmdb, SQLite thuần Go) phải xem xét giấy phép, kích thước, bảo trì trước khi dùng (P0, ADR 0007).
- Secmatch: image distroless, không shell, chạy không root.
- Khóa ký DB riêng, khác khóa ký gói, khóa cập nhật của Agent, khóa
DeploymentLicense(Q23). Nhiều khóa công khai nhúng trong secmatch để xoay.
5. Tối thiểu hóa dữ liệu
| Gửi đi | Không bao giờ gửi |
|---|---|
| Hệ điều hành, kernel đang chạy và đã cài | Nội dung tệp |
| Gói: tên, phiên bản, kiến trúc, gói nguồn, nhà phát hành, module | Danh sách tệp của gói |
| Socket đang nghe: giao thức, địa chỉ, cổng | Tên tiến trình đầy đủ, dòng lệnh, biến môi trường, danh sách tiến trình |
Kết quả kiểm tra: trạng thái và bằng chứng trong danh sách trắng (giá trị chỉ thị như PermitRootLogin=yes, giá trị sysctl, chế độ và chủ sở hữu tệp, tối đa 50 đường dẫn cho kiểm tra tệp) | Băm mật khẩu, khóa riêng, chứng chỉ riêng, token, nội dung dòng sudoers đầy đủ |
Tên tài khoản liên quan (AHS-AUTH-001, 002, 006) nếu Q12 đồng ý | Thư mục nhà, lịch sử lệnh, nội dung mạng, địa chỉ MAC |
| Thống kê lần quét (thời gian, CPU, RSS, số tệp đã duyệt, mã lỗi) | Thông điệp lỗi thô có thể chứa nội dung tệp (chỉ gửi mã lỗi) |
Finding nội dung: mã detector, đường dẫn, dòng, cột, preview che giấu (chỉ bí mật dài từ 16 ký tự), fingerprint có khóa, mức độ, mốc thời gian, match_count, confidence, exposure (ADR 0011) | Giá trị bí mật, dữ liệu cá nhân dưới mọi dạng; đoạn văn bản quanh vị trí khớp; tên khóa cấu hình; claim JWT; tên người dùng trong chuỗi kết nối; độ dài chính xác của giá trị |
| Thống kê tệp theo gốc, tệp đáng chú ý (siêu dữ liệu) | Danh sách đầy đủ mọi tệp (ở lại trong chỉ mục cục bộ) |
| Dịch vụ, phần mềm ngoài gói (tên, phiên bản, đường dẫn, purl) | Cấu hình của dịch vụ, biến môi trường của unit |
Thống kê lượt nội dung (độ phủ, byte đã đọc, số lần nhường, rules_version) | K_host |
Tên tài khoản và đường dẫn có thể là dữ liệu cá nhân hoặc nhạy cảm (ví dụ tên người trong tên tài khoản): là dữ liệu vận hành nội bộ của công ty, lưu có cô lập tenant, không mã hóa ứng dụng (theo quyết định ENC-2: chỉ bí mật mới mã hóa), xóa khi xóa máy hoặc công ty.
6. Cô lập tenant
| Lớp | Biện pháp | Kiểm thử |
|---|---|---|
| Máy | Spool chỉ chứa dữ liệu của máy đó; bộ gửi ký bằng khóa của máy Scanner | Không áp dụng |
| Ingest (secmatch) | Danh tính từ registry máy Scanner theo chữ ký, bỏ trường danh tính trong payload, khử trùng theo host_id, kiểm giấy phép theo công ty | Ma trận hai tenant cho /scan/v1/*: hai công ty, cùng report_id, khóa máy của A ký báo cáo khai là B, mã enroll của A dùng cho B |
| Secmatch | Mọi bảng có company_id, khóa chính gồm company_id; mọi truy vấn qua lớp truy cập bắt buộc tham số company_id; API nội bộ không có endpoint "tất cả công ty" trừ stats/global (đã gộp, ngưỡng k); xóa theo công ty có bia mộ | Hai công ty có cùng server_id giả, cùng gói: tra cứu, tìm gói, xóa của A không thấy, không đụng B; fuzz tham số truy vấn |
| Access Hub | CompanyScope trên mọi model tenant, company_id, server_id gửi secmatch lấy từ bản ghi, không từ tham số; sự kiện từ secmatch kiểm tra máy thuộc công ty | Pest hai công ty cho mọi endpoint, job, xuất, thông báo, webhook |
| Nền tảng | Bảng thống kê không định danh công ty, ngưỡng k | Kiểm thử cấu trúc bảng và ngưỡng |
| DB lỗ hổng | Dữ liệu toàn cục công khai, không chứa dữ liệu khách hàng | Kiểm thử gói DB không chứa trường nào từ inventory |
| Finding nội dung | Trạng thái ở secmatch khóa theo (company_id, server_id); finding_key gồm company_id; fingerprint c dùng khóa riêng từng công ty nên không so được chéo công ty; tra "cùng bí mật trên N máy" luôn lọc theo company_id | Hai công ty có cùng bí mật canary trên máy: fingerprint khác nhau, không thấy nhau; xóa của A không đụng B |
K_company | Sinh và mã hóa theo từng công ty (ENC-2), chỉ phát xuống máy Scanner của công ty đó qua GET /scan/v1/config | Máy Scanner công ty A không nhận khóa của B (ma trận hai tenant ở ingest) |
| Thống kê nền tảng về nội dung | Chỉ số đếm theo họ detector, ngưỡng k; không đường dẫn, fingerprint, preview | Kiểm thử cấu trúc bảng |
7. Bí mật (ENC-2)
| Bí mật | Nơi giữ |
|---|---|
| Token ingest và token admin của secmatch | Kho bí mật của nền tảng triển khai (biến môi trường, secret manager), không vào repo |
| Token Sanctum của tài khoản dịch vụ secmatch | Như token dịch vụ hiện có của Access Hub; Access Hub chỉ giữ băm |
| Khóa riêng Ed25519 của máy Scanner | Chỉ trên máy, /var/lib/accesshub-scan-uploader/host.key (0600, chủ accesshub-scan-uploader), sinh lúc enroll; trung tâm chỉ giữ khóa công khai |
| Mã enroll Scanner | Access Hub giữ băm SHA-256, bản rõ chỉ hiện một lần |
| API key NVD | Kho bí mật của hạ tầng secdb-build, không bao giờ vào gói DB hay secmatch của khách hàng |
| Khóa riêng ký DB | KMS hoặc HSM, không có trên máy dựng thường |
| Bí mật webhook | Đã có cơ chế ENC-2 với khóa theo công ty (CompanyCrypto) |
K_company (khóa fingerprint theo công ty) | Access Hub, mã hóa bằng CompanyCrypto (ENC-2); phát xuống qua SecurityConfig trên TLS; trên máy ở config.pb (0640, chủ accesshub-scan-uploader, bộ đọc đọc bằng CAP_DAC_READ_SEARCH) và tệp khóa của scanner (0600); không log |
K_host (khóa fingerprint theo máy) | Chỉ trên máy, /var/lib/accesshub-scanner/keys/fp_host.key (0600), sinh lúc cài, không bao giờ gửi đi |
Finding (kể cả finding nội dung, vì chúng không chứa giá trị), gói, kết quả kiểm tra, ngoại lệ không mã hóa ứng dụng (phải tìm kiếm, lọc). Mã hóa đĩa theo chính sách hạ tầng.
8. Danh sách kiểm tra trước mỗi bản phát hành
- [ ] Kiểm thử hai công ty đạt ở ingest, matcher, Access Hub.
- [ ] Bộ "không giá trị rời máy" (canary cho mọi detector, mọi đầu ra, mọi tầng) đạt.
- [ ] Precision và recall của detector không giảm so với bản trước (SNFR-47, SNFR-48).
- [ ] Ngân sách lượt nội dung đạt trên ma trận, p99 tải chuẩn không xấu đi (SNFR-12 đến SNFR-17).
- [ ] Review hai người cho mọi thay đổi trong ranh giới che giấu (
internal/detect, dựng phần nội dung của báo cáo). - [ ] Fuzz các parser trong thời gian giới hạn không lỗi.
- [ ] Unit systemd được kiểm bằng
systemd-analyze securitytrên các distro hỗ trợ, điểm không kém bản trước. - [ ] Gói ký, SBOM đính kèm,
govulnchecksạch. - [ ] Xác minh chữ ký DB từ máy sạch; thử DB sai chữ ký và DB hạ phiên bản bị từ chối.