Skip to content

BackendGroups with namespace starts with digit doesn't proxy_passed to split_clients correctly #2606

Closed
@eseiker

Description

@eseiker

Describe the bug
BackendGroups with namespace starts with digit doesn't proxy_passed to split_clients correctly.
For example, we have a namespace named 9c-network and one of its routes has multiple backends.
So ngf creates a split_clients named $9c_network__some_route_name_rule0 and generates a line proxy_pass http://$9c_network__some_route_name_rule0$request_uri;
However, it seems nginx processes the proxy_pass parameter as $9, c_network__..., not $9c_network__....
nginx responds with 502 Bad Gateway and I found a log that says no resolver defined to resolve c_network__some_route_name_rule0.
I suspect nginx think it's regex capture group if a split_clients starts with number.

To Reproduce
Steps to reproduce the behavior:

  1. create a namespace which its name starts with a digit
  2. create a random HTTPRoute in the namespace with parentRef pointing nginx-gateway-fabric
  3. http request to the route and see if it works

Expected behavior
responds with 2xx~4xx, not 502 Bad Gateway

Your environment

  • Version of the NGINX Gateway Fabric - release version or a specific commit. The first line of the nginx-gateway container logs includes the commit info.: "version":"1.4.0","commit":"8e653d6dfc671ca8f8d51f3eed29c25462f96e41"
  • Version of Kubernetes: 1.28
  • Kubernetes platform (e.g. Mini-kube or GCP): AWS EKS
  • Details on how you expose the NGINX Gateway Fabric Pod (e.g. Service of type LoadBalancer or port-forward): LoadBalancer with AWS NLB

Logs of NGINX container: kubectl -n nginx-gateway logs -l app=nginx-gateway -c nginx

Details
kubectl -n nginx-gateway logs -l app.kubernetes.io/name=nginx-gateway-fabric -c nginx
10.0.43.121 - - [26/Sep/2024:06:26:48 +0000] "GET /metrics HTTP/1.1" 404 146 "-" "Prometheus/2.41.0"
10.0.43.121 - - [26/Sep/2024:06:27:48 +0000] "GET /metrics HTTP/1.1" 404 146 "-" "Prometheus/2.41.0"
34.223.53.32 - - [26/Sep/2024:06:28:21 +0000] "GET / HTTP/1.1" 404 548 "-" "Mozilla/5.0 (Linux; Android 7.1.1; 1713-A01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36"
10.0.43.121 - - [26/Sep/2024:06:28:48 +0000] "GET /metrics HTTP/1.1" 404 146 "-" "Prometheus/2.41.0"
10.0.43.121 - - [26/Sep/2024:06:29:48 +0000] "GET /metrics HTTP/1.1" 404 146 "-" "Prometheus/2.41.0"
10.0.43.121 - - [26/Sep/2024:06:30:48 +0000] "GET /metrics HTTP/1.1" 404 146 "-" "Prometheus/2.41.0"
10.0.43.121 - - [26/Sep/2024:06:31:48 +0000] "GET /metrics HTTP/1.1" 404 146 "-" "Prometheus/2.41.0"
2024/09/26 06:31:51 [error] 52#52: *6 no resolver defined to resolve c_network__gateway_remote_headless_graphql_9c_network_rule0, client: 106.101.131.240, server: 9c-main-rpc.nine-chronicles.com, request: "GET /graphql HTTP/1.1", host: "9c-main-rpc.nine-chronicles.com"
106.101.131.240 - - [26/Sep/2024:06:31:51 +0000] "GET /graphql HTTP/1.1" 502 150 "-" "curl/8.7.1"
2024/09/26 06:31:52 [info] 52#52: *6 client 106.101.131.240 closed keepalive connection

NGINX Configuration: kubectl -n nginx-gateway exec <gateway-pod> -c nginx -- nginx -T

