Skip to content

Tổng quan cấu hình ​

Agent (blackhole-agt) đọc cấu hình từ một file YAML. Trong file đó bạn khai báo các source (thu thập dữ liệu), sink (gửi đi) và các section cấu hình chung (logging, inventory, hot-reload, registry...).

Mọi ví dụ YAML trên trang này đều có thể copy trực tiếp vào file cấu hình. Khi một trường có giá trị mặc định, bạn chỉ cần viết nó khi muốn đổi giá trị đó.

Phạm vi của Agent:

  • Agent là tiến trình send-only: trong mọi cấu hình, Agent không mở cổng nghe TCP/UDP nào.
  • Source hợp lệ: file, apm, sca, windows_event.
  • Sink hợp lệ: grpc, kafka, mqtt, blackhole (OpenSearch), file, alert.
  • Không có source mqtt, kafka, grpc, rsyslog, snmp trong Agent — các source đó thuộc Forwarder. File cấu hình dùng type: mqtt (hoặc kafka, grpc, rsyslog, snmp) dưới sources: sẽ lỗi parse trên Agent.
  • Các section server nhúng (rsyslog_server, snmp_server, mqtt_server, grpc_server, proxy_server) không thuộc cấu hình của Agent — Agent không mở port lắng nghe, các section đó thuộc Forwarder, xem cấu hình Forwarder.
  • Section transforms: vẫn được Agent chấp nhận (không bị lỗi parse), nhưng Agent không phải nơi dùng transform. Danh sách transform và tham số chi tiết nằm ở cấu hình Forwarder.

Vị trí file cấu hình ​

Phương thứcHành vi
blackhole-agt (không chỉ định gì)Đọc blackhole-agt.yml trong thư mục làm việc; nếu không có thì thử ./config.yml, rồi ./config.yaml, cuối cùng dùng cấu hình rỗng built-in (không source, không sink)
-c, --config <PATH>Chỉ định chính xác file cấu hình phải dùng
--config-dir <DIR>Ưu tiên hơn --config: tìm config.yml hoặc config.yaml trong DIR, rồi merge mọi file *.blh.yml / *.blh.yaml nằm bên trong DIR (kể cả thư mục con)

Nếu --config-dir chỉ định thư mục mà không có config.yml lẫn config.yaml, tiến trình báo lỗi:

text
No config file (config.yml or config.yaml) found in directory: <DIR>
⚠️
Khi chạy `blackhole-agt start`, file tại đúng đường dẫn `--config` **phải tồn tại trước khi khởi động**. Watcher hot-reload luôn băm (hash) file cấu hình lúc khởi động, nên nếu file không có bạn sẽ gặp lỗi:
text
Failed to read file for hashing: blackhole-agt.yml

Hãy tạo file tại chính xác đường dẫn bạn truyền cho --config (hoặc tạo config.yml/config.yaml trong thư mục mà --config-dir trỏ tới) trước khi chạy start.

📝
Đường dẫn tương đối trong YAML (thư mục log, `path` của file sink...) và giá trị `--config` mặc định được resolve theo **thư mục làm việc** của tiến trình. Trên Windows, Agent tự chuyển thư mục làm việc về thư mục chứa binary; khi cài bằng `service install`, working directory cũng được đặt là thư mục chứa binary. Muốn chắc chắn, hãy dùng đường dẫn tuyệt đối.

Các section cấp cao nhất ​

SectionVai tròChi tiết
loggingFile log, mức log, xoay vòngCấu hình logging
channel_buffersBộ đệm kênh giữa pipelineChannel buffers
inventoryHàng đợi tin nhắn bền vững, retry, backpressureInventory
hot_reloadTự nạp lại cấu hình khi file đổiHot-reload
resources_thresholdNgưỡng CPU/RAM/đĩa để tạm dừng pipelineNgưỡng tài nguyên
registryKết nối Registry (kéo/đẩy cấu hình, xác thực)Registry
sourcesCác nguồn dữ liệu (map đặt tên)Sources
sinksCác đích gửi dữ liệu (map đặt tên)Sinks

Tất cả section đều tùy chọn — thiếu section thì dùng giá trị mặc định (hoặc, với registry, nghĩa là Agent chạy độc lập không gắn Registry).

Lệnh CLI liên quan tới cấu hình ​

text
blackhole-agt [-c|--config <PATH>] [--config-dir <DIR>] [-v|--verbose] [--service]
              [--service-name <N>] [-V|--version] [-h] [COMMAND]

  (không có COMMAND)                In banner

  configure | config  [-f|--force] [--output <PATH>] <ACTION>
      pull              Đọc cấu hình từ Registry, lưu ra file local
                        (--output: tùy chọn, dump YAML ra file khác)
      push              Đẩy file --config lên Registry
      schema            Viết file config.jsonschema cạnh file --config

  service [-f|--force] [--service-name <N>] <install|uninstall|start|stop|status>
  auth -k|--key <KEY>
  start [-s|--service]

Ví dụ:

bash
# Kéo cấu hình từ Registry về file local
blackhole-agt -c config.yml configure pull

# Kéo và đồng thời dump YAML đã merge ra một file khác
blackhole-agt -c config.yml configure pull --output resolved.yml

# Đẩy file cấu hình local lên Registry
blackhole-agt -c config.yml configure push

# Sinh JSON schema cạnh file cấu hình
blackhole-agt -c config.yml configure schema
📝
Các lệnh/không có thật — **không dùng**: `configure default`, `configure sample`, `config validate`, `service restart`, `--path`, `--log-level`, `--dry-run`. Muốn có cấu hình mẫu, hãy viết YAML thủ công theo các ví dụ trên trang này, hoặc dùng `configure pull` để lấy cấu hình từ Registry.
  • Không có --log-level. Muốn log debug, dùng cờ toàn cục -v / --verbose (đặt logging.level thành debug) hoặc khai báo logging.level trong YAML.
  • -c/--config và --config-dir là cờ toàn cục, đặt trước tên subcommand. --output chỉ có ý nghĩa với configure pull.
  • auth --key <KEY> dùng để khai báo API key; key không bao giờ được ghi vào log hay file cấu hình.
  • Không có lệnh restart cho service: dùng service stop rồi service start.

Cấu hình logging ​

Toàn bộ section này là tùy chọn — thiếu section logging thì mọi trường dùng giá trị mặc định.

Cú pháp ​

yaml
logging:
  level: "info"
  dir: "./logs"
  file: "default.log"
  error_file: "default-error.log"
  max_size_mb: 10

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
levelStringKhông"info"Mức log: trace, debug, info, warn, error. Cũng chấp nhận chỉ định theo target kiểu collectors=trace
dirString (đường dẫn)Không"./logs"Thư mục chứa file log, tính tương đối so với thư mục làm việc
fileStringKhông"default.log"Tên file log chính
error_fileStringKhông"default-error.log"Tên file log riêng cho lỗi
max_size_mbInt (MB)Không10Tổng dung lượng file log được phép trước khi xoay vòng (xem Lưu ý)

Ví dụ ​

Cơ bản:

yaml
logging:
  level: "info"

Nâng cao (log chi tiết cho một module, đổi thư mục và tăng ngân sách dung lượng):

yaml
logging:
  level: "supervisor=debug"
  dir: "/var/log/blackhole-agt"
  file: "default.log"
  error_file: "default-error.log"
  max_size_mb: 50
📝
Giữ nguyên tên `default.log` / `default-error.log` nếu bạn muốn các lệnh theo dõi trong [Vận hành](./operation) và [Xử lý sự cố](./troubleshooting) áp dụng được. Chỉ `dir` là nên đổi sang đường dẫn tuyệt đối khi muốn ghi log vào `/var/log`.

Lưu ý ​

  • Xoay vòng luôn bật. Không có cờ bật/tắt. max_size_mb là tổng dung lượng cho phép cho file log chính, không phải ngưỡng của từng file:
    • File log chính (file): xoay thành 5 file cũ, mỗi file bị cắt ở max_size_mb / 5.
    • File log lỗi (error_file): xoay thành 10 file cũ, mỗi file cắt ở max_size_mb — tức dung lượng tối đa của nhóm file lỗi có thể lên tới ~10 lần giá trị bạn đặt.
  • File log thực tế là <dir>/<file> (mặc định ./logs/default.log), file lỗi là <dir>/<error_file> (mặc định ./logs/default-error.log). File lỗi chỉ nhận mức error.
  • dir là tương đối so với thư mục làm việc của tiến trình, không phải /var/log/... (xem Vị trí file cấu hình). Muốn ghi vào /var/log, hãy khai báo đường dẫn tuyệt đối cho dir.
  • Ở chế độ service, stdout bị tắt — file log là nguồn output duy nhất.
  • -v/--verbose trên dòng lệnh sẽ đặt logging.level thành debug.

Channel buffers ​

Điều chỉnh độ sâu của các kênh nội bộ giữa source và sink. Tùy chọn toàn bộ.

Cú pháp ​

yaml
channel_buffers:
  orchestrator_capacity: 100000
  shipper_capacity: 100000
  router_max_in_flight_routes: 4

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
orchestrator_capacityIntKhông100000Số sự kiện tối đa xếp hàng giữa source và orchestrator
shipper_capacityIntKhông100000Số sự kiện tối đa xếp hàng giữa orchestrator và từng sink
router_max_in_flight_routesIntKhông4Số tuyến định tuyến chạy song song tối đa khi phát sự kiện sang nhiều sink

Ví dụ ​

Cơ bản:

yaml
channel_buffers:
  orchestrator_capacity: 100000
  shipper_capacity: 100000

Nâng cao (dự phòng burst lớn hơn, CPU cao hơn):

yaml
channel_buffers:
  orchestrator_capacity: 500000
  shipper_capacity: 500000
  router_max_in_flight_routes: 8

Lưu ý ​

  • Buffer chiếm bộ nhớ theo quy mô: chỉ tăng khi pipeline thực sự cần dự phòng burst.
  • router_max_in_flight_routes càng cao thì throughput khi fan-out sang nhiều sink càng tốt, nhưng tốn CPU hơn.

Inventory (hàng đợi tin nhắn) ​

Inventory là hàng đợi tin nhắn bền vững (persistent queue): khi sink tạm thời không gửi được, sự kiện được giữ lại ở đây để gửi lại sau.

Cú pháp ​

yaml
inventory:
  max_messages: 100000
  max_bytes: 268435456
  backpressure_on_limit: false
  per_shipper:
    file:
      ttl: 3600
      max_retries: 10
      flush_interval_secs: 10
    mqtt:
      ttl: 86400
      max_retries: 20
      flush_interval_secs: 5

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
max_messagesInt hoặc nullCó (khi viết section)100000Số message tối đa trong hàng đợi; null = không giới hạn
max_bytesInt hoặc nullCó (khi viết section)268435456 (256 MB)Dung lượng tối đa của hàng đợi; null = không giới hạn
backpressure_on_limitBoolCó (khi viết section)falsetrue: chặn nhận thêm khi đạt giới hạn (giữ dữ liệu); false: bỏ message cũ nhất (giữ luồng chạy)
per_shipperMapCó (khi viết section)—Chính sách retry/TTL cho từng loại sink; key hợp lệ: file, mqtt, kafka, grpc, blackhole, alert

Mỗi entry trong per_shipper có ba trường, đều bắt buộc:

TrườngKiểuBắt buộcMặc địnhMô tả
ttlInt (giây)Có—Thời gian sống tối đa của message trong hàng đợi; quá hạn bị loại bỏ
max_retriesIntCó—Số lần gửi lại tối đa; hết số lần thì message bị bỏ
flush_interval_secsInt (giây)Có—Chu kỳ nền cố gắng gửi lại hàng đợi

Ví dụ ​

Cơ bản (giữ nguyên hành vi mặc định, chỉ giới hạn hàng đợi):

yaml
inventory:
  max_messages: 100000
  max_bytes: 268435456
  backpressure_on_limit: false
  per_shipper:
    blackhole:
      ttl: 86400
      max_retries: 20
      flush_interval_secs: 5

Nâng cao (không giới hạn số message, bật backpressure, chính sách riêng cho từng sink):

yaml
inventory:
  max_messages: null
  max_bytes: null
  backpressure_on_limit: true
  per_shipper:
    file:
      ttl: 3600
      max_retries: 10
      flush_interval_secs: 10
    mqtt:
      ttl: 86400
      max_retries: 20
      flush_interval_secs: 5
    kafka:
      ttl: 3600
      max_retries: 10
      flush_interval_secs: 10
    grpc:
      ttl: 3600
      max_retries: 10
      flush_interval_secs: 10
    blackhole:
      ttl: 7200
      max_retries: 15
      flush_interval_secs: 5
    alert:
      ttl: 600
      max_retries: 5
      flush_interval_secs: 5

Lưu ý ​

⚠️
Nếu viết section `inventory`, bạn **phải khai báo cả bốn trường** `max_messages`, `max_bytes`, `backpressure_on_limit`, `per_shipper` (và cả ba trường trong mỗi entry của `per_shipper`). Một block thiếu trường sẽ **lỗi parse** (ví dụ: `missing field backpressure_on_limit`). Muốn chỉ chỉnh một phần, hãy bỏ trọn section và dùng mặc định — hoặc khai báo đầy đủ như ví dụ trên.
  • Bỏ trọn section inventory bạn vẫn có hàng đợi hoạt động với: max_messages: 100000, max_bytes: 268435456, backpressure_on_limit: false, và per_shipper mặc định cho mqtt, kafka, grpc, blackhole (mỗi loại: ttl 86400, max_retries 20, flush_interval_secs 5).
  • Sink không có entry trong per_shipper (theo mặc định là file và alert) dùng chính sách fallback: ttl: 3600, max_retries: 10, flush_interval_secs: 10.
  • max_messages/max_bytes đặt null nghĩa là không giới hạn — chỉ an toàn khi bạn kiểm soát được lưu lượng đầu vào.
  • backpressure_on_limit: true bảo toàn dữ liệu nhưng có thể làm chậm pipeline khi backend chặn.

Hot-reload ​

Agent kiểm tra file cấu hình theo chu kỳ và nạp lại khi file thay đổi. Toàn bộ section là tùy chọn.

Cú pháp ​

yaml
hot_reload:
  enabled: true
  poll_interval_ms: 5000
  debounce_ms: 1000

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
enabledBoolKhôngtrueBật/tắt hot-reload
poll_interval_msInt (ms)Không5000Chu kỳ kiểm tra thay đổi của file cấu hình
debounce_msInt (ms)Không1000Thời gian chờ ổn định sau khi phát hiện thay đổi, tránh nạp lại liên tục

Ví dụ ​

Cơ bản:

yaml
hot_reload:
  enabled: true

Nâng cao (phát hiện nhanh hơn, chờ ổn định lâu hơn):

yaml
hot_reload:
  enabled: true
  poll_interval_ms: 2000
  debounce_ms: 3000

Tắt hot-reload:

yaml
hot_reload:
  enabled: false

Lưu ý ​

  • Cơ chế là polling SHA-256: cứ mỗi poll_interval_ms, Agent tính lại hash của file cấu hình chính và mọi file *.blh.yml / *.blh.yaml trong thư mục cấu hình; khi phát hiện hash đổi thì chờ debounce_ms rồi mới nạp lại. Không có inotify, không có tín hiệu SIGHUP.
  • Bỏ trọn section thì hot-reload vẫn bật với các giá trị mặc định ở trên.
⚠️
**Phạm vi thực tế của một thay đổi local** (chỉnh file YAML khi Agent đang chạy):
  • Cấu hình được đọc lại vào bộ nhớ và file snapshot .blackhole-resolved.yaml (nằm cạnh file cấu hình) được ghi lại.
  • Collector, sink không được khởi tạo lại từ chỉnh sửa local — muốn thêm/bớt source hay sink, hãy restart Agent.
  • Nếu nguồn cấu hình hiện hành là bản pull từ Registry, mọi chỉnh sửa local bị bỏ qua hoàn toàn; log sẽ ghi: Remote config is active — ignoring local config change.

Chỉ cập nhật push từ Registry mới thực hiện diff theo từng component (thêm, bỏ hoặc khởi động lại riêng lẻ từng collector/sink).

Ngưỡng tài nguyên ​

Resource guard: khi CPU, RAM hoặc ổ đĩa vượt ngưỡng quá lâu, pipeline tạm dừng để hệ thống hồi phục. Section tùy chọn.

Cú pháp ​

