Skip to content

proxyconf/api-fence

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

API Fence for Envoy [WIP / Experimental]

An HTTP filter for Envoy Proxy that validates requests against OpenAPI specifications, built as a dynamic module using Rust.

Quick Start

# Install mise (if not already installed)
# See https://mise.jdx.dev/getting-started.html

# Enter development environment
mise install

# Build the filter
mise run build

# Run tests
mise run test

# The compiled filter is at:
# target/release/libapi_fence.so

Features

  • OpenAPI Validation: Validates HTTP requests and responses against OpenAPI 3.x specifications
    • Path parameter validation with JSON Schema
    • Query parameter validation with JSON Schema
    • Request header validation (required, pattern, format, etc.)
    • Request body validation (JSON with schema)
    • Response header validation (required, pattern, format, etc.)
    • Response body validation (JSON with schema)
  • ModSecurity WAF Integration: Web Application Firewall protection using libmodsecurity3
    • Request and response body scanning
    • Bundled OWASP CoreRuleSet (CRS) v4.0.0 with zero-configuration setup
    • Protection against SQLi, XSS, RCE, LFI/RFI, and protocol attacks
    • Multiple ruleset profiles: full, request-only, or minimal (fastest)
    • Dual ruleset support for safe migration between CRS versions
    • Async scanning with thread pool for non-blocking operation
    • Configurable timeout and fail-open/fail-closed behavior
    • JSON string extraction optimization to reduce false positives
    • Base64 detection to skip encoded data scanning
    • Block or alert modes for matched rules
    • Custom rules via inline, file path, or remote URL
  • Mock Response Generation: Generate mock responses for API testing without a backend
    • Example-based: Use examples from OpenAPI response definitions
    • Schema-based: Generate realistic fake data matching response schemas
    • Random selection: Automatically chooses from multiple possible response codes (200, 201, 206, etc.)
    • Validation-first: Requests are validated before mocking (useful for contract testing)
    • Works with all request types (GET, POST, PUT, etc.)
  • Dynamic Module: Loads into Envoy without recompilation
  • Schema Caching: Compiled JSON schemas are cached with configurable TTL for optimal performance
  • Flexible Validation: Configure request/response validation independently
  • Error Handling: Choose to fail requests on validation errors or pass them through with metadata
  • Rich Metrics: Track cache hits/misses, schema compilation time, validation errors, and WAF detections (scoped per API)
  • Dynamic Metadata: Validation and WAF results are exposed as Envoy dynamic metadata for logging
  • Production Ready: Optimized builds with LTO and stripping, static linking for portability

Metrics

The filter exposes the following metrics, scoped under your configured api_name:

OpenAPI Validation:

  • api_fence.<api_name>.cache.hits - Number of schema cache hits
  • api_fence.<api_name>.cache.misses - Number of schema cache misses
  • api_fence.<api_name>.schema.compile_time_ms - Histogram of schema compilation times
  • api_fence.<api_name>.request.validation_errors - Count of request validation errors
  • api_fence.<api_name>.response.validation_errors - Count of response validation errors

ModSecurity WAF (when enabled):

  • api_fence.<api_name>.modsec.request.scans - Total request scans performed
  • api_fence.<api_name>.modsec.request.blocked - Requests blocked by WAF rules
  • api_fence.<api_name>.modsec.request.alerts - Requests with alerts (matched but not blocked)
  • api_fence.<api_name>.modsec.request.timeouts - Request scan timeouts
  • api_fence.<api_name>.modsec.request.scan_time_ms - Request scan duration histogram
  • api_fence.<api_name>.modsec.response.scans - Total response scans performed
  • api_fence.<api_name>.modsec.response.blocked - Responses blocked by WAF rules
  • api_fence.<api_name>.modsec.response.alerts - Responses with alerts
  • api_fence.<api_name>.modsec.response.timeouts - Response scan timeouts
  • api_fence.<api_name>.modsec.response.scan_time_ms - Response scan duration histogram
  • api_fence.<api_name>.modsec.strings_extracted - Total strings extracted from JSON
  • api_fence.<api_name>.modsec.base64_skipped - Base64 strings skipped to reduce false positives

For example, with api_name: "users_api", metrics will appear as:

  • api_fence.users_api.cache.hits
  • api_fence.users_api.request.validation_errors
  • api_fence.users_api.modsec.request.blocked

This allows multiple filter instances to track metrics independently.

Access metrics at http://localhost:9901/stats/prometheus

Dynamic Metadata

Validation and WAF results are exposed as dynamic metadata in the api_fence namespace:

OpenAPI Validation:

  • request.verdict - "valid" or "invalid"
  • request.error_count - Number of validation errors
  • request.errors - Pipe-separated list of error messages
  • response.verdict - "valid" or "invalid"
  • response.error_count - Number of validation errors
  • response.errors - Pipe-separated list of error messages

ModSecurity WAF (when enabled):

  • modsec.request.verdict - "blocked", "allowed", or "alert"
  • modsec.request.ruleset - Name of ruleset used for enforcement
  • modsec.request.matched_rules - JSON array of matched rule IDs (e.g., [942100, 941110])
  • modsec.request.matched_messages - Pipe-separated rule messages
  • modsec.request.scan_time_ms - Scan duration in milliseconds
  • modsec.request.timed_out - Boolean indicating if scan timed out
  • modsec.response.verdict - "blocked", "allowed", or "alert"
  • modsec.response.ruleset - Name of ruleset used for enforcement
  • modsec.response.matched_rules - JSON array of matched rule IDs
  • modsec.response.matched_messages - Pipe-separated rule messages
  • modsec.response.scan_time_ms - Scan duration in milliseconds
  • modsec.response.timed_out - Boolean indicating if scan timed out

Use these in access logs to track validation and security issues:

%DYNAMIC_METADATA(api_fence:request.verdict)%
%DYNAMIC_METADATA(api_fence:request.errors)%
%DYNAMIC_METADATA(api_fence:modsec.request.verdict)%
%DYNAMIC_METADATA(api_fence:modsec.request.matched_messages)%

Development

This project uses Mise for development environment management. See Agent.md for detailed documentation.

Requirements

  • Mise installed
  • System dependencies: libmodsecurity3-dev, clang, llvm (for bindgen)
  • (Optional) Envoy binary for integration tests

Building

mise run build  # or: cargo build --release

The compiled shared library will be at target/release/libapi_fence.so.

Testing

# Unit tests
mise run test-unit

# Integration tests with Envoy
mise run test-integration

# All tests
mise run test

# See available tasks
mise tasks

See tests/README.md for details.

Configuration

The filter supports comprehensive configuration options:

http_filters:
  - name: envoy.filters.http.dynamic_module
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter
      dynamic_module_config:
        name: api_fence
        do_not_close: true
      filter_name: api_fence
      filter_config:
        "@type": "type.googleapis.com/google.protobuf.StringValue"
        value: |
          {
            "api_name": "my_api",
            "openapi_spec_path": "/path/to/openapi.yaml",
            "cache": {
              "max_capacity": 1000,
              "ttl_seconds": 3600
            },
            "validation": {
              "validate_request": true,
              "validate_response": false,
              "fail_on_request_error": true,
              "fail_on_response_error": false
            }
          }

Configuration Options

API Name (required):

  • api_name - Unique identifier for this API/filter instance. Used for metric scoping to allow multiple filter instances to have separate metrics. Example: "users_api", "orders_api"

OpenAPI Spec (required, one of):

  • openapi_spec_path - Path to OpenAPI spec file (YAML or JSON)
  • openapi_spec_inline - Inline OpenAPI spec as YAML/JSON string

Cache Configuration (optional):

  • cache.max_capacity - Maximum cached schemas (default: 1000)
  • cache.ttl_seconds - Cache time-to-live in seconds (default: 3600)

Validation Configuration (optional):

  • validation.validate_request - Enable request validation (default: true)
  • validation.validate_response - Enable response validation (default: false)
  • validation.fail_on_request_error - Reject invalid requests (default: true)
  • validation.fail_on_response_error - Reject invalid responses (default: false)

When fail_on_*_error is false, validation errors are recorded in metrics and metadata but the request/response continues.

ModSecurity WAF Configuration (optional):

  • modsecurity.scan_request - Enable request body scanning (default: false)
  • modsecurity.scan_response - Enable response body scanning (default: false)
  • modsecurity.scan_response_as_request - Use request scanning API for responses (default: false)
  • modsecurity.request_action - Action on match: "block" or "alert" (default: "block")
  • modsecurity.response_action - Action on match: "block" or "alert" (default: "alert")
  • modsecurity.pool.timeout_ms - Maximum scan timeout in milliseconds (default: 100)
  • modsecurity.pool.timeout_action - Action on timeout: "allow" or "block" (default: "allow")
  • modsecurity.pool.queue_capacity - Maximum queue depth for pending scans (default: 1000)

ModSecurity Ruleset Configuration:

  • modsecurity.primary_ruleset.name - Ruleset name for metrics/metadata (required)
  • modsecurity.primary_ruleset.use_bundled_crs - Use bundled OWASP CRS v4.0.0 (default: false)
  • modsecurity.primary_ruleset.bundled_crs_profile - CRS profile: "full", "request", or "minimal" (default: "full")
  • modsecurity.primary_ruleset.rules_path - Paths to rule files (supports glob patterns like /path/*.conf)
  • modsecurity.primary_ruleset.rules_inline - Inline rules as a string
  • modsecurity.primary_ruleset.rules_remote.url - Remote URL to fetch rules from
  • modsecurity.primary_ruleset.rules_remote.key - Optional API key for authentication
  • modsecurity.secondary_ruleset.* - Optional secondary ruleset for safe migration testing

The bundled CRS profiles provide zero-configuration WAF protection:

  • full: All essential CRS rules (request + response scanning) - comprehensive protection
  • request: Request-only rules (no response scanning) - faster, good for most APIs
  • minimal: SQLi, XSS, RCE only - fastest, protects against most critical attacks

Mocking Configuration (optional):

  • mocking.enabled - Enable mock response generation (default: false)
  • mocking.prefer_examples - Use OpenAPI examples before schema-based generation (default: true)
  • mocking.default_status_code - Override default status code for mocking (default: first 2xx response)
  • mocking.add_mock_header - Include x-mock-response: true header in mock responses (default: true)

When mocking is enabled, requests are still validated (if configured), but instead of forwarding to the backend, the filter generates and returns a mock response. This is useful for:

  • Contract testing: Validate requests without needing a backend
  • Frontend development: Test UI against API contracts
  • Integration testing: Test API consumers with realistic responses
  • Load testing: Test proxy/middleware performance without backend load

Example Configurations

See examples/ directory:

  • envoy-config.yaml - Basic configuration with request validation
  • envoy-config-advanced.yaml - Advanced config with response validation, pass-through mode, and full access logging
  • envoy-config-mock.yaml - Mock response generation for API testing (no backend required)
  • envoy-modsec-config.yaml - ModSecurity WAF with bundled CRS rules
  • sample-openapi.yaml - Example OpenAPI spec with header validation
  • header-validation-example.yaml - Comprehensive header validation examples (required/optional, patterns, formats, enums)
  • mock-example-openapi.yaml - OpenAPI spec with response examples for mocking

ModSecurity WAF Configuration Example

Enable WAF scanning with bundled OWASP CoreRuleSet:

filter_config:
  value: |
    {
      "api_name": "protected_api",
      "openapi_spec_path": "./examples/sample-openapi.yaml",
      "validation": {
        "validate_request": true,
        "fail_on_request_error": true
      },
      "modsecurity": {
        "scan_request": true,
        "scan_response": false,
        "request_action": "block",
        "response_action": "alert",
        "pool": {
          "timeout_ms": 100,
          "timeout_action": "allow"
        },
        "primary_ruleset": {
          "name": "crs_v4",
          "use_bundled_crs": true,
          "bundled_crs_profile": "request"
        }
      }
    }

This configuration provides:

  • OpenAPI validation for request structure
  • ModSecurity WAF scanning for attack patterns (SQLi, XSS, RCE, etc.)
  • Fast request-only CRS profile
  • 100ms scan timeout with fail-open behavior
  • Block on WAF matches, continue on timeouts

For custom rules or external CRS installations:

"modsecurity": {
  "scan_request": true,
  "primary_ruleset": {
    "name": "custom_rules",
    "rules_path": [
      "/etc/modsecurity/modsecurity.conf",
      "/etc/modsecurity/crs/*.conf"
    ]
  }
}

For safe migration testing with dual rulesets:

"modsecurity": {
  "scan_request": true,
  "primary_ruleset": {
    "name": "crs_v3",
    "rules_path": ["/etc/modsecurity/crs-v3/*.conf"]
  },
  "secondary_ruleset": {
    "name": "crs_v4",
    "use_bundled_crs": true
  }
}

Both rulesets are evaluated, but if both match, the secondary (NEW) result is used for enforcement.

Mock Response Generation Example

Enable mocking to test API contracts without a backend:

filter_config:
  value: |
    {
      "api_name": "mock_api",
      "openapi_spec_path": "./examples/mock-example-openapi.yaml",
      "validation": {
        "validate_request": true,
        "fail_on_request_error": false
      },
      "mocking": {
        "enabled": true,
        "prefer_examples": true,
        "add_mock_header": true
      }
    }

Test with curl:

# GET request - returns mock data from OpenAPI examples
curl -v http://localhost:10000/users

# POST request - validates body, then returns mock response
curl -v http://localhost:10000/users/1 \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"name":"John","email":"john@example.com"}'

# Mock response includes indicator header
# x-mock-response: true

Mock responses are generated using:

  1. Examples first (if prefer_examples: true): Uses example fields from OpenAPI responses
  2. Schema-based fallback: Generates realistic fake data matching the schema (emails, UUIDs, dates, etc.)
  3. Random selection: For operations with multiple 2xx responses (200, 201, 206), randomly chooses one

Supported schema types for generation:

  • Strings: Supports formats (email, uri, uuid, date, date-time) and enums
  • Numbers/Integers: Respects min/max constraints
  • Booleans: Random true/false
  • Arrays: Generates 1-5 items
  • Objects: Generates all properties
  • Limitations: OneOf/AllOf/AnyOf schemas not yet supported

Project Status

🚧 Early Development - This project is in active development.

License

Mozilla Public License 2.0 (MPL-2.0)

All source files include SPDX license identifiers:

// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2026 ProxyConf Authors

Contributing

When contributing code:

  • Every Rust file (.rs) must include the SPDX header shown above
  • Follow the project rules in .opencode/rules/rust.md
  • Use templates from .opencode/templates/ for new files
  • Run tests and linters before submitting

Resources

About

Envoy flter for API security

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors