opnsense / opnsense/plugins

[os-nginx] Add native Layer-7 enforcement of the autoblock/banned IP list behind trusted reverse proxies/CDNs

Open
#5,662 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
PHP
Stars
1.2k
Forks
863
Avg merge
2d 6h
Merged PRs (30d)
10

Description

Important notices
Before you add a new report, we ask you kindly to acknowledge the following:

Is your feature request related to a problem? Please describe.

Yes.

The os-nginx autoblock/permanent-ban functionality can detect an offending client and add its IP address to the existing Nginx Banned list and nginx_autoblock PF table.

This works well when clients connect directly to OPNsense, because PF sees the actual client IP as the TCP source.

However, when os-nginx is used behind a trusted reverse proxy or CDN such as Cloudflare, PF only sees the proxy/CDN address as the TCP source.

Nginx itself can correctly restore the real client IP, for example using:

real_ip_header CF-Connecting-IP;
set_real_ip_from <trusted proxy networks>;

After real-IP processing Nginx therefore knows the real attacking client IP, and that real IP can correctly end up in the existing OPNsense Nginx Banned list.

The problem is that PF still cannot enforce the ban against that restored client IP, because the underlying TCP connection originates from the CDN/reverse proxy.

Adding the restored client IP to a PF table therefore does not block the proxied connection. Blocking the CDN address instead is not acceptable because one CDN address can serve many unrelated visitors.

This creates a Layer-3 / Layer-7 enforcement gap for os-nginx deployments behind trusted reverse proxies or CDNs.

Describe the solution you'd like

I would like an optional native Nginx Layer-7 enforcement mechanism for the existing os-nginx banned/autoblock list.

For example:

  • Generate an Nginx geo or map from the existing active Nginx banned IP entries.
  • Respect the existing ban_ttl.
  • Enforce the ban against $remote_addr after trusted real-IP processing.
  • Keep the existing PF nginx_autoblock mechanism for direct connections.
  • Make Layer-7 enforcement optional.
  • Allow enforcement globally or on selected HTTP server objects.
  • Allow an optional trusted/exempt ACL, for example management LAN or VPN networks.
  • Support both IPv4 and IPv6 entries.
  • Reload Nginx only when the effective ban list changes.

A possible GUI implementation could be similar to:

[ ] Enforce banned IPs inside Nginx (Layer 7)
Scope: [All enabled HTTP servers / Selected HTTP servers]
Exempt ACL: [optional ACL]

This would also make it possible for one central os-nginx ban to be enforced across multiple public virtual hosts, even when requests arrive through a trusted reverse proxy/CDN.

Describe alternatives you've considered

  1. Existing PF nginx_autoblock

This works correctly for clients connecting directly to OPNsense, but cannot match a restored Layer-7 client IP when the TCP source is a CDN/reverse proxy.

  1. Blocking the CDN/reverse-proxy address

This is not appropriate because a single proxy address can serve many unrelated visitors.

  1. CDN-specific API blocking

For example, Cloudflare API/WAF rules could be used, but this is vendor-specific and duplicates ban state that os-nginx already maintains.

  1. Custom Nginx include hooks

I tested a working workaround using the existing os-nginx include hooks, an Nginx geo map, a small synchronization script, the existing ban_ttl, and trusted-network exemptions.

The workaround works, but native os-nginx support would be preferable because OPNsense could manage its lifecycle, configuration regeneration, server selection and exemptions.

Additional context

I tested the Layer-7 approach successfully with os-nginx behind Cloudflare.

The tested flow was:

malicious request
    ->
os-nginx detects the request
    ->
real client IP enters the existing OPNsense Nginx Banned list
    ->
active bans are made available to an Nginx geo map
    ->
restored client IP is rejected inside Nginx
    ->
HTTP 403 on all selected public virtual hosts

The test confirmed that:

  • the actual client IP was banned instead of a Cloudflare edge IP;
  • the same banned client was subsequently blocked on other public os-nginx virtual hosts;
  • Cloudflare addresses themselves were not blocked;
  • unlocking the IP through Services -> Nginx -> Banned restored access after synchronization;
  • IPv4 and IPv6 entries can be handled by the Nginx geo mechanism.

This request does not need to replace the current PF autoblock mechanism. Layer-7 enforcement could be an additional option specifically useful for trusted reverse-proxy/CDN deployments.

This is related to, but different from #4294. That issue concerns CrowdSec bouncers behind Cloudflare. This request is specifically about enforcing the existing native os-nginx autoblock/banned-IP list inside Nginx.

Replaces #5661, which was closed and recreated using the official Feature Request template at the request of OPNsense-bot.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the existing os-nginx Nginx Banned list, autoblock/PF handling, and include hooks, then review how the existing ban_ttl is exposed. Define the native geo or map synchronization, trusted-network exemptions, server scope, and reload behavior; done means restored IPv4 and IPv6 client addresses are blocked on selected hosts without blocking proxy addresses, while direct PF enforcement remains intact.

Written by the indexing model from the issue text.

Assessment

Tech stack
nginx
Domain
devops, networking, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.