Details
kubectl -n nginx-gateway exec nginx-gateway-fabric-56dc457fcd-2mwjg -c nginx -- nginx -T
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# configuration file /etc/nginx/nginx.conf:
load_module /usr/lib/nginx/modules/ngx_http_js_module.so;
include /etc/nginx/module-includes/*.conf;

worker_processes auto;

pid /var/run/nginx/nginx.pid;
error_log stderr info;

events {
worker_connections 1024;
}

http {
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/mime.types;
js_import /usr/lib/nginx/modules/njs/httpmatches.js;

default_type application/octet-stream;

proxy_headers_hash_bucket_size 512;
proxy_headers_hash_max_size 1024;
server_names_hash_bucket_size 256;
server_names_hash_max_size 1024;
variables_hash_bucket_size 512;
variables_hash_max_size 1024;

sendfile on;
tcp_nopush on;

server_tokens off;

server {
listen unix:/var/run/nginx/nginx-status.sock;
access_log off;

location /stub_status {
    stub_status;
}

}
}

stream {
variables_hash_bucket_size 512;
variables_hash_max_size 1024;

map_hash_max_size 2048;
map_hash_bucket_size 256;

log_format stream-main '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time "$ssl_preread_server_name"';
access_log /dev/stdout stream-main;
include /etc/nginx/stream-conf.d/*.conf;
}

configuration file /etc/nginx/module-includes/load-modules.conf:

configuration file /etc/nginx/conf.d/config-version.conf:

server {
listen unix:/var/run/nginx/nginx-config-version.sock;
access_log off;

location /version {
    return 200 2;
}

}

configuration file /etc/nginx/conf.d/http.conf:

http2 on;

Set $gw_api_compliant_host variable to the value of $http_host unless $http_host is empty, then set it to the value

of $host. We prefer $http_host because it contains the original value of the host header, which is required by the

Gateway API. However, in an HTTP/1.0 request, it's possible that $http_host can be empty. In this case, we will use

the value of $host. See http://nginx.org/en/docs/http/ngx_http_core_module.html#var_host.

map $http_host $gw_api_compliant_host {
'' $host;
default $http_host;
}

Set $connection_header variable to upgrade when the $http_upgrade header is set, otherwise, set it to close. This

allows support for websocket connections. See https://nginx.org/en/docs/http/websocket.html.

map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}

Returns just the path from the original request URI.

map $request_uri $request_uri_path {
"~^(?P[^?])(?.)?$" $path;
}

js_preload_object matches from /etc/nginx/conf.d/matches.json;

server {
listen 80 default_server;
listen [::]:80 default_server;

default_type text/html;
return 404;

}

server {
listen 80;
listen [::]:80;

server_name 9c-main-rpc.nine-chronicles.com;


location / {




    proxy_http_version 1.1;
    proxy_set_header Host "$gw_api_compliant_host";
    proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
    proxy_set_header Upgrade "$http_upgrade";
    proxy_set_header Connection "$connection_upgrade";
    proxy_pass http://$9c_network__gateway_remote_headless_graphql_9c_network_rule0$request_uri;



}

}

server {
listen 80;
listen [::]:80;

server_name heimdall-arena.9c.gg;


location / {




    proxy_http_version 1.1;
    proxy_set_header Host "$gw_api_compliant_host";
    proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
    proxy_set_header Upgrade "$http_upgrade";
    proxy_set_header Connection "$connection_upgrade";
    proxy_pass http://heimdall_arena-service_80$request_uri;



}

}

server {
listen 80;
listen [::]:80;

server_name heimdall-dp.9c.gg;


location / {




    proxy_http_version 1.1;
    proxy_set_header Host "$gw_api_compliant_host";
    proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
    proxy_set_header Upgrade "$http_upgrade";
    proxy_set_header Connection "$connection_upgrade";
    proxy_pass http://invalid-backend-ref$request_uri;



}

}

server {
listen 80;
listen [::]:80;

server_name heimdall-market.9c.gg;


location / {




    proxy_http_version 1.1;
    proxy_set_header Host "$gw_api_compliant_host";
    proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
    proxy_set_header Upgrade "$http_upgrade";
    proxy_set_header Connection "$connection_upgrade";
    proxy_pass http://heimdall_market-service_80$request_uri;



}

}

server {
listen 80;
listen [::]:80;

server_name heimdall-patrol.9c.gg;


location / {




    proxy_http_version 1.1;
    proxy_set_header Host "$gw_api_compliant_host";
    proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
    proxy_set_header Upgrade "$http_upgrade";
    proxy_set_header Connection "$connection_upgrade";
    proxy_pass http://heimdall_patrol-reward-service_80$request_uri;



}

}

server {
listen 80;
listen [::]:80;

server_name heimdall-rpc.nine-chronicles.com;


location / {




    proxy_http_version 1.1;
    proxy_set_header Host "$gw_api_compliant_host";
    proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
    proxy_set_header Upgrade "$http_upgrade";
    proxy_set_header Connection "$connection_upgrade";
    proxy_pass http://$heimdall__gateway_remote_headless_graphql_heimdall_rule0$request_uri;



}

}

server {
listen 80;
listen [::]:80;

server_name heimdall-world-boss.9c.gg;


location / {




    proxy_http_version 1.1;
    proxy_set_header Host "$gw_api_compliant_host";
    proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
    proxy_set_header Upgrade "$http_upgrade";
    proxy_set_header Connection "$connection_upgrade";
    proxy_pass http://heimdall_world-boss-service_80$request_uri;



}

}

server {
listen 80;
listen [::]:80;

server_name odin-arena.9c.gg;


location / {




    proxy_http_version 1.1;
    proxy_set_header Host "$gw_api_compliant_host";
    proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
    proxy_set_header Upgrade "$http_upgrade";
    proxy_set_header Connection "$connection_upgrade";
    proxy_pass http://9c-network_arena-service_80$request_uri;



}

}

server {
listen 80;
listen [::]:80;

server_name odin-dp.9c.gg;


location / {




    proxy_http_version 1.1;
    proxy_set_header Host "$gw_api_compliant_host";
    proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
    proxy_set_header Upgrade "$http_upgrade";
    proxy_set_header Connection "$connection_upgrade";
    proxy_pass http://invalid-backend-ref$request_uri;



}

}

server {
listen 80;
listen [::]:80;

server_name odin-market.9c.gg;


location / {




    proxy_http_version 1.1;
    proxy_set_header Host "$gw_api_compliant_host";
    proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
    proxy_set_header Upgrade "$http_upgrade";
    proxy_set_header Connection "$connection_upgrade";
    proxy_pass http://9c-network_market-service_80$request_uri;



}

}

server {
listen 80;
listen [::]:80;

server_name odin-patrol.9c.gg;


location / {




    proxy_http_version 1.1;
    proxy_set_header Host "$gw_api_compliant_host";
    proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
    proxy_set_header Upgrade "$http_upgrade";
    proxy_set_header Connection "$connection_upgrade";
    proxy_pass http://9c-network_patrol-reward-service_80$request_uri;



}

}

server {
listen 80;
listen [::]:80;

server_name odin-world-boss.9c.gg;


location / {




    proxy_http_version 1.1;
    proxy_set_header Host "$gw_api_compliant_host";
    proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
    proxy_set_header Upgrade "$http_upgrade";
    proxy_set_header Connection "$connection_upgrade";
    proxy_pass http://9c-network_world-boss-service_80$request_uri;



}

}

server {
listen 31238 default_server;
listen [::]:31238 default_server;

default_type text/html;
return 404;

}

server {
listen 31238;
listen [::]:31238;

server_name 9c-main-rpc.nine-chronicles.com;


location / {



    include /etc/nginx/grpc-error-pages.conf;

    proxy_http_version 1.1;
    grpc_set_header Host "$gw_api_compliant_host";
    grpc_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
    grpc_set_header Authority "$gw_api_compliant_host";
    grpc_pass grpc://$9c_network__gateway_remote_headless_grpc_9c_network_rule0;



}
    include /etc/nginx/grpc-error-locations.conf;

}

server {
listen 31238;
listen [::]:31238;

server_name heimdall-rpc.nine-chronicles.com;


location / {



    include /etc/nginx/grpc-error-pages.conf;

    proxy_http_version 1.1;
    grpc_set_header Host "$gw_api_compliant_host";
    grpc_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
    grpc_set_header Authority "$gw_api_compliant_host";
    grpc_pass grpc://$heimdall__gateway_remote_headless_grpc_heimdall_rule0;



}
    include /etc/nginx/grpc-error-locations.conf;

}

server {
listen unix:/var/run/nginx/nginx-502-server.sock;
access_log off;

return 502;

}

server {
listen unix:/var/run/nginx/nginx-500-server.sock;
access_log off;

return 500;

}

upstream heimdall_remote-headless-2_80 {
random two least_conn;
zone heimdall_remote-headless-2_80 512k;

server 10.0.33.5:80;

}

upstream 9c-network_market-service_80 {
random two least_conn;
zone 9c-network_market-service_80 512k;

server 10.0.39.117:80;

}

upstream 9c-network_patrol-reward-service_80 {
random two least_conn;
zone 9c-network_patrol-reward-service_80 512k;

server 10.0.36.40:80;

}

upstream heimdall_remote-headless-4_31238 {
random two least_conn;
zone heimdall_remote-headless-4_31238 512k;

server 10.0.37.227:31238;

}

upstream heimdall_remote-headless-1_80 {
random two least_conn;
zone heimdall_remote-headless-1_80 512k;

server 10.0.47.171:80;

}

upstream 9c-network_remote-headless-2_80 {
random two least_conn;
zone 9c-network_remote-headless-2_80 512k;

server 10.0.45.39:80;

}

upstream 9c-network_remote-headless-1_31238 {
random two least_conn;
zone 9c-network_remote-headless-1_31238 512k;

server 10.0.34.40:31238;

}

upstream heimdall_remote-headless-4_80 {
random two least_conn;
zone heimdall_remote-headless-4_80 512k;

server 10.0.37.227:80;

}

upstream heimdall_world-boss-service_80 {
random two least_conn;
zone heimdall_world-boss-service_80 512k;

server 10.0.35.193:5000;

}

upstream 9c-network_arena-service_80 {
random two least_conn;
zone 9c-network_arena-service_80 512k;

server 10.0.40.113:8080;

}

upstream heimdall_remote-headless-1_31238 {
random two least_conn;
zone heimdall_remote-headless-1_31238 512k;

server 10.0.47.171:31238;

}

upstream 9c-network_remote-headless-1_80 {
random two least_conn;
zone 9c-network_remote-headless-1_80 512k;

server 10.0.34.40:80;

}

upstream heimdall_patrol-reward-service_80 {
random two least_conn;
zone heimdall_patrol-reward-service_80 512k;

server 10.0.41.135:80;

}

upstream heimdall_arena-service_80 {
random two least_conn;
zone heimdall_arena-service_80 512k;

server 10.0.44.99:8080;

}

upstream 9c-network_world-boss-service_80 {
random two least_conn;
zone 9c-network_world-boss-service_80 512k;

server 10.0.47.137:5000;

}

upstream heimdall_market-service_80 {
random two least_conn;
zone heimdall_market-service_80 512k;

server 10.0.41.214:80;

}

upstream 9c-network_remote-headless-2_31238 {
random two least_conn;
zone 9c-network_remote-headless-2_31238 512k;

server 10.0.45.39:31238;

}

upstream heimdall_remote-headless-2_31238 {
random two least_conn;
zone heimdall_remote-headless-2_31238 512k;

server 10.0.33.5:31238;

}

upstream heimdall_remote-headless-3_31238 {
random two least_conn;
zone heimdall_remote-headless-3_31238 512k;

server 10.0.47.143:31238;

}

upstream heimdall_remote-headless-3_80 {
random two least_conn;
zone heimdall_remote-headless-3_80 512k;

server 10.0.47.143:80;

}

upstream invalid-backend-ref {
random two least_conn;

server unix:/var/run/nginx/nginx-500-server.sock;

}

split_clients $request_id $9c_network__gateway_remote_headless_graphql_9c_network_rule0 {
50.00% 9c-network_remote-headless-1_80;
50.00% 9c-network_remote-headless-2_80;
}

split_clients $request_id $9c_network__gateway_remote_headless_grpc_9c_network_rule0 {
50.00% 9c-network_remote-headless-1_31238;
50.00% 9c-network_remote-headless-2_31238;
}

split_clients $request_id $heimdall__gateway_remote_headless_graphql_heimdall_rule0 {
25.00% heimdall_remote-headless-1_80;
25.00% heimdall_remote-headless-2_80;
25.00% heimdall_remote-headless-3_80;
25.00% heimdall_remote-headless-4_80;
}

split_clients $request_id $heimdall__gateway_remote_headless_grpc_heimdall_rule0 {
25.00% heimdall_remote-headless-1_31238;
25.00% heimdall_remote-headless-2_31238;
25.00% heimdall_remote-headless-3_31238;
25.00% heimdall_remote-headless-4_31238;
}

configuration file /etc/nginx/grpc-error-pages.conf:

error_page 400 = @grpc_internal;
error_page 401 = @grpc_unauthenticated;
error_page 403 = @grpc_permission_denied;
error_page 404 = @grpc_unimplemented;
error_page 429 = @grpc_unavailable;
error_page 502 = @grpc_unavailable;
error_page 503 = @grpc_unavailable;
error_page 504 = @grpc_unavailable;
error_page 405 = @grpc_internal;
error_page 408 = @grpc_deadline_exceeded;
error_page 413 = @grpc_resource_exhausted;
error_page 414 = @grpc_resource_exhausted;
error_page 415 = @grpc_internal;
error_page 426 = @grpc_internal;
error_page 495 = @grpc_unauthenticated;
error_page 496 = @grpc_unauthenticated;
error_page 497 = @grpc_internal;
error_page 500 = @grpc_internal;
error_page 501 = @grpc_internal;

configuration file /etc/nginx/grpc-error-locations.conf:

location @grpc_deadline_exceeded {
default_type application/grpc;
add_header content-type application/grpc;
add_header grpc-status 4;
add_header grpc-message 'deadline exceeded';
return 204;
}

location @grpc_permission_denied {
default_type application/grpc;
add_header content-type application/grpc;
add_header grpc-status 7;
add_header grpc-message 'permission denied';
return 204;
}

location @grpc_resource_exhausted {
default_type application/grpc;
add_header content-type application/grpc;
add_header grpc-status 8;
add_header grpc-message 'resource exhausted';
return 204;
}

location @grpc_unimplemented {
default_type application/grpc;
add_header content-type application/grpc;
add_header grpc-status 12;
add_header grpc-message unimplemented;
return 204;
}

location @grpc_internal {
default_type application/grpc;
add_header content-type application/grpc;
add_header grpc-status 13;
add_header grpc-message 'internal error';
return 204;
}

location @grpc_unavailable {
default_type application/grpc;
add_header content-type application/grpc;
add_header grpc-status 14;
add_header grpc-message unavailable;
return 204;
}

location @grpc_unauthenticated {
default_type application/grpc;
add_header content-type application/grpc;
add_header grpc-status 16;
add_header grpc-message unauthenticated;
return 204;
}

configuration file /etc/nginx/mime.types:

types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/javascript js;
application/atom+xml atom;
application/rss+xml rss;

text/mathml                                      mml;
text/plain                                       txt;
text/vnd.sun.j2me.app-descriptor                 jad;
text/vnd.wap.wml                                 wml;
text/x-component                                 htc;

image/avif                                       avif;
image/png                                        png;
image/svg+xml                                    svg svgz;
image/tiff                                       tif tiff;
image/vnd.wap.wbmp                               wbmp;
image/webp                                       webp;
image/x-icon                                     ico;
image/x-jng                                      jng;
image/x-ms-bmp                                   bmp;

font/woff                                        woff;
font/woff2                                       woff2;

application/java-archive                         jar war ear;
application/json                                 json;
application/mac-binhex40                         hqx;
application/msword                               doc;
application/pdf                                  pdf;
application/postscript                           ps eps ai;
application/rtf                                  rtf;
application/vnd.apple.mpegurl                    m3u8;
application/vnd.google-earth.kml+xml             kml;
application/vnd.google-earth.kmz                 kmz;
application/vnd.ms-excel                         xls;
application/vnd.ms-fontobject                    eot;
application/vnd.ms-powerpoint                    ppt;
application/vnd.oasis.opendocument.graphics      odg;
application/vnd.oasis.opendocument.presentation  odp;
application/vnd.oasis.opendocument.spreadsheet   ods;
application/vnd.oasis.opendocument.text          odt;
application/vnd.openxmlformats-officedocument.presentationml.presentation
                                                 pptx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
                                                 xlsx;
application/vnd.openxmlformats-officedocument.wordprocessingml.document
                                                 docx;
application/vnd.wap.wmlc                         wmlc;
application/wasm                                 wasm;
application/x-7z-compressed                      7z;
application/x-cocoa                              cco;
application/x-java-archive-diff                  jardiff;
application/x-java-jnlp-file                     jnlp;
application/x-makeself                           run;
application/x-perl                               pl pm;
application/x-pilot                              prc pdb;
application/x-rar-compressed                     rar;
application/x-redhat-package-manager             rpm;
application/x-sea                                sea;
application/x-shockwave-flash                    swf;
application/x-stuffit                            sit;
application/x-tcl                                tcl tk;
application/x-x509-ca-cert                       der pem crt;
application/x-xpinstall                          xpi;
application/xhtml+xml                            xhtml;
application/xspf+xml                             xspf;
application/zip                                  zip;

application/octet-stream                         bin exe dll;
application/octet-stream                         deb;
application/octet-stream                         dmg;
application/octet-stream                         iso img;
application/octet-stream                         msi msp msm;

audio/midi                                       mid midi kar;
audio/mpeg                                       mp3;
audio/ogg                                        ogg;
audio/x-m4a                                      m4a;
audio/x-realaudio                                ra;

video/3gpp                                       3gpp 3gp;
video/mp2t                                       ts;
video/mp4                                        mp4;
video/mpeg                                       mpeg mpg;
video/quicktime                                  mov;
video/webm                                       webm;
video/x-flv                                      flv;
video/x-m4v                                      m4v;
video/x-mng                                      mng;
video/x-ms-asf                                   asx asf;
video/x-ms-wmv                                   wmv;
video/x-msvideo                                  avi;

}

configuration file /etc/nginx/stream-conf.d/stream.conf:

server {
listen unix:/var/run/nginx/connection-closed-server.sock;
return "";
}

Additional context
I think it can be resolved by simply adding something before first %s
https://github.com/nginxinc/nginx-gateway-fabric/blob/88269accb505d58567fde59dec3830cf963dc968/internal/mode/static/state/dataplane/types.go#L258
https://github.com/nginx/nginx/blob/51857ce40400b48bc8900b9e3930cf7474fa0c41/src/http/ngx_http_script.c#L474-L480

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingcommunityrefinedRequirements are refined and the issue is ready to be implemented.size/mediumEstimated to be completed within a week

Type

No type

Projects

Status

✅ Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions