Skip to content

Commit d8699e5

Browse files
authored
Add user guide for log centralization with rsyslog (#788)
1 parent 2e38edc commit d8699e5

File tree

4 files changed

+280
-2
lines changed

4 files changed

+280
-2
lines changed

crowdsec-docs/docs/intro.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ This architecture allows for both simple/standalone setups, or more distributed
6262

6363
- Single machine ? Follow our [getting started guide](/getting_started/install_crowdsec)
6464
- Multiple machines? Use the [distributed setup guide](/u/user_guides/multiserver_setup)
65-
- Already have a log pit (such as rsyslog or loki)? Run crowdsec next to it, not on the production workloads
65+
- Already have a log pit (such as rsyslog or loki)? [Run crowdsec next to it](/u/user_guides/log_centralization), not on the production workloads
6666
- Running Kubernetes? Have a look at [our helm chart](/u/getting_started/installation/kubernetes)
6767
- Running containers? The [docker data source](/docs/data_sources/docker) might be what you need
6868
- Just looking for a WAF? Look at [our quickstart](appsec/intro)

crowdsec-docs/sidebarsUnversioned.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ module.exports = {
523523
"user_guides/multiserver_setup",
524524
"user_guides/consuming_fastly_logs",
525525
"user_guides/alert_context",
526-
"user_guides/appsec_tuto",
526+
"user_guides/log_centralization",
527527
],
528528
gettingStarted: [
529529
"getting_started/intro",

crowdsec-docs/static/img/user_guide_log_centralization.svg

Lines changed: 4 additions & 0 deletions
Loading
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
---
2+
id: log_centralization
3+
title: Log Centralization
4+
sidebar_position: 10
5+
---
6+
7+
## Introduction
8+
9+
If you expose services on the internet from multiple servers, setting up crowdsec on all of them might make the overall setup more complex.
10+
11+
To simplify things, you can use a central server to receive all your logs and only run a single instance of crowdsec on this server.
12+
13+
In this guide, our goal is to centralize two types of logs:
14+
- Nginx logs
15+
- SSH auth logs
16+
17+
We'll configure nginx to forward the access logs to our central rsyslog server.<br/>
18+
We'll configure a local rsyslog for the auth logs on each web server and forward them to our central server.
19+
20+
On the central server, a rsyslog server will receive those logs and write them into files.<br/>
21+
The Security Engine will analyze those logs on this same server to detect malicious behaviours.<br/>
22+
Finally, we will have a Firewall Remediation Component running on each web server to block the malicious IPs.
23+
24+
25+
Our infrastructure will look like this:
26+
27+
![target-infra](/img/user_guide_log_centralization.svg)
28+
29+
Before diving into the setup, a few key points:
30+
- If you have a firewall, you will need to allow communication on 514/UDP (Syslog) and 8080/TCP (crowdsec LAPI) from the web servers to the central server
31+
- By default, rsyslog is a clear-text protocol. If all the machines interact over LAN, this is probably not an issue, but if they communicate over the internet, you will probably want to set up TLS on the syslog server.
32+
33+
## Rsyslog Server Setup
34+
35+
Let's start by setting up our central rsyslog.
36+
37+
If rsyslog is not installed, you can install it with `apt install rsyslog` (assuming a debian-like distribution).
38+
39+
The first step is to configure rsyslog with a UDP listener and a template to write the received logs to disk.
40+
41+
Create the file `/etc/rsyslog.d/10_remote.conf` with the following content:
42+
```
43+
# Load the UDP receiver
44+
module(load="imudp")
45+
input(type="imudp" port="514")
46+
47+
# Create a template for the logs
48+
template(name="NginxLogs" type="string" string="/var/log/remote-logs/nginx/%HOSTNAME%.log")
49+
template(name="AuthLogs" type="string" string="/var/log/remote-logs/auth/%HOSTNAME%.log")
50+
51+
# Rsyslog will write both access logs and error logs to the same file
52+
# You can split them by using a custom program name on the nginx side
53+
if ($inputname == 'imudp' and $programname == 'nginx') then ?NginxLogs
54+
& stop
55+
56+
# Write SSH logs to auth.log
57+
if ($inputname == 'imudp' and $programname == 'sshd') then ?AuthLogs
58+
& stop
59+
60+
# Drop everything else; we are not interested in them
61+
if ($inputname == 'imudp') then stop
62+
```
63+
64+
Then, we need to create the `/var/log/remote-logs/` to store logs:
65+
```bash
66+
$ sudo mkdir /var/log/remote-logs/ && sudo chown syslog:syslog /var/log/remote-logs/
67+
```
68+
69+
You will also need to edit `/etc/rsyslog.conf` to make sure `$RepeatedMsgReduction` is set to `off` (some distributions set it to `on` by default, but this is rarely recommended, especially when consuming potentially a high volume of logs)
70+
71+
Finally, restart rsyslog to use the new configuration:
72+
```bash
73+
systemctl restart rsyslog
74+
```
75+
76+
We will also set up Logrotate to avoid filling our disk with the logs. Create a file `/etc/logrotate.d/remote-logs` with the following content:
77+
```
78+
/var/log/remote-logs/*/*.log {
79+
daily
80+
rotate 7
81+
compress
82+
missingok
83+
notifempty
84+
create 0640 syslog adm
85+
sharedscripts
86+
postrotate
87+
/bin/systemctl reload rsyslog.service > /dev/null 2>&1 || true
88+
endscript
89+
}
90+
```
91+
92+
This configuration will keep 7 days of compressed logs.
93+
94+
## Rsyslog Client Setup
95+
96+
### Nginx logs
97+
98+
Update your nginx configuration to send the access and error logs over syslog to our central server:
99+
```
100+
access_log syslog:server=<central-server-ip>;
101+
error_log syslog:server=<central-server-ip>;
102+
```
103+
104+
As nginx supports multiple `access_log` and `error_log` directives, you can keep the existing directives to keep a local copy of the logs.
105+
106+
### Auth logs
107+
108+
Create a file `/etc/rsyslog.d/99-auth-forward.conf` with the following content:
109+
```
110+
auth,authpriv.* @<central-server-ip>:514
111+
```
112+
113+
Restart the rsyslog client:
114+
```bash
115+
$ systemctl restart rsyslog
116+
```
117+
118+
## CrowdSec Setup
119+
120+
### Central Server
121+
122+
Back on the central server, let's install crowdsec.
123+
124+
First, we need to add the crowdsec repository:
125+
```bash
126+
$ curl https://install.crowdsec.net | sudo bash
127+
```
128+
129+
Next, we install crowdsec:
130+
```bash
131+
$ sudo apt install crowdsec
132+
```
133+
134+
CrowdSec will automatically detect we are running on a Linux server and install the base Linux collection.
135+
136+
But because our logs are not in a standard location, we need to configure the acquisition to tell crowdsec where our logs are.
137+
138+
Create a file in `/etc/crowdsec/acquis.d/nginx.yaml` with the following content:
139+
```
140+
filenames:
141+
- /var/log/remote-logs/nginx/*.log
142+
labels:
143+
type: syslog
144+
```
145+
146+
Repeat for auth logs, create a file `/etc/crowdsec/acquis.d/ssh.yaml` with the following content:
147+
```
148+
filenames:
149+
- /var/log/remote-logs/auth/*.log
150+
labels:
151+
type: syslog
152+
```
153+
154+
Note that we are setting the type label to `syslog`, instructing crowdsec to use the `syslog` parser to extract the actual type from the log itself.
155+
156+
Then, we need to install the nginx collection for crowdsec to be able to detect attacks:
157+
```bash
158+
$ sudo cscli collections install crowdsecurity/nginx
159+
```
160+
161+
Lastly, we will also need to make crowdsec on all interfaces to make sure our web servers can contact LAPI.<br/>
162+
Edit the file `/etc/crowdsec/config.yaml`, and set `api.server.listen_uri` to `0.0.0.0:8080`:
163+
```yaml
164+
api:
165+
server:
166+
listen_uri: 0.0.0.0:8080
167+
```
168+
169+
Finally, restart crowdsec:
170+
```bash
171+
$ sudo systemctl restart crowdsec
172+
```
173+
174+
### Remediation components setup
175+
176+
CrowdSec, by itself, will only detect bad behaviors and make decisions about IPs; it will not block them.
177+
178+
To block an IP, you need to install a [remediation component](/unversioned/bouncers/intro.md).
179+
180+
For this guide, we'll be using the [firewall remediation component](/unversioned/bouncers/firewall.mdx) that will add local firewall rules to block malicious IPs.
181+
182+
On your web servers, add the crowdsec repository:
183+
```bash
184+
$ curl https://install.crowdsec.net/ | bash
185+
```
186+
187+
Then, install the firewall remediation component:
188+
```bash
189+
$ sudo apt install crowdsec-firewall-bouncer-nftables
190+
```
191+
192+
We now need to create API keys for both our remediation components.
193+
On the central server, run the commands:
194+
```bash
195+
$ sudo cscli bouncers add fw-bouncer-web-1
196+
API key for 'fw-bouncer-web-1':
197+
198+
v3G2V//B4IAEFUkON3zWq5yz331UGZDQlQercn3n5T8
199+
200+
Please keep this key since you will not be able to retrieve it!
201+
$ sudo cscli bouncers add fw-bouncer-web-2
202+
API key for 'fw-bouncer-web-2':
203+
204+
Nda9MreJsUBt/EEmz3TI0Jr6p1a9U2XSx5CEeVfkNRw
205+
206+
Please keep this key since you will not be able to retrieve it!
207+
```
208+
209+
Now, on each web server, edit the file `/etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml` and update the `api_url` options with the IP on the central server, and paste the API key in `api_key`:
210+
211+
```yaml
212+
api_url: http://<central-server-ip>:8080/
213+
api_key: <API_KEY>
214+
```
215+
216+
Finally, restart the remediation component:
217+
```bash
218+
$ sudo systemctl restart crowdsec-firewall-bouncer
219+
```
220+
221+
## Test
222+
223+
Now that everything is setup, it's time to test !
224+
225+
We'll scan one of our web servers, and because both of them are querying the same crowdsec instance if one detects the attack, the other server will also block the attacker.
226+
227+
:::info
228+
229+
Replace the placeholders with the actual IP of your servers
230+
231+
:::
232+
233+
```bash
234+
$ nikto -h <server_1>
235+
```
236+
237+
After the scan is done, try to access the two servers with curl:
238+
239+
```bash
240+
$ curl --connect-timeout 2 <server_1>
241+
curl: (28) Connection timed out after 2002 milliseconds
242+
$ curl --connect-timeout 2 <server_2>
243+
curl: (28) Connection timed out after 2002 milliseconds
244+
```
245+
246+
You can also check on the central server that everything is working correctly:
247+
248+
```bash
249+
$ sudo cscli metrics
250+
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
251+
│ Acquisition Metrics │
252+
├─────────────────────────────────────────────────────┬────────────┬──────────────┬────────────────┬────────────────────────┬───────────────────┤
253+
│ Source │ Lines read │ Lines parsed │ Lines unparsed │ Lines poured to bucket │ Lines whitelisted │
254+
├─────────────────────────────────────────────────────┼────────────┼──────────────┼────────────────┼────────────────────────┼───────────────────┤
255+
│ file:/var/log/remote-logs/ip-172-31-11-52/auth.log │ 5 │ - │ 5 │ - │ - │
256+
│ file:/var/log/remote-logs/ip-172-31-11-52/nginx.log │ 1 │ 1 │ - │ 1 │ - │
257+
│ file:/var/log/remote-logs/ip-172-31-3-141/auth.log │ 3 │ - │ 3 │ - │ - │
258+
│ file:/var/log/remote-logs/ip-172-31-3-141/nginx.log │ 99 │ 99 │ - │ 195 │ - │
259+
│ file:/var/log/syslog │ 3 │ - │ 3 │ - │ - │
260+
╰─────────────────────────────────────────────────────┴────────────┴──────────────┴────────────────┴────────────────────────┴───────────────────╯
261+
```
262+
263+
And view the current decisions:
264+
265+
```bash
266+
$ sudo cscli decisions list
267+
╭───────┬──────────┬──────────────────┬──────────────────────────────────────┬────────┬─────────┬────────────────┬────────┬────────────┬──────────╮
268+
│ ID │ Source │ Scope:Value │ Reason │ Action │ Country │ AS │ Events │ expiration │ Alert ID │
269+
├───────┼──────────┼──────────────────┼──────────────────────────────────────┼────────┼─────────┼────────────────┼────────┼────────────┼──────────┤
270+
│ 30011 │ crowdsec │ Ip:X.X.X.X │ crowdsecurity/http-crawl-non_statics │ ban │ FR │ 12322 Free SAS │ 43 │ 3h57m29s │ 14 │
271+
╰───────┴──────────┴──────────────────┴──────────────────────────────────────┴────────┴─────────┴────────────────┴────────┴────────────┴──────────╯
272+
```
273+
274+
You can delete the decision with `cscli decision delete` to regain access to the web servers.

0 commit comments

Comments
 (0)