nginxinc / nginx-gateway-fabric

NGINX Gateway Fabric provides an implementation for the Gateway API using NGINX as the data plane.
Apache License 2.0
497 stars 96 forks source link

Enable Proxy Protocol #1406

Closed mpstefan closed 1 month ago

mpstefan commented 10 months ago

As a user of NGF I want to enable proxy protocol for my application's endpoints So that the client's IP address is preserved as the traffic is forwarded to my application.

Acceptance

github-actions[bot] commented 8 months ago

This issue is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 14 days.

kate-osborn commented 3 months ago

Questions

  1. Would a user want to configure the directives in the real ip module to preserve client IP without enabling proxy protocol?

    _Yes. A user can leverage the directives in the real ip module to replace the $remote_addr and $remote_port variables with the original client IP address and port. For example, a user can configure NGINX to replace the $remote_addr and $remote_port variables using the value of the X-Forwarded-For header. This may be useful when the proxy fronting NGF doesn't implement PROXY protocol or isn't configured to accept & send PROXY protocol._

  2. If proxy_protocol is enabled but do not specify directives from realIP module , would that preserve any information of client's?

    Yes. Enabling proxy_protocol on the listener configures NGINX to accept the PROXY protocol. NGINX will also set the $proxy_protocol_addr and $proxy_protocol_port variables to the original client address and port. A user can then pass those values to the backend via headers, log the values, or configure rate limiting based on the values.

  3. If proxy_protocol is disabled, how will NGINX use set_real_ip_from directive, if set to CIDR/ Address.

    There are two important points to consider here. First, the default value for real_ip_header is X-Real-IP. Second, the default value for set_real_ip_from is empty string. This means that by default NGINX will not replace the $remote_addr and $remote_port variables because it does not trust any addresses. However, if a user sets the set_real_ip_from header to say "92.23.12.22", then NGINX will replace the $remote_addr and $remote_port variables to the value of the X-Real-IP header IF that header is sent by 92.23.12.22. So this is a valid use case even when proxy_protocol is disabled.

Methods for preserving client IP addresses

Choosing a method will depend on how the Load Balancer fronting NGF preserves the client IP address, and what the user wants to do with the client IP. If passing the client IP to the backend, then it's important to consider how the backend expects to receive this information.

Directive Behavior

proxy_protocol listen param

The proxy_protocol listen parameter configures NGINX server to accept the PROXY protocol. NGINX will also set the $proxy_protocol_addr and $proxy_protocol_port variables to the original client address and port.

real ip module

The real-ip module rewrites the values in the $remote_addr and $remote_port variables to the client IP address and port. Without this module, the $remote_addr and $remote_port variables are set to the IP address and port of the load balancer.

How the real-ip modules determines the client IP address and port depends on how you configure it.

set_real_ip_from

The set_real_ip_from directive tells NGINX to only trust replacement IPs from these addresses.

If not provided, the $remote_addr and $remote_port variables will never be replaced.

To trust all addresses, set to 0.0.0.0/0.

This directive is also used by the real_ip_recursive directive.

real_ip_header

By default NGINX will use the value of the X-Real-IP header. This directive can be set to X-Forwarded-To, proxy_protocol, or any other header name. If set to proxy_protocol, proxy_protocol must be enabled on the server.

real_ip_recursive

Only makes sense when the header specified in real_ip_header is a multi-value header (e.g. contains a list of addresses). Commonly used with X-Forwarded-For. For example:

Say you have the following setup:

[USER: 11.11.11.11] → [PROXY: 22.22.22.22] → [LB: 55.55.55.1] → [NGF: 77.77.77.77]

and the following NGINX config:

 set_real_ip_from 55.55.55.1;
 real_ip_header X-Forwarded-For;
 real_ip_recursive on;

Once the request hits NGF, the X-Forwarded-For header contains three IP addresses: X-Forwarded-For: [11.11.11.11, 22.22.22.22, 55.55.55.1]

Because real_ip_recursiveis on, NGINX will set $remote_addr to 22.22.22.22. This is because it recurses on the values in X-Forwarded-Header from end of array to start of array and selects the first untrusted ip. If you wanted to set $remote_addr to the user's IP address instead, and you trust the Proxy, you could achieve that by also specifying the Proxy's IP using set_real_ip_from:

 set_real_ip_from 55.55.55.1;
 set_real_ip_from 22.22.22.22;
 real_ip_header X-Forwarded-For;
 real_ip_recursive on;

If real_ip_recursive is off, NGINX will set $remote_addr to 55.55.55.1 because it will select the rightmost address.