Skip to content

CrowdSec: share blocked IPs with all subscribed machines #8184

Closed

Description

@gsanchietti

Attackers usually target many servers at once. Today, when a NethServer blocks an attacker, every other NethServer still has to detect the same attacker on its own.

Proposed solution

Share blocked attackers across all NethServer and NethSecurity machines with a subscription.

  • Every IP blocked by CrowdSec is sent to a central server.
  • An IP reported by at least X different machines goes into a shared blocklist.
  • CrowdSec downloads the shared blocklist every 15 minutes and blocks those IPs.
  • A new Threat Shield page in the CrowdSec app lets the admin:
    • enable or disable the shared blocklist and the other blocklists accessible only with Threat Shield entitlement
    • check whether an IP is blocked by one of these blocklists
  • Requires a subscription with the Threat Shield entitlement. Without it, the page explains what is missing.

Additional context

Mockup: https://www.figma.com/design/OsYqPXdkKJz0tBJRsiQgAf/NethServer-shared-file?node-id=5052-67725&t=Y5JZZT2M3PICjkfo-4

See also

Activity

  1. self-assigned this
    on Sep 24, 2026
  2. moved this from ToDo to In Progress in NethServeron Sep 24, 2026
  3. gsanchietti commented on Sep 29, 2026

    @gsanchietti
    MemberAuthor

    Testing versions: ns8-crowdsec:1.3.0-dev.2

    Install a new instance:

    add-module ghcr.io/nethserver/crowdsec:1.3.0-dev.2 1
    

    Update an existing instance:

    update-module ghcr.io/nethserver/crowdsec:1.3.0-dev.2 crowdsec1
    

    Test case 1: clean install, machine without subscription

    1. Install the module on a machine with no subscription.
    2. Open the Threat Shield page.
    3. Check that the page says a subscription is missing and that you can't enable any blocklist.

    Test case 2: clean install, machine with subscription and Threat Shield

    1. Install the module on a machine that has a subscription with the Threat Shield entitlement.
    2. Open the CrowdSec app and go to the new Threat Shield page.
    3. Check that the list of blocklists is shown, including the shared blocklist, and that you can change it.

    Test case 3: subscription without the Threat Shield entitlement

    1. Use a machine with a subscription that lacks the Threat Shield entitlement.
    2. Open the Threat Shield page.
    3. Check that the page says the entitlement is missing and that you can't enable any blocklist.

    Test case 4: update from the previous version

    1. Install the previous version and note your current settings and allowlist.
    2. Update to 1.3.0-dev.1.
    3. Check that the app still works and your settings are kept.
    4. Open the Threat Shield page and check that it loads.

    Test case 5: after test case 2, enable and disable blocklists

    1. On the Threat Shield page, turn on one or more blocklists.
    2. Wait about 30 minutes, or run the import from the command line.
    3. Check that the page shows an import time and a count of blocked IPs for each turned-on blocklist.
    4. Turn one blocklist off.
    5. Check that its blocked IPs disappear after the next refresh and the other lists stay.

    Test case 6: check whether an IP is blocked

    1. On the Threat Shield page, type an IP that is in one of the enabled blocklists.
    2. Check that the page says it is blocked and names the blocklist.
    3. Type an IP that is in none of the lists.
    4. Check that the page says it is not blocked.
    5. Type an invalid IP and check that you get a clear error.

    Test case 7: shared blocklist gets your blocked attackers

    1. On a machine with a subscription, make CrowdSec block a test IP, for example by repeating failed logins from it.
    2. Check with the Threat Shield team that the central server received the report.

    Test case 9: Nethesis servers are never blocked

    1. Enable all blocklists on a machine with a subscription.
    2. Check that the machine can still reach the Nethesis subscription portal and that the connection is not blocked.
      Command: podman exec crowdsec1 cscli allowlists inspect nethesis_threat_shield
  4. added
    testingPackages are available from testing repositories
    on Sep 29, 2026
  5. removed their assignment
    on Sep 29, 2026
  6. added this to the NethServer 8.10 milestone on Sep 29, 2026
  7. self-assigned this
    on Sep 29, 2026
  8. stephdl commented on Sep 29, 2026

    @stephdl

    Result: not verified.

    I tested ns8-crowdsec:1.3.0-dev.2 on a 3-node Rocky 9 cluster. The issue header says dev.2 but test case 4 says dev.1. I used dev.2.

    TC1, no subscription: OK. On a clean install, the page shows "Subscription required" and every control is disabled. The timer is disabled, and there is no allowlist, no Insights push and no decision. When I removed the subscription from a working instance, the allowlist, the notification and the decisions were cleaned.

    TC2, clean install with Threat Shield: OK. The page lists 6 blocklists, including the shared Nethesis Insights list, with confidence levels and a tooltip. I can enable and save them.

    TC3, subscription without the add-on: OK. The page shows "Threat Shield add-on required" and every control is disabled. The decisions are purged. The global allowlist and the Insights push stay active.

    TC4, update from 1.2.3: OK. I kept the settings, the IP and FQDN allowlist, the extra collections and the nethvoice collection. The Threat Shield page loads and the global allowlist is created.

    TC5, enable and disable: OK. The import starts right after Save. The counts in the UI match the backend: 805, 6913, 12606 and 2. The 19790 IPs are in the nft set. When I disabled one list, only its decisions were removed.

    TC6, IP search: OK. A listed IP shows the blocklist name. An unlisted IP shows "not found". An invalid IP shows a clear error.

    TC7, sharing: to confirm. I banned 198.51.100.77 with ssh-bf at 2026-09-29 10:34:52 UTC, system_id C32D6058-22CD-4C6E-AA2C-32FC69A4E9BF. Can the Threat Shield team check that the server received it?

    TC9, Nethesis never blocked: OK. The allowlist has 347 entries. cscli decisions add is rejected for the Nethesis IPs, and my.nethesis.it is reachable.

    Issues found:

    1. The premium blocklists are sent to the CrowdSec CAPI. Import alerts have origin cscli-import and no scenario hash, so CrowdSec treats them as "custom". With share_custom: true in console.yaml, they are pushed as signals. I saw about 12 signals, one per import batch, each with up to 5000 IPs. Is this intended? I think the import should not be shared.
    2. The L3 feed has 15727 entries, but only 12606 are imported. The 3121 CIDR entries are dropped on purpose. But the search text says "including addresses covered by a blocked network". For example, 1.19.5.5 is inside 1.19.0.0/16 and is reported as not found. Should the text change, or should CIDRs be supported?
    3. After I removed the subscription, 1008 Threat Shield IPs stayed in the nft set crowdsec-blacklists-cscli-import. They are gone from the CrowdSec database, but they stay blocked until they expire, at most 65 minutes.
    4. The set-threat-shield API accepts feeds without the entitlement. The UI then shows "Enabled" on a disabled row.
    5. On a 375px screen, the Nethesis Insights tooltip goes off-screen on the right and its text is cut. The search result notification also overflows its card by about 9px.
    6. If I search an invalid IP after a valid search, the old "Address not found" message stays under the error.
    7. The Refresh button only reloads the page data. It does not start an import. Its position under "All blocklists refresh every 30 minutes" can mislead users.

    Desktop at 1440px and tablet at 768px look fine. On phone, the table scrolls horizontally without problems.

    I think the issues above need to be discussed and probably fixed before we mark this issue as verified.

  9. stephdl commented on Sep 29, 2026

    @stephdl

    About point 2. I checked it again. The search text is misleading. Network entries are dropped at import, so the search only matches exact IPs.

    I suggest changing the text to "Check whether an address is blocked by a Threat Shield blocklist". I also think we should say somewhere that network entries from the feeds are not imported.

  10. gsanchietti commented on Sep 29, 2026

    @gsanchietti
    MemberAuthor

    New testing image: ns8-crowdsec:1.3.0-dev.3

    The premium blocklists are sent to the CrowdSec CAPI. Import alerts have origin cscli-import and no scenario hash, so CrowdSec treats them as "custom". With share_custom: true in console.yaml, they are pushed as signals. I saw about 12 signals, one per import batch, each with up to 5000 IPs. Is this intended? I think the import should not be shared.

    We accept the limitation, otherwise findings for NethVoice scenarios will not be shared.

    The L3 feed has 15727 entries, but only 12606 are imported. The 3121 CIDR entries are dropped on purpose. But the search text says "including addresses covered by a blocked network". For example, 1.19.5.5 is inside 1.19.0.0/16 and is reported as not found. Should the text change, or should CIDRs be supported?

    Already known and documented: CIDR are not supported by banip.

    After I removed the subscription, 1008 Threat Shield IPs stayed in the nft set crowdsec-blacklists-cscli-import. They are gone from the CrowdSec database, but they stay blocked until they expire, at most 65 minutes.

    Fixed.

    The set-threat-shield API accepts feeds without the entitlement. The UI then shows "Enabled" on a disabled row.

    Non an issue, the lists can't be downloaded.

    On a 375px screen, the Nethesis Insights tooltip goes off-screen on the right and its text is cut. The search result notification also overflows its card by about 9px.

    Fix, but mobile UI is not the focus of this page

    If I search an invalid IP after a valid search, the old "Address not found" message stays under the error.

    Fixed.

    The Refresh button only reloads the page data. It does not start an import. Its position under "All blocklists refresh every 30 minutes" can mislead users.

    Refresh button has been removed

  11. stephdl commented on Sep 29, 2026

    @stephdl

    I retested ns8-crowdsec:1.3.0-dev.3. I updated from dev.2 with an enterprise subscription.

    Point 3: fixed. With all feeds disabled, the nft set crowdsec-blacklists-cscli-import is emptied right away. The no-subscription path calls the same refresh_firewall(), but I did not test it live.

    Point 5: mostly fixed. The search notification now fits its card on a 375px screen. The tooltip is fine on desktop and tablet. On 375px it now starts at x=21, under the 48px side rail, so the first letter of each line is hidden. Minor, since mobile is not the focus.

    Point 6: fixed. Only "Invalid IP address" is shown after I edit the IP.

    Point 7: fixed. The Refresh button is gone.

    The search hint now says "Check whether an address is blocked by a Threat Shield blocklist." That is fine for me.

    I accept the answers on points 1, 2 and 4.

    TC7: Giacomo confirmed that the central server received the ban from system key C32D6058-22CD-4C6E-AA2C-32FC69A4E9BF.

    For me this is verified.

  12. added
    verifiedAll test cases were verified successfully
    and removed
    testingPackages are available from testing repositories
    on Sep 29, 2026
  13. stephdl commented on Oct 5, 2026

    @stephdl

    @gsanchietti can we release this version or you have work on the backend side

  14. gsanchietti commented on Oct 5, 2026

    @gsanchietti
    MemberAuthor

    I still need few days to validate the backend part

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    verifiedAll test cases were verified successfully

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions