f66bb53509
The names of a few configuration variables have changed in version 1.9. EnableRealIp to EnableRealIP HttpAccessLogPath to HTTPAccessLogPath whitelist to allowlist Whitelist to Allowlist Additionally, ajp_temp_path is no longer valid. Change-Id: I2ebb658bd237216c43306dab6cd7f7a1ca6388ac
1429 lines
53 KiB
Cheetah
1429 lines
53 KiB
Cheetah
{{ $all := . }}
|
|
{{ $servers := .Servers }}
|
|
{{ $cfg := .Cfg }}
|
|
{{ $IsIPV6Enabled := .IsIPV6Enabled }}
|
|
{{ $healthzURI := .HealthzURI }}
|
|
{{ $backends := .Backends }}
|
|
{{ $proxyHeaders := .ProxySetHeaders }}
|
|
{{ $addHeaders := .AddHeaders }}
|
|
|
|
# Configuration checksum: {{ $all.Cfg.Checksum }}
|
|
|
|
# setup custom paths that do not require root access
|
|
pid {{ .PID }};
|
|
|
|
{{ if $cfg.UseGeoIP2 }}
|
|
load_module /etc/nginx/modules/ngx_http_geoip2_module.so;
|
|
{{ end }}
|
|
|
|
{{ if $cfg.EnableBrotli }}
|
|
load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;
|
|
load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;
|
|
{{ end }}
|
|
|
|
|
|
{{ if (shouldLoadAuthDigestModule $servers) }}
|
|
load_module /etc/nginx/modules/ngx_http_auth_digest_module.so;
|
|
{{ end }}
|
|
|
|
{{ if (shouldLoadModSecurityModule $cfg $servers) }}
|
|
load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;
|
|
{{ end }}
|
|
|
|
{{ if (shouldLoadOpentracingModule $cfg $servers) }}
|
|
load_module /etc/nginx/modules/ngx_http_opentracing_module.so;
|
|
{{ end }}
|
|
|
|
daemon off;
|
|
|
|
worker_processes {{ $cfg.WorkerProcesses }};
|
|
{{ if gt (len $cfg.WorkerCPUAffinity) 0 }}
|
|
worker_cpu_affinity {{ $cfg.WorkerCPUAffinity }};
|
|
{{ end }}
|
|
|
|
worker_rlimit_nofile {{ $cfg.MaxWorkerOpenFiles }};
|
|
|
|
{{/* http://nginx.org/en/docs/ngx_core_module.html#worker_shutdown_timeout */}}
|
|
{{/* avoid waiting too long during a reload */}}
|
|
worker_shutdown_timeout {{ $cfg.WorkerShutdownTimeout }} ;
|
|
|
|
{{ if not (empty $cfg.MainSnippet) }}
|
|
{{ $cfg.MainSnippet }}
|
|
{{ end }}
|
|
|
|
events {
|
|
multi_accept {{ if $cfg.EnableMultiAccept }}on{{ else }}off{{ end }};
|
|
worker_connections {{ $cfg.MaxWorkerConnections }};
|
|
use epoll;
|
|
}
|
|
|
|
http {
|
|
lua_package_path "/etc/nginx/lua/?.lua;;";
|
|
|
|
{{ buildLuaSharedDictionaries $cfg $servers }}
|
|
|
|
init_by_lua_block {
|
|
collectgarbage("collect")
|
|
|
|
-- init modules
|
|
local ok, res
|
|
|
|
ok, res = pcall(require, "lua_ingress")
|
|
if not ok then
|
|
error("require failed: " .. tostring(res))
|
|
else
|
|
lua_ingress = res
|
|
lua_ingress.set_config({{ configForLua $all }})
|
|
end
|
|
|
|
ok, res = pcall(require, "configuration")
|
|
if not ok then
|
|
error("require failed: " .. tostring(res))
|
|
else
|
|
configuration = res
|
|
end
|
|
|
|
ok, res = pcall(require, "balancer")
|
|
if not ok then
|
|
error("require failed: " .. tostring(res))
|
|
else
|
|
balancer = res
|
|
end
|
|
|
|
{{ if $all.EnableMetrics }}
|
|
ok, res = pcall(require, "monitor")
|
|
if not ok then
|
|
error("require failed: " .. tostring(res))
|
|
else
|
|
monitor = res
|
|
end
|
|
{{ end }}
|
|
|
|
ok, res = pcall(require, "certificate")
|
|
if not ok then
|
|
error("require failed: " .. tostring(res))
|
|
else
|
|
certificate = res
|
|
certificate.is_ocsp_stapling_enabled = {{ $cfg.EnableOCSP }}
|
|
end
|
|
|
|
ok, res = pcall(require, "plugins")
|
|
if not ok then
|
|
error("require failed: " .. tostring(res))
|
|
else
|
|
plugins = res
|
|
end
|
|
-- load all plugins that'll be used here
|
|
plugins.init({ {{ range $idx, $plugin := $cfg.Plugins }}{{ if $idx }},{{ end }}{{ $plugin | quote }}{{ end }} })
|
|
}
|
|
|
|
init_worker_by_lua_block {
|
|
lua_ingress.init_worker()
|
|
balancer.init_worker()
|
|
{{ if $all.EnableMetrics }}
|
|
monitor.init_worker({{ $all.MonitorMaxBatchSize }})
|
|
{{ end }}
|
|
|
|
plugins.run()
|
|
}
|
|
|
|
{{/* Enable the real_ip module only if we use either X-Forwarded headers or Proxy Protocol. */}}
|
|
{{/* we use the value of the real IP for the geo_ip module */}}
|
|
{{ if or (or $cfg.UseForwardedHeaders $cfg.UseProxyProtocol) $cfg.EnableRealIP }}
|
|
{{ if $cfg.UseProxyProtocol }}
|
|
real_ip_header proxy_protocol;
|
|
{{ else }}
|
|
real_ip_header {{ $cfg.ForwardedForHeader }};
|
|
{{ end }}
|
|
|
|
real_ip_recursive on;
|
|
{{ range $trusted_ip := $cfg.ProxyRealIPCIDR }}
|
|
set_real_ip_from {{ $trusted_ip }};
|
|
{{ end }}
|
|
{{ end }}
|
|
|
|
{{ if $all.Cfg.EnableModsecurity }}
|
|
modsecurity on;
|
|
|
|
modsecurity_rules_file /etc/nginx/modsecurity/modsecurity.conf;
|
|
|
|
{{ if $all.Cfg.EnableOWASPCoreRules }}
|
|
modsecurity_rules_file /etc/nginx/owasp-modsecurity-crs/nginx-modsecurity.conf;
|
|
{{ else if (not (empty $all.Cfg.ModsecuritySnippet)) }}
|
|
modsecurity_rules '
|
|
{{ $all.Cfg.ModsecuritySnippet }}
|
|
';
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
{{ if $cfg.UseGeoIP }}
|
|
{{/* databases used to determine the country depending on the client IP address */}}
|
|
{{/* http://nginx.org/en/docs/http/ngx_http_geoip_module.html */}}
|
|
{{/* this is require to calculate traffic for individual country using GeoIP in the status page */}}
|
|
geoip_country /etc/nginx/geoip/GeoIP.dat;
|
|
geoip_city /etc/nginx/geoip/GeoLiteCity.dat;
|
|
geoip_org /etc/nginx/geoip/GeoIPASNum.dat;
|
|
geoip_proxy_recursive on;
|
|
{{ end }}
|
|
|
|
{{ if $cfg.UseGeoIP2 }}
|
|
# https://github.com/leev/ngx_http_geoip2_module#example-usage
|
|
|
|
{{ range $index, $file := $all.MaxmindEditionFiles }}
|
|
{{ if eq $file "GeoLite2-Country.mmdb" }}
|
|
geoip2 /etc/nginx/geoip/GeoLite2-Country.mmdb {
|
|
$geoip2_country_code source=$remote_addr country iso_code;
|
|
$geoip2_country_name source=$remote_addr country names en;
|
|
$geoip2_continent_name source=$remote_addr continent names en;
|
|
}
|
|
{{ end }}
|
|
|
|
{{ if eq $file "GeoIP2-Country.mmdb" }}
|
|
geoip2 /etc/nginx/geoip/GeoIP2-Country.mmdb {
|
|
$geoip2_country_code source=$remote_addr country iso_code;
|
|
$geoip2_country_name source=$remote_addr country names en;
|
|
$geoip2_continent_name source=$remote_addr continent names en;
|
|
}
|
|
{{ end }}
|
|
|
|
{{ if eq $file "GeoLite2-City.mmdb" }}
|
|
geoip2 /etc/nginx/geoip/GeoLite2-City.mmdb {
|
|
$geoip2_city_country_code source=$remote_addr country iso_code;
|
|
$geoip2_city_country_name source=$remote_addr country names en;
|
|
$geoip2_city source=$remote_addr city names en;
|
|
$geoip2_postal_code source=$remote_addr postal code;
|
|
$geoip2_dma_code source=$remote_addr location metro_code;
|
|
$geoip2_latitude source=$remote_addr location latitude;
|
|
$geoip2_longitude source=$remote_addr location longitude;
|
|
$geoip2_time_zone source=$remote_addr location time_zone;
|
|
$geoip2_region_code source=$remote_addr subdivisions 0 iso_code;
|
|
$geoip2_region_name source=$remote_addr subdivisions 0 names en;
|
|
}
|
|
{{ end }}
|
|
|
|
{{ if eq $file "GeoIP2-City.mmdb" }}
|
|
geoip2 /etc/nginx/geoip/GeoIP2-City.mmdb {
|
|
$geoip2_city_country_code source=$remote_addr country iso_code;
|
|
$geoip2_city_country_name source=$remote_addr country names en;
|
|
$geoip2_city source=$remote_addr city names en;
|
|
$geoip2_postal_code source=$remote_addr postal code;
|
|
$geoip2_dma_code source=$remote_addr location metro_code;
|
|
$geoip2_latitude source=$remote_addr location latitude;
|
|
$geoip2_longitude source=$remote_addr location longitude;
|
|
$geoip2_time_zone source=$remote_addr location time_zone;
|
|
$geoip2_region_code source=$remote_addr subdivisions 0 iso_code;
|
|
$geoip2_region_name source=$remote_addr subdivisions 0 names en;
|
|
}
|
|
{{ end }}
|
|
|
|
{{ if eq $file "GeoLite2-ASN.mmdb" }}
|
|
geoip2 /etc/nginx/geoip/GeoLite2-ASN.mmdb {
|
|
$geoip2_asn source=$remote_addr autonomous_system_number;
|
|
$geoip2_org source=$remote_addr autonomous_system_organization;
|
|
}
|
|
{{ end }}
|
|
|
|
{{ if eq $file "GeoIP2-ASN.mmdb" }}
|
|
geoip2 /etc/nginx/geoip/GeoIP2-ASN.mmdb {
|
|
$geoip2_asn source=$remote_addr autonomous_system_number;
|
|
$geoip2_org source=$remote_addr autonomous_system_organization;
|
|
}
|
|
{{ end }}
|
|
|
|
{{ if eq $file "GeoIP2-ISP.mmdb" }}
|
|
geoip2 /etc/nginx/geoip/GeoIP2-ISP.mmdb {
|
|
$geoip2_isp isp;
|
|
$geoip2_isp_org organization;
|
|
}
|
|
{{ end }}
|
|
|
|
{{ if eq $file "GeoIP2-Connection-Type.mmdb" }}
|
|
geoip2 /etc/nginx/geoip/GeoIP2-Connection-Type.mmdb {
|
|
$geoip2_connection_type connection_type;
|
|
}
|
|
{{ end }}
|
|
|
|
{{ if eq $file "GeoIP2-Anonymous-IP.mmdb" }}
|
|
geoip2 /etc/nginx/geoip/GeoIP2-Anonymous-IP.mmdb {
|
|
$geoip2_is_anon source=$remote_addr is_anonymous;
|
|
$geoip2_is_hosting_provider source=$remote_addr is_hosting_provider;
|
|
$geoip2_is_public_proxy source=$remote_addr is_public_proxy;
|
|
}
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|
|
|
|
aio threads;
|
|
aio_write on;
|
|
|
|
tcp_nopush on;
|
|
tcp_nodelay on;
|
|
|
|
log_subrequest on;
|
|
|
|
reset_timedout_connection on;
|
|
|
|
keepalive_timeout {{ $cfg.KeepAlive }}s;
|
|
keepalive_requests {{ $cfg.KeepAliveRequests }};
|
|
|
|
client_body_temp_path /tmp/client-body;
|
|
fastcgi_temp_path /tmp/fastcgi-temp;
|
|
proxy_temp_path /tmp/proxy-temp;
|
|
|
|
client_header_buffer_size {{ $cfg.ClientHeaderBufferSize }};
|
|
client_header_timeout {{ $cfg.ClientHeaderTimeout }}s;
|
|
large_client_header_buffers {{ $cfg.LargeClientHeaderBuffers }};
|
|
|
|
# NOTE: obsolete directive. removed.
|
|
#client_body_buffer_size {{ $cfg.ClientBodyBufferSize }};
|
|
client_body_timeout {{ $cfg.ClientBodyTimeout }}s;
|
|
|
|
# NOTE: the "http2_max_field_size" directive is obsolete,
|
|
# use the "large_client_header_buffers" directive instead
|
|
#http2_max_field_size {{ $cfg.HTTP2MaxFieldSize }};
|
|
|
|
# NOTE: the "http2_max_header_size" directive is obsolete,
|
|
# use the "large_client_header_buffers" directive instead
|
|
#http2_max_header_size {{ $cfg.HTTP2MaxHeaderSize }};
|
|
|
|
# NOTE: the "http2_max_requests" directive is obsolete,
|
|
# use the "keepalive_requests" directive instead
|
|
#http2_max_requests {{ $cfg.HTTP2MaxRequests }};
|
|
http2_max_concurrent_streams {{ $cfg.HTTP2MaxConcurrentStreams }};
|
|
|
|
types_hash_max_size 2048;
|
|
server_names_hash_max_size {{ $cfg.ServerNameHashMaxSize }};
|
|
server_names_hash_bucket_size {{ $cfg.ServerNameHashBucketSize }};
|
|
map_hash_bucket_size {{ $cfg.MapHashBucketSize }};
|
|
|
|
proxy_headers_hash_max_size {{ $cfg.ProxyHeadersHashMaxSize }};
|
|
proxy_headers_hash_bucket_size {{ $cfg.ProxyHeadersHashBucketSize }};
|
|
|
|
variables_hash_bucket_size {{ $cfg.VariablesHashBucketSize }};
|
|
variables_hash_max_size {{ $cfg.VariablesHashMaxSize }};
|
|
|
|
underscores_in_headers {{ if $cfg.EnableUnderscoresInHeaders }}on{{ else }}off{{ end }};
|
|
ignore_invalid_headers {{ if $cfg.IgnoreInvalidHeaders }}on{{ else }}off{{ end }};
|
|
|
|
limit_req_status {{ $cfg.LimitReqStatusCode }};
|
|
limit_conn_status {{ $cfg.LimitConnStatusCode }};
|
|
|
|
{{ buildOpentracing $cfg $servers }}
|
|
|
|
include /etc/nginx/mime.types;
|
|
default_type {{ $cfg.DefaultType }};
|
|
|
|
{{ if $cfg.EnableBrotli }}
|
|
brotli on;
|
|
brotli_comp_level {{ $cfg.BrotliLevel }};
|
|
brotli_types {{ $cfg.BrotliTypes }};
|
|
{{ end }}
|
|
|
|
{{ if $cfg.UseGzip }}
|
|
gzip on;
|
|
gzip_comp_level {{ $cfg.GzipLevel }};
|
|
gzip_http_version 1.1;
|
|
gzip_min_length {{ $cfg.GzipMinLength}};
|
|
gzip_types {{ $cfg.GzipTypes }};
|
|
gzip_proxied any;
|
|
gzip_vary on;
|
|
{{ end }}
|
|
|
|
# Custom headers for response
|
|
{{ range $k, $v := $addHeaders }}
|
|
more_set_headers {{ printf "%s: %s" $k $v | quote }};
|
|
{{ end }}
|
|
|
|
server_tokens {{ if $cfg.ShowServerTokens }}on{{ else }}off{{ end }};
|
|
{{ if not $cfg.ShowServerTokens }}
|
|
more_clear_headers Server;
|
|
{{ end }}
|
|
|
|
# disable warnings
|
|
uninitialized_variable_warn off;
|
|
|
|
# Additional available variables:
|
|
# $namespace
|
|
# $ingress_name
|
|
# $service_name
|
|
# $service_port
|
|
log_format upstreaminfo {{ if $cfg.LogFormatEscapeJSON }}escape=json {{ end }}'{{ $cfg.LogFormatUpstream }}';
|
|
|
|
{{/* map urls that should not appear in access.log */}}
|
|
{{/* http://nginx.org/en/docs/http/ngx_http_log_module.html#access_log */}}
|
|
map $request_uri $loggable {
|
|
{{ range $reqUri := $cfg.SkipAccessLogURLs }}
|
|
{{ $reqUri }} 0;{{ end }}
|
|
default 1;
|
|
}
|
|
|
|
{{ if or $cfg.DisableAccessLog $cfg.DisableHTTPAccessLog }}
|
|
access_log off;
|
|
{{ else }}
|
|
{{ if $cfg.EnableSyslog }}
|
|
access_log syslog:server={{ $cfg.SyslogHost }}:{{ $cfg.SyslogPort }} upstreaminfo if=$loggable;
|
|
{{ else }}
|
|
access_log {{ or $cfg.HTTPAccessLogPath $cfg.AccessLogPath }} upstreaminfo {{ $cfg.AccessLogParams }} if=$loggable;
|
|
{{ end }}
|
|
{{ end }}
|
|
|
|
{{ if $cfg.EnableSyslog }}
|
|
error_log syslog:server={{ $cfg.SyslogHost }}:{{ $cfg.SyslogPort }} {{ $cfg.ErrorLogLevel }};
|
|
{{ else }}
|
|
error_log {{ $cfg.ErrorLogPath }} {{ $cfg.ErrorLogLevel }};
|
|
{{ end }}
|
|
|
|
{{ buildResolvers $cfg.Resolver $cfg.DisableIpv6DNS }}
|
|
|
|
# See https://www.nginx.com/blog/websocket-nginx
|
|
map $http_upgrade $connection_upgrade {
|
|
default upgrade;
|
|
{{ if (gt $cfg.UpstreamKeepaliveConnections 0) }}
|
|
# See http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive
|
|
'' '';
|
|
{{ else }}
|
|
'' close;
|
|
{{ end }}
|
|
}
|
|
|
|
# Reverse proxies can detect if a client provides a X-Request-ID header, and pass it on to the backend server.
|
|
# If no such header is provided, it can provide a random value.
|
|
map $http_x_request_id $req_id {
|
|
default $http_x_request_id;
|
|
{{ if $cfg.GenerateRequestID }}
|
|
"" $request_id;
|
|
{{ end }}
|
|
}
|
|
|
|
{{ if and $cfg.UseForwardedHeaders $cfg.ComputeFullForwardedFor }}
|
|
# We can't use $proxy_add_x_forwarded_for because the realip module
|
|
# replaces the remote_addr too soon
|
|
map $http_x_forwarded_for $full_x_forwarded_for {
|
|
{{ if $all.Cfg.UseProxyProtocol }}
|
|
default "$http_x_forwarded_for, $proxy_protocol_addr";
|
|
'' "$proxy_protocol_addr";
|
|
{{ else }}
|
|
default "$http_x_forwarded_for, $realip_remote_addr";
|
|
'' "$realip_remote_addr";
|
|
{{ end}}
|
|
}
|
|
|
|
{{ end }}
|
|
|
|
# Create a variable that contains the literal $ character.
|
|
# This works because the geo module will not resolve variables.
|
|
geo $literal_dollar {
|
|
default "$";
|
|
}
|
|
|
|
server_name_in_redirect off;
|
|
port_in_redirect off;
|
|
|
|
ssl_protocols {{ $cfg.SSLProtocols }};
|
|
|
|
ssl_early_data {{ if $cfg.SSLEarlyData }}on{{ else }}off{{ end }};
|
|
|
|
# turn on session caching to drastically improve performance
|
|
{{ if $cfg.SSLSessionCache }}
|
|
ssl_session_cache builtin:1000 shared:SSL:{{ $cfg.SSLSessionCacheSize }};
|
|
ssl_session_timeout {{ $cfg.SSLSessionTimeout }};
|
|
{{ end }}
|
|
|
|
# allow configuring ssl session tickets
|
|
ssl_session_tickets {{ if $cfg.SSLSessionTickets }}on{{ else }}off{{ end }};
|
|
|
|
{{ if not (empty $cfg.SSLSessionTicketKey ) }}
|
|
ssl_session_ticket_key /etc/nginx/tickets.key;
|
|
{{ end }}
|
|
|
|
# slightly reduce the time-to-first-byte
|
|
ssl_buffer_size {{ $cfg.SSLBufferSize }};
|
|
|
|
{{ if not (empty $cfg.SSLCiphers) }}
|
|
# allow configuring custom ssl ciphers
|
|
ssl_ciphers '{{ $cfg.SSLCiphers }}';
|
|
ssl_prefer_server_ciphers on;
|
|
{{ end }}
|
|
|
|
{{ if not (empty $cfg.SSLDHParam) }}
|
|
# allow custom DH file http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_dhparam
|
|
ssl_dhparam {{ $cfg.SSLDHParam }};
|
|
{{ end }}
|
|
|
|
ssl_ecdh_curve {{ $cfg.SSLECDHCurve }};
|
|
|
|
# PEM sha: {{ $cfg.DefaultSSLCertificate.PemSHA }}
|
|
ssl_certificate {{ $cfg.DefaultSSLCertificate.PemFileName }};
|
|
ssl_certificate_key {{ $cfg.DefaultSSLCertificate.PemFileName }};
|
|
|
|
{{ if gt (len $cfg.CustomHTTPErrors) 0 }}
|
|
proxy_intercept_errors on;
|
|
{{ end }}
|
|
|
|
{{ range $errCode := $cfg.CustomHTTPErrors }}
|
|
error_page {{ $errCode }} = @custom_upstream-default-backend_{{ $errCode }};{{ end }}
|
|
|
|
proxy_ssl_session_reuse on;
|
|
|
|
{{ if $cfg.AllowBackendServerHeader }}
|
|
proxy_pass_header Server;
|
|
{{ end }}
|
|
|
|
{{ range $header := $cfg.HideHeaders }}proxy_hide_header {{ $header }};
|
|
{{ end }}
|
|
|
|
{{ if not (empty $cfg.HTTPSnippet) }}
|
|
# Custom code snippet configured in the configuration configmap
|
|
{{ $cfg.HTTPSnippet }}
|
|
{{ end }}
|
|
|
|
upstream upstream_balancer {
|
|
### Attention!!!
|
|
#
|
|
# We no longer create "upstream" section for every backend.
|
|
# Backends are handled dynamically using Lua. If you would like to debug
|
|
# and see what backends ingress-nginx has in its memory you can
|
|
# install our kubectl plugin https://kubernetes.github.io/ingress-nginx/kubectl-plugin.
|
|
# Once you have the plugin you can use "kubectl ingress-nginx backends" command to
|
|
# inspect current backends.
|
|
#
|
|
###
|
|
|
|
server 0.0.0.1; # placeholder
|
|
|
|
balancer_by_lua_block {
|
|
balancer.balance()
|
|
}
|
|
|
|
{{ if (gt $cfg.UpstreamKeepaliveConnections 0) }}
|
|
keepalive {{ $cfg.UpstreamKeepaliveConnections }};
|
|
|
|
keepalive_timeout {{ $cfg.UpstreamKeepaliveTimeout }}s;
|
|
keepalive_requests {{ $cfg.UpstreamKeepaliveRequests }};
|
|
{{ end }}
|
|
}
|
|
|
|
{{ range $rl := (filterRateLimits $servers ) }}
|
|
# Ratelimit {{ $rl.Name }}
|
|
geo $remote_addr $allowlist_{{ $rl.ID }} {
|
|
default 0;
|
|
{{ range $ip := $rl.Allowlist }}
|
|
{{ $ip }} 1;{{ end }}
|
|
}
|
|
|
|
# Ratelimit {{ $rl.Name }}
|
|
map $allowlist_{{ $rl.ID }} $limit_{{ $rl.ID }} {
|
|
0 {{ $cfg.LimitConnZoneVariable }};
|
|
1 "";
|
|
}
|
|
{{ end }}
|
|
|
|
{{/* build all the required rate limit zones. Each annotation requires a dedicated zone */}}
|
|
{{/* 1MB -> 16 thousand 64-byte states or about 8 thousand 128-byte states */}}
|
|
{{ range $zone := (buildRateLimitZones $servers) }}
|
|
{{ $zone }}
|
|
{{ end }}
|
|
|
|
# Cache for internal auth checks
|
|
proxy_cache_path /tmp/nginx-cache-auth levels=1:2 keys_zone=auth_cache:10m max_size=128m inactive=30m use_temp_path=off;
|
|
|
|
# Global filters
|
|
{{ range $ip := $cfg.BlockCIDRs }}deny {{ trimSpace $ip }};
|
|
{{ end }}
|
|
|
|
{{ if gt (len $cfg.BlockUserAgents) 0 }}
|
|
map $http_user_agent $block_ua {
|
|
default 0;
|
|
|
|
{{ range $ua := $cfg.BlockUserAgents }}{{ trimSpace $ua }} 1;
|
|
{{ end }}
|
|
}
|
|
{{ end }}
|
|
|
|
{{ if gt (len $cfg.BlockReferers) 0 }}
|
|
map $http_referer $block_ref {
|
|
default 0;
|
|
|
|
{{ range $ref := $cfg.BlockReferers }}{{ trimSpace $ref }} 1;
|
|
{{ end }}
|
|
}
|
|
{{ end }}
|
|
|
|
{{/* Build server redirects (from/to www) */}}
|
|
{{ range $redirect := .RedirectServers }}
|
|
## start server {{ $redirect.From }}
|
|
server {
|
|
server_name {{ $redirect.From }};
|
|
|
|
{{ buildHTTPListener $all $redirect.From }}
|
|
{{ buildHTTPSListener $all $redirect.From }}
|
|
|
|
ssl_certificate_by_lua_block {
|
|
certificate.call()
|
|
}
|
|
|
|
{{ if gt (len $cfg.BlockUserAgents) 0 }}
|
|
if ($block_ua) {
|
|
return 403;
|
|
}
|
|
{{ end }}
|
|
{{ if gt (len $cfg.BlockReferers) 0 }}
|
|
if ($block_ref) {
|
|
return 403;
|
|
}
|
|
{{ end }}
|
|
|
|
set_by_lua_block $redirect_to {
|
|
local request_uri = ngx.var.request_uri
|
|
if string.sub(request_uri, -1) == "/" then
|
|
request_uri = string.sub(request_uri, 1, -2)
|
|
end
|
|
|
|
{{ if ne $all.ListenPorts.HTTPS 443 }}
|
|
{{ $redirect_port := (printf ":%v" $all.ListenPorts.HTTPS) }}
|
|
return string.format("%s://%s%s%s", ngx.var.scheme, "{{ $redirect.To }}", "{{ $redirect_port }}", request_uri)
|
|
{{ else }}
|
|
return string.format("%s://%s%s", ngx.var.scheme, "{{ $redirect.To }}", request_uri)
|
|
{{ end }}
|
|
}
|
|
|
|
return {{ $all.Cfg.HTTPRedirectCode }} $redirect_to;
|
|
}
|
|
## end server {{ $redirect.From }}
|
|
{{ end }}
|
|
|
|
{{ range $server := $servers }}
|
|
|
|
## start server {{ $server.Hostname }}
|
|
server {
|
|
server_name {{ buildServerName $server.Hostname }} {{range $server.Aliases }}{{ . }} {{ end }};
|
|
|
|
{{ if gt (len $cfg.BlockUserAgents) 0 }}
|
|
if ($block_ua) {
|
|
return 403;
|
|
}
|
|
{{ end }}
|
|
{{ if gt (len $cfg.BlockReferers) 0 }}
|
|
if ($block_ref) {
|
|
return 403;
|
|
}
|
|
{{ end }}
|
|
|
|
{{ template "SERVER" serverConfig $all $server }}
|
|
|
|
{{ if not (empty $cfg.ServerSnippet) }}
|
|
# Custom code snippet configured in the configuration configmap
|
|
{{ $cfg.ServerSnippet }}
|
|
{{ end }}
|
|
|
|
{{ template "CUSTOM_ERRORS" (buildCustomErrorDeps "upstream-default-backend" $cfg.CustomHTTPErrors $all.EnableMetrics $all.Cfg.EnableModsecurity) }}
|
|
}
|
|
## end server {{ $server.Hostname }}
|
|
|
|
{{ end }}
|
|
|
|
# backend for when default-backend-service is not configured or it does not have endpoints
|
|
server {
|
|
listen {{ $all.ListenPorts.Default }} default_server {{ if $all.Cfg.ReusePort }}reuseport{{ end }} backlog={{ $all.BacklogSize }};
|
|
{{ if $IsIPV6Enabled }}listen [::]:{{ $all.ListenPorts.Default }} default_server {{ if $all.Cfg.ReusePort }}reuseport{{ end }} backlog={{ $all.BacklogSize }};{{ end }}
|
|
set $proxy_upstream_name "internal";
|
|
|
|
access_log off;
|
|
|
|
location / {
|
|
return 404;
|
|
}
|
|
}
|
|
|
|
# default server, used for NGINX healthcheck and access to nginx stats
|
|
server {
|
|
listen 127.0.0.1:{{ .StatusPort }};
|
|
set $proxy_upstream_name "internal";
|
|
|
|
keepalive_timeout 0;
|
|
gzip off;
|
|
|
|
access_log off;
|
|
|
|
{{ if $cfg.EnableOpentracing }}
|
|
opentracing off;
|
|
{{ end }}
|
|
|
|
location {{ $healthzURI }} {
|
|
return 200;
|
|
}
|
|
|
|
location /is-dynamic-lb-initialized {
|
|
content_by_lua_block {
|
|
local configuration = require("configuration")
|
|
local backend_data = configuration.get_backends_data()
|
|
if not backend_data then
|
|
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
|
|
return
|
|
end
|
|
|
|
ngx.say("OK")
|
|
ngx.exit(ngx.HTTP_OK)
|
|
}
|
|
}
|
|
|
|
location {{ .StatusPath }} {
|
|
stub_status on;
|
|
}
|
|
|
|
location /configuration {
|
|
# NOTE: obsolete directive. removed.
|
|
#client_max_body_size {{ luaConfigurationRequestBodySize $cfg }}m;
|
|
|
|
# NOTE: obsolete directive. removed.
|
|
#client_body_buffer_size {{ luaConfigurationRequestBodySize $cfg }}m;
|
|
proxy_buffering off;
|
|
|
|
content_by_lua_block {
|
|
configuration.call()
|
|
}
|
|
}
|
|
|
|
location / {
|
|
content_by_lua_block {
|
|
ngx.exit(ngx.HTTP_NOT_FOUND)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
stream {
|
|
lua_package_path "/etc/nginx/lua/?.lua;/etc/nginx/lua/vendor/?.lua;;";
|
|
|
|
lua_shared_dict tcp_udp_configuration_data 5M;
|
|
|
|
init_by_lua_block {
|
|
collectgarbage("collect")
|
|
|
|
-- init modules
|
|
local ok, res
|
|
|
|
ok, res = pcall(require, "configuration")
|
|
if not ok then
|
|
error("require failed: " .. tostring(res))
|
|
else
|
|
configuration = res
|
|
end
|
|
|
|
ok, res = pcall(require, "tcp_udp_configuration")
|
|
if not ok then
|
|
error("require failed: " .. tostring(res))
|
|
else
|
|
tcp_udp_configuration = res
|
|
end
|
|
|
|
ok, res = pcall(require, "tcp_udp_balancer")
|
|
if not ok then
|
|
error("require failed: " .. tostring(res))
|
|
else
|
|
tcp_udp_balancer = res
|
|
end
|
|
}
|
|
|
|
init_worker_by_lua_block {
|
|
tcp_udp_balancer.init_worker()
|
|
}
|
|
|
|
lua_add_variable $proxy_upstream_name;
|
|
|
|
log_format log_stream '{{ $cfg.LogFormatStream }}';
|
|
|
|
{{ if or $cfg.DisableAccessLog $cfg.DisableStreamAccessLog }}
|
|
access_log off;
|
|
{{ else }}
|
|
access_log {{ or $cfg.StreamAccessLogPath $cfg.AccessLogPath }} log_stream {{ $cfg.AccessLogParams }};
|
|
{{ end }}
|
|
|
|
error_log {{ $cfg.ErrorLogPath }} {{ $cfg.ErrorLogLevel }};
|
|
|
|
{{ if $cfg.EnableRealIP }}
|
|
{{ range $trusted_ip := $cfg.ProxyRealIPCIDR }}
|
|
set_real_ip_from {{ $trusted_ip }};
|
|
{{ end }}
|
|
{{ end }}
|
|
|
|
upstream upstream_balancer {
|
|
server 0.0.0.1:1234; # placeholder
|
|
|
|
balancer_by_lua_block {
|
|
local cjson = require("cjson.safe")
|
|
local b = require "ngx.balancer"
|
|
local ngx = ngx
|
|
local ngx_log = ngx.log
|
|
local backends_data = tcp_udp_configuration.get_backends_data()
|
|
local new_backends, err = cjson.decode(backends_data)
|
|
if not new_backends then
|
|
ngx.log(ngx.ERR, "could not parse backends data: ", err)
|
|
return
|
|
end
|
|
for _, new_backend in pairs(new_backends) do
|
|
for _, addr in pairs(new_backend.endpoints) do
|
|
local address = addr["address"]
|
|
local port = addr["port"]
|
|
local ok, err = b.set_current_peer(address, port)
|
|
end
|
|
end
|
|
}
|
|
}
|
|
|
|
server {
|
|
listen 127.0.0.1:{{ .StreamPort }};
|
|
|
|
access_log off;
|
|
|
|
content_by_lua_block {
|
|
tcp_udp_configuration.call()
|
|
}
|
|
}
|
|
|
|
# TCP services
|
|
{{ range $tcpServer := .TCPBackends }}
|
|
server {
|
|
preread_by_lua_block {
|
|
ngx.var.proxy_upstream_name="tcp-{{ $tcpServer.Backend.Namespace }}-{{ $tcpServer.Backend.Name }}-{{ $tcpServer.Backend.Port }}";
|
|
}
|
|
|
|
{{ range $address := $all.Cfg.BindAddressIpv4 }}
|
|
listen {{ $address }}:{{ $tcpServer.Port }}{{ if $tcpServer.Backend.ProxyProtocol.Decode }} proxy_protocol{{ end }};
|
|
{{ else }}
|
|
listen {{ $tcpServer.Port }}{{ if $tcpServer.Backend.ProxyProtocol.Decode }} proxy_protocol{{ end }};
|
|
{{ end }}
|
|
{{ if $IsIPV6Enabled }}
|
|
{{ range $address := $all.Cfg.BindAddressIpv6 }}
|
|
listen {{ $address }}:{{ $tcpServer.Port }}{{ if $tcpServer.Backend.ProxyProtocol.Decode }} proxy_protocol{{ end }};
|
|
{{ else }}
|
|
listen [::]:{{ $tcpServer.Port }}{{ if $tcpServer.Backend.ProxyProtocol.Decode }} proxy_protocol{{ end }};
|
|
{{ end }}
|
|
{{ end }}
|
|
proxy_timeout {{ $cfg.ProxyStreamTimeout }};
|
|
proxy_next_upstream {{ if $cfg.ProxyStreamNextUpstream }}on{{ else }}off{{ end }};
|
|
proxy_next_upstream_timeout {{ $cfg.ProxyStreamNextUpstreamTimeout }};
|
|
proxy_next_upstream_tries {{ $cfg.ProxyStreamNextUpstreamTries }};
|
|
|
|
proxy_pass upstream_balancer;
|
|
{{ if $tcpServer.Backend.ProxyProtocol.Encode }}
|
|
proxy_protocol on;
|
|
{{ end }}
|
|
}
|
|
{{ end }}
|
|
|
|
# UDP services
|
|
{{ range $udpServer := .UDPBackends }}
|
|
server {
|
|
preread_by_lua_block {
|
|
ngx.var.proxy_upstream_name="udp-{{ $udpServer.Backend.Namespace }}-{{ $udpServer.Backend.Name }}-{{ $udpServer.Backend.Port }}";
|
|
}
|
|
|
|
{{ range $address := $all.Cfg.BindAddressIpv4 }}
|
|
listen {{ $address }}:{{ $udpServer.Port }} udp;
|
|
{{ else }}
|
|
listen {{ $udpServer.Port }} udp;
|
|
{{ end }}
|
|
{{ if $IsIPV6Enabled }}
|
|
{{ range $address := $all.Cfg.BindAddressIpv6 }}
|
|
listen {{ $address }}:{{ $udpServer.Port }} udp;
|
|
{{ else }}
|
|
listen [::]:{{ $udpServer.Port }} udp;
|
|
{{ end }}
|
|
{{ end }}
|
|
proxy_responses {{ $cfg.ProxyStreamResponses }};
|
|
proxy_timeout {{ $cfg.ProxyStreamTimeout }};
|
|
proxy_next_upstream {{ if $cfg.ProxyStreamNextUpstream }}on{{ else }}off{{ end }};
|
|
proxy_next_upstream_timeout {{ $cfg.ProxyStreamNextUpstreamTimeout }};
|
|
proxy_next_upstream_tries {{ $cfg.ProxyStreamNextUpstreamTries }};
|
|
proxy_pass upstream_balancer;
|
|
}
|
|
{{ end }}
|
|
}
|
|
|
|
{{/* definition of templates to avoid repetitions */}}
|
|
{{ define "CUSTOM_ERRORS" }}
|
|
{{ $enableMetrics := .EnableMetrics }}
|
|
{{ $upstreamName := .UpstreamName }}
|
|
{{ range $errCode := .ErrorCodes }}
|
|
location @custom_{{ $upstreamName }}_{{ $errCode }} {
|
|
internal;
|
|
|
|
proxy_intercept_errors off;
|
|
|
|
proxy_set_header X-Code {{ $errCode }};
|
|
proxy_set_header X-Format $http_accept;
|
|
proxy_set_header X-Original-URI $request_uri;
|
|
proxy_set_header X-Namespace $namespace;
|
|
proxy_set_header X-Ingress-Name $ingress_name;
|
|
proxy_set_header X-Service-Name $service_name;
|
|
proxy_set_header X-Service-Port $service_port;
|
|
proxy_set_header X-Request-ID $req_id;
|
|
proxy_set_header Host $best_http_host;
|
|
|
|
set $proxy_upstream_name {{ $upstreamName | quote }};
|
|
|
|
rewrite (.*) / break;
|
|
|
|
proxy_pass http://upstream_balancer;
|
|
log_by_lua_block {
|
|
{{ if $enableMetrics }}
|
|
monitor.call()
|
|
{{ end }}
|
|
}
|
|
}
|
|
{{ end }}
|
|
{{ end }}
|
|
|
|
{{/* CORS support from https://michielkalkman.com/snippets/nginx-cors-open-configuration.html */}}
|
|
{{ define "CORS" }}
|
|
{{ $cors := .CorsConfig }}
|
|
# Cors Preflight methods needs additional options and different Return Code
|
|
if ($request_method = 'OPTIONS') {
|
|
more_set_headers 'Access-Control-Allow-Origin: {{ $cors.CorsAllowOrigin }}';
|
|
{{ if $cors.CorsAllowCredentials }} more_set_headers 'Access-Control-Allow-Credentials: {{ $cors.CorsAllowCredentials }}'; {{ end }}
|
|
more_set_headers 'Access-Control-Allow-Methods: {{ $cors.CorsAllowMethods }}';
|
|
more_set_headers 'Access-Control-Allow-Headers: {{ $cors.CorsAllowHeaders }}';
|
|
{{ if not (empty $cors.CorsExposeHeaders) }} more_set_headers 'Access-Control-Expose-Headers: {{ $cors.CorsExposeHeaders }}'; {{ end }}
|
|
more_set_headers 'Access-Control-Max-Age: {{ $cors.CorsMaxAge }}';
|
|
more_set_headers 'Content-Type: text/plain charset=UTF-8';
|
|
more_set_headers 'Content-Length: 0';
|
|
return 204;
|
|
}
|
|
|
|
more_set_headers 'Access-Control-Allow-Origin: {{ $cors.CorsAllowOrigin }}';
|
|
{{ if $cors.CorsAllowCredentials }} more_set_headers 'Access-Control-Allow-Credentials: {{ $cors.CorsAllowCredentials }}'; {{ end }}
|
|
{{ if not (empty $cors.CorsExposeHeaders) }} more_set_headers 'Access-Control-Expose-Headers: {{ $cors.CorsExposeHeaders }}'; {{ end }}
|
|
|
|
{{ end }}
|
|
|
|
{{/* definition of server-template to avoid repetitions with server-alias */}}
|
|
{{ define "SERVER" }}
|
|
{{ $all := .First }}
|
|
{{ $server := .Second }}
|
|
|
|
{{ buildHTTPListener $all $server.Hostname }}
|
|
{{ buildHTTPSListener $all $server.Hostname }}
|
|
|
|
set $proxy_upstream_name "-";
|
|
|
|
ssl_certificate_by_lua_block {
|
|
certificate.call()
|
|
}
|
|
|
|
{{ if not (empty $server.AuthTLSError) }}
|
|
# {{ $server.AuthTLSError }}
|
|
return 403;
|
|
{{ else }}
|
|
|
|
{{ if not (empty $server.CertificateAuth.CAFileName) }}
|
|
# PEM sha: {{ $server.CertificateAuth.CASHA }}
|
|
ssl_client_certificate {{ $server.CertificateAuth.CAFileName }};
|
|
ssl_verify_client {{ $server.CertificateAuth.VerifyClient }};
|
|
ssl_verify_depth {{ $server.CertificateAuth.ValidationDepth }};
|
|
|
|
{{ if not (empty $server.CertificateAuth.CRLFileName) }}
|
|
# PEM sha: {{ $server.CertificateAuth.CRLSHA }}
|
|
ssl_crl {{ $server.CertificateAuth.CRLFileName }};
|
|
{{ end }}
|
|
|
|
{{ if not (empty $server.CertificateAuth.ErrorPage)}}
|
|
error_page 495 496 = {{ $server.CertificateAuth.ErrorPage }};
|
|
{{ end }}
|
|
{{ end }}
|
|
|
|
{{ if not (empty $server.ProxySSL.CAFileName) }}
|
|
# PEM sha: {{ $server.ProxySSL.CASHA }}
|
|
proxy_ssl_trusted_certificate {{ $server.ProxySSL.CAFileName }};
|
|
proxy_ssl_ciphers {{ $server.ProxySSL.Ciphers }};
|
|
proxy_ssl_protocols {{ $server.ProxySSL.Protocols }};
|
|
proxy_ssl_verify {{ $server.ProxySSL.Verify }};
|
|
proxy_ssl_verify_depth {{ $server.ProxySSL.VerifyDepth }};
|
|
{{ if not (empty $server.ProxySSL.ProxySSLName) }}
|
|
proxy_ssl_name {{ $server.ProxySSL.ProxySSLName }};
|
|
proxy_ssl_server_name {{ $server.ProxySSL.ProxySSLServerName }};
|
|
{{ end }}
|
|
{{ end }}
|
|
|
|
{{ if not (empty $server.ProxySSL.PemFileName) }}
|
|
proxy_ssl_certificate {{ $server.ProxySSL.PemFileName }};
|
|
proxy_ssl_certificate_key {{ $server.ProxySSL.PemFileName }};
|
|
{{ end }}
|
|
|
|
{{ if not (empty $server.SSLCiphers) }}
|
|
ssl_ciphers {{ $server.SSLCiphers }};
|
|
{{ end }}
|
|
|
|
{{ if not (empty $server.SSLPreferServerCiphers) }}
|
|
ssl_prefer_server_ciphers {{ $server.SSLPreferServerCiphers }};
|
|
{{ end }}
|
|
|
|
{{ if not (empty $server.ServerSnippet) }}
|
|
# Custom code snippet configured for host {{ $server.Hostname }}
|
|
{{ $server.ServerSnippet }}
|
|
{{ end }}
|
|
|
|
{{ range $errorLocation := (buildCustomErrorLocationsPerServer $server) }}
|
|
{{ template "CUSTOM_ERRORS" (buildCustomErrorDeps $errorLocation.UpstreamName $errorLocation.Codes $all.EnableMetrics $all.Cfg.EnableModsecurity) }}
|
|
{{ end }}
|
|
|
|
{{ buildMirrorLocations $server.Locations }}
|
|
|
|
{{ $enforceRegex := enforceRegexModifier $server.Locations }}
|
|
{{ range $location := $server.Locations }}
|
|
{{ $path := buildLocation $location $enforceRegex }}
|
|
{{ $proxySetHeader := proxySetHeader $location }}
|
|
{{ $authPath := buildAuthLocation $location $all.Cfg.GlobalExternalAuth.URL }}
|
|
{{ $applyGlobalAuth := shouldApplyGlobalAuth $location $all.Cfg.GlobalExternalAuth.URL }}
|
|
|
|
{{ $externalAuth := $location.ExternalAuth }}
|
|
{{ if eq $applyGlobalAuth true }}
|
|
{{ $externalAuth = $all.Cfg.GlobalExternalAuth }}
|
|
{{ end }}
|
|
|
|
{{ if not (empty $location.Rewrite.AppRoot) }}
|
|
if ($uri = /) {
|
|
return 302 $scheme://$http_host{{ $location.Rewrite.AppRoot }};
|
|
}
|
|
{{ end }}
|
|
|
|
{{ if $authPath }}
|
|
location = {{ $authPath }} {
|
|
internal;
|
|
|
|
{{ if (or $all.Cfg.EnableOpentracing $location.Opentracing.Enabled) }}
|
|
opentracing on;
|
|
opentracing_propagate_context;
|
|
{{ end }}
|
|
|
|
{{ if $externalAuth.AuthCacheKey }}
|
|
set $tmp_cache_key '{{ $server.Hostname }}{{ $authPath }}{{ $externalAuth.AuthCacheKey }}';
|
|
set $cache_key '';
|
|
|
|
rewrite_by_lua_block {
|
|
ngx.var.cache_key = ngx.encode_base64(ngx.sha1_bin(ngx.var.tmp_cache_key))
|
|
}
|
|
|
|
proxy_cache auth_cache;
|
|
|
|
{{- range $dur := $externalAuth.AuthCacheDuration }}
|
|
proxy_cache_valid {{ $dur }};
|
|
{{- end }}
|
|
|
|
proxy_cache_key "$cache_key";
|
|
{{ end }}
|
|
|
|
# ngx_auth_request module overrides variables in the parent request,
|
|
# therefore we have to explicitly set this variable again so that when the parent request
|
|
# resumes it has the correct value set for this variable so that Lua can pick backend correctly
|
|
set $proxy_upstream_name {{ buildUpstreamName $location | quote }};
|
|
|
|
proxy_pass_request_body off;
|
|
proxy_set_header Content-Length "";
|
|
proxy_set_header X-Forwarded-Proto "";
|
|
proxy_set_header X-Request-ID $req_id;
|
|
|
|
{{ if $externalAuth.Method }}
|
|
proxy_method {{ $externalAuth.Method }};
|
|
proxy_set_header X-Original-URI $request_uri;
|
|
proxy_set_header X-Scheme $pass_access_scheme;
|
|
{{ end }}
|
|
|
|
proxy_set_header Host {{ $externalAuth.Host }};
|
|
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
|
|
proxy_set_header X-Original-Method $request_method;
|
|
proxy_set_header X-Sent-From "nginx-ingress-controller";
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
{{ if and $all.Cfg.UseForwardedHeaders $all.Cfg.ComputeFullForwardedFor }}
|
|
proxy_set_header X-Forwarded-For $full_x_forwarded_for;
|
|
{{ else }}
|
|
proxy_set_header X-Forwarded-For $remote_addr;
|
|
{{ end }}
|
|
|
|
{{ if $externalAuth.RequestRedirect }}
|
|
proxy_set_header X-Auth-Request-Redirect {{ $externalAuth.RequestRedirect }};
|
|
{{ else }}
|
|
proxy_set_header X-Auth-Request-Redirect $request_uri;
|
|
{{ end }}
|
|
|
|
{{ if $externalAuth.AuthCacheKey }}
|
|
proxy_buffering "on";
|
|
{{ else }}
|
|
proxy_buffering {{ $location.Proxy.ProxyBuffering }};
|
|
{{ end }}
|
|
proxy_buffer_size {{ $location.Proxy.BufferSize }};
|
|
proxy_buffers {{ $location.Proxy.BuffersNumber }} {{ $location.Proxy.BufferSize }};
|
|
proxy_request_buffering {{ $location.Proxy.RequestBuffering }};
|
|
proxy_http_version {{ $location.Proxy.ProxyHTTPVersion }};
|
|
|
|
proxy_ssl_server_name on;
|
|
proxy_pass_request_headers on;
|
|
{{ if isValidByteSize $location.Proxy.BodySize true }}
|
|
# NOTE: obsolete directive. removed.
|
|
#client_max_body_size {{ $location.Proxy.BodySize }};
|
|
{{ end }}
|
|
{{ if isValidByteSize $location.ClientBodyBufferSize false }}
|
|
|
|
# NOTE: obsolete directive. removed.
|
|
#client_body_buffer_size {{ $location.ClientBodyBufferSize }};
|
|
{{ end }}
|
|
|
|
# Pass the extracted client certificate to the auth provider
|
|
{{ if not (empty $server.CertificateAuth.CAFileName) }}
|
|
{{ if $server.CertificateAuth.PassCertToUpstream }}
|
|
proxy_set_header ssl-client-cert $ssl_client_escaped_cert;
|
|
{{ end }}
|
|
proxy_set_header ssl-client-verify $ssl_client_verify;
|
|
proxy_set_header ssl-client-subject-dn $ssl_client_s_dn;
|
|
proxy_set_header ssl-client-issuer-dn $ssl_client_i_dn;
|
|
{{ end }}
|
|
|
|
{{- range $line := buildAuthProxySetHeaders $externalAuth.ProxySetHeaders}}
|
|
{{ $line }}
|
|
{{- end }}
|
|
|
|
{{ if not (empty $externalAuth.AuthSnippet) }}
|
|
{{ $externalAuth.AuthSnippet }}
|
|
{{ end }}
|
|
|
|
set $target {{ $externalAuth.URL }};
|
|
proxy_pass $target;
|
|
}
|
|
{{ end }}
|
|
|
|
{{ if isLocationAllowed $location }}
|
|
{{ if $externalAuth.SigninURL }}
|
|
location {{ buildAuthSignURLLocation $location.Path $externalAuth.SigninURL }} {
|
|
internal;
|
|
|
|
add_header Set-Cookie $auth_cookie;
|
|
|
|
return 302 {{ buildAuthSignURL $externalAuth.SigninURL $externalAuth.SigninURLRedirectParam }};
|
|
}
|
|
{{ end }}
|
|
{{ end }}
|
|
|
|
location {{ $path }} {
|
|
{{ $ing := (getIngressInformation $location.Ingress $server.Hostname $location.IngressPath) }}
|
|
set $namespace {{ $ing.Namespace | quote}};
|
|
set $ingress_name {{ $ing.Rule | quote }};
|
|
set $service_name {{ $ing.Service | quote }};
|
|
set $service_port {{ $ing.ServicePort | quote }};
|
|
set $location_path {{ $ing.Path | escapeLiteralDollar | quote }};
|
|
|
|
{{ buildOpentracingForLocation $all.Cfg.EnableOpentracing true $location }}
|
|
|
|
{{ if $location.Mirror.Source }}
|
|
mirror {{ $location.Mirror.Source }};
|
|
mirror_request_body {{ $location.Mirror.RequestBody }};
|
|
{{ end }}
|
|
|
|
rewrite_by_lua_block {
|
|
lua_ingress.rewrite({{ locationConfigForLua $location $all }})
|
|
balancer.rewrite()
|
|
plugins.run()
|
|
}
|
|
|
|
# be careful with `access_by_lua_block` and `satisfy any` directives as satisfy any
|
|
# will always succeed when there's `access_by_lua_block` that does not have any lua code doing `ngx.exit(ngx.DECLINED)`
|
|
# other authentication method such as basic auth or external auth useless - all requests will be allowed.
|
|
#access_by_lua_block {
|
|
#}
|
|
|
|
header_filter_by_lua_block {
|
|
lua_ingress.header()
|
|
plugins.run()
|
|
}
|
|
|
|
body_filter_by_lua_block {
|
|
}
|
|
|
|
log_by_lua_block {
|
|
balancer.log()
|
|
{{ if $all.EnableMetrics }}
|
|
monitor.call()
|
|
{{ end }}
|
|
|
|
plugins.run()
|
|
}
|
|
|
|
{{ if not $location.Logs.Access }}
|
|
access_log off;
|
|
{{ end }}
|
|
|
|
{{ if $location.Logs.Rewrite }}
|
|
rewrite_log on;
|
|
{{ end }}
|
|
|
|
{{ if $location.HTTP2PushPreload }}
|
|
http2_push_preload on;
|
|
{{ end }}
|
|
|
|
port_in_redirect {{ if $location.UsePortInRedirects }}on{{ else }}off{{ end }};
|
|
|
|
set $balancer_ewma_score -1;
|
|
set $proxy_upstream_name {{ buildUpstreamName $location | quote }};
|
|
set $proxy_host $proxy_upstream_name;
|
|
set $pass_access_scheme $scheme;
|
|
|
|
{{ if $all.Cfg.UseProxyProtocol }}
|
|
set $pass_server_port $proxy_protocol_server_port;
|
|
{{ else }}
|
|
set $pass_server_port $server_port;
|
|
{{ end }}
|
|
|
|
set $best_http_host $http_host;
|
|
set $pass_port $pass_server_port;
|
|
|
|
set $proxy_alternative_upstream_name "";
|
|
|
|
{{ buildModSecurityForLocation $all.Cfg $location }}
|
|
|
|
{{ if isLocationAllowed $location }}
|
|
{{ if gt (len $location.Allowlist.CIDR) 0 }}
|
|
{{ range $ip := $location.Allowlist.CIDR }}
|
|
allow {{ $ip }};{{ end }}
|
|
deny all;
|
|
{{ end }}
|
|
|
|
{{ if not (isLocationInLocationList $location $all.Cfg.NoAuthLocations) }}
|
|
{{ if $authPath }}
|
|
# this location requires authentication
|
|
auth_request {{ $authPath }};
|
|
auth_request_set $auth_cookie $upstream_http_set_cookie;
|
|
add_header Set-Cookie $auth_cookie;
|
|
{{- range $line := buildAuthResponseHeaders $externalAuth.ResponseHeaders }}
|
|
{{ $line }}
|
|
{{- end }}
|
|
{{ end }}
|
|
|
|
{{ if $externalAuth.SigninURL }}
|
|
set_escape_uri $escaped_request_uri $request_uri;
|
|
error_page 401 = {{ buildAuthSignURLLocation $location.Path $externalAuth.SigninURL }};
|
|
{{ end }}
|
|
|
|
{{ if $location.BasicDigestAuth.Secured }}
|
|
{{ if eq $location.BasicDigestAuth.Type "basic" }}
|
|
auth_basic {{ $location.BasicDigestAuth.Realm | quote }};
|
|
auth_basic_user_file {{ $location.BasicDigestAuth.File }};
|
|
{{ else }}
|
|
auth_digest {{ $location.BasicDigestAuth.Realm | quote }};
|
|
auth_digest_user_file {{ $location.BasicDigestAuth.File }};
|
|
{{ end }}
|
|
proxy_set_header Authorization "";
|
|
{{ end }}
|
|
{{ end }}
|
|
|
|
{{/* if the location contains a rate limit annotation, create one */}}
|
|
{{ $limits := buildRateLimit $location }}
|
|
{{ range $limit := $limits }}
|
|
{{ $limit }}{{ end }}
|
|
|
|
{{ if $location.CorsConfig.CorsEnabled }}
|
|
{{ template "CORS" $location }}
|
|
{{ end }}
|
|
|
|
{{ if isValidByteSize $location.Proxy.BodySize true }}
|
|
# NOTE: obsolete directive. removed.
|
|
#client_max_body_size {{ $location.Proxy.BodySize }};
|
|
{{ end }}
|
|
{{ if isValidByteSize $location.ClientBodyBufferSize false }}
|
|
|
|
# NOTE: obsolete directive. removed.
|
|
#client_body_buffer_size {{ $location.ClientBodyBufferSize }};
|
|
{{ end }}
|
|
|
|
{{/* By default use vhost as Host to upstream, but allow overrides */}}
|
|
{{ if not (eq $proxySetHeader "grpc_set_header") }}
|
|
{{ if not (empty $location.UpstreamVhost) }}
|
|
{{ $proxySetHeader }} Host {{ $location.UpstreamVhost | quote }};
|
|
{{ else }}
|
|
{{ $proxySetHeader }} Host $best_http_host;
|
|
{{ end }}
|
|
{{ end }}
|
|
|
|
# Pass the extracted client certificate to the backend
|
|
{{ if not (empty $server.CertificateAuth.CAFileName) }}
|
|
{{ if $server.CertificateAuth.PassCertToUpstream }}
|
|
{{ $proxySetHeader }} ssl-client-cert $ssl_client_escaped_cert;
|
|
{{ end }}
|
|
{{ $proxySetHeader }} ssl-client-verify $ssl_client_verify;
|
|
{{ $proxySetHeader }} ssl-client-subject-dn $ssl_client_s_dn;
|
|
{{ $proxySetHeader }} ssl-client-issuer-dn $ssl_client_i_dn;
|
|
{{ end }}
|
|
|
|
# Allow websocket connections
|
|
{{ $proxySetHeader }} Upgrade $http_upgrade;
|
|
{{ if $location.Connection.Enabled}}
|
|
{{ $proxySetHeader }} Connection {{ $location.Connection.Header }};
|
|
{{ else }}
|
|
{{ $proxySetHeader }} Connection $connection_upgrade;
|
|
{{ end }}
|
|
|
|
{{ $proxySetHeader }} X-Request-ID $req_id;
|
|
{{ $proxySetHeader }} X-Real-IP $remote_addr;
|
|
{{ if and $all.Cfg.UseForwardedHeaders $all.Cfg.ComputeFullForwardedFor }}
|
|
{{ $proxySetHeader }} X-Forwarded-For $full_x_forwarded_for;
|
|
{{ else }}
|
|
{{ $proxySetHeader }} X-Forwarded-For $remote_addr;
|
|
{{ end }}
|
|
{{ $proxySetHeader }} X-Forwarded-Host $best_http_host;
|
|
{{ $proxySetHeader }} X-Forwarded-Port $pass_port;
|
|
{{ $proxySetHeader }} X-Forwarded-Proto $pass_access_scheme;
|
|
{{ if $all.Cfg.ProxyAddOriginalURIHeader }}
|
|
{{ $proxySetHeader }} X-Original-URI $request_uri;
|
|
{{ end }}
|
|
{{ $proxySetHeader }} X-Scheme $pass_access_scheme;
|
|
|
|
# Pass the original X-Forwarded-For
|
|
{{ $proxySetHeader }} X-Original-Forwarded-For {{ buildForwardedFor $all.Cfg.ForwardedForHeader }};
|
|
|
|
# mitigate HTTPoxy Vulnerability
|
|
# https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
|
|
{{ $proxySetHeader }} Proxy "";
|
|
|
|
# Custom headers to proxied server
|
|
{{ range $k, $v := $all.ProxySetHeaders }}
|
|
{{ $proxySetHeader }} {{ $k }} {{ $v | quote }};
|
|
{{ end }}
|
|
|
|
proxy_connect_timeout {{ $location.Proxy.ConnectTimeout }}s;
|
|
proxy_send_timeout {{ $location.Proxy.SendTimeout }}s;
|
|
proxy_read_timeout {{ $location.Proxy.ReadTimeout }}s;
|
|
|
|
proxy_buffering {{ $location.Proxy.ProxyBuffering }};
|
|
proxy_buffer_size {{ $location.Proxy.BufferSize }};
|
|
proxy_buffers {{ $location.Proxy.BuffersNumber }} {{ $location.Proxy.BufferSize }};
|
|
{{ if isValidByteSize $location.Proxy.ProxyMaxTempFileSize true }}
|
|
proxy_max_temp_file_size {{ $location.Proxy.ProxyMaxTempFileSize }};
|
|
{{ end }}
|
|
proxy_request_buffering {{ $location.Proxy.RequestBuffering }};
|
|
proxy_http_version {{ $location.Proxy.ProxyHTTPVersion }};
|
|
|
|
proxy_cookie_domain {{ $location.Proxy.CookieDomain }};
|
|
proxy_cookie_path {{ $location.Proxy.CookiePath }};
|
|
|
|
# In case of errors try the next upstream server before returning an error
|
|
proxy_next_upstream {{ buildNextUpstream $location.Proxy.NextUpstream $all.Cfg.RetryNonIdempotent }};
|
|
proxy_next_upstream_timeout {{ $location.Proxy.NextUpstreamTimeout }};
|
|
proxy_next_upstream_tries {{ $location.Proxy.NextUpstreamTries }};
|
|
|
|
{{/* Add any additional configuration defined */}}
|
|
{{ $location.ConfigurationSnippet }}
|
|
|
|
{{ if not (empty $all.Cfg.LocationSnippet) }}
|
|
# Custom code snippet configured in the configuration configmap
|
|
{{ $all.Cfg.LocationSnippet }}
|
|
{{ end }}
|
|
|
|
{{/* if we are sending the request to a custom default backend, we add the required headers */}}
|
|
{{ if (hasPrefix $location.Backend "custom-default-backend-") }}
|
|
proxy_set_header X-Code 503;
|
|
proxy_set_header X-Format $http_accept;
|
|
proxy_set_header X-Namespace $namespace;
|
|
proxy_set_header X-Ingress-Name $ingress_name;
|
|
proxy_set_header X-Service-Name $service_name;
|
|
proxy_set_header X-Service-Port $service_port;
|
|
proxy_set_header X-Request-ID $req_id;
|
|
{{ end }}
|
|
|
|
{{ if $location.Satisfy }}
|
|
satisfy {{ $location.Satisfy }};
|
|
{{ end }}
|
|
|
|
{{/* if a location-specific error override is set, add the proxy_intercept here */}}
|
|
{{ if $location.CustomHTTPErrors }}
|
|
# Custom error pages per ingress
|
|
proxy_intercept_errors on;
|
|
{{ end }}
|
|
|
|
{{ range $errCode := $location.CustomHTTPErrors }}
|
|
error_page {{ $errCode }} = @custom_{{ $location.DefaultBackendUpstreamName }}_{{ $errCode }};{{ end }}
|
|
|
|
{{ if (eq $location.BackendProtocol "FCGI") }}
|
|
include /etc/nginx/fastcgi_params;
|
|
{{ end }}
|
|
{{- if $location.FastCGI.Index -}}
|
|
fastcgi_index {{ $location.FastCGI.Index | quote }};
|
|
{{- end -}}
|
|
{{ range $k, $v := $location.FastCGI.Params }}
|
|
fastcgi_param {{ $k }} {{ $v | quote }};
|
|
{{ end }}
|
|
|
|
{{ if not (empty $location.Redirect.URL) }}
|
|
return {{ $location.Redirect.Code }} {{ $location.Redirect.URL }};
|
|
{{ end }}
|
|
|
|
{{ buildProxyPass $server.Hostname $all.Backends $location }}
|
|
{{ if (or (eq $location.Proxy.ProxyRedirectFrom "default") (eq $location.Proxy.ProxyRedirectFrom "off")) }}
|
|
proxy_redirect {{ $location.Proxy.ProxyRedirectFrom }};
|
|
{{ else if not (eq $location.Proxy.ProxyRedirectTo "off") }}
|
|
proxy_redirect {{ $location.Proxy.ProxyRedirectFrom }} {{ $location.Proxy.ProxyRedirectTo }};
|
|
{{ end }}
|
|
{{ else }}
|
|
# Location denied. Reason: {{ $location.Denied | quote }}
|
|
return 503;
|
|
{{ end }}
|
|
{{ if not (empty $location.ProxySSL.CAFileName) }}
|
|
# PEM sha: {{ $location.ProxySSL.CASHA }}
|
|
proxy_ssl_trusted_certificate {{ $location.ProxySSL.CAFileName }};
|
|
proxy_ssl_ciphers {{ $location.ProxySSL.Ciphers }};
|
|
proxy_ssl_protocols {{ $location.ProxySSL.Protocols }};
|
|
proxy_ssl_verify {{ $location.ProxySSL.Verify }};
|
|
proxy_ssl_verify_depth {{ $location.ProxySSL.VerifyDepth }};
|
|
{{ end }}
|
|
|
|
{{ if not (empty $location.ProxySSL.ProxySSLName) }}
|
|
proxy_ssl_name {{ $location.ProxySSL.ProxySSLName }};
|
|
{{ end }}
|
|
{{ if not (empty $location.ProxySSL.ProxySSLServerName) }}
|
|
proxy_ssl_server_name {{ $location.ProxySSL.ProxySSLServerName }};
|
|
{{ end }}
|
|
|
|
{{ if not (empty $location.ProxySSL.PemFileName) }}
|
|
proxy_ssl_certificate {{ $location.ProxySSL.PemFileName }};
|
|
proxy_ssl_certificate_key {{ $location.ProxySSL.PemFileName }};
|
|
{{ end }}
|
|
}
|
|
{{ end }}
|
|
{{ end }}
|
|
|
|
{{ if eq $server.Hostname "_" }}
|
|
# health checks in cloud providers require the use of port {{ $all.ListenPorts.HTTP }}
|
|
location {{ $all.HealthzURI }} {
|
|
{{ if $all.Cfg.EnableOpentracing }}
|
|
opentracing off;
|
|
{{ end }}
|
|
|
|
access_log off;
|
|
return 200;
|
|
}
|
|
|
|
# this is required to avoid error if nginx is being monitored
|
|
# with an external software (like sysdig)
|
|
location /nginx_status {
|
|
{{ if $all.Cfg.EnableOpentracing }}
|
|
opentracing off;
|
|
{{ end }}
|
|
|
|
{{ range $v := $all.NginxStatusIpv4Whitelist }}
|
|
allow {{ $v }};
|
|
{{ end }}
|
|
{{ if $all.IsIPV6Enabled -}}
|
|
{{ range $v := $all.NginxStatusIpv6Whitelist }}
|
|
allow {{ $v }};
|
|
{{ end }}
|
|
{{ end -}}
|
|
deny all;
|
|
|
|
access_log off;
|
|
stub_status on;
|
|
}
|
|
|
|
{{ end }}
|
|
|
|
{{ end }}
|