Dev.to Security 🔐 Cybersecurity 👁 0 📖 3 min read

Nginx variable proxy_pass rules turn DNS into an access-control dependency

Nginx variable proxy_pass rules turn DNS into an access-control dependency An nginx reverse proxy can resolve an upstream name at startup or defer resolution until a request is evaluated. The difference changes startup

Nginx variable proxy_pass rules turn DNS into an access-control dependency

An nginx reverse proxy can resolve an upstream name at startup or defer resolution until a request is evaluated. The difference changes startup behavior, failover behavior, and, in security-sensitive environments, who can influence the address that receives traffic.

Two resolution models

The proxy module documents that an address in proxy_pass can be a domain name. When proxy_pass is written with variables, nginx postpones parsing the target until variable evaluation. If the name is not found in a defined server group, the configured resolver determines the address. That is why a variable-based proxy_pass usually needs a resolver directive.

A literal upstream name can be resolved once when the configuration is loaded. A named upstream block also gives the proxy a place to define server groups and health behavior. A variable target is useful for tenant routing, blue-green cutovers, and dynamic service discovery. It also moves the resolution decision into the request path.

The resolver is not a neutral implementation detail. It determines which DNS answer nginx trusts, how long the answer is cached, and whether an attacker who can register or compromise a name can steer the proxy to a new address.

The unsafe pattern

A rule that forwards to a user-controlled hostname is easy to write:

location /internal/ {
    proxy_pass http://$http_x_target$request_uri;
}

That example is intentionally unsafe. The client controls the target, and the proxy becomes a general request forwarder unless another layer removes the header or rewrites the route. Variables alone do not provide authorization.

A less obvious case uses a service name that the application team can change through a deployment system. The proxy may be configured correctly, but the DNS zone or service registry becomes the effective allowlist. If a service account can create a record for admin.internal.example, the proxy may reach it even when the application's own route map never mentioned that destination.

Make the target set explicit

For fixed internal services, prefer an explicit upstream block or a literal address. Keep the upstream boundary in configuration that requires the same review as a firewall rule. If dynamic resolution is necessary, limit it to names in a controlled zone and choose resolvers inside that trust boundary.

The core resolver directive allows an optional timeout and valid parameter. The valid parameter controls how long a resolved address may be cached. Choose it from the service-discovery model, not from a copied example. At the same time, block unintended path and method combinations with explicit location rules and remove client-supplied routing headers at the edge.

Do not use $host in proxy_pass as a convenience for forwarding. $host can reflect the incoming host header. If the proxy accepts arbitrary host names, that value is an input, not an authorization decision.

For outbound TLS, verify the certificate chain and the name nginx uses for the upstream. Internal TLS does not remove the need to validate identity. If the target address is resolved at request time, consider whether a hostname that changes after certificate validation can cause a mismatch. Keep the resolution and TLS validation behavior in the same test.

Test a change with the same care as a network rule

Run nginx -T and inspect the effective resolver, proxy_pass, and upstream definitions. Test a known-good service, a name that does not resolve, and a name outside the allowed zone. Confirm that the failure mode is a controlled error and that no retry path reaches a different host.

Observe DNS query volume and cache behavior after the change. A short valid interval can produce a large resolver load, while an overly long interval can keep traffic on a retired or compromised address. Record the exact resolver configuration and the service registry permissions beside the proxy policy.

Finally, review the people and systems that can change DNS records. A proxy can have a strong configuration and still inherit a weak resolver supply chain. The practical control is to make the destination set explicit, make name resolution observable, and ensure that the same review applies to every mechanism that can change the answer.

References

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.