yaml
resources_threshold:
  cpu:
    threshold_percentage: 80.0
    sustained_secs: 60
  memory:
    threshold_percentage: 80.0
    sustained_secs: 60
  disk:
    threshold_percentage: 101.0
    sustained_secs: 60
  check_interval: 10

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
cpu.threshold_percentageFloat (%)Không80.0Ngưỡng CPU; đặt > 100 để tắt theo dõi
cpu.sustained_secsInt (giây)Không60CPU phải duy trì ở ngưỡng trong bao lâu trước khi tạm dừng
memory.threshold_percentageFloat (%)Không80.0Ngưỡng RAM; đặt > 100 để tắt theo dõi
memory.sustained_secsInt (giây)Không60RAM phải duy trì ở ngưỡng trong bao lâu trước khi tạm dừng
disk.threshold_percentageFloat (%)Không101.0Ngưỡng ổ đĩa; mặc định 101.0 = tắt theo dõi ổ đĩa
disk.sustained_secsInt (giây)Không60Đĩa phải duy trì ở ngưỡng trong bao lâu trước khi tạm dừng
check_intervalInt (giây)Không10Chu kỳ kiểm tra mức sử dụng tài nguyên

Ví dụ ​

Cơ bản (giữ mặc định):

yaml
resources_threshold:
  check_interval: 10

Nâng cao (nới ngưỡng CPU, bật theo dõi ổ đĩa):

yaml
resources_threshold:
  cpu:
    threshold_percentage: 90.0
    sustained_secs: 120
  memory:
    threshold_percentage: 85.0
    sustained_secs: 60
  disk:
    threshold_percentage: 95.0
    sustained_secs: 300
  check_interval: 30

Lưu ý ​

  • Guard cho một tài nguyên chỉ hoạt động khi threshold_percentage <= 100 — đó là lý do disk mặc định 101.0 (tắt).
  • Theo mặc định: CPU và RAM được theo dõi (80% liên tục trong 60 giây thì pipeline tạm dừng), ổ đĩa thì không.
  • Khi mức sử dụng xuống dưới ngưỡng, pipeline tự động tiếp tục — không cần can thiệp tay.
  • check_interval càng nhỏ thì phản hồi càng nhanh nhưng càng tốn CPU đọc số liệu.

Registry ​

Registry là điểm điều phối trung tâm (tùy chọn): Agent kéo cấu hình từ Registry, đẩy cấu hình local lên Registry và xác thực bằng API key. Bỏ trọn section nghĩa là Agent chạy độc lập, không gắn Registry.

Cú pháp ​

yaml
registry:
  api_url: "https://blackhole.glabs.one"
  config_update_interval: "15s"
  tls:
    ca_cert_path: null
    insecure_skip_verify_https: false
  proxy:
    enable: true
    http: "http://proxy.company.com:8080"
    https: "https://proxy.company.com:8443"

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
api_urlString (URL)Có (khi viết section)—API endpoint của Registry; giá trị chuẩn dùng trong mẫu là https://blackhole.glabs.one
config_update_intervalString (duration)Không"15s"Chu kỳ kiểm tra cập nhật cấu hình từ Registry, dạng 15s, 1m, 5m...
tls.ca_cert_pathStringKhôngnullĐường dẫn CA bundle (PEM) để xác thực Registry
tls.insecure_skip_verify_httpsBoolKhôngfalseBỏ qua xác thực chứng chỉ HTTPS (không khuyến nghị ở production)
proxy.enableBoolKhôngtrueBật/tắt proxy cho kết nối ra ngoài
proxy.httpString (URL)KhôngnullHTTP proxy, dạng http://user:pass@proxy.company.com:8080
proxy.httpsString (URL)KhôngnullHTTPS proxy, dạng https://user:pass@proxy.company.com:8443

Ví dụ ​

Cơ bản:

yaml
registry:
  api_url: "https://blackhole.glabs.one"

Nâng cao (chu kỳ riêng, CA riêng, đi qua proxy):

yaml
registry:
  api_url: "https://blackhole.glabs.one"
  config_update_interval: "30s"
  tls:
    ca_cert_path: "/etc/blackhole/ca.pem"
    insecure_skip_verify_https: false
  proxy:
    enable: true
    http: "http://proxy.company.com:8080"
    https: "https://proxy.company.com:8443"

Lưu ý ​

  • Section registry có mặt thì api_url bắt buộc — thiếu sẽ lỗi parse (missing field api_url).
  • Nếu dùng Registry, hãy xác thực trước bằng blackhole-agt auth --key <KEY>; API key không bao giờ được ghi vào log hay file cấu hình.
  • Khi có Registry, lúc khởi động Agent ưu tiên cấu hình lấy từ Registry — lúc đó chỉnh sửa file local bị bỏ qua (xem Hot-reload).
  • insecure_skip_verify_https chỉ có ý nghĩa với api_url dạng https://.
  • config_update_interval không đọc được (sai định dạng duration) thì sẽ cảnh báo và dùng 60 giây.

Sources ​

sources là map đặt tên: key là định danh (identifier) của source, value là cấu hình của nó. Agent hỗ trợ đúng bốn loại source.

yaml
sources:
  <ten-source>:
    type: "file"   # hoặc "apm", "sca", "windows_event"
    # các trường khác tùy loại source

Tổng quan sources ​

typeThu thập dữ liệuGhi chú
fileLog từ file (glob patterns)Có sẵn trên mọi nền tảng
apmMetrics hệ thống theo chu kỳCó sẵn trên mọi nền tảng
scaĐánh giá cấu hình bảo mật (policy tương thích Wazuh)Có sẵn trên mọi nền tảng
windows_eventWindows Event Log channelsChỉ có trên build Windows
  • Key của map chính là identifier của source; identifier này được dùng trong inputs của sink. Key không được là * (dành riêng cho wildcard của sink) và không được rỗng.
  • Trường identifier bên trong source không cần khai báo — Agent tự gán từ key của map.
  • Cả bốn source đều có index và sourcetype (tùy chọn, mặc định null) để gắn metadata cho sự kiện khi gửi đi.
  • Các loại source khác (mqtt, kafka, grpc, rsyslog, snmp) không tồn tại trong Agent — xem cấu hình Forwarder.

file source ​

Theo dõi và thu thập log từ các file.

Cú pháp ​

yaml
sources:
  security_logs:
    type: "file"
    includes:
      - "/var/log/auth.log"
      - "/var/log/secure.log"
    index: "security"
    sourcetype: "auth_logs"
    tail: true
    debounce_ms: 1000

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
typeStringCó—Phải là "file"
includesArray of StringKhông["/var/log/auth.log", "/var/log/secure.log", "/var/log/commands.log"]Danh sách glob pattern cần theo dõi (*, **, ?), ví dụ "/var/log/*.log", "/opt/app/**/*.log"
indexStringKhôngnullIndex gắn cho dữ liệu thu thập được
sourcetypeStringKhôngnullLoại dữ liệu, giúp downstream biết định dạng log
tailBoolKhôngtruetrue: chỉ đọc phần thêm sau khi khởi động (giống tail -f); false: đọc toàn bộ file từ đầu rồi theo dõi tiếp
debounce_msInt (ms)Không1000Cửa sổ gộp các thay đổi file liên tiếp thành một lần xử lý
⚠️
Không có trường `paths`. Nếu bạn viết `paths:` trong YAML, nó sẽ bị **bỏ qua im lặng** (không báo lỗi) và Agent dùng danh sách file mặc định — nên log của bạn sẽ không được thu thập. Trường đúng là `includes`.

Ví dụ ​

Cơ bản:

yaml
sources:
  security_logs:
    type: "file"
    includes:
      - "/var/log/auth.log"
      - "/var/log/secure.log"

Nâng cao (nhiều nguồn, debounce khác nhau):

yaml
sources:
  # Theo dõi security logs với phản hồi nhanh
  security_logs:
    type: "file"
    includes:
      - "/var/log/auth.log"
      - "/var/log/secure.log"
      - "/var/log/audit/audit.log"
    index: "security"
    sourcetype: "auth_logs"
    tail: true
    debounce_ms: 500

  # Đọc lại toàn bộ application logs
  app_logs:
    type: "file"
    includes:
      - "/var/log/application/*.log"
      - "/opt/app/logs/**/*.log"
    index: "application"
    sourcetype: "app_logs"
    tail: false
    debounce_ms: 2000

Lưu ý ​

  • Hỗ trợ glob patterns; tự phát hiện log rotation (file bị xoay thì tiếp tục theo dõi file mới).
  • debounce_ms nhỏ = phản hồi nhanh hơn nhưng tăng CPU; lớn = gộp nhiều thay đổi, giảm số event lẻ.
  • Đặt tail: false ở môi trường có sẵn nhiều log cũ sẽ đọc lại toàn bộ file đó lúc khởi động — hãy cân nhắc kỹ includes để giới hạn đúng phạm vi.

apm source ​

Thu thập metrics hệ thống (CPU, bộ nhớ, ổ đĩa, mạng, tiến trình) theo chu kỳ.

Cú pháp ​

yaml
sources:
  apm_system:
    type: "apm"
    interval: 30
    index: "apm"
    sourcetype: "apm_metrics"

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
typeStringCó—Phải là "apm"
intervalInt (giây)Có—Chu kỳ thu thập metrics (giây). Không có giá trị mặc định khi đọc YAML — giá trị thường dùng là 30
indexStringKhôngnullIndex gắn cho metrics
sourcetypeStringKhôngnullLoại dữ liệu

Ví dụ ​

Cơ bản:

yaml
sources:
  apm_system:
    type: "apm"
    interval: 30

Nâng cao (metrics real-time cho monitoring + bản tổng hợp cho báo cáo):

yaml
sources:
  apm_realtime:
    type: "apm"
    interval: 10
    index: "system_metrics"
    sourcetype: "apm_realtime"

  apm_summary:
    type: "apm"
    interval: 300
    index: "system_summary"
    sourcetype: "apm_summary"

Lưu ý ​

  • Thiếu interval sẽ lỗi parse: missing field interval — đây là trường bắt buộc duy nhất của source này.
  • interval càng nhỏ thì dữ liệu càng chi tiết nhưng càng tốn tài nguyên; 30 giây là giá trị cân bằng thường dùng.
  • Metrics được thu thập: CPU usage, memory usage, disk, network interfaces và process information.

sca source ​

Thu thập và đánh giá cấu hình bảo mật theo các policy tương thích Wazuh: Agent đọc file policy YAML từ thư mục chỉ định, chạy các check trên máy cục bộ và phát kết quả dạng sự kiện.

Cú pháp ​

yaml
sources:
  sca_policy:
    type: "sca"
    policy_directory: "/etc/agent/sca/policies"
    scan_interval: "86400s"
    run_on_start: true
    allow_commands: false
    enabled_policies: []
    index: "sca"
    sourcetype: "sca_results"

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
typeStringCó—Phải là "sca"
policy_directoryStringKhông/etc/agent/sca/policies (Linux) · C:\ProgramData\agent\sca\policies (Windows)Thư mục chứa policy YAML; quét đệ quy mọi file .yml/.yaml
scan_intervalString (duration)Khôngnull → dùng 1hChu kỳ quét dạng chuỗi duration: "1h", "30m", "90s", "86400s"; đặt "0s" để tắt quét định kỳ. Alias: scan_interval_secs
scan_cronStringKhôngnullCron expression cho lịch quét, ví dụ "0 */15 * * * * *" (mỗi 15 phút); loại trừ với scan_interval
run_on_startBoolKhôngtrueQuét ngay khi collector khởi động
allow_commandsBoolKhôngfalseCho phép thực thi các rule kiểu c: (mặc định tắt vì lý do bảo mật)
enabled_policiesArray of StringKhông[] (tất cả policy)Chỉ xử lý những file policy có tên trong danh sách (phân biệt hoa thường)
indexStringKhôngnullIndex gắn cho kết quả quét
sourcetypeStringKhôngnullLoại dữ liệu
⚠️
`scan_interval` là **chuỗi duration**, nên luôn đặt trong dấu ngoặc kép:
yaml
scan_interval: "86400s"     # ✅ đúng — 86400 giây
scan_interval_secs: 86400   # ❌ lỗi parse: invalid type: integer `86400`, expected a string

Alias scan_interval_secs nhận cùng kiểu chuỗi ("86400s", "1h"), không phải số giây dạng số.

Ví dụ ​

Cơ bản (quét mỗi 24 giờ):

yaml
sources:
  sca_policy:
    type: "sca"
    policy_directory: "/etc/agent/sca/policies"
    scan_interval: "86400s"
    run_on_start: true

Nâng cao (cron cho CIS, và một source SCA trên Windows):

yaml
sources:
  sca_cis:
    type: "sca"
    policy_directory: "/etc/agent/sca/policies"
    scan_cron: "0 */15 * * * * *"
    run_on_start: true
    allow_commands: false
    enabled_policies:
      - "cis_ubuntu22.yml"
      - "cis_debian11.yml"
    index: "compliance"
    sourcetype: "sca_cis"

  sca_windows:
    type: "sca"
    policy_directory: "C:\\ProgramData\\agent\\sca\\policies"
    scan_interval: "1h"
    enabled_policies:
      - "cis_windows_server_2022.yml"
    index: "windows_compliance"
    sourcetype: "sca_windows"

Lưu ý ​

  • scan_interval và scan_cron loại trừ nhau — chỉ được dùng một trong hai; đặt cùng lúc sẽ bị báo lỗi lịch trình (mutually exclusive).
  • Không khai báo scan_interval thì mặc định quét mỗi 1 giờ.
  • allow_commands mặc định false: các check cần chạy lệnh bị đánh dấu "not applicable" (hoặc error tùy policy). Chỉ bật khi bạn tin tưởng file policy.
  • Kết quả mỗi check gồm: policy_id, check_id, check_title, result (pass / fail / not_applicable / error), evidence, và các trường phụ trợ như description, rationale, remediation, compliance, references.

Các loại rule trong policy:

PrefixPhạm viVí dụ
f:File (tồn tại, nội dung, regex)f:/etc/passwd -> exists
d:Thư mụcd:/etc/ssh
p:Tiến trình đang chạyp:sshd
c:Thực thi lệnh (cần allow_commands: true)c:systemctl is-enabled sshd -> r:enabled
r:Windows registry (chỉ Windows)r:HKLM\SOFTWARE\Policies -> ValueName

Cấu trúc file policy YAML (tương thích Wazuh):

yaml
policy:
  id: "example_policy"
  name: "Example Security Policy"
  description: "Sample policy for demonstration"

variables:
  sshd_config: "/etc/ssh/sshd_config"

requirements:
  title: "System requirements"
  description: "Check if this policy applies"
  condition: all
  rules:
    - "f:/etc/os-release -> r:Ubuntu"

checks:
  - id: 1001
    title: "Ensure SSH root login is disabled"
    description: "Root login via SSH should be disabled"
    rationale: "Prevents direct root access via SSH"
    remediation: "Set PermitRootLogin no in /etc/ssh/sshd_config"
    compliance:
      - cis: ["5.2.10"]
      - pci_dss: ["2.2.4"]
    condition: all
    rules:
      - 'f:$sshd_config -> r:^\s*PermitRootLogin\s+no'

windows_event source ​

Thu thập Windows Event Log từ các channel chỉ định. Source này chỉ tồn tại trong bản build cho Windows — trên Linux, type: "windows_event" sẽ không được nhận diện.

Cú pháp ​

yaml
sources:
  windows_events:
    type: "windows_event"
    channels:
      - name: "Application"
        ids: []

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
typeStringCó—Phải là "windows_event"
channelsArray of ObjectKhông[] (không kênh nào)Danh sách kênh cần thu thập; mỗi phần tử là một object, không phải chuỗi
channels[].nameStringCó (với mỗi phần tử)—Tên kênh (alias: channel), ví dụ Application, Security, System, Setup, ForwardedEvents
channels[].idsArray of IntKhông[] = lấy mọi eventLọc theo Event ID, ví dụ [4624, 4625]
indexStringKhôngnullIndex gắn cho sự kiện
sourcetypeStringKhôngnullLoại dữ liệu
⚠️
`channels` là danh sách **object**, không phải danh sách chuỗi:
yaml
channels: ["Application", "Security"]   # ❌ lỗi: invalid type: string "Application", expected struct WindowsEventChannel

channels:                               # ✅ đúng
  - name: "Application"
    ids: []
  - name: "Security"
    ids: [4624, 4625]

Nếu không khai báo channels thì danh sách rỗng và không kênh nào được subscribe — hãy luôn liệt kê kênh cần thu thập.

Ví dụ ​

Cơ bản:

yaml
sources:
  windows_events:
    type: "windows_event"
    channels:
      - name: "Application"
        ids: []

Nâng cao (chỉ login/logout events, tách nguồn theo kênh):

yaml
sources:
  security_events:
    type: "windows_event"
    channels:
      - name: "Security"
        ids: [4624, 4625, 4634, 4648, 4768, 4769]
    index: "security"
    sourcetype: "windows_security"

  system_events:
    type: "windows_event"
    channels:
      - name: "System"
        ids: []
      - name: "Application"
        ids: []
    index: "system"
    sourcetype: "windows_system"

Lưu ý ​

  • ids: [] nghĩa là lấy tất cả event của kênh đó.
  • Các kênh phổ biến: Application (ứng dụng), Security (đăng nhập/phân quyền — cần quyền administrator), System (sự kiện hệ điều hành).
  • Thu thập Security channel thường yêu cầu Agent chạy bằng tài khoản có quyền đọc Security log.

Sinks ​

sinks là map đặt tên: key là identifier của sink, value là cấu hình. Agent hỗ trợ sáu loại sink.

typeĐiểm đếnYêu cầu tối thiểu
grpcgRPC endpoint (thường là Forwarder)url
kafkaKafka clusterbootstrap_servers
mqttMQTT brokerurl, auth
blackholeOpenSearch / BlackHole indexurl
fileFile local (debug, lưu trữ)không — có sẵn giá trị mặc định
alertCảnh báo gửi về Registrykhông — URL lấy từ registry.api_url
  • Key của map chính là identifier của sink; trường identifier bên trong không cần khai báo.
  • inputs (tùy chọn, mặc định ["*"], alias includes) chọn dữ liệu nào được gửi vào sink: ["*"] là nhận tất cả, hoặc nêu đích danh ["security_logs", "apm_system"].
  • TLS có sẵn ở các sink grpc, kafka, mqtt, blackhole nhưng mặc định tắt — muốn dùng phải khai báo tường minh.

Cấu hình batch (chung cho nhiều sink) ​

⚠️
**`rate_limit` không phải là key lồng nhau.** Ba trường batch được *nằm trực tiếp* ở cấp cao nhất của sink. Nếu viết `rate_limit:` thành một block con, YAML vẫn đọc được nhưng **bị bỏ qua im lặng** và giá trị mặc định được dùng:
yaml
# ❌ SAI — khối rate_limit bị bỏ qua im lặng, batch_size vẫn là 500
sinks:
  my_sink:
    type: "mqtt"
    url: "mqtt://broker:1883"
    auth: { type: "none" }
    rate_limit:
      batch_size: 100
yaml
# ✅ Đúng — ba trường ở cấp cao nhất của sink
sinks:
  my_sink:
    type: "mqtt"
    url: "mqtt://broker:1883"
    auth: { type: "none" }
    batch_size: 100
    batch_interval: 500
    batch_max_bytes: 1048576

Ba trường batch áp dụng cho sink grpc, kafka, mqtt, blackhole, file (sink alert không có):

TrườngKiểuBắt buộcMặc địnhMô tả
batch_sizeIntKhông500Số message tối đa trong một lô gửi
batch_intervalInt (ms)Không1000Thời gian chờ tối đa trước khi gửi lô (dù lô chưa đầy)
batch_max_bytesInt (bytes)Không10485760 (10 MB)Tổng kích thước tối đa của một lô, chặn lô quá lớn

grpc sink ​

Gửi sự kiện tới một gRPC endpoint (ví dụ: Forwarder chạy gRPC server nhúng). Mỗi LogEvent được serialize JSON và gửi qua RPC Publish (unary) hoặc PublishStream (client-streaming); trường topic của request lấy từ index của event.

Cú pháp ​

yaml
sinks:
  grpc_forwarder:
    type: "grpc"
    url: "http://forwarder.company.com:50051"
    inputs: ["*"]
    headers:
      x-api-key: "forwarder-secret"
    use_streaming: true
    max_concurrent_requests: 4
    batch_size: 500
    batch_interval: 1000
    batch_max_bytes: 10485760

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
typeStringCó—Phải là "grpc"
urlString (URL)Có—Endpoint đầy đủ gồm scheme, host, port (http:// hoặc https://). Alias: endpoint. Không có giá trị mặc định khi đọc YAML
inputsArray of StringKhông["*"]Nguồn gửi vào sink (alias includes)
headersMapKhông{}Header tùy chỉnh, gửi kèm mọi request dạng gRPC metadata
use_streamingBoolKhôngtruetrue: dùng PublishStream (throughput cao); false: gửi từng event qua Publish
max_concurrent_requestsIntKhôngnull (shipper dùng 1)Số request gRPC đồng thời tối đa mỗi lô
message_limitsObjectKhôngnullGiới hạn kích thước message: max_decoding_message_size, max_encoding_message_size (bytes)
batch_size / batch_interval / batch_max_bytesIntKhông500 / 1000 / 10485760Xem batch chung

Các tùy chọn nâng cao (tùy chọn) ​

TrườngKiểuMặc địnhMô tả
tlsObjectnullTLS client: ca_cert_path, client_cert_path, client_key_path, domain_name, insecure_skip_verify (mặc định false)
connect_timeout_secsInt (giây)nullTimeout kết nối TCP
request_timeout_secsInt (giây)nullTimeout mỗi RPC (alias: timeout_secs)
tcp_keepalive_secsInt (giây)nullTCP keepalive
tcp_nodelayBoolnullBật/tắt TCP_NODELAY
http2_keep_alive_interval_secsInt (giây)nullChu kỳ HTTP/2 keep-alive
http2_keep_alive_timeout_secsInt (giây)nullTimeout HTTP/2 keep-alive
http2_keep_alive_while_idleBoolnullKeep-alive khi kết nối nhàn rỗi
initial_stream_window_sizeInt (bytes)nullCửa sổ stream ban đầu (HTTP/2)
initial_connection_window_sizeInt (bytes)nullCửa sổ connection ban đầu (HTTP/2)
http2_adaptive_windowBoolnullBật kiểm soát luồng thích ứng (HTTP/2)
concurrency_limitIntnullGiới hạn concurrency ở tầng kết nối
buffer_sizeIntnullKích thước buffer nội bộ của endpoint
user_agentStringnullUser-Agent gửi đi
proxyObjectnullProxy (cùng cấu trúc với proxy của Registry)
reflectionObjectnullClient reflection: enabled (Bool, mặc định false), timeout_secs
protoObjectnullTrỏ tới schema: path (bắt buộc trong object), include_paths, service, method

Ví dụ ​

Cơ bản:

yaml
sinks:
  grpc_forwarder:
    type: "grpc"
    url: "http://forwarder.company.com:50051"

Nâng cao (TLS, header, tinh chỉnh HTTP/2):

yaml
sinks:
  grpc_forwarder:
    type: "grpc"
    url: "https://forwarder.company.com:50051"
    inputs: ["security_logs", "apm_system"]
    headers:
      x-api-key: "forwarder-secret"
    tls:
      ca_cert_path: "/etc/blackhole/ca.pem"
      domain_name: "forwarder.company.com"
    connect_timeout_secs: 10
    use_streaming: true
    max_concurrent_requests: 4
    message_limits:
      max_encoding_message_size: 4194304
      max_decoding_message_size: 4194304
    http2_keep_alive_interval_secs: 30
    batch_size: 500
    batch_interval: 1000
    batch_max_bytes: 10485760

Lưu ý ​

⚠️
`url` là trường **bắt buộc**: thiếu sẽ lỗi parse (`missing field url`). Giá trị `http://localhost:50051` chỉ tồn tại trong mẫu nội bộ của chương trình — **không phải** mặc định YAML, đừng chờ nó tự có.
  • Các giá trị null trong bảng nâng cao nghĩa là "không khai báo thì dùng mặc định của gRPC library".
  • Một số tùy chọn chưa được áp dụng ở phía shipper hiện tại: request_timeout_secs, proxy, ca_cert_path / client_cert_path / client_key_path, reflection, proto — khai báo được nhưng hành vi thực tế chưa thay đổi; domain_name thì có hiệu lực (override SNI/hostname verify).
  • TLS cho grpc chỉ hoạt động khi url dùng scheme https://.

kafka sink ​

Gửi sự kiện tới Kafka cluster qua librdkafka.

Cú pháp ​

yaml
sinks:
  kafka_production:
    type: "kafka"
    inputs: ["*"]
    bootstrap_servers:
      - "kafka1.company.com:9092"
      - "kafka2.company.com:9092"
    client_id: "blackhole-agent"
    security:
      type: "sasl"
      sasl:
        mechanism: "PLAIN"
        username: "agent"
        password: "secure-password"
    acks: "leader"
    compression: "gzip"
    enable_idempotence: true
    batching:
      linger_ms: 100
      batch_num_messages: 1000
      batch_kbytes: 1024
    retries:
      max_retries: 10
      backoff_ms: 100
    producer_pool_size: 4
    batch_size: 500
    batch_interval: 1000
    batch_max_bytes: 10485760

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
typeStringCó—Phải là "kafka"
bootstrap_serversArray of StringCó—Danh sách broker, dạng "host:port". Thiếu sẽ lỗi parse (missing field bootstrap_servers)
inputsArray of StringKhông["*"]Nguồn gửi vào sink (alias includes)
client_idStringKhôngnull (tự sinh)Tên client nhận diện producer
securityObjectKhông{ type: "none" }Xem Cấu hình security
acksStringKhông"leader"Mức xác nhận: "none" (mất dữ liệu có thể, nhanh nhất), "leader" (acks=1), "all" (mọi replica, an toàn nhất)
compressionStringKhông"none"Nén: "none", "gzip", "snappy", "lz4", "zstd"
enable_idempotenceBoolKhôngfalseBật idempotent producer, tránh trùng lặp (nên kèm acks: "all")
transactional_idStringKhôngnullTransaction ID cho ngữ nghĩa exactly-once
batchingObjectKhônglinger_ms: 0, batch_num_messages: 100000, batch_kbytes: 1048576Tinh chỉnh lô của librdkafka: chờ linger_ms (ms), số message, tổng KB
retriesObjectKhôngmax_retries: 10, backoff_ms: 100Retry gửi: số lần và khoảng nghỉ (ms)
timeoutsObjectKhôngsocket_timeout_ms: 60000, request_timeout_ms: 30000, message_timeout_ms: 300000, connections_max_idle_ms: 300000Các timeout (ms) của Kafka client
proxyObjectKhôngnullProxy (cùng cấu trúc với proxy của Registry)
producer_pool_sizeIntKhông4Số producer trong pool (1–64); giữ nguyên thứ tự theo key
extraMap (String → String)Không{}Thuộc tính librdkafka truyền thẳng, ví dụ batch.size: "16384"
batch_size / batch_interval / batch_max_bytesIntKhông500 / 1000 / 10485760Xem batch chung

Cấu hình security ​

TrườngKiểuBắt buộcMặc địnhMô tả
security.typeStringKhông"none""none" (PLAINTEXT), "tls" (chỉ mã hóa), "sasl" (xác thực SASL)
security.tls.ca_locationStringKhôngnullCA bundle (PEM); thiếu thì dùng CA hệ thống
security.tls.certificate_locationStringKhôngnullClient certificate cho mTLS
security.tls.key_locationStringKhôngnullPrivate key của client certificate
security.tls.key_passwordStringKhôngnullMật khẩu private key (nếu key có mật khẩu)
security.tls.verify_certificateBoolKhôngtrueXác minh chain + hostname của broker
security.sasl.mechanismStringKhông"PLAIN"PLAIN, SCRAM_SHA256, SCRAM_SHA512, GSSAPI, OAUTHBEARER
security.sasl.usernameStringKhi dùng PLAIN/SCRAMnullTên đăng nhập
security.sasl.passwordStringKhi dùng PLAIN/SCRAMnullMật khẩu
security.sasl.gssapiObjectKhi mechanism: "GSSAPI"nullprincipal (bắt buộc), keytab (bắt buộc), service_name (mặc định "kafka"), krb5_config
security.sasl.oauthbearerObjectKhi mechanism: "OAUTHBEARER"nulltoken, oidc_config
security.sasl.tlsObjectKhôngnullKhi có mặt thì chạy SASL qua TLS (SASL_SSL); schema giống security.tls
⚠️
`mechanism` của SASL dùng dạng **SCREAMING_SNAKE_CASE**, viết đúng chính tả:
yaml
mechanism: "SCRAM_SHA256"    # ✅
mechanism: "SCRAM-SHA-256"   # ❌ lỗi parse: unknown variant

Các giá trị hợp lệ: PLAIN, SCRAM_SHA256, SCRAM_SHA512, GSSAPI, OAUTHBEARER.

Ví dụ ​

Cơ bản (PLAINTEXT):

yaml
sinks:
  kafka_local:
    type: "kafka"
    bootstrap_servers:
      - "localhost:9092"
    acks: "leader"
    compression: "none"

Nâng cao (SASL/SCRAM + TLS, high throughput):

yaml
sinks:
  kafka_production:
    type: "kafka"
    bootstrap_servers:
      - "kafka1.company.com:9092"
      - "kafka2.company.com:9092"
      - "kafka3.company.com:9092"
    client_id: "blackhole-agent"
    security:
      type: "sasl"
      sasl:
        mechanism: "SCRAM_SHA256"
        username: "agent"
        password: "secure-password"
        tls:
          ca_location: "/etc/blackhole/ca.pem"
          verify_certificate: true
    acks: "all"
    compression: "gzip"
    enable_idempotence: true
    batching:
      linger_ms: 100
      batch_num_messages: 1000
      batch_kbytes: 1024
    retries:
      max_retries: 10
      backoff_ms: 100
    producer_pool_size: 8
    batch_size: 1000
    batch_interval: 500
    batch_max_bytes: 10485760
    extra:
      linger.ms: "5"

Lưu ý ​

  • bootstrap_servers là trường bắt buộc duy nhất; mọi trường khác đều có mặc định.
  • TLS chỉ hoạt động khi bạn chọn security.type: "tls" (hoặc sasl.tls); mặc định là none — không mã hóa.
  • acks: "all" + enable_idempotence: true là tổ hợp khuyến nghị cho dữ liệu quan trọng (chậm hơn nhưng không mất/không trùng).
  • batch_kbytes tính bằng KiB: mặc định 1048576 = 1 GiB ngưỡng queue của librdkafka.
  • extra ghi đè trực tiếp lên cấu hình librdkafka — chỉ dùng khi bạn biết chắc ý nghĩa của key.

mqtt sink ​

Publish sự kiện tới MQTT broker.

Cú pháp ​

yaml
sinks:
  mqtt_production:
    type: "mqtt"
    url: "mqtts://broker.company.com:8883?client_id=agent-001"
    inputs: ["*"]
    auth:
      type: "basic"
      username: "agent"
      password: "secure-password"
    batch_size: 500
    batch_interval: 1000
    batch_max_bytes: 10485760

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
typeStringCó—Phải là "mqtt"
urlString (URL)Có—URL broker dạng mqtt:// (không mã hóa) hoặc mqtts:// (TLS), có thể kèm query như ?client_id=agent-001
inputsArray of StringKhông["*"]Nguồn gửi vào sink (alias includes)
authObjectCó—Xác thực với broker — xem bảng dưới
tlsObjectKhôngnullTLS/mTLS cho broker — xem bảng dưới
proxyObjectKhôngnullProxy (cùng cấu trúc với proxy của Registry)
batch_size / batch_interval / batch_max_bytesIntKhông500 / 1000 / 10485760Xem batch chung

Cấu hình auth và tls ​

TrườngKiểuBắt buộcMặc địnhMô tả
auth.typeStringCó—"none" (không xác thực) hoặc "basic" (username/password)
auth.usernameStringKhi type: "basic"—Tên đăng nhập
auth.passwordStringKhi type: "basic"—Mật khẩu
tls.ca_cert_pathStringKhôngnullCA certificate (PEM) — cần với broker dùng chứng chỉ tự ký
tls.client_cert_pathStringKhôngnullClient certificate cho mTLS (alias của khóa viết gọn certpath)
tls.client_key_pathStringKhôngnullPrivate key cho mTLS (alias của khóa viết gọn keypath)
tls.insecureBoolKhôngfalseBỏ qua xác minh chứng chỉ (chỉ để thử nghiệm)

Ví dụ ​

Cơ bản (broker nội bộ, không xác thực):

yaml
sinks:
  mqtt_local:
    type: "mqtt"
    url: "mqtt://localhost:1883?client_id=agent-local"
    auth:
      type: "none"

Nâng cao (TLS + basic auth + proxy):

yaml
sinks:
  mqtt_secure:
    type: "mqtt"
    url: "mqtts://broker.company.com:8883?client_id=agent-001"
    auth:
      type: "basic"
      username: "agent"
      password: "secure-password"
    tls:
      ca_cert_path: "/etc/blackhole/mqtt/ca-cert.pem"
      client_cert_path: "/etc/blackhole/mqtt/client-cert.pem"
      client_key_path: "/etc/blackhole/mqtt/client-key.pem"
    proxy:
      enable: true
      https: "https://proxy.company.com:8443"
    batch_size: 200
    batch_interval: 500
    batch_max_bytes: 2097152

Lưu ý ​

⚠️
`url` và `auth` là **bắt buộc** — thiếu một trong hai sẽ lỗi parse (`missing field url` / `missing field auth`). Giá trị `mqtt://localhost:1883?client_id=siem-agent` chỉ là mặc định trong chương trình, **không phải** mặc định YAML.
  • Muốn TLS thì dùng scheme mqtts:// (thường cổng 8883) và khai báo tls; TLS mặc định tắt.
  • tls chấp nhận cả khóa viết gọn (capath, certpath, keypath) lẫn khóa đầy đủ (ca_cert_path, client_cert_path, client_key_path).
  • Khóa client_cert_path và client_key_path phải đi kèm nhau khi broker yêu cầu mutual TLS.

opensearch (blackhole) sink ​

Index sự kiện vào OpenSearch / BlackHole. Trong YAML, sink này được chọn bằng type: "blackhole".

⚠️
**Chỉ `type: "blackhole"` là hợp lệ.** Viết `type: "opensearch"` sẽ lỗi parse: `unknown variant opensearch, expected one of file, mqtt, kafka, grpc, blackhole, alert`.
yaml
sinks:
  my_index:
    type: "blackhole"   # ✅ đúng
    url: "https://opensearch.company.com:9200"

Tên "opensearch" chỉ dùng để gọi tên sink trong tài liệu; khóa nhận diện trong cấu hình là blackhole.

Cú pháp ​

yaml
sinks:
  blackhole_production:
    type: "blackhole"
    inputs: ["*"]
    url: "https://blackhole.company.com:9200"
    healthcheck: false
    auth:
      type: "basic"
      username: "agent"
      password: "secure-password"
    tls:
      insecure_skip_verify: false
    headers:
      X-Custom-Header: "value"
    timeouts:
      request_timeout_secs: 30
      connect_timeout_secs: 10
    batch_size: 200
    batch_interval: 2000
    batch_max_bytes: 2097152

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
typeStringCó—Phải là "blackhole"
urlString (URL)Có—Endpoint của cluster, dạng http:// hoặc https:// (alias: endpoint)
inputsArray of StringKhông["*"]Nguồn gửi vào sink (alias includes)
healthcheckBoolKhôngfalseGửi request kiểm tra sức khỏe cluster
requestObjectKhôngnullTương thích ngược: retry_attempts (Int), timeout_secs (Int)
authObjectKhông{ type: "none" }Xác thực — xem bảng auth
tlsObjectKhôngca_cert_path: null, insecure_skip_verify: falseca_cert_path (CA bundle PEM), insecure_skip_verify (bỏ qua xác minh — không khuyến nghị)
proxyObjectKhôngnullProxy (cùng cấu trúc với proxy của Registry)
headersMapKhông{}HTTP header gửi kèm mọi request (hữu ích cho API versioning, auth tùy chỉnh)
timeoutsObjectKhôngrequest_timeout_secs: 30, connect_timeout_secs: 10Timeout (giây) cho request và kết nối
bulk_doc_metadata_overhead_bytesInt (bytes)Không128Ước tính overhead metadata mỗi document trong bulk request
bulk_max_docs_hard_capIntKhông5000Giới hạn cứng số document mỗi bulk request
bulk_max_bytes_hard_capInt (bytes)Không67108864 (64 MiB)Giới hạn cứng kích thước payload mỗi bulk request
batch_size / batch_interval / batch_max_bytesIntKhông500 / 1000 / 10485760Xem batch chung

Cấu hình auth ​

TrườngKiểuBắt buộcMặc địnhMô tả
auth.typeStringKhông"none""none", "basic", "clientcert", "jwt", "awssigv4"
auth.usernameStringKhi type: "basic"—Tên đăng nhập basic auth
auth.passwordStringKhi type: "basic"—Mật khẩu basic auth
auth.pkcs12_pathStringKhi type: "clientcert"—File chứng chỉ client dạng PKCS#12/PFX
auth.pkcs12_passwordStringKhi type: "clientcert"—Mật khẩu file PKCS#12
auth.tokenStringKhi type: "jwt"—JWT/OIDC bearer token
auth.header_nameStringKhông"Authorization"Tên header mang token
auth.regionStringKhi type: "awssigv4"—AWS region, ví dụ us-east-1
auth.profileStringKhôngnullAWS profile (thiếu thì dùng default credential chain)
auth.role_arnStringKhôngnullIAM role ARN để assume
auth.serviceStringKhông"es"Dịch vụ AWS: "es" (OpenSearch Service) hoặc "aoss" (OpenSearch Serverless)

Ví dụ ​

Cơ bản (không xác thực):

yaml
sinks:
  blackhole_local:
    type: "blackhole"
    url: "http://localhost:9200"
    auth:
      type: "none"

Nâng cao (basic auth + custom headers):

yaml
sinks:
  blackhole_secure:
    type: "blackhole"
    url: "https://blackhole.company.com:9200"
    inputs: ["*"]
    healthcheck: true
    auth:
      type: "basic"
      username: "agent"
      password: "secure-password"
    tls:
      ca_cert_path: "/etc/blackhole/ca.pem"
      insecure_skip_verify: false
    headers:
      X-Api-Version: "1.0"
    timeouts:
      request_timeout_secs: 30
      connect_timeout_secs: 10
    batch_size: 200
    batch_interval: 2000
    batch_max_bytes: 2097152

Lưu ý ​

  • Kích thước lô thực tế: số document = min(batch_size, bulk_max_docs_hard_cap), bytes = min(batch_max_bytes, bulk_max_bytes_hard_cap).
  • auth mặc định none; insecure_skip_verify mặc định false — đừng tắt xác minh ở production.
  • Chọn chứng chỉ nào (basic, jwt, awssigv4...) tùy policy của cluster; khi không chắc, dùng basic.

file sink ​

Ghi sự kiện ra file local — dùng để debug hoặc lưu trữ tạm.

Cú pháp ​

yaml
sinks:
  file_debug:
    type: "file"
    path: "./debug-events/"
    max_size_mb: 10
    max_files: 5
    inputs: ["*"]
    batch_size: 100
    batch_interval: 1000
    batch_max_bytes: 1048576

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
typeStringCó—Phải là "file"
pathString (thư mục)Không"./debug-events/"Thư mục ghi file; đường dẫn tương đối tính theo thư mục làm việc
max_size_mbInt (MB)Không10Kích thước tối đa mỗi file trước khi tạo file mới
max_filesIntKhông5Số file giữ lại; file cũ hơn bị xóa
inputsArray of StringKhông["*"]Nguồn gửi vào sink (alias includes)
batch_size / batch_interval / batch_max_bytesIntKhông500 / 1000 / 10485760Xem batch chung

Ví dụ ​

Cơ bản:

yaml
sinks:
  file_debug:
    type: "file"

Nâng cao (riêng cho security logs, giữ nhiều file hơn):

yaml
sinks:
  file_security:
    type: "file"
    path: "/var/log/blackhole/security/"
    max_size_mb: 100
    max_files: 20
    inputs: ["security_logs"]

Lưu ý ​

  • Theo mặc định mọi file sink ghi vào ./debug-events/ (tính theo thư mục làm việc).
  • Rotation chạy theo cặp max_size_mb / max_files: vượt kích thước thì tạo file mới, vượt số file thì xóa cái cũ nhất.

alert sink ​

Gửi cảnh báo (alert events) về Registry bằng HTTP POST. Đây là sink không cấu hình URL — địa chỉ đích được lấy từ registry.api_url tại runtime và xác thực bằng header x-device-token, để endpoint cảnh báo luôn gắn với Registry mà thiết bị đã đăng ký. Không có giao diện web đi kèm: chỉ là một sink HTTP.

Cú pháp ​

yaml
sinks:
  alerts:
    type: "alert"
    inputs: ["alerts"]
    max_retry: 3
    timeout_ms: 5000

Các trường cấu hình ​

TrườngKiểuBắt buộcMặc địnhMô tả
typeStringCó—Phải là "alert"
inputsArray of StringKhôngnull → tự nhận channel "alerts"Alert events được phát vào channel dành riêng "alerts", thông thường giữ mặc định
max_retryIntKhôngnull (shipper dùng 3)Số lần gửi lại tối đa cho lỗi tạm thời
timeout_msInt (ms)Khôngnull (shipper dùng 10000)Timeout mỗi request

Ví dụ ​

Cơ bản (chỉ khai báo loại sink):

yaml
sinks:
  alerts:
    type: "alert"

Nâng cao (đổi retry/timeout):

yaml
sinks:
  alerts:
    type: "alert"
    inputs: ["alerts"]
    max_retry: 5
    timeout_ms: 3000

Lưu ý ​

  • Mỗi alert event = một HTTP POST tới {registry.api_url}/client/alerts, kèm header x-device-token.
  • Chỉ lỗi tạm thời (5xx, lỗi mạng) được retry; lỗi 4xx bị bỏ qua ngay (backend từ chối). Hết số retry thì event được giữ trong inventory để gửi lại sau.
  • Kết nối dùng tls và proxy từ section Registry.
  • Không có section registry thì alert events không gửi đi được — chúng được lưu vào inventory cho tới khi Registry sẵn sàng.

Hướng dẫn tạo chứng chỉ SSL ​

Các sink mqtt, kafka, grpc, blackhole đều hỗ trợ TLS nhưng mặc định tắt. Khi backend dùng chứng chỉ tự ký (self-signed), bạn cần cấu hình CA tương ứng. Phần dưới đây hướng dẫn tạo chứng chỉ tự ký bằng openssl / keytool.

Tạo chứng chỉ SSL tự ký cho MQTT Broker ​

Bước 1: Tạo thư mục lưu trữ chứng chỉ ​

bash
sudo mkdir -p /etc/ssl/mqtt
sudo chmod 700 /etc/ssl/mqtt

Bước 2: Tạo CA (Certificate Authority) tự ký ​

bash
# Tạo private key cho CA
sudo openssl genrsa -out /etc/ssl/mqtt/ca-key.pem 4096

# Tạo certificate cho CA
sudo openssl req -new -x509 -days 365 -key /etc/ssl/mqtt/ca-key.pem -out /etc/ssl/mqtt/ca-cert.pem

Khi được hỏi, điền thông tin (Country Name, State, City, Organization...); Common Name ví dụ: MQTT CA.

Bước 3: Tạo server certificate ​

bash
# Tạo private key cho server
sudo openssl genrsa -out /etc/ssl/mqtt/server-key.pem 4096

# Tạo CSR
sudo openssl req -new -key /etc/ssl/mqtt/server-key.pem -out /etc/ssl/mqtt/server.csr

Thông tin giống CA, nhưng Common Name phải là hostname hoặc IP của MQTT broker.

Bước 4: Ký server certificate bằng CA ​

bash
sudo openssl x509 -req -in /etc/ssl/mqtt/server.csr \
  -CA /etc/ssl/mqtt/ca-cert.pem -CAkey /etc/ssl/mqtt/ca-key.pem \
  -CAcreateserial -out /etc/ssl/mqtt/server-cert.pem -days 365

Bước 5: Tạo client certificate (tùy chọn, cho mutual TLS) ​

bash
sudo openssl genrsa -out /etc/ssl/mqtt/client-key.pem 4096
sudo openssl req -new -key /etc/ssl/mqtt/client-key.pem -out /etc/ssl/mqtt/client.csr
sudo openssl x509 -req -in /etc/ssl/mqtt/client.csr \
  -CA /etc/ssl/mqtt/ca-cert.pem -CAkey /etc/ssl/mqtt/ca-key.pem \
  -CAcreateserial -out /etc/ssl/mqtt/client-cert.pem -days 365

Bước 6: Cấu hình MQTT sink với TLS ​

yaml
sinks:
  mqtt_secure:
    type: "mqtt"
    url: "mqtts://broker.company.com:8883?client_id=agent-001"
    auth:
      type: "basic"
      username: "agent"
      password: "secure-password"
    tls:
      ca_cert_path: "/etc/ssl/mqtt/ca-cert.pem"
      client_cert_path: "/etc/ssl/mqtt/client-cert.pem"
      client_key_path: "/etc/ssl/mqtt/client-key.pem"

Xử lý lỗi TLS ​

Nếu gặp TLS: I/O: tls handshake eof hoặc lỗi TLS khác, kiểm tra theo thứ tự:

  1. Đường dẫn CA: ca_cert_path trỏ đúng file và tiến trình có quyền đọc.
  2. Định dạng file: certificate phải là PEM (bắt đầu bằng -----BEGIN CERTIFICATE-----).
  3. Scheme URL: dùng mqtts:// thay vì mqtt://.
  4. Cổng: MQTT over TLS thường là 8883, không phải 1883.
  5. Common Name/SAN: hostname trong URL phải khớp certificate của broker.

Tạo chứng chỉ SSL cho Kafka ​

Bước 1: Tạo keystore cho Kafka broker ​

bash
# Tạo keystore
keytool -keystore kafka.server.keystore.jks -alias localhost -validity 365 \
  -genkey -keyalg RSA -keysize 2048 -storepass password -keypass password \
  -dname "CN=localhost, OU=IT, O=YourCompany, L=HCMC, ST=HCMC, C=VN"

# Tạo CSR
keytool -keystore kafka.server.keystore.jks -alias localhost \
  -certreq -file cert-file -storepass password

# Ký certificate bằng CA
openssl x509 -req -CA ca-cert -CAkey ca-key -in cert-file -out cert-signed \
  -days 365 -CAcreateserial -passin pass:password

# Import CA vào keystore
keytool -keystore kafka.server.keystore.jks -alias CARoot \
  -import -file ca-cert -storepass password

# Import certificate đã ký vào keystore
keytool -keystore kafka.server.keystore.jks -alias localhost \
  -import -file cert-signed -storepass password

Bước 2: Tạo truststore cho client ​

bash
keytool -keystore kafka.client.truststore.jks -alias CARoot \
  -import -file ca-cert -storepass password

Bước 3: Cấu hình Kafka sink với TLS ​

yaml
sinks:
  kafka_secure:
    type: "kafka"
    bootstrap_servers:
      - "kafka1.company.com:9093"
    security:
      type: "tls"
      tls:
        ca_location: "/path/to/ca-cert"
        certificate_location: "/path/to/client-cert"
        key_location: "/path/to/client-key"
        verify_certificate: true
    batch_size: 500
    batch_interval: 1000
    batch_max_bytes: 10485760

Cấu hình nâng cao ​

High Availability ​

Cho Kafka, tăng độ bền bằng acks: "all" và idempotent producer; đưa nhiều broker vào bootstrap_servers để dự phòng:

yaml
sinks:
  kafka_ha:
    type: "kafka"
    bootstrap_servers:
      - "kafka1.company.com:9092"
      - "kafka2.company.com:9092"
      - "kafka3.company.com:9092"
    acks: "all"
    enable_idempotence: true
    retries:
      max_retries: 2147483647
      backoff_ms: 100
    batch_size: 1000
    batch_interval: 500
    batch_max_bytes: 10485760

Performance Tuning ​

Tối ưu cho high-throughput — tăng buffer, giảm độ trễ batch:

yaml
channel_buffers:
  orchestrator_capacity: 500000
  shipper_capacity: 500000
  router_max_in_flight_routes: 8

sources:
  high_freq_apm:
    type: "apm"
    interval: 5

sinks:
  high_throughput_kafka:
    type: "kafka"
    bootstrap_servers:
      - "kafka1.company.com:9092"
    batching:
      linger_ms: 0
      batch_num_messages: 10000
      batch_kbytes: 10240
    batch_size: 1000
    batch_interval: 100
    batch_max_bytes: 10485760
📝
Muốn nới giới hạn hàng đợi (inventory) hoặc đổi chính sách retry, xem [Inventory](#inventory-hang-doi-tin-nhan) — nhớ khai báo **đầy đủ** bốn trường của section nếu bạn viết nó.

Xem thêm ​

Released under the MIT License.