lua-resty-waf controller (#2304)
This commit is contained in:
parent
b17ed7b6fd
commit
a6fe800a47
15 changed files with 455 additions and 37 deletions
|
|
@ -503,6 +503,10 @@ type Configuration struct {
|
|||
// NoAuthLocations is a comma-separated list of locations that
|
||||
// should not get authenticated
|
||||
NoAuthLocations string `json:"no-auth-locations"`
|
||||
|
||||
// DisableLuaRestyWAF disables lua-resty-waf globally regardless
|
||||
// of whether there's an ingress that has enabled the WAF using annotation
|
||||
DisableLuaRestyWAF bool `json:"disable-lua-resty-waf"`
|
||||
}
|
||||
|
||||
// NewDefault returns the default nginx configuration
|
||||
|
|
|
|||
|
|
@ -457,6 +457,7 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
|
|||
loc.Connection = anns.Connection
|
||||
loc.Logs = anns.Logs
|
||||
loc.GRPC = anns.GRPC
|
||||
loc.LuaRestyWAF = anns.LuaRestyWAF
|
||||
|
||||
if loc.Redirect.FromToWWW {
|
||||
server.RedirectFromToWWW = true
|
||||
|
|
@ -492,6 +493,7 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
|
|||
Connection: anns.Connection,
|
||||
Logs: anns.Logs,
|
||||
GRPC: anns.GRPC,
|
||||
LuaRestyWAF: anns.LuaRestyWAF,
|
||||
}
|
||||
|
||||
if loc.Redirect.FromToWWW {
|
||||
|
|
@ -928,6 +930,7 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
|
|||
defLoc.Whitelist = anns.Whitelist
|
||||
defLoc.Denied = anns.Denied
|
||||
defLoc.GRPC = anns.GRPC
|
||||
defLoc.LuaRestyWAF = anns.LuaRestyWAF
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,29 +119,30 @@ var (
|
|||
}
|
||||
return true
|
||||
},
|
||||
"buildLocation": buildLocation,
|
||||
"buildAuthLocation": buildAuthLocation,
|
||||
"buildAuthResponseHeaders": buildAuthResponseHeaders,
|
||||
"buildLoadBalancingConfig": buildLoadBalancingConfig,
|
||||
"buildProxyPass": buildProxyPass,
|
||||
"filterRateLimits": filterRateLimits,
|
||||
"buildRateLimitZones": buildRateLimitZones,
|
||||
"buildRateLimit": buildRateLimit,
|
||||
"buildResolvers": buildResolvers,
|
||||
"buildUpstreamName": buildUpstreamName,
|
||||
"isLocationInLocationList": isLocationInLocationList,
|
||||
"isLocationAllowed": isLocationAllowed,
|
||||
"buildLogFormatUpstream": buildLogFormatUpstream,
|
||||
"buildDenyVariable": buildDenyVariable,
|
||||
"getenv": os.Getenv,
|
||||
"contains": strings.Contains,
|
||||
"hasPrefix": strings.HasPrefix,
|
||||
"hasSuffix": strings.HasSuffix,
|
||||
"toUpper": strings.ToUpper,
|
||||
"toLower": strings.ToLower,
|
||||
"formatIP": formatIP,
|
||||
"buildNextUpstream": buildNextUpstream,
|
||||
"getIngressInformation": getIngressInformation,
|
||||
"buildLuaSharedDictionaries": buildLuaSharedDictionaries,
|
||||
"buildLocation": buildLocation,
|
||||
"buildAuthLocation": buildAuthLocation,
|
||||
"buildAuthResponseHeaders": buildAuthResponseHeaders,
|
||||
"buildLoadBalancingConfig": buildLoadBalancingConfig,
|
||||
"buildProxyPass": buildProxyPass,
|
||||
"filterRateLimits": filterRateLimits,
|
||||
"buildRateLimitZones": buildRateLimitZones,
|
||||
"buildRateLimit": buildRateLimit,
|
||||
"buildResolvers": buildResolvers,
|
||||
"buildUpstreamName": buildUpstreamName,
|
||||
"isLocationInLocationList": isLocationInLocationList,
|
||||
"isLocationAllowed": isLocationAllowed,
|
||||
"buildLogFormatUpstream": buildLogFormatUpstream,
|
||||
"buildDenyVariable": buildDenyVariable,
|
||||
"getenv": os.Getenv,
|
||||
"contains": strings.Contains,
|
||||
"hasPrefix": strings.HasPrefix,
|
||||
"hasSuffix": strings.HasSuffix,
|
||||
"toUpper": strings.ToUpper,
|
||||
"toLower": strings.ToLower,
|
||||
"formatIP": formatIP,
|
||||
"buildNextUpstream": buildNextUpstream,
|
||||
"getIngressInformation": getIngressInformation,
|
||||
"serverConfig": func(all config.TemplateConfig, server *ingress.Server) interface{} {
|
||||
return struct{ First, Second interface{} }{all, server}
|
||||
},
|
||||
|
|
@ -167,6 +168,47 @@ func formatIP(input string) string {
|
|||
return fmt.Sprintf("[%s]", input)
|
||||
}
|
||||
|
||||
func buildLuaSharedDictionaries(s interface{}, dynamicConfigurationEnabled bool, disableLuaRestyWAF bool) string {
|
||||
servers, ok := s.([]*ingress.Server)
|
||||
if !ok {
|
||||
glog.Errorf("expected an '[]*ingress.Server' type but %T was returned", s)
|
||||
return ""
|
||||
}
|
||||
|
||||
out := []string{}
|
||||
|
||||
if dynamicConfigurationEnabled {
|
||||
out = append(out,
|
||||
"lua_shared_dict configuration_data 5M",
|
||||
"lua_shared_dict round_robin_state 1M",
|
||||
"lua_shared_dict locks 512k",
|
||||
"lua_shared_dict balancer_ewma 1M",
|
||||
"lua_shared_dict balancer_ewma_last_touched_at 1M",
|
||||
)
|
||||
}
|
||||
|
||||
if !disableLuaRestyWAF {
|
||||
luaRestyWAFEnabled := func() bool {
|
||||
for _, server := range servers {
|
||||
for _, location := range server.Locations {
|
||||
if location.LuaRestyWAF.Enabled {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}()
|
||||
if luaRestyWAFEnabled {
|
||||
out = append(out, "lua_shared_dict waf_storage 64M")
|
||||
}
|
||||
}
|
||||
|
||||
if len(out) == 0 {
|
||||
return ""
|
||||
}
|
||||
return strings.Join(out, ";\n\r") + ";"
|
||||
}
|
||||
|
||||
// buildResolvers returns the resolvers reading the /etc/resolv.conf file
|
||||
func buildResolvers(res interface{}, disableIpv6 interface{}) string {
|
||||
// NGINX need IPV6 addresses to be surrounded by brackets
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/file"
|
||||
"k8s.io/ingress-nginx/internal/ingress"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/authreq"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/luarestywaf"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/rewrite"
|
||||
"k8s.io/ingress-nginx/internal/ingress/controller/config"
|
||||
)
|
||||
|
|
@ -296,6 +297,46 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
func TestBuildLuaSharedDictionaries(t *testing.T) {
|
||||
servers := []*ingress.Server{
|
||||
{
|
||||
Hostname: "foo.bar",
|
||||
Locations: []*ingress.Location{{Path: "/", LuaRestyWAF: luarestywaf.Config{}}},
|
||||
},
|
||||
{
|
||||
Hostname: "another.host",
|
||||
Locations: []*ingress.Location{{Path: "/", LuaRestyWAF: luarestywaf.Config{}}},
|
||||
},
|
||||
}
|
||||
|
||||
config := buildLuaSharedDictionaries(servers, false, false)
|
||||
if config != "" {
|
||||
t.Errorf("expected to not configure any lua shared dictionary, but generated %s", config)
|
||||
}
|
||||
config = buildLuaSharedDictionaries(servers, true, false)
|
||||
if !strings.Contains(config, "lua_shared_dict configuration_data") {
|
||||
t.Errorf("expected to include 'configuration_data' but got %s", config)
|
||||
}
|
||||
if strings.Contains(config, "waf_storage") {
|
||||
t.Errorf("expected to not include 'waf_storage' but got %s", config)
|
||||
}
|
||||
|
||||
servers[1].Locations[0].LuaRestyWAF = luarestywaf.Config{Enabled: true}
|
||||
config = buildLuaSharedDictionaries(servers, false, false)
|
||||
if !strings.Contains(config, "lua_shared_dict waf_storage") {
|
||||
t.Errorf("expected to configure 'waf_storage', but got %s", config)
|
||||
}
|
||||
config = buildLuaSharedDictionaries(servers, true, false)
|
||||
if !strings.Contains(config, "lua_shared_dict waf_storage") {
|
||||
t.Errorf("expected to configure 'waf_storage', but got %s", config)
|
||||
}
|
||||
|
||||
config = buildLuaSharedDictionaries(servers, false, true)
|
||||
if config != "" {
|
||||
t.Errorf("expected to not configure any lua shared dictionary, but generated %s", config)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatIP(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
Input, Output string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue