Template init lua cfg and fix configs

This commit is contained in:
Ricardo Katz 2024-08-25 18:33:19 -03:00
parent 2614b485ac
commit e327abd32d
13 changed files with 202 additions and 140 deletions

View file

@ -690,6 +690,10 @@ func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error {
return err return err
} }
err = n.createLuaConfig(&cfg)
if err != nil {
return err
}
err = createOpentelemetryCfg(&cfg) err = createOpentelemetryCfg(&cfg)
if err != nil { if err != nil {
return err return err
@ -1079,6 +1083,32 @@ func createOpentelemetryCfg(cfg *ngx_config.Configuration) error {
return os.WriteFile(cfg.OpentelemetryConfig, tmplBuf.Bytes(), file.ReadWriteByUser) return os.WriteFile(cfg.OpentelemetryConfig, tmplBuf.Bytes(), file.ReadWriteByUser)
} }
func (n *NGINXController) createLuaConfig(cfg *ngx_config.Configuration) error {
luaconfigs := &ngx_template.LuaConfig{
EnableMetrics: n.cfg.EnableMetrics,
ListenPorts: ngx_template.LuaListenPorts{
HTTPSPort: strconv.Itoa(n.cfg.ListenPorts.HTTPS),
StatusPort: strconv.Itoa(nginx.StatusPort),
SSLProxyPort: strconv.Itoa(n.cfg.ListenPorts.SSLProxy),
},
UseProxyProtocol: cfg.UseProxyProtocol,
UseForwardedHeaders: cfg.UseForwardedHeaders,
IsSSLPassthroughEnabled: n.cfg.EnableSSLPassthrough,
HTTPRedirectCode: cfg.HTTPRedirectCode,
EnableOCSP: cfg.EnableOCSP,
MonitorBatchMaxSize: n.cfg.MonitorMaxBatchSize,
HSTS: cfg.HSTS,
HSTSMaxAge: cfg.HSTSMaxAge,
HSTSIncludeSubdomains: cfg.HSTSIncludeSubdomains,
HSTSPreload: cfg.HSTSPreload,
}
jsonCfg, err := json.Marshal(luaconfigs)
if err != nil {
return err
}
return os.WriteFile(luaCfgPath, jsonCfg, file.ReadWriteByUser)
}
func cleanTempNginxCfg() error { func cleanTempNginxCfg() error {
var files []string var files []string

View file

@ -194,13 +194,39 @@ func cleanConf(in, out *bytes.Buffer) error {
} }
} }
type LuaConfigs struct { /* LuaConfig defines the structure that will be written as a config for lua scripts
EnableMetrics bool `json:"enable_metrics"` The json format should follow what's expected by lua:
HTTPSPort string `json:"httpsPort"` use_forwarded_headers = %t,
StatusPort string `json:"status_port"` use_proxy_protocol = %t,
UseForwardedPorts bool `json:"use_forwarded_ports"` is_ssl_passthrough_enabled = %t,
EnableOCSP bool `json:"enable_ocsp"` http_redirect_code = %v,
MonitorBatchMaxSize int `json:"monitor_batch_max_size"` listen_ports = { ssl_proxy = "%v", https = "%v" },
hsts = %t,
hsts_max_age = %v,
hsts_include_subdomains = %t,
hsts_preload = %t,
*/
type LuaConfig struct {
EnableMetrics bool `json:"enable_metrics"`
ListenPorts LuaListenPorts `json:"listen_ports"`
UseForwardedHeaders bool `json:"use_forwarded_headers"`
UseProxyProtocol bool `json:"use_proxy_protocol"`
IsSSLPassthroughEnabled bool `json:"is_ssl_passthrough_enabled"`
HTTPRedirectCode int `json:"http_redirect_code"`
EnableOCSP bool `json:"enable_ocsp"`
MonitorBatchMaxSize int `json:"monitor_batch_max_size"`
HSTS bool `json:"hsts"`
HSTSMaxAge string `json:"hsts_max_age"`
HSTSIncludeSubdomains bool `json:"hsts_include_subdomains"`
HSTSPreload bool `json:"hsts_preload"`
}
type LuaListenPorts struct {
HTTPSPort string `json:"https"`
StatusPort string `json:"status_port"`
SSLProxyPort string `json:"ssl_proxy"`
} }
// Write populates a buffer using a template with NGINX configuration // Write populates a buffer using a template with NGINX configuration
@ -441,13 +467,21 @@ func locationConfigForLua(l, a interface{}) string {
return "{}" return "{}"
} }
return fmt.Sprintf(`{ /* Lua expects the following vars
force_ssl_redirect = %t, force_ssl_redirect = string_to_bool(ngx.var.force_ssl_redirect),
ssl_redirect = %t, ssl_redirect = string_to_bool(ngx.var.ssl_redirect),
force_no_ssl_redirect = %t, force_no_ssl_redirect = string_to_bool(ngx.var.force_no_ssl_redirect),
preserve_trailing_slash = %t, preserve_trailing_slash = string_to_bool(ngx.var.preserve_trailing_slash),
use_port_in_redirects = %t, use_port_in_redirects = string_to_bool(ngx.var.use_port_in_redirects),
}`, */
return fmt.Sprintf(`
set $force_ssl_redirect "%t";
set $ssl_redirect "%t";
set $force_no_ssl_redirect "%t";
set $preserve_trailing_slash "%t";
set $use_port_in_redirects "%t";
`,
location.Rewrite.ForceSSLRedirect, location.Rewrite.ForceSSLRedirect,
location.Rewrite.SSLRedirect, location.Rewrite.SSLRedirect,
isLocationInLocationList(l, all.Cfg.NoTLSRedirectLocations), isLocationInLocationList(l, all.Cfg.NoTLSRedirectLocations),

View file

@ -98,8 +98,9 @@ func rlimitMaxNumFiles() int {
} }
const ( const (
defBinary = "/usr/bin/nginx" defBinary = "/usr/bin/nginx"
cfgPath = "/etc/nginx/nginx.conf" cfgPath = "/etc/nginx/nginx.conf"
luaCfgPath = "/etc/nginx/lua/cfg.json"
) )
// NginxExecTester defines the interface to execute // NginxExecTester defines the interface to execute

View file

@ -1,4 +1,5 @@
local ngx_re_split = require("ngx.re").split local ngx_re_split = require("ngx.re").split
local string_to_bool = require("util").string_to_bool
local certificate_configured_for_current_request = local certificate_configured_for_current_request =
require("certificate").configured_for_current_request require("certificate").configured_for_current_request
@ -108,7 +109,16 @@ end
-- rewrite gets called in every location context. -- rewrite gets called in every location context.
-- This is where we do variable assignments to be used in subsequent -- This is where we do variable assignments to be used in subsequent
-- phases or redirection -- phases or redirection
function _M.rewrite(location_config) function _M.rewrite()
local location_config = {
force_ssl_redirect = string_to_bool(ngx.var.force_ssl_redirect),
ssl_redirect = string_to_bool(ngx.var.ssl_redirect),
force_no_ssl_redirect = string_to_bool(ngx.var.force_no_ssl_redirect),
preserve_trailing_slash = string_to_bool(ngx.var.preserve_trailing_slash),
use_port_in_redirects = string_to_bool(ngx.var.use_port_in_redirects),
}
ngx.var.pass_access_scheme = ngx.var.scheme ngx.var.pass_access_scheme = ngx.var.scheme
ngx.var.best_http_host = ngx.var.http_host or ngx.var.host ngx.var.best_http_host = ngx.var.http_host or ngx.var.host

View file

@ -0,0 +1,5 @@
local lua_ingress = require("lua_ingress")
local balancer = require("balancer")
lua_ingress.rewrite()
balancer.rewrite()

View file

@ -1,46 +1,54 @@
local function initialize_ingress(statusport, enablemetrics, ocsp, ingress) local cjson = require("cjson.safe")
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(ingress)
end
ok, res = pcall(require, "configuration") collectgarbage("collect")
if not ok then local f = io.open("/etc/nginx/lua/cfg.json", "r")
error("require failed: " .. tostring(res)) local content = f:read("*a")
else f:close()
configuration = res local configfile = cjson.decode(content)
configuration.prohibited_localhost_port = statusport
end
ok, res = pcall(require, "balancer") local luaconfig = ngx.shared.luaconfig
luaconfig:set("enablemetrics", configfile.enable_metrics)
luaconfig:set("listen_https_ports", configfile.listen_ports.https)
luaconfig:set("use_forwarded_headers", configfile.use_forwarded_headers)
-- 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(configfile)
end
ok, res = pcall(require, "configuration")
if not ok then
error("require failed: " .. tostring(res))
else
configuration = res
if not configfile.listen_ports.status_port then
error("required status port not found")
end
configuration.prohibited_localhost_port = configfile.listen_ports.status_port
end
ok, res = pcall(require, "balancer")
if not ok then
error("require failed: " .. tostring(res))
else
balancer = res
end
if configfile.enable_metrics then
ok, res = pcall(require, "monitor")
if not ok then if not ok then
error("require failed: " .. tostring(res)) error("require failed: " .. tostring(res))
else else
balancer = res monitor = res
end
if enablemetrics then
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 = ocsp
end end
end end
ok, res = pcall(require, "certificate")
return { initialize_ingress = initialize_ingress } if not ok then
error("require failed: " .. tostring(res))
else
certificate = res
if configfile.enable_ocsp then
certificate.is_ocsp_stapling_enabled = configfile.enable_ocsp
end
end

View file

@ -1,31 +1,30 @@
local function initialize_stream(statusport) local cjson = require("cjson.safe")
collectgarbage("collect") collectgarbage("collect")
local f = io.open("/etc/nginx/lua/cfg.json", "r")
-- init modules local content = f:read("*a")
local ok, res f:close()
local configfile = cjson.decode(content)
ok, res = pcall(require, "configuration") -- init modules
if not ok then local ok, res
error("require failed: " .. tostring(res)) ok, res = pcall(require, "configuration")
else if not ok then
configuration = res error("require failed: " .. tostring(res))
end else
configuration = res
ok, res = pcall(require, "tcp_udp_configuration") end
if not ok then ok, res = pcall(require, "tcp_udp_configuration")
error("require failed: " .. tostring(res)) if not ok then
else error("require failed: " .. tostring(res))
tcp_udp_configuration = res else
tcp_udp_configuration.prohibited_localhost_port = statusport tcp_udp_configuration = res
if not configfile.listen_ports.status_port then
end error("required status port not found")
end
ok, res = pcall(require, "tcp_udp_balancer") tcp_udp_configuration.prohibited_localhost_port = configfile.listen_ports.status_port
if not ok then end
error("require failed: " .. tostring(res)) ok, res = pcall(require, "tcp_udp_balancer")
else if not ok then
tcp_udp_balancer = res error("require failed: " .. tostring(res))
end else
tcp_udp_balancer = res
end end
return { initialize_stream = initialize_stream }

View file

@ -1,12 +1,15 @@
local function initialize_worker(enablemetrics, monitorbatchsize) local cjson = require("cjson.safe")
local lua_ingress = require("lua_ingress")
local balancer = require("balancer")
local monitor = require("monitor")
lua_ingress.init_worker()
balancer.init_worker()
if enablemetrics then
monitor.init_worker(monitorbatchsize)
end
end
return { initialize_worker = initialize_worker } local f = io.open("/etc/nginx/lua/cfg.json", "r")
local content = f:read("*a")
f:close()
local configfile = cjson.decode(content)
local lua_ingress = require("lua_ingress")
local balancer = require("balancer")
local monitor = require("monitor")
lua_ingress.init_worker()
balancer.init_worker()
if configfile.enable_metrics and configfile.monitor_batch_max_size then
monitor.init_worker(configfile.monitor_batch_max_size)
end

View file

@ -146,6 +146,11 @@ function _M.is_blank(str)
return str == nil or string_len(str) == 0 return str == nil or string_len(str) == 0
end end
function _M.string_to_bool(str)
if str == "true" then return true end
return false
end
-- this implementation is taken from: -- this implementation is taken from:
-- https://github.com/luafun/luafun/blob/master/fun.lua#L33 -- https://github.com/luafun/luafun/blob/master/fun.lua#L33
-- SHA: 04c99f9c393e54a604adde4b25b794f48104e0d0 -- SHA: 04c99f9c393e54a604adde4b25b794f48104e0d0

View file

@ -70,21 +70,9 @@ http {
lua_shared_dict luaconfig 5m; lua_shared_dict luaconfig 5m;
{{/* We need to keep this lua block inline, because init_worker_by_lua_file does not support using arguments */}} init_by_lua_file /etc/nginx/lua/ngx_conf_init.lua;
init_by_lua_block {
local luaconfig = ngx.shared.luaconfig
local ingresscfg = {{ configForLua $all }}
luaconfig:set("enablemetrics", {{ $all.EnableMetrics }})
luaconfig:set("listen_https_ports", '{{ $all.ListenPorts.HTTPS }}')
luaconfig:set("use_forwarded_headers", {{ $cfg.UseForwardedHeaders }})
local ngx_conf_init = require('ngx_conf_init')
ngx_conf_init.initialize_ingress('{{ .StatusPort }}', {{ $all.EnableMetrics }}, {{ $cfg.EnableOCSP }}, ingresscfg)
}
init_worker_by_lua_block { init_worker_by_lua_file /etc/nginx/lua/ngx_conf_init_worker.lua;
local ngx_conf_init_worker = require('ngx_conf_init_worker')
ngx_conf_init_worker.initialize_worker({{ $all.EnableMetrics }}, {{ $all.MonitorMaxBatchSize }})
}
{{/* Enable the real_ip module only if we use either X-Forwarded headers or Proxy Protocol. */}} {{/* 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 */}} {{/* we use the value of the real IP for the geo_ip module */}}
@ -703,10 +691,7 @@ stream {
{{ buildResolvers $cfg.Resolver $cfg.DisableIpv6DNS }} {{ buildResolvers $cfg.Resolver $cfg.DisableIpv6DNS }}
init_by_lua_block { init_by_lua_file /etc/nginx/lua/ngx_conf_init_stream.lua;
local ngx_conf_init_stream = require('ngx_conf_init_stream')
ngx_conf_init_stream.initialize_stream('{{ .StatusPort }}')
}
init_worker_by_lua_file /etc/nginx/lua/nginx/ngx_conf_init_tcp_udp.lua; init_worker_by_lua_file /etc/nginx/lua/nginx/ngx_conf_init_tcp_udp.lua;
@ -1134,10 +1119,9 @@ stream {
mirror_request_body {{ $location.Mirror.RequestBody }}; mirror_request_body {{ $location.Mirror.RequestBody }};
{{ end }} {{ end }}
rewrite_by_lua_block { {{ locationConfigForLua $location $all }}
lua_ingress.rewrite({{ locationConfigForLua $location $all }})
balancer.rewrite() rewrite_by_lua_file /etc/nginx/lua/nginx/ngx_rewrite.lua;
}
header_filter_by_lua_file /etc/nginx/lua/nginx/ngx_conf_srv_hdr_filter.lua; header_filter_by_lua_file /etc/nginx/lua/nginx/ngx_conf_srv_hdr_filter.lua;

View file

@ -48,12 +48,7 @@ var _ = framework.IngressNginxDescribe("[Lua] dynamic configuration", func() {
ginkgo.It("configures balancer Lua middleware correctly", func() { ginkgo.It("configures balancer Lua middleware correctly", func() {
f.WaitForNginxConfiguration(func(cfg string) bool { f.WaitForNginxConfiguration(func(cfg string) bool {
return strings.Contains(cfg, "balancer.init_worker()") && strings.Contains(cfg, "balancer_by_lua_file /etc/nginx/lua/nginx/ngx_conf_balancer.lua") return strings.Contains(cfg, "balancer_by_lua_file /etc/nginx/lua/nginx/ngx_conf_balancer.lua")
})
host := "foo.com"
f.WaitForNginxServer(host, func(server string) bool {
return strings.Contains(server, "balancer.rewrite()") && strings.Contains(server, "balancer.log()")
}) })
}) })

View file

@ -33,7 +33,7 @@ var _ = framework.DescribeSetting("Add no tls redirect locations", func() {
f.EnsureIngress(ing) f.EnsureIngress(ing)
f.WaitForNginxConfiguration(func(server string) bool { f.WaitForNginxConfiguration(func(server string) bool {
return !strings.Contains(server, "force_no_ssl_redirect = true,") return strings.Contains(server, "set $force_no_ssl_redirect \"false\"")
}) })
wlKey := "no-tls-redirect-locations" wlKey := "no-tls-redirect-locations"
@ -42,7 +42,7 @@ var _ = framework.DescribeSetting("Add no tls redirect locations", func() {
f.UpdateNginxConfigMapData(wlKey, wlValue) f.UpdateNginxConfigMapData(wlKey, wlValue)
f.WaitForNginxConfiguration(func(server string) bool { f.WaitForNginxConfiguration(func(server string) bool {
return strings.Contains(server, "force_no_ssl_redirect = true,") return strings.Contains(server, "set $force_no_ssl_redirect \"true\"")
}) })
}) })
}) })

View file

@ -109,10 +109,6 @@ var _ = framework.DescribeSetting("[SSL] TLS protocols, ciphers and headers)", f
ginkgo.It("setting max-age parameter", func() { ginkgo.It("setting max-age parameter", func() {
f.UpdateNginxConfigMapData(hstsMaxAge, "86400") f.UpdateNginxConfigMapData(hstsMaxAge, "86400")
f.WaitForNginxConfiguration(func(server string) bool {
return strings.Contains(server, `hsts_max_age = 86400,`)
})
f.HTTPTestClientWithTLSConfig(tlsConfig). f.HTTPTestClientWithTLSConfig(tlsConfig).
GET("/"). GET("/").
WithURL(f.GetURL(framework.HTTPS)). WithURL(f.GetURL(framework.HTTPS)).
@ -128,10 +124,6 @@ var _ = framework.DescribeSetting("[SSL] TLS protocols, ciphers and headers)", f
hstsIncludeSubdomains: "false", hstsIncludeSubdomains: "false",
}) })
f.WaitForNginxConfiguration(func(server string) bool {
return strings.Contains(server, `hsts_include_subdomains = false,`)
})
f.HTTPTestClientWithTLSConfig(tlsConfig). f.HTTPTestClientWithTLSConfig(tlsConfig).
GET("/"). GET("/").
WithURL(f.GetURL(framework.HTTPS)). WithURL(f.GetURL(framework.HTTPS)).
@ -148,10 +140,6 @@ var _ = framework.DescribeSetting("[SSL] TLS protocols, ciphers and headers)", f
hstsIncludeSubdomains: "false", hstsIncludeSubdomains: "false",
}) })
f.WaitForNginxConfiguration(func(server string) bool {
return strings.Contains(server, `hsts_preload = true,`)
})
f.HTTPTestClientWithTLSConfig(tlsConfig). f.HTTPTestClientWithTLSConfig(tlsConfig).
GET("/"). GET("/").
WithURL(f.GetURL(framework.HTTPS)). WithURL(f.GetURL(framework.HTTPS)).