Skip to content

Commit 1c73733

Browse files
committed
Merge branch 'backlog/v12.0.0' of https://github.com/utmstack/UTMStack into backlog/v12.0.0
2 parents 880eb2a + 86f7410 commit 1c73733

65 files changed

Lines changed: 8019 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

collectors/forwarder/README.md

Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
# UTMStack Forwarder
2+
3+
The UTMStack Forwarder is a standalone log collection service that receives logs from external integrations and forwards them to the UTMStack backend in real time.
4+
5+
It runs as an independent Linux service (`UTMStackForwarder`) alongside the UTMStack Agent. Both connect directly to the backend — there is no communication between them.
6+
7+
---
8+
9+
## What it does
10+
11+
The Forwarder opens listeners on your server and waits for logs to arrive. As soon as a log comes in, it sends it to the UTMStack backend immediately — no local storage, no buffering.
12+
13+
It supports four types of listeners:
14+
15+
| Listener | Protocol | Typical use |
16+
|---|---|---|
17+
| **Syslog** | TCP, UDP, TLS | Firewalls, switches, routers, security appliances |
18+
| **Netflow** | UDP | Network traffic data (v5, v9, IPFIX) |
19+
| **File** || Log files on the local server (nginx, postgresql) |
20+
| **HTTP/HTTPS** | HTTP, HTTPS | Webhooks, APIs, custom applications |
21+
22+
---
23+
24+
## How it works
25+
26+
### Boot sequence
27+
28+
When the service starts:
29+
30+
1. Reads the encrypted configuration (`collector-config.yml`)
31+
2. Connects to the UTMStack backend
32+
3. Starts a ping goroutine (heartbeat every 15 seconds)
33+
4. Starts the log forwarding goroutine
34+
5. Syncs the integration config file (`log-collector-config.json`)
35+
6. Starts all enabled listeners
36+
37+
### Log flow
38+
39+
```
40+
Syslog listener ──────┐
41+
Netflow listener ──────┤──► Internal queue (10,000 slots) ──► UTMStack backend
42+
File listener ──────┤
43+
HTTP listener ──────┘
44+
```
45+
46+
Every listener pushes logs into a shared internal queue. A single goroutine drains that queue and streams logs to the backend over gRPC. If the backend is unreachable, logs arriving during the outage are dropped — there is no local buffer by design.
47+
48+
### Live configuration
49+
50+
The Forwarder watches `log-collector-config.json` for changes using `fsnotify`. When you run a CLI command to enable or disable an integration, the file changes and the relevant listener starts or stops automatically — **no service restart needed**.
51+
52+
---
53+
54+
## Installation
55+
56+
```bash
57+
# Install the service
58+
./utmstack_forwarder install <server_address> <utm_key> <yes|no>
59+
60+
# yes = skip TLS certificate validation
61+
# no = validate TLS certificate (recommended for production)
62+
```
63+
64+
Example:
65+
```bash
66+
./utmstack_forwarder install 192.168.1.100 my-utm-key no
67+
```
68+
69+
This will:
70+
1. Verify connectivity to the backend (ports 9000 and 50051)
71+
2. Register the forwarder with the UTMStack backend
72+
3. Save the encrypted configuration
73+
4. Install and start the `UTMStackForwarder` system service
74+
75+
```bash
76+
# Uninstall
77+
./utmstack_forwarder uninstall
78+
```
79+
80+
---
81+
82+
## Managing integrations
83+
84+
### Enable a syslog integration
85+
86+
```bash
87+
# UDP (most common for syslog)
88+
./utmstack_forwarder enable-integration firewall-fortigate-traffic 7005 udp
89+
90+
# TCP
91+
./utmstack_forwarder enable-integration firewall-fortigate-traffic 7005 tcp
92+
93+
# TCP with TLS (requires a certificate loaded first)
94+
./utmstack_forwarder enable-integration firewall-fortigate-traffic 7005 tls
95+
```
96+
97+
### Enable a netflow integration
98+
99+
```bash
100+
./utmstack_forwarder enable-integration netflow 2055 udp
101+
```
102+
103+
### Enable an HTTP integration
104+
105+
```bash
106+
# No authentication — for trusted internal networks
107+
./utmstack_forwarder enable-integration my-app 7999 http
108+
109+
# Bearer token authentication
110+
./utmstack_forwarder enable-integration my-app 7999 http --auth bearer
111+
112+
# HMAC authentication — compatible with Meta, GitHub, Stripe, etc.
113+
./utmstack_forwarder enable-integration meta 7999 http --auth hmac --signature-header X-Hub-Signature-256
114+
./utmstack_forwarder enable-integration github 7999 http --auth hmac --signature-header X-Hub-Signature-256
115+
./utmstack_forwarder enable-integration stripe 7999 http --auth hmac --signature-header Stripe-Signature
116+
```
117+
118+
### Enable an HTTPS integration
119+
120+
```bash
121+
# Load the TLS certificate first
122+
./utmstack_forwarder load-tls-certs /path/to/cert.crt /path/to/key.key
123+
124+
# Then enable
125+
./utmstack_forwarder enable-integration my-app 443 https --auth bearer
126+
```
127+
128+
### Disable an integration
129+
130+
```bash
131+
./utmstack_forwarder disable-integration firewall-fortigate-traffic udp
132+
./utmstack_forwarder disable-integration my-app http
133+
```
134+
135+
### Change a port
136+
137+
```bash
138+
./utmstack_forwarder change-port firewall-fortigate-traffic udp 7010
139+
./utmstack_forwarder change-port my-app http 8080
140+
```
141+
142+
### Adding a custom integration type
143+
144+
If the integration name you want does not exist in the built-in catalog, the Forwarder creates it automatically:
145+
146+
```bash
147+
./utmstack_forwarder enable-integration my-custom-firewall 7999 udp
148+
# Output: New data type "my-custom-firewall" created.
149+
# Integration "my-custom-firewall" enabled on udp port 7999
150+
```
151+
152+
The new type is saved in `log-collector-catalog.json`. You can manage custom types:
153+
154+
```bash
155+
# List all types (built-in and custom)
156+
./utmstack_forwarder list-datatypes
157+
158+
# Remove a custom type (must be disabled first)
159+
./utmstack_forwarder remove-datatype my-custom-firewall
160+
```
161+
162+
---
163+
164+
## HTTP/HTTPS authentication
165+
166+
### No authentication
167+
168+
The listener accepts every POST without any check. Use only on isolated networks.
169+
170+
```bash
171+
./utmstack_forwarder enable-integration my-app 7999 http
172+
```
173+
174+
Sending logs:
175+
```bash
176+
curl -X POST http://your-server:7999/logs \
177+
-d '{"event": "login", "user": "john"}'
178+
```
179+
180+
---
181+
182+
### Bearer token
183+
184+
When enabled, the Forwarder generates a random token and displays it **once**. Store it securely.
185+
186+
```bash
187+
./utmstack_forwarder enable-integration my-app 7999 http --auth bearer
188+
# Output:
189+
# Token for my-app: a3f8c2d1e4b57f9...
190+
# Store this token securely — it won't be shown again.
191+
```
192+
193+
Sending logs:
194+
```bash
195+
curl -X POST http://your-server:7999/logs \
196+
-H "Authorization: Bearer a3f8c2d1e4b57f9..." \
197+
-d '{"event": "login", "user": "john"}'
198+
```
199+
200+
Configure this token as an HTTP header secret in your external platform.
201+
202+
---
203+
204+
### HMAC signature
205+
206+
Used by platforms like Meta, GitHub, and Stripe. The platform signs each request with a shared secret — the Forwarder verifies the signature without the secret ever travelling in the request.
207+
208+
```bash
209+
./utmstack_forwarder enable-integration meta 7999 http \
210+
--auth hmac \
211+
--signature-header X-Hub-Signature-256
212+
```
213+
214+
When enabled, a token file is generated at `certs/integration-http-meta.token`. Configure this token as the webhook secret in the external platform (Meta, GitHub, etc.).
215+
216+
The `--signature-header` flag specifies which header the platform uses to send the signature:
217+
218+
| Platform | Header |
219+
|---|---|
220+
| Meta / Facebook | `X-Hub-Signature-256` |
221+
| GitHub | `X-Hub-Signature-256` |
222+
| Stripe | `Stripe-Signature` |
223+
| Custom | any header you choose |
224+
225+
---
226+
227+
## HTTP/HTTPS body format
228+
229+
The HTTP and HTTPS listeners accept **any format** — JSON, NDJSON, plain text, XML, or anything else. The body is forwarded as-is to the UTMStack event processor, which applies the corresponding filter for that DataType. No parsing or transformation happens in the Forwarder.
230+
231+
```bash
232+
# JSON
233+
curl -X POST http://your-server:7999/logs \
234+
-H "Content-Type: application/json" \
235+
-d '{"event":"login","user":"john"}'
236+
237+
# Plain syslog text
238+
curl -X POST http://your-server:7999/logs \
239+
-H "Content-Type: text/plain" \
240+
-d 'Jan 10 12:00:01 fw01 kernel: packet blocked src=1.2.3.4'
241+
242+
# Any other format — the event processor handles it
243+
curl -X POST http://your-server:7999/logs \
244+
--data-binary @/path/to/logfile.xml
245+
```
246+
247+
The only limit is **8 MB per request**.
248+
249+
---
250+
251+
## TLS for syslog
252+
253+
```bash
254+
# Load your certificates
255+
./utmstack_forwarder load-tls-certs /path/to/cert.crt /path/to/key.key /path/to/ca.crt
256+
257+
# Enable TLS on a syslog integration
258+
./utmstack_forwarder enable-integration firewall-cisco-asa 1470 tls
259+
```
260+
261+
All TLS connections use TLS 1.2/1.3 only with AEAD cipher suites.
262+
263+
---
264+
265+
## Configuration files
266+
267+
All files are stored in the Forwarder's installation directory.
268+
269+
| File | Description |
270+
|---|---|
271+
| `collector-config.yml` | Encrypted credentials (server address, ID, key) |
272+
| `collector-uuid.yml` | Unique installation identifier |
273+
| `log-collector-config.json` | Integration settings (ports, protocols, enabled status) |
274+
| `log-collector-catalog.json` | User-defined custom DataTypes |
275+
| `certs/integration.crt` | TLS certificate for syslog TLS and HTTPS |
276+
| `certs/integration.key` | TLS private key |
277+
| `certs/integration-http-<name>.token` | Auth token for HTTP/HTTPS integrations |
278+
| `logs/utmstack_collector.log` | Service log file |
279+
280+
---
281+
282+
## Built-in integration types
283+
284+
| Name | Protocol | Default port |
285+
|---|---|---|
286+
| `syslog` | UDP/TCP | 7014 |
287+
| `vmware-esxi` | UDP/TCP | 7002 |
288+
| `antivirus-esmc-eset` | UDP/TCP | 7003 |
289+
| `antivirus-kaspersky` | UDP/TCP | 7004 |
290+
| `firewall-cisco-asa` | UDP/TCP | 514/1470 |
291+
| `firewall-cisco-firepower` | UDP/TCP | 514/1470 |
292+
| `cisco-switch` | UDP/TCP | 514/1470 |
293+
| `firewall-meraki` | UDP/TCP | 514/1470 |
294+
| `firewall-fortigate-traffic` | UDP/TCP | 7005 |
295+
| `firewall-paloalto` | UDP/TCP | 7006 |
296+
| `firewall-mikrotik` | UDP/TCP | 7007 |
297+
| `firewall-sophos-xg` | UDP/TCP | 7008 |
298+
| `firewall-sonicwall` | UDP/TCP | 7009 |
299+
| `deceptive-bytes` | UDP/TCP | 7010 |
300+
| `antivirus-sentinel-one` | UDP/TCP | 7012 |
301+
| `ibm-aix` | UDP/TCP | 7016 |
302+
| `firewall-pfsense` | UDP/TCP | 7017 |
303+
| `firewall-fortiweb` | UDP/TCP | 7018 |
304+
| `suricata` | UDP/TCP | 7019 |
305+
| `netflow` | UDP | 2055 |
306+
| `nginx` | file | `/var/log/nginx/` |
307+
| `postgresql` | file | `/var/log/postgresql/` |
308+
309+
---
310+
311+
## Service management
312+
313+
```bash
314+
systemctl start UTMStackForwarder
315+
systemctl stop UTMStackForwarder
316+
systemctl restart UTMStackForwarder
317+
systemctl status UTMStackForwarder
318+
```
319+
320+
---
321+
322+
## Platform support
323+
324+
Linux only (amd64, arm64).
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strings"
7+
"time"
8+
9+
"github.com/spf13/cobra"
10+
collectorpkg "github.com/utmstack/UTMStack/collectors/forwarder/collector"
11+
)
12+
13+
var changePathsCmd = &cobra.Command{
14+
Use: "change-paths <name> <path1> [path2 ...]",
15+
Short: "Change the file paths watched by a file-based integration",
16+
Long: `Change the file paths monitored by a file-based log integration.
17+
At least one path must be provided.
18+
19+
Examples:
20+
utmstack_forwarder change-paths nginx /var/log/nginx/access.log
21+
utmstack_forwarder change-paths postgresql /var/log/postgresql/postgresql.log`,
22+
Args: cobra.MinimumNArgs(2),
23+
PreRunE: requireInstalled,
24+
RunE: func(cmd *cobra.Command, args []string) error {
25+
name := args[0]
26+
paths := args[1:]
27+
28+
fmt.Printf("Changing paths for integration %q to: %s ...\n", name, strings.Join(paths, ", "))
29+
30+
result, err := collectorpkg.ChangeFilePaths(name, paths)
31+
if err != nil {
32+
fmt.Printf("Error changing paths: %v\n", err)
33+
os.Exit(1)
34+
}
35+
36+
if len(result.OldPaths) > 0 {
37+
fmt.Printf("Old paths: %s\n", strings.Join(result.OldPaths, ", "))
38+
}
39+
fmt.Printf("Paths updated for integration %q\n", name)
40+
time.Sleep(2 * time.Second)
41+
return nil
42+
},
43+
}
44+
45+
func init() {
46+
rootCmd.AddCommand(changePathsCmd)
47+
}

0 commit comments

Comments
 (0)