iprepd-nginx

iprepd OpenResty 模块

$ opm get moz-hwine/iprepd-nginx

iprepd-nginx 模块

iprepd-nginx 是一个用于与 iprepd 集成的 OpenResty 模块。

您可以使用此仓库中的示例配置来进行独立代理,或使用 opm 进行安装并自行集成。

注意:如果 Nginx 位于负载均衡器之后,请确保使用类似 ngx_http_realip_module 的模块。

iprepd-nginx 到底做了什么?

通过在 iprepd-nginx 中使用 iprepd 客户端,您可以配置 Nginx 在 iprepd 中检查传入客户端 IP 的信誉。根据此信誉,iprepd-nginx 将在转发到应用程序的请求上附加最多三个 HTTP 头,并且可以拒绝信誉低于配置阈值的请求。

这三个 HTTP 头是

| 头部 | 值 | 描述 | |---|---|---| | X-Foxsec-IP-Reputation | 整数 (0-100) | iprepd 返回的信誉分数 | | X-Foxsec-IP-Reputation-Below-Threshold | 布尔值 ('true'/'false') | 信誉是否低于配置的阈值 | | X-Foxsec-Block | 布尔值 ('true'/'false') | 请求是否应被阻止的高级指示(此指示的含义可能会发生变化) |

此外,iprepd-nginx 旨在故障开放,并优先考虑性能而非准确性。作为操作员,可以稍微更改性能优先于准确性的偏好,但只能在一定程度上进行更改(将在下面进一步讨论)。

(Mozilla 特定)架构图

!架构图

安装

使用 opm 进行安装

    opm get mozilla-services/iprepd-nginx

操作指南

先决条件

  • iprepd,最好靠近您的 iprepd-nginx 服务器(例如,在 AWS 或 GCP 的同一区域内)

  • 一种更新 iprepd 的机制。在 Mozilla,这是通过将来自负载均衡器、应用程序服务器和可能的其他位置的日志馈送到我们的 欺诈检测管道 来完成的。

  • (可选)一种收集 statsd 指标的机制。

关于性能的说明

iprepd-nginx 的核心要求是,它不会在请求中增加超过 10 毫秒的延迟。为了实现这一点,作为操作员,您应该了解一些机制

大量使用来自 iprepd 的响应缓存

默认情况下,iprepd-nginx 将缓存来自 iprepd 的所有非错误响应 30 秒。在生产环境中缓存错误是一个好主意,这可以通过启用 cache_errors 来完成(将在下面进一步讨论)。此外,您可能希望延长缓存 TTL。

对 iprepd 的严格超时

默认情况下,iprepd-nginx 对 iprepd 的请求将在 10 毫秒后超时。在生产环境中不应增加此值,如果网络设计可以支持,则可能值得减少。

客户端配置

threshold 参数

客户端中的 threshold 值是在 0 到 100 之间的数值,如果客户端 IP 在 iprepd 中的信誉低于此值,则将阻止这些客户端。

您希望将此值设置为多少将高度依赖于您的应用程序和环境,并考虑存在哪些类型的违规行为、客户端激活这些违规行为的可能性、客户端重试的频率等。

一个不错的起始值为 50,但您需要确保在您的环境中针对已实施的 iprepd 违规行为对其进行测试。

审计参数

客户端中的 audit 值允许配置将被阻止的请求记录到日志中,以用于安全审计目的。审计消息包括请求正文(如果足够小,可以在内存中缓冲),或者如果必须写入磁盘,则包含正文文件的名称。这取决于 nginx 设置 client_body_buffer_size

audit_blocked_requests 启用审计,默认情况下它被禁用。

audit_include_headers 在审计消息中包含请求头部。默认情况下,它被禁用。启用后,将删除 Authorization 和 Proxy-Authorization 头部值。

audit_uri_list 是一个应进行审计的 URI 表。启用审计时,此表是必需的。URI 可以是简单的字符串或 Lua 模式。例如,audit_uri_list = {"test", "/test/%d/somethingelse"} 将允许记录对 /test/1/somethingelse 以及 /test 的请求。

示例

    -- Parameters within options:
    --  Required parameters:
    --    api_key - An active API key for authenticating to iprepd
    --    threshold - The reputation threshold, where IP's with a reputation below this number will
    --                be blocked. There is no default for this, as it will be application specific,
    --                but as described above 50 is a good starting place.
    --
    --  Optional parameters:
    --    url - The base URL to iprepd (defaults to "http://localhost:8080/")
    --    timeout - The timeout for making requests to iprepd in milliseconds (defaults to 10)
    --    cache_ttl - The iprepd response cache ttl in seconds (defaults to 60)
    --    cache_buffer_count - Max number of entries allowed in the cache. (defaults to 5000)
    --    cache_errors - Enables (1) or disables (0) caching errors. Caching errors is a good
    --                   idea in production, as it can reduce the average additional latency
    --                   caused by this module if anything goes wrong with the underlying
    --                   infrastructure. (defaults to disabled)
    --    cache_errors_ttl - The iprepd response cache ttl for error responses (not 200 or 404) in seconds (defaults to 10)
    --    statsd_host - Host of statsd collector. Setting this will enable statsd metrics collection
    --    statsd_port - Port of statsd collector. (defaults to 8125)
    --    statsd_max_buffer_count - Max number of metrics in buffer before metrics should be submitted
    --                              to statsd (defaults to 100)
    --    statsd_flush_timer - Interval for attempting to flush the stats in seconds. (defaults to 5)
    --    blocking_mode - Enables (1) or disables (0) blocking within nginx by returning a
    --                    403. (defaults to disabled)
    --    verbose - Enables (1) or disables (0) verbose logging. Messages are logged with a
    --              severity of "ERROR" so that nginx log levels do not need to be changed. (defaults
    --              to disabled)
    --    whitelist - List of whitelisted IP's and IP CIDR's. (defaults to empty)
    -- audit_blocked_requests - records the body and optionally headers of requests that are being blocked within nginx (defaults disabled, if enabled the uris to audit must be given)
    -- audit_include_headers - if audit_blocked_requests is enabled, also record the headers (defaults disabled)
    -- audit_uri_list - a list of endpoints that will be audited if audit_blocked_requests is enabled (defaults to empty)
    --
    client = require("resty.iprepd").new({
      api_key = os.getenv("IPREPD_API_KEY"),
      threshold = 50,
      url = "http://127.0.0.1:8080",
      timeout = 10,
      cache_ttl = 30,
      cache_buffer_count = 1000,
      cache_errors = 1,
      cache_errors_ttl = 10,
      statsd_host = "127.0.0.1",
      statsd_port = 8125,
      statsd_max_buffer_count = 100,
      statsd_flush_timer = 10,
      blocking_mode = 0,
      verbose = 0,
      whitelist = {"127.0.0.1", "10.10.10.0/24", "192.168.0.0/16"},
      audit_blocked_requests = 0,
      audit_include_headers = 0,
      audit_uri_list = {}
    })

指标 (statsd)

收集的指标

| 名称 | 类型 | 描述 | |---|---|---| | iprepd.status.below_threshold | 计数 | 客户端 IP 的信誉低于配置的阈值。 | | iprepd.status.rejected | 计数 | 请求被阻止(如果 blocking_mode 被禁用,则不会发送)。 | | iprepd.status.accepted | 计数 | 请求被接受。如果 blocking_mode 被禁用,信誉仍然可能低于阈值。 | iprepd.get_reputation | 计数 | 对 iprepd 的请求 | | iprepd.cache_hit | 计数 | 从内部缓存获取信誉 | | iprepd.err.timeout | 计数 | 对 iprepd 的请求超时 | | iprepd.err.500 | 计数 | 从 iprepd 获取 500 响应 | | iprepd.err.401 | 计数 | 从 iprepd 获取 401 响应,通常表示正在使用的 API 密钥无效或 Nginx 发送错误。 | | iprepd.err.dns_timeout | 计数 | iprepd URL 的域名解析超时。请务必检查 nginx 的 resolver_timeout 设置 | | iprepd.err.* | 计数 | 在向 iprepd 发送请求时出现错误。例如,这可能是其他 4xx 或 5xx 状态代码。 |

设置自定义指标

您可以使用 client.statsd(其中 client = require("resty.iprepd").new({...}))来提交您自己的自定义指标。请注意,没有前缀,因此它将像任何其他 statsd 客户端一样工作。

可用的 statsd 函数

    client = require("resty.iprepd").new({...})
    
    client.statsd.count(name, value)
    client.statsd.incr(name) # Increments a count by 1
    client.statsd.time(name, value)
    client.statsd.set(name, value)

Nginx 配置中的示例

    init_by_lua_block {
      client = require("resty.iprepd").new({
        url = os.getenv("IPREPD_URL"),
        api_key = os.getenv("IPREPD_API_KEY"),
        statsd_host = os.getenv("STATSD_HOST"),
      })
    }
    
    init_worker_by_lua_block {
      # async flushing of metrics
      client:config_flush_timer()
    }
    
    server {
      ...
    
      location / {
        ...
    
        access_by_lua_block {
          client:check(ngx.var.remote_addr)
        }
    
        log_by_lua_block {
          # This conditional is not required, but can be helpful to not cause problems
          # if you want to temporarily disable statsd. This will evaluate to false if
          # `statsd_host` is not set.
          if client.statsd then
            # Here is our custom metric
            client.statsd.set("iprepd.ips_seen", ngx.var.remote_addr)
          end
        }
      }
    }

常见问题

  • 确保 iprepd-nginx 能够看到真实的客户端 IP。您通常需要使用类似 ngx_http_realip_module 的模块,并确认它已正确配置。

在本地运行

在此仓库中创建一个 .env 文件,其中包含所需的环境变量(文档如下)。

然后运行

    $ make build
    $ make run_dev

然后您将能够使用以下命令访问此代理:curl http://localhost:80

开发环境变量

注意

env 变量中的引号在 nginx 中很重要。如果您在 Docker 中使用 --env-file,请不要使用它们。

    # required
    backend=http://<>               # URL to proxy to
    IPREPD_URL=http://<>            # iprepd url
    IPREPD_API_KEY="api-key"        # iprepd api key
    IPREPD_REPUTATION_THRESHOLD=50  # iprepd reputation threshold, block all IP's with a reputation below the threshold
    
    #
    # optional
    #
    IPREPD_TIMEOUT=10
    IPREPD_CACHE_TTL=30
    IPREPD_CACHE_ERRORS=0
    STATSD_HOST=127.0.0.1
    STATSD_PORT=8125
    STATSD_MAX_BUFFER_COUNT=200
    STATSD_FLUSH_TIMER=2
    BLOCKING_MODE=0
    AUDIT_BLOCKED_REQUESTS=0
    AUDIT_INCLUDE_HEADERS=0

作者

AJ Bahnken (ajvb), Katie Kleemola (kkleemola)

许可证

mozilla2

依赖项

版本