iprepd-nginx

iprepd openresty 模块

$ opm get mozilla-services/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 头,并可以拒绝低于配置阈值的请求。

这三个头是

| 头部 | 值 | 描述 | |---|---|---| | 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 var 中的引号对 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

依赖项

版本