From b99c25f090e03a64b01ac7ee54825b414e2d551c Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Tue, 27 Feb 2024 11:23:23 -0500 Subject: [PATCH] feat: add support for setting underscores-in-headers for nginx, openresty, and k3s Closes #6627 --- docs/networking/proxies/nginx.md | 1 + plugins/nginx-vhosts/command-functions | 3 +++ plugins/nginx-vhosts/functions | 2 ++ plugins/nginx-vhosts/internal-functions | 21 +++++++++++++++++++ plugins/nginx-vhosts/nginx_vhosts.go | 17 +++++++++++++++ .../src/nginx-property/nginx-property.go | 6 ++++++ plugins/nginx-vhosts/subcommands/set | 4 ++-- .../nginx-vhosts/templates/nginx.conf.sigil | 4 ++++ plugins/openresty-vhosts/command-functions | 1 + .../docker-args-process-deploy | 2 ++ plugins/openresty-vhosts/internal-functions | 7 +++++++ plugins/openresty-vhosts/subcommands/set | 4 ++-- plugins/scheduler-k3s/functions.go | 9 ++++++++ 13 files changed, 77 insertions(+), 4 deletions(-) diff --git a/docs/networking/proxies/nginx.md b/docs/networking/proxies/nginx.md index a9cdc48cc..3636f508b 100644 --- a/docs/networking/proxies/nginx.md +++ b/docs/networking/proxies/nginx.md @@ -323,6 +323,7 @@ Changing these value globally or on a per-app basis will require rebuilding the | proxy-buffers | `8 8k` | string | Number and size of the buffers used for reading the proxied server response, for a single connection | | proxy-busy-buffers-size | `16k` | string | Limits the total size of buffers that can be busy sending a response to the client while the response is not yet fully read. | | proxy-read-timeout | `60s` | string | Timeout (with units) for reading response from your backend server | +| underscore-in-headers | `off` | string | Enables or disables the use of underscores in client request header fields. | | x-forwarded-for-value | `$remote_addr` | string | Used for specifying the header value to set for the `X-Forwared-For` header | | x-forwarded-port-value | `$server_port` | string | Used for specifying the header value to set for the `X-Forwared-Port` header | | x-forwarded-proto-value | `$scheme` | string | Used for specifying the header value to set for the `X-Forwared-Proto` header | diff --git a/plugins/nginx-vhosts/command-functions b/plugins/nginx-vhosts/command-functions index 61956263f..41c4fb426 100755 --- a/plugins/nginx-vhosts/command-functions +++ b/plugins/nginx-vhosts/command-functions @@ -89,6 +89,9 @@ cmd-nginx-report-single() { "--nginx-proxy-read-timeout: $(fn-nginx-proxy-read-timeout "$APP")" "--nginx-computed-proxy-read-timeout: $(fn-nginx-computed-proxy-read-timeout "$APP")" "--nginx-global-proxy-read-timeout: $(fn-nginx-global-proxy-read-timeout "$APP")" + "--nginx-underscore-in-headers: $(fn-nginx-underscore-in-headers "$APP")" + "--nginx-computed-underscore-in-headers: $(fn-nginx-computed-underscore-in-headers "$APP")" + "--nginx-global-underscore-in-headers: $(fn-nginx-global-underscore-in-headers "$APP")" "--nginx-x-forwarded-for-value: $(fn-nginx-x-forwarded-for-value "$APP")" "--nginx-computed-x-forwarded-for-value: $(fn-nginx-computed-x-forwarded-for-value "$APP")" "--nginx-global-x-forwarded-for-value: $(fn-nginx-global-x-forwarded-for-value "$APP")" diff --git a/plugins/nginx-vhosts/functions b/plugins/nginx-vhosts/functions index c6689ade3..195031792 100755 --- a/plugins/nginx-vhosts/functions +++ b/plugins/nginx-vhosts/functions @@ -341,6 +341,7 @@ nginx_build_config() { local NGINX_BIND_ADDRESS_IP4="$(fn-nginx-computed-bind-address-ipv4 "$APP")" local NGINX_BIND_ADDRESS_IP6="$(fn-nginx-computed-bind-address-ipv6 "$APP")" + local NGINX_UNDERSCORE_IN_HEADERS="$(fn-nginx-computed-underscore-in-headers "$APP")" local PROXY_X_FORWARDED_FOR="$(fn-nginx-computed-x-forwarded-for-value "$APP")" local PROXY_X_FORWARDED_PORT="$(fn-nginx-computed-x-forwarded-port-value "$APP")" local PROXY_X_FORWARDED_PROTO="$(fn-nginx-computed-x-forwarded-proto-value "$APP")" @@ -372,6 +373,7 @@ nginx_build_config() { PROXY_BUFFERING="$PROXY_BUFFERING" PROXY_BUFFERS="$PROXY_BUFFERS" PROXY_BUSY_BUFFERS_SIZE="$PROXY_BUSY_BUFFERS_SIZE" + NGINX_UNDERSCORE_IN_HEADERS="$NGINX_UNDERSCORE_IN_HEADERS" # Deprecated: Remove this after a few versions NGINX_PORT="$PROXY_PORT" NGINX_SSL_PORT="$PROXY_SSL_PORT" PROXY_PORT="$PROXY_PORT" PROXY_SSL_PORT="$PROXY_SSL_PORT" diff --git a/plugins/nginx-vhosts/internal-functions b/plugins/nginx-vhosts/internal-functions index 05ed3c4d9..121a9d122 100755 --- a/plugins/nginx-vhosts/internal-functions +++ b/plugins/nginx-vhosts/internal-functions @@ -347,6 +347,27 @@ fn-nginx-global-proxy-read-timeout() { fn-get-property --app "$APP" --global "proxy-read-timeout" } +fn-nginx-underscore-in-headers() { + declare desc="get the configured underscore in headers value" + declare APP="$1" + + fn-get-property --app "$APP" "underscore-in-headers" +} + +fn-nginx-computed-underscore-in-headers() { + declare desc="get the computed underscore in headers value" + declare APP="$1" + + fn-get-property --app "$APP" --computed "underscore-in-headers" +} + +fn-nginx-global-underscore-in-headers() { + declare desc="get the global underscore in headers value" + declare APP="$1" + + fn-get-property --app "$APP" --global "underscore-in-headers" +} + fn-nginx-x-forwarded-for-value() { declare desc="get the configured x-forwarded-for value" declare APP="$1" diff --git a/plugins/nginx-vhosts/nginx_vhosts.go b/plugins/nginx-vhosts/nginx_vhosts.go index eba391bbf..f84953670 100644 --- a/plugins/nginx-vhosts/nginx_vhosts.go +++ b/plugins/nginx-vhosts/nginx_vhosts.go @@ -298,6 +298,23 @@ func GlobalProxyReadTimeout() string { return common.PropertyGetDefault("nginx", "--global", "proxy-read-timeout", "60s") } +func AppUnderscoreInHeaders(appName string) string { + return common.PropertyGet("nginx", appName, "underscore-in-headers") +} + +func ComputedUnderscoreInHeaders(appName string) string { + appValue := AppUnderscoreInHeaders(appName) + if appValue != "" { + return appValue + } + + return GlobalUnderscoreInHeaders() +} + +func GlobalUnderscoreInHeaders() string { + return common.PropertyGetDefault("nginx", "--global", "underscore-in-headers", "off") +} + func AppXForwardedForValue(appName string) string { return common.PropertyGet("nginx", appName, "x-forwarded-for-value") } diff --git a/plugins/nginx-vhosts/src/nginx-property/nginx-property.go b/plugins/nginx-vhosts/src/nginx-property/nginx-property.go index 8d67d36f5..b65878e8d 100644 --- a/plugins/nginx-vhosts/src/nginx-property/nginx-property.go +++ b/plugins/nginx-vhosts/src/nginx-property/nginx-property.go @@ -69,6 +69,8 @@ func appValue(appName string, property string) string { value = nginx_vhosts.AppProxyBusyBuffersSize(appName) case "proxy-read-timeout": value = nginx_vhosts.AppProxyReadTimeout(appName) + case "underscore-in-headers": + value = nginx_vhosts.AppUnderscoreInHeaders(appName) case "x-forwarded-for-value": value = nginx_vhosts.AppXForwardedForValue(appName) case "x-forwarded-port-value": @@ -119,6 +121,8 @@ func computedValue(appName string, property string) string { value = nginx_vhosts.ComputedProxyBusyBuffersSize(appName) case "proxy-read-timeout": value = nginx_vhosts.ComputedProxyReadTimeout(appName) + case "underscore-in-headers": + value = nginx_vhosts.ComputedUnderscoreInHeaders(appName) case "x-forwarded-for-value": value = nginx_vhosts.ComputedXForwardedForValue(appName) case "x-forwarded-port-value": @@ -169,6 +173,8 @@ func globalValue(appName string, property string) string { value = nginx_vhosts.GlobalProxyBusyBuffersSize() case "proxy-read-timeout": value = nginx_vhosts.GlobalProxyReadTimeout() + case "underscore-in-headers": + value = nginx_vhosts.GlobalUnderscoreInHeaders() case "x-forwarded-for-value": value = nginx_vhosts.GlobalXForwardedForValue() case "x-forwarded-port-value": diff --git a/plugins/nginx-vhosts/subcommands/set b/plugins/nginx-vhosts/subcommands/set index b3ae03c93..53d107302 100755 --- a/plugins/nginx-vhosts/subcommands/set +++ b/plugins/nginx-vhosts/subcommands/set @@ -9,13 +9,13 @@ cmd-nginx-set() { declare cmd="nginx:set" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" KEY="$2" VALUE="$3" - local VALID_KEYS=("access-log-format" "access-log-path" "bind-address-ipv4" "bind-address-ipv6" "client-max-body-size" "disable-custom-config" "error-log-path" "hsts" "hsts-include-subdomains" "hsts-preload" "hsts-max-age" "nginx-conf-sigil-path" "proxy-read-timeout" "proxy-buffer-size" "proxy-buffering" "proxy-buffers" "proxy-busy-buffers-size" "x-forwarded-for-value" "x-forwarded-port-value" "x-forwarded-proto-value" "x-forwarded-ssl") + local VALID_KEYS=("access-log-format" "access-log-path" "bind-address-ipv4" "bind-address-ipv6" "client-max-body-size" "disable-custom-config" "error-log-path" "hsts" "hsts-include-subdomains" "hsts-preload" "hsts-max-age" "nginx-conf-sigil-path" "proxy-read-timeout" "proxy-buffer-size" "proxy-buffering" "proxy-buffers" "proxy-busy-buffers-size" "underscore-in-headers" "x-forwarded-for-value" "x-forwarded-port-value" "x-forwarded-proto-value" "x-forwarded-ssl") local GLOBAL_KEYS=("hsts" "nginx-conf-sigil-path") [[ -z "$KEY" ]] && dokku_log_fail "No key specified" if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then - dokku_log_fail "Invalid key specified, valid keys include: access-log-format, access-log-path, bind-address-ipv4, bind-address-ipv6, client-max-body-size, disable-custom-config, error-log-path, hsts, hsts-include-subdomains, hsts-preload, hsts-max-age, nginx-conf-sigil-path, proxy-read-timeout, proxy-buffer-size, proxy-buffering, proxy-buffers, proxy-busy-buffers-size, x-forwarded-for-value, x-forwarded-port-value, x-forwarded-proto-value, x-forwarded-ssl" + dokku_log_fail "Invalid key specified, valid keys include: access-log-format, access-log-path, bind-address-ipv4, bind-address-ipv6, client-max-body-size, disable-custom-config, error-log-path, hsts, hsts-include-subdomains, hsts-preload, hsts-max-age, nginx-conf-sigil-path, proxy-read-timeout, proxy-buffer-size, proxy-buffering, proxy-buffers, proxy-busy-buffers-size, underscore-in-headers, x-forwarded-for-value, x-forwarded-port-value, x-forwarded-proto-value, x-forwarded-ssl" fi if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then diff --git a/plugins/nginx-vhosts/templates/nginx.conf.sigil b/plugins/nginx-vhosts/templates/nginx.conf.sigil index 59a40a6b7..be13943f6 100644 --- a/plugins/nginx-vhosts/templates/nginx.conf.sigil +++ b/plugins/nginx-vhosts/templates/nginx.conf.sigil @@ -11,6 +11,7 @@ server { {{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }} access_log {{ $.NGINX_ACCESS_LOG_PATH }}{{ if and ($.NGINX_ACCESS_LOG_FORMAT) (ne $.NGINX_ACCESS_LOG_PATH "off") }} {{ $.NGINX_ACCESS_LOG_FORMAT }}{{ end }}; error_log {{ $.NGINX_ERROR_LOG_PATH }}; + underscores_in_headers {{ $.NGINX_UNDERSCORE_IN_HEADERS }}; {{ if (and (eq $listen_port "80") ($.SSL_INUSE)) }} include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf; location / { @@ -73,6 +74,7 @@ server { {{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }} access_log {{ $.NGINX_ACCESS_LOG_PATH }}{{ if and ($.NGINX_ACCESS_LOG_FORMAT) (ne $.NGINX_ACCESS_LOG_PATH "off") }} {{ $.NGINX_ACCESS_LOG_FORMAT }}{{ end }}; error_log {{ $.NGINX_ERROR_LOG_PATH }}; + underscores_in_headers {{ $.NGINX_UNDERSCORE_IN_HEADERS }}; ssl_certificate {{ $.APP_SSL_PATH }}/server.crt; ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key; @@ -143,6 +145,7 @@ server { {{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }} access_log {{ $.NGINX_ACCESS_LOG_PATH }}{{ if and ($.NGINX_ACCESS_LOG_FORMAT) (ne $.NGINX_ACCESS_LOG_PATH "off") }} {{ $.NGINX_ACCESS_LOG_FORMAT }}{{ end }}; error_log {{ $.NGINX_ERROR_LOG_PATH }}; + underscores_in_headers {{ $.NGINX_UNDERSCORE_IN_HEADERS }}; location / { grpc_pass grpc://{{ $.APP }}-{{ $upstream_port }}; } @@ -159,6 +162,7 @@ server { {{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }} access_log {{ $.NGINX_ACCESS_LOG_PATH }}{{ if and ($.NGINX_ACCESS_LOG_FORMAT) (ne $.NGINX_ACCESS_LOG_PATH "off") }} {{ $.NGINX_ACCESS_LOG_FORMAT }}{{ end }}; error_log {{ $.NGINX_ERROR_LOG_PATH }}; + underscores_in_headers {{ $.NGINX_UNDERSCORE_IN_HEADERS }}; ssl_certificate {{ $.APP_SSL_PATH }}/server.crt; ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key; diff --git a/plugins/openresty-vhosts/command-functions b/plugins/openresty-vhosts/command-functions index d630d87d5..33c2150e8 100755 --- a/plugins/openresty-vhosts/command-functions +++ b/plugins/openresty-vhosts/command-functions @@ -55,6 +55,7 @@ cmd-openresty-report-single() { "--openresty-proxy-buffers: $(fn-openresty-proxy-buffers "$APP")" "--openresty-proxy-busy-buffers-size: $(fn-openresty-proxy-busy-buffers-size "$APP")" "--openresty-proxy-read-timeout: $(fn-openresty-proxy-read-timeout "$APP")" + "--openresty-underscore-in-headers: $(fn-openresty-underscore-in-headers "$APP")" "--openresty-x-forwarded-for-value: $(fn-openresty-x-forwarded-for-value "$APP")" "--openresty-x-forwarded-port-value: $(fn-openresty-x-forwarded-port-value "$APP")" "--openresty-x-forwarded-proto-value: $(fn-openresty-x-forwarded-proto-value "$APP")" diff --git a/plugins/openresty-vhosts/docker-args-process-deploy b/plugins/openresty-vhosts/docker-args-process-deploy index 4a507bf72..be20cce72 100755 --- a/plugins/openresty-vhosts/docker-args-process-deploy +++ b/plugins/openresty-vhosts/docker-args-process-deploy @@ -160,6 +160,8 @@ trigger-openresty-vhosts-docker-args-process-deploy() { [[ -n "$value" ]] && output="$output '--label=openresty.proxy-send-timeout=$value'" value="$(fn-openresty-send-timeout "$APP")" [[ -n "$value" ]] && output="$output '--label=openresty.send-timeout=$value'" + value="$(fn-openresty-underscore-in-headers "$APP")" + [[ -n "$value" ]] && output="$output '--label=openresty.underscore-in-headers=$value'" value="$(fn-openresty-x-forwarded-for-value "$APP")" [[ -n "$value" ]] && output="$output '--label=openresty.x-forwarded-for-value=$value'" value="$(fn-openresty-x-forwarded-port-value "$APP")" diff --git a/plugins/openresty-vhosts/internal-functions b/plugins/openresty-vhosts/internal-functions index 7204d0c8f..7018923d9 100755 --- a/plugins/openresty-vhosts/internal-functions +++ b/plugins/openresty-vhosts/internal-functions @@ -224,6 +224,13 @@ fn-openresty-template-compose-file() { sigil -f "$COMPOSE_TEMPLATE" "${SIGIL_PARAMS[@]}" | cat -s >"$OUTPUT_PATH" } +fn-openresty-underscore-in-headers() { + declare desc="get the configured underscore in headers value" + declare APP="$1" + + fn-plugin-property-get-default "openresty" "$APP" "underscore-in-headers" "off" +} + fn-openresty-x-forwarded-for-value() { declare desc="get the configured x-forwarded-for value" declare APP="$1" diff --git a/plugins/openresty-vhosts/subcommands/set b/plugins/openresty-vhosts/subcommands/set index 079e0019e..8aed28371 100755 --- a/plugins/openresty-vhosts/subcommands/set +++ b/plugins/openresty-vhosts/subcommands/set @@ -9,13 +9,13 @@ cmd-openresty-set() { declare cmd="openresty:set" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" KEY="$2" VALUE="$3" - local VALID_KEYS=("access-log-format" "access-log-path" "bind-address-ipv4" "bind-address-ipv6" "client-max-body-size" "error-log-path" "hsts" "hsts-include-subdomains" "hsts-preload" "hsts-max-age" "image" "log-level" "letsencrypt-email" "letsencrypt-server" "proxy-read-timeout" "proxy-buffer-size" "proxy-buffering" "proxy-buffers" "proxy-busy-buffers-size" "x-forwarded-for-value" "x-forwarded-port-value" "x-forwarded-proto-value" "x-forwarded-ssl") + local VALID_KEYS=("access-log-format" "access-log-path" "bind-address-ipv4" "bind-address-ipv6" "client-max-body-size" "error-log-path" "hsts" "hsts-include-subdomains" "hsts-preload" "hsts-max-age" "image" "log-level" "letsencrypt-email" "letsencrypt-server" "proxy-read-timeout" "proxy-buffer-size" "proxy-buffering" "proxy-buffers" "proxy-busy-buffers-size" "underscore-in-headers" "x-forwarded-for-value" "x-forwarded-port-value" "x-forwarded-proto-value" "x-forwarded-ssl") local GLOBAL_KEYS=("image" "log-level" "letsencrypt-email" "letsencrypt-server") [[ -z "$KEY" ]] && dokku_log_fail "No key specified" if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then - dokku_log_fail "Invalid key specified, valid keys include: access-log-format, access-log-path, bind-address-ipv4, bind-address-ipv6, client-max-body-size, error-log-path, hsts, hsts-include-subdomains, hsts-preload, hsts-max-age, image, log-level, letsencrypt-email, letsencrypt-server, proxy-read-timeout, proxy-buffer-size, proxy-buffering, proxy-buffers, proxy-busy-buffers-size, x-forwarded-for-value, x-forwarded-port-value, x-forwarded-proto-value, x-forwarded-ssl" + dokku_log_fail "Invalid key specified, valid keys include: access-log-format, access-log-path, bind-address-ipv4, bind-address-ipv6, client-max-body-size, error-log-path, hsts, hsts-include-subdomains, hsts-preload, hsts-max-age, image, log-level, letsencrypt-email, letsencrypt-server, proxy-read-timeout, proxy-buffer-size, proxy-buffering, proxy-buffers, proxy-busy-buffers-size, underscore-in-headers, x-forwarded-for-value, x-forwarded-port-value, x-forwarded-proto-value, x-forwarded-ssl" fi if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then diff --git a/plugins/scheduler-k3s/functions.go b/plugins/scheduler-k3s/functions.go index 02648d068..d8478b526 100644 --- a/plugins/scheduler-k3s/functions.go +++ b/plugins/scheduler-k3s/functions.go @@ -581,6 +581,15 @@ func getIngressAnnotations(appName string, processType string) (map[string]strin annotation: "nginx.ingress.kubernetes.io/proxy-read-timeout", getter: nginxvhosts.ComputedProxyReadTimeout, }, + "underscore-in-headers": { + getter: nginxvhosts.ComputedUnderscoreInHeaders, + locationSnippet: func(value string) string { + if value == "" { + return "" + } + return fmt.Sprintf("underscores_in_headers %s;", value) + }, + }, "x-forwarded-for-value": { getter: nginxvhosts.ComputedXForwardedForValue, locationSnippet: func(value string) string {