YARP IP Filters

Configuration

Service registration and the IPFilterConfiguration section

Service Registration

Two things must be wired up: the policy provider (a singleton service that holds the parsed policies) and the middleware (added to YARP's pipeline).

AddIPFilterPolicies() — from configuration

The common path binds the IPFilterConfiguration section from your IConfiguration:

builder.Services.AddIPFilterPolicies(builder.Configuration);

The section name defaults to "IPFilterConfiguration". Pass a different name if you keep the policies elsewhere:

builder.Services.AddIPFilterPolicies(builder.Configuration, configSectionName: "MyIpFilters");

This registers IIPFilterPolicyProvider (implemented by IPFilterPolicyProvider) as a singleton and binds IPFilterPoliciesConfiguration via the options system, so configuration reloads are picked up at runtime.

AddIPFilterPolicies() — from code

To build policies imperatively instead of from configuration, pass a configuration action:

builder.Services.AddIPFilterPolicies(policies =>
{
    policies.Add(new IPFilterPolicy
    {
        PolicyName = "Intranet",
        Mode = IPFilterPolicyMode.AllowList,
        IPNetworks = ["192.168.0.0/24"]
    });
});

See Advanced for the full programmatic setup, including the global policy.

UseIPFilterPolicies() — the middleware

Register the middleware inside MapReverseProxy:

app.MapReverseProxy(proxyPipeline =>
{
    proxyPipeline.UseIPFilterPolicies();
    proxyPipeline.UseLoadBalancing();
});

Important: UseIPFilterPolicies() extends YARP's IReverseProxyApplicationBuilder. Do not add the middleware to the regular ASP.NET Core pipeline (app.UseMiddleware<...>()) — it reads the current route from the YARP reverse-proxy feature, which is only present inside MapReverseProxy. Adding it first means blocked requests are rejected before load balancing, session affinity, or transforms run.

The IPFilterConfiguration section

{
  "IPFilterConfiguration": {
    "EnableGlobalPolicy": true,
    "GlobalPolicyName": "Global",
    "Policies": [
      {
        "PolicyName": "Global",
        "Mode": "BlockList",
        "IPAddresses": ["192.168.0.3", "192.168.0.4"]
      },
      {
        "PolicyName": "Intranet",
        "Mode": "AllowList",
        "IPNetworks": ["192.168.0.0/24"]
      },
      {
        "PolicyName": "TestPolicy",
        "Mode": "Disabled",
        "IPAddresses": ["192.168.0.3", "192.168.0.4"],
        "IPNetworks": ["192.168.0.0/24"]
      }
    ]
  }
}

Top-level keys

KeyTypeDefaultDescription
Policiesarray[]The list of policies. Each PolicyName must be unique — the provider indexes policies by name.
EnableGlobalPolicyboolfalseWhen true, the policy named by GlobalPolicyName is evaluated for every request before route-specific policies. See Global Policy.
GlobalPolicyNamestring"Global"The name of the policy used as the global policy when EnableGlobalPolicy is true.

When EnableGlobalPolicy is true but no policy matches GlobalPolicyName, the provider throws at startup (and on every reload). Either add the matching policy or set EnableGlobalPolicy to false.

Policy keys

KeyTypeDefaultDescription
PolicyNamestring"DefaultPolicy"Unique name used to reference the policy from route metadata or as the global policy.
ModeenumAllowListDisabled, AllowList, or BlockList. See Policies.
IPAddressesarray[]Individual IP addresses (IPv4 or IPv6).
IPNetworksarray[]CIDR networks, e.g. "192.168.0.0/24".

IPAddresses and IPNetworks may be used together in a single policy — a request matches the policy if it matches either list. See Policies for exactly how each mode interprets a match.

Logging

The middleware logs through Microsoft.Extensions.Logging. It uses the high-performance LoggerMessage pattern on the request-handling path, with these events:

Event IDLevelWhen
1001 RequestBlockedGlobalWarningA request was blocked by the global policy.
1002 NoIPPolicyFoundDebugThe route has no IPFilterPolicy metadata; middleware is bypassed.
1003 PolicyIsNullCriticalA route references a policy name that does not exist.
1004 PolicyIsDisabledInformationThe referenced policy is in Disabled mode; request passes through.
1005 RequestBlockedWarningA request was blocked by a route-specific policy.
1006 RequestAllowedInformationA request was allowed by a route-specific policy.

Configure levels per category as you would for any ASP.NET Core app:

{
  "Logging": {
    "LogLevel": {
      "BBelius.Yarp.ReverseProxy.IPFilters": "Information"
    }
  }
}