Security AWS

CrowdSec 1.8.1 on AWS User Guide

| Product: CrowdSec 1.8.1 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using the CrowdSec 1.8.1 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg WAF and Email Security listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.

CrowdSec is an open source, behaviour based intrusion detection and prevention engine. The crowdsec agent reads your logs, runs them through detection scenarios (SSH brute force, user enumeration, port scans and more) and records a decision, usually a ban, in its Local API. The firewall bouncer pulls those decisions from the Local API and drops traffic from banned addresses in nftables, the host firewall. The instance also subscribes to the CrowdSec community blocklist through the Central API, so addresses that attack other CrowdSec users are blocked before they reach you.

The image is headless: there is no web interface. You operate it with the cscli command line over SSH.

What cloudimg adds:

  • CrowdSec 1.8.1 and the nftables firewall bouncer 0.0.36 from the official CrowdSec apt repository, with the repository signing key and both packages pinned by checksum. They are not held, so apt upgrade keeps them patched.
  • Detection out of the box. The Linux and SSH collections are installed and the agent reads the system log and the SSH authentication log, so an SSH brute force against the instance is banned within seconds.
  • Per-instance secrets. On the first boot your instance creates its own Local API machine login and password, its own firewall bouncer API key and its own Central API registration. None of them ships in the image, and no two instances share one.
  • Authentication on the Local API. The agent logs in with its machine password and the bouncer with its API key. A request with a wrong or missing key is refused.
  • Loopback only. The Local API (127.0.0.1:8080) and the Prometheus metrics endpoint (127.0.0.1:6060) are not reachable from the network. SSH on port 22 is the only open port.
  • No lock-out. The source address of every successful SSH login is added to a CrowdSec allowlist for 30 days, which also lifts any ban on it, so the firewall bouncer never locks you out of your own instance.
  • Instance metadata blocked. The CrowdSec services cannot reach the EC2 instance metadata service. The instance requires IMDSv2.

Prerequisites

  • An AWS account subscribed to the cloudimg WAF and Email Security listing on AWS Marketplace.
  • An EC2 key pair in the Region you launch in.
  • A security group that allows inbound TCP 22 from your own address. No other inbound port is needed.

Step 1: Launch the instance

  1. Open the listing on AWS Marketplace, choose Continue to Subscribe, then Continue to Configuration.
  2. In Software version, choose CrowdSec 1.8.1 on Ubuntu 24.04, choose your Region, then Continue to Launch.
  3. Choose an instance type. m5.large is recommended; CrowdSec itself is light, so smaller types work for a single host.
  4. Choose your VPC, subnet, key pair and a security group that opens TCP 22 to your address only.
  5. Launch.

The first boot takes about a minute. It creates the instance's own credentials, registers with the Central API and then starts the engine and the firewall bouncer.

You can also allowlist your management addresses before the first boot, with user data. Each line of /etc/cloudimg/crowdsec-allowlist is an IPv4 or IPv6 address or CIDR range that CrowdSec never bans:

#cloud-config
write_files:
  - path: /etc/cloudimg/crowdsec-allowlist
    permissions: "0644"
    content: |
      <your-mgmt-cidr>

From the AWS CLI, with the AMI ID of the version you chose:

aws ec2 run-instances \
  --image-id <ami-id> \
  --instance-type m5.large \
  --key-name <key-name> \
  --security-group-ids <security-group-id> \
  --subnet-id <subnet-id> \
  --metadata-options HttpTokens=required \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=crowdsec}]'

Step 2: Connect to your instance

Connect over SSH as the ubuntu user with your key pair:

OS variant SSH login user
Ubuntu 24.04 ubuntu
ssh -i <key-name>.pem ubuntu@<public-ip>

The login message names the main commands and the instance notes file.

Step 3: Check the services and the ports

The engine and the firewall bouncer run as two system services:

systemctl is-active crowdsec crowdsec-firewall-bouncer crowdsec-firstboot
active
active
active

Confirm the installed versions:

sudo cscli version 2>&1 | head -1
sudo crowdsec-firewall-bouncer -version 2>&1 | head -1
version: v1.8.1-debian-pragmatic-amd64-909b5157
version: v0.0.36-debian-pragmatic-amd64-4c315193cd4f19e3937cdee2f15183ec4d602f56

Only SSH listens on the network. The Local API (8080) and the metrics endpoint (6060) listen on 127.0.0.1:

sudo ss -ltnp | awk 'NR==1 || /crowdsec|sshd/'
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0      4096       127.0.0.1:6060      0.0.0.0:*    users:(("crowdsec",pid=7823,fd=24))
LISTEN 0      4096       127.0.0.1:8080      0.0.0.0:*    users:(("crowdsec",pid=7823,fd=14))
LISTEN 0      4096         0.0.0.0:22        0.0.0.0:*    users:(("sshd",pid=985,fd=3),("systemd",pid=1,fd=109))
LISTEN 0      4096            [::]:22           [::]:*    users:(("sshd",pid=985,fd=4),("systemd",pid=1,fd=110))

Step 4: Your instance notes

The first boot writes a notes file for root. It holds no secrets: it tells you where this instance's credentials are and how to use them.

sudo cat /root/crowdsec-info.txt

The end of the file names this instance's own Local API machine and whether the Central API registration worked:

CROWDSEC_VERSION=1.8.1
CROWDSEC_MACHINE=<this instance's machine name>
CROWDSEC_FIREWALL_BOUNCER=crowdsec-firewall-bouncer
CROWDSEC_CENTRAL=registered

The credentials themselves are in root-only files (mode 0600):

File Holds
/etc/crowdsec/local_api_credentials.yaml the agent's Local API machine login and password
/etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml.local the firewall bouncer's API key
/etc/crowdsec/online_api_credentials.yaml this instance's Central API registration

Step 5: The Local API and its authentication

Check that the agent can log in to its Local API:

sudo cscli lapi status
Loaded credentials from /etc/crowdsec/local_api_credentials.yaml
Trying to authenticate with username "<this instance's machine name>" on http://127.0.0.1:8080/
You can successfully interact with Local API (LAPI)

The health endpoint answers on loopback:

curl -s -w '\n%{http_code}\n' http://127.0.0.1:8080/health
{"status":"up"}
200

Every other Local API call needs credentials. A request without a bouncer key is refused with HTTP 403:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/v1/decisions
403

List the registered machine and bouncer. There is exactly one of each, created on this instance's first boot:

sudo cscli machines list
sudo cscli bouncers list

Step 6: The community blocklist

Each instance registers itself with the CrowdSec Central API on its first boot. That shares the attacks your instance sees (the attacking address and the scenario, never your logs) and pulls the community blocklist, which the bouncer enforces like any other ban.

sudo cscli capi status
sudo cscli metrics show decisions
You can successfully interact with Central API (CAPI)
Sharing signals is enabled
Pulling community blocklist is enabled
Pulling blocklists from the console is enabled
+------------------------------------------+
| Local API Decisions                      |
+----------------+--------+--------+-------+
| Reason         | Origin | Action | Count |
+----------------+--------+--------+-------+
| generic:scan   | CAPI   | ban    | 6548  |
| ssh:bruteforce | CAPI   | ban    | 7365  |
| ssh:exploit    | CAPI   | ban    | 1087  |
+----------------+--------+--------+-------+

A brand new registration can receive an empty list on its very first pull (the engine logs received 0 new entries (expected if you just installed crowdsec)); the list fills on a later pull, every two hours or when the engine restarts.

The decisions with origin CAPI come from the community blocklist. If the instance has no internet route when it first boots, the engine runs with local detection only and the notes file says CROWDSEC_CENTRAL=not-registered. Register it later with sudo cscli capi register followed by sudo systemctl restart crowdsec.

To stop sharing signals and pulling the community blocklist, empty the Central API registration file and restart the engine; it then runs with local detection only:

sudo truncate -s 0 /etc/crowdsec/online_api_credentials.yaml
sudo systemctl restart crowdsec

Step 7: Detection and bans

The agent reads the system log and the SSH authentication log:

sudo cscli metrics show acquisition
+------------------------+------------+--------------+----------------+------------------------+-------------------+
| Source                 | Lines read | Lines parsed | Lines unparsed | Lines poured to bucket | Lines whitelisted |
+------------------------+------------+--------------+----------------+------------------------+-------------------+
| file:/var/log/auth.log | 143        | 26           | 117            | 96                     | -                 |
| file:/var/log/syslog   | 92         | -            | 92             | -                      | -                 |
+------------------------+------------+--------------+----------------+------------------------+-------------------+

The Linux and SSH collections are installed:

sudo cscli collections list
 crowdsecurity/linux                  ✔️  enabled  0.4      /etc/crowdsec/collections/linux.yaml
 crowdsecurity/sshd                   ✔️  enabled  0.9      /etc/crowdsec/collections/sshd.yaml
 crowdsecurity/whitelist-good-actors  ✔️  enabled  0.4      /etc/crowdsec/collections/whitelist-good-actors.yaml

List the alerts and the bans the engine has made. Within minutes of launch an internet-facing instance usually shows SSH brute force attempts here:

sudo cscli alerts list
sudo cscli decisions list

The firewall bouncer keeps the banned addresses in nftables sets in the crowdsec and crowdsec6 tables, and drops their traffic on the input and forward hooks:

sudo nft list tables
table ip crowdsec
table ip6 crowdsec6

Step 8: Never lock yourself out

The firewall bouncer drops every banned address, including on port 22. Three things keep you from banning yourself:

  1. Successful SSH logins. When you log in over SSH, a PAM hook adds your source address to the allowlist cloudimg-ssh-logins for 30 days (renewed at every login) and lifts any ban on it. Failed logins are never allowlisted.
  2. Private ranges. Addresses in 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16 are never banned, so bastion hosts and VPN gateways inside your VPC are safe.
  3. Your own allowlist. Add your office or VPN ranges to the cloudimg-admins allowlist, or put them in /etc/cloudimg/crowdsec-allowlist with user data before the first boot (Step 1).
sudo cscli allowlists list
sudo cscli allowlists inspect cloudimg-ssh-logins

To add a range for good:

sudo cscli allowlists add cloudimg-admins <your-mgmt-cidr> -d "office"

Adding an address to an allowlist also deletes any active ban on it. If you are ever locked out before your first successful login (for example, you connect from a shared address on the community blocklist), connect from another address or through AWS Systems Manager Session Manager and run sudo cscli decisions delete --ip <your address>.

Step 9: Ban and unban by hand

sudo cscli decisions add --ip 192.0.2.10 --duration 4h --reason "manual block"
sudo cscli decisions list --ip 192.0.2.10
sudo cscli decisions delete --ip 192.0.2.10

The bouncer applies a new decision within about ten seconds and removes it when the decision is deleted or expires.

Step 10: Protect your other services

Install the collection that matches each service you run on the instance, point the agent at its log, then reload the engine. For example, for nginx:

sudo cscli collections install crowdsecurity/nginx
sudo tee /etc/crowdsec/acquis.d/nginx.yaml <<'EOF'
filenames:
  - /var/log/nginx/access.log
  - /var/log/nginx/error.log
labels:
  type: nginx
EOF
sudo systemctl reload crowdsec

Browse the available collections with sudo cscli collections list -a. To protect other hosts, run a bouncer there and register it against this Local API (sudo cscli bouncers add <name>); the Local API listens on loopback only, so you decide how to expose it (for example by changing listen_uri in /etc/crowdsec/config.yaml and allowing the port from those hosts only).

Step 11: Updates

CrowdSec and the firewall bouncer come from the official CrowdSec apt repository, so they update with the rest of the system:

sudo apt update && sudo apt upgrade

The detection content (parsers, scenarios, collections) updates daily through crowdsec-hubupdate.timer:

systemctl list-timers crowdsec-hubupdate.timer --no-pager

Step 12: Security notes

  • The CrowdSec services run with a systemd IPAddressDeny for the instance metadata addresses only (169.254.169.254, fd00:ec2::254 and 168.63.129.16). The hub and the Central API stay reachable.
systemctl show -p IPAddressDeny crowdsec crowdsec-firewall-bouncer
IPAddressDeny=169.254.169.254/32 fd00:ec2::254/128 168.63.129.16/32

IPAddressDeny=169.254.169.254/32 fd00:ec2::254/128 168.63.129.16/32
  • The CrowdSec services do not start until the first boot has created this instance's credentials.
  • SSH accepts keys only; password logins are refused.
  • CrowdSec writes its logs to /var/log/crowdsec.log, /var/log/crowdsec_api.log and /var/log/crowdsec-firewall-bouncer.log.

Support and licensing

CrowdSec and the CrowdSec firewall bouncer are open source under the MIT licence; copies are in /usr/share/doc/cloudimg/crowdsec/LICENSE and /usr/share/doc/cloudimg/crowdsec-firewall-bouncer/LICENSE. cloudimg provides 24/7 support for this image: email support@cloudimg.co.uk.

CrowdSec is a trademark of its owner. cloudimg is not affiliated with or endorsed by CrowdSec.