Merge pull request #4779 from aledbf/update-image

Remove lua-resty-waf feature
This commit is contained in:
Kubernetes Prow Robot 2019-11-27 11:45:05 -08:00 committed by GitHub
commit a85d5ed93a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 12 additions and 565 deletions

View file

@ -45,7 +45,6 @@ import (
"k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist" "k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist"
"k8s.io/ingress-nginx/internal/ingress/annotations/loadbalancing" "k8s.io/ingress-nginx/internal/ingress/annotations/loadbalancing"
"k8s.io/ingress-nginx/internal/ingress/annotations/log" "k8s.io/ingress-nginx/internal/ingress/annotations/log"
"k8s.io/ingress-nginx/internal/ingress/annotations/luarestywaf"
"k8s.io/ingress-nginx/internal/ingress/annotations/mirror" "k8s.io/ingress-nginx/internal/ingress/annotations/mirror"
"k8s.io/ingress-nginx/internal/ingress/annotations/opentracing" "k8s.io/ingress-nginx/internal/ingress/annotations/opentracing"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser" "k8s.io/ingress-nginx/internal/ingress/annotations/parser"
@ -111,7 +110,6 @@ type Ingress struct {
XForwardedPrefix string XForwardedPrefix string
SSLCiphers string SSLCiphers string
Logs log.Config Logs log.Config
LuaRestyWAF luarestywaf.Config
InfluxDB influxdb.Config InfluxDB influxdb.Config
ModSecurity modsecurity.Config ModSecurity modsecurity.Config
Mirror mirror.Config Mirror mirror.Config
@ -160,7 +158,6 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
"XForwardedPrefix": xforwardedprefix.NewParser(cfg), "XForwardedPrefix": xforwardedprefix.NewParser(cfg),
"SSLCiphers": sslcipher.NewParser(cfg), "SSLCiphers": sslcipher.NewParser(cfg),
"Logs": log.NewParser(cfg), "Logs": log.NewParser(cfg),
"LuaRestyWAF": luarestywaf.NewParser(cfg),
"InfluxDB": influxdb.NewParser(cfg), "InfluxDB": influxdb.NewParser(cfg),
"BackendProtocol": backendprotocol.NewParser(cfg), "BackendProtocol": backendprotocol.NewParser(cfg),
"ModSecurity": modsecurity.NewParser(cfg), "ModSecurity": modsecurity.NewParser(cfg),

View file

@ -1,126 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package luarestywaf
import (
"strings"
networking "k8s.io/api/networking/v1beta1"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/resolver"
"k8s.io/ingress-nginx/internal/sets"
)
var luaRestyWAFModes = map[string]bool{"ACTIVE": true, "INACTIVE": true, "SIMULATE": true}
// Config returns lua-resty-waf configuration for an Ingress rule
type Config struct {
Mode string `json:"mode"`
Debug bool `json:"debug"`
IgnoredRuleSets []string `json:"ignored-rulesets"`
ExtraRulesetString string `json:"extra-ruleset-string"`
ScoreThreshold int `json:"score-threshold"`
AllowUnknownContentTypes bool `json:"allow-unknown-content-types"`
ProcessMultipartBody bool `json:"process-multipart-body"`
}
// Equal tests for equality between two Config types
func (e1 *Config) Equal(e2 *Config) bool {
if e1 == e2 {
return true
}
if e1 == nil || e2 == nil {
return false
}
if e1.Mode != e2.Mode {
return false
}
if e1.Debug != e2.Debug {
return false
}
match := sets.StringElementsMatch(e1.IgnoredRuleSets, e2.IgnoredRuleSets)
if !match {
return false
}
if e1.ExtraRulesetString != e2.ExtraRulesetString {
return false
}
if e1.ScoreThreshold != e2.ScoreThreshold {
return false
}
if e1.AllowUnknownContentTypes != e2.AllowUnknownContentTypes {
return false
}
if e1.ProcessMultipartBody != e2.ProcessMultipartBody {
return false
}
return true
}
type luarestywaf struct {
r resolver.Resolver
}
// NewParser creates a new CORS annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return luarestywaf{r}
}
// Parse parses the annotations contained in the ingress rule
// used to indicate if the location/s contains a fragment of
// configuration to be included inside the paths of the rules
func (a luarestywaf) Parse(ing *networking.Ingress) (interface{}, error) {
var err error
config := &Config{}
mode, err := parser.GetStringAnnotation("lua-resty-waf", ing)
if err != nil {
return &Config{}, err
}
config.Mode = strings.ToUpper(mode)
if _, ok := luaRestyWAFModes[config.Mode]; !ok {
return &Config{}, errors.NewInvalidAnnotationContent("lua-resty-waf", mode)
}
config.Debug, _ = parser.GetBoolAnnotation("lua-resty-waf-debug", ing)
ignoredRuleSetsStr, _ := parser.GetStringAnnotation("lua-resty-waf-ignore-rulesets", ing)
config.IgnoredRuleSets = strings.FieldsFunc(ignoredRuleSetsStr, func(c rune) bool {
strC := string(c)
return strC == "," || strC == " "
})
// TODO(elvinefendi) maybe validate the ruleset string here
config.ExtraRulesetString, _ = parser.GetStringAnnotation("lua-resty-waf-extra-rules", ing)
config.ScoreThreshold, _ = parser.GetIntAnnotation("lua-resty-waf-score-threshold", ing)
config.AllowUnknownContentTypes, _ = parser.GetBoolAnnotation("lua-resty-waf-allow-unknown-content-types", ing)
config.ProcessMultipartBody, err = parser.GetBoolAnnotation("lua-resty-waf-process-multipart-body", ing)
if err != nil {
config.ProcessMultipartBody = true
}
return config, nil
}

View file

@ -1,86 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package luarestywaf
import (
"testing"
api "k8s.io/api/core/v1"
networking "k8s.io/api/networking/v1beta1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
func TestParse(t *testing.T) {
luaRestyWAFAnnotation := parser.GetAnnotationWithPrefix("lua-resty-waf")
luaRestyWAFDebugAnnotation := parser.GetAnnotationWithPrefix("lua-resty-waf-debug")
luaRestyWAFIgnoredRuleSetsAnnotation := parser.GetAnnotationWithPrefix("lua-resty-waf-ignore-rulesets")
luaRestyWAFScoreThresholdAnnotation := parser.GetAnnotationWithPrefix("lua-resty-waf-score-threshold")
luaRestyWAFAllowUnknownContentTypesAnnotation := parser.GetAnnotationWithPrefix("lua-resty-waf-allow-unknown-content-types")
luaRestyWAFProcessMultipartBody := parser.GetAnnotationWithPrefix("lua-resty-waf-process-multipart-body")
ap := NewParser(&resolver.Mock{})
if ap == nil {
t.Fatalf("expected a parser.IngressAnnotation but returned nil")
}
testCases := []struct {
annotations map[string]string
expected *Config
}{
{nil, &Config{}},
{map[string]string{}, &Config{}},
{map[string]string{luaRestyWAFAnnotation: "active"}, &Config{Mode: "ACTIVE", Debug: false, IgnoredRuleSets: []string{}, ProcessMultipartBody: true}},
{map[string]string{luaRestyWAFDebugAnnotation: "true"}, &Config{Debug: false}},
{map[string]string{luaRestyWAFAnnotation: "active", luaRestyWAFDebugAnnotation: "true"}, &Config{Mode: "ACTIVE", Debug: true, IgnoredRuleSets: []string{}, ProcessMultipartBody: true}},
{map[string]string{luaRestyWAFAnnotation: "active", luaRestyWAFDebugAnnotation: "false"}, &Config{Mode: "ACTIVE", Debug: false, IgnoredRuleSets: []string{}, ProcessMultipartBody: true}},
{map[string]string{luaRestyWAFAnnotation: "inactive", luaRestyWAFDebugAnnotation: "true"}, &Config{Mode: "INACTIVE", Debug: true, IgnoredRuleSets: []string{}, ProcessMultipartBody: true}},
{map[string]string{
luaRestyWAFAnnotation: "active",
luaRestyWAFDebugAnnotation: "true",
luaRestyWAFIgnoredRuleSetsAnnotation: "ruleset1, ruleset2 ruleset3, another.ruleset",
luaRestyWAFScoreThresholdAnnotation: "10",
luaRestyWAFAllowUnknownContentTypesAnnotation: "true"},
&Config{Mode: "ACTIVE", Debug: true, IgnoredRuleSets: []string{"ruleset1", "ruleset2", "ruleset3", "another.ruleset"}, ScoreThreshold: 10, AllowUnknownContentTypes: true, ProcessMultipartBody: true}},
{map[string]string{luaRestyWAFAnnotation: "siMulate", luaRestyWAFDebugAnnotation: "true"}, &Config{Mode: "SIMULATE", Debug: true, IgnoredRuleSets: []string{}, ProcessMultipartBody: true}},
{map[string]string{luaRestyWAFAnnotation: "siMulateX", luaRestyWAFDebugAnnotation: "true"}, &Config{Debug: false}},
{map[string]string{luaRestyWAFAnnotation: "active", luaRestyWAFProcessMultipartBody: "false"}, &Config{Mode: "ACTIVE", ProcessMultipartBody: false, IgnoredRuleSets: []string{}}},
}
ing := &networking.Ingress{
ObjectMeta: meta_v1.ObjectMeta{
Name: "foo",
Namespace: api.NamespaceDefault,
},
Spec: networking.IngressSpec{},
}
for _, testCase := range testCases {
ing.SetAnnotations(testCase.annotations)
result, _ := ap.Parse(ing)
config := result.(*Config)
if !config.Equal(testCase.expected) {
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
}
}
}

View file

@ -610,10 +610,6 @@ type Configuration struct {
// +optional // +optional
GlobalExternalAuth GlobalExternalAuth `json:"global-external-auth"` GlobalExternalAuth GlobalExternalAuth `json:"global-external-auth"`
// 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"`
// EnableInfluxDB enables the nginx InfluxDB extension // EnableInfluxDB enables the nginx InfluxDB extension
// http://github.com/influxdata/nginx-influxdb-module/ // http://github.com/influxdata/nginx-influxdb-module/
// By default this is disabled // By default this is disabled

View file

@ -1178,7 +1178,6 @@ func locationApplyAnnotations(loc *ingress.Location, anns *annotations.Ingress)
loc.UsePortInRedirects = anns.UsePortInRedirects loc.UsePortInRedirects = anns.UsePortInRedirects
loc.Connection = anns.Connection loc.Connection = anns.Connection
loc.Logs = anns.Logs loc.Logs = anns.Logs
loc.LuaRestyWAF = anns.LuaRestyWAF
loc.InfluxDB = anns.InfluxDB loc.InfluxDB = anns.InfluxDB
loc.DefaultBackend = anns.DefaultBackend loc.DefaultBackend = anns.DefaultBackend
loc.BackendProtocol = anns.BackendProtocol loc.BackendProtocol = anns.BackendProtocol

View file

@ -93,11 +93,6 @@ func (t *Template) Write(conf config.TemplateConfig) ([]byte, error) {
outCmdBuf := t.bp.Get() outCmdBuf := t.bp.Get()
defer t.bp.Put(outCmdBuf) defer t.bp.Put(outCmdBuf)
// TODO: remove once we found a fix for coredump running luarocks install lrexlib
if runtime.GOARCH == "arm" {
conf.Cfg.DisableLuaRestyWAF = true
}
if klog.V(3) { if klog.V(3) {
b, err := json.Marshal(conf) b, err := json.Marshal(conf)
if err != nil { if err != nil {
@ -134,7 +129,6 @@ var (
return true return true
}, },
"escapeLiteralDollar": escapeLiteralDollar, "escapeLiteralDollar": escapeLiteralDollar,
"shouldConfigureLuaRestyWAF": shouldConfigureLuaRestyWAF,
"buildLuaSharedDictionaries": buildLuaSharedDictionaries, "buildLuaSharedDictionaries": buildLuaSharedDictionaries,
"luaConfigurationRequestBodySize": luaConfigurationRequestBodySize, "luaConfigurationRequestBodySize": luaConfigurationRequestBodySize,
"buildLocation": buildLocation, "buildLocation": buildLocation,
@ -225,15 +219,7 @@ func quote(input interface{}) string {
return fmt.Sprintf("%q", inputStr) return fmt.Sprintf("%q", inputStr)
} }
func shouldConfigureLuaRestyWAF(disableLuaRestyWAF bool, mode string) bool { func buildLuaSharedDictionaries(c interface{}, s interface{}) string {
if !disableLuaRestyWAF && len(mode) > 0 {
return true
}
return false
}
func buildLuaSharedDictionaries(c interface{}, s interface{}, disableLuaRestyWAF bool) string {
var out []string var out []string
cfg, ok := c.(config.Configuration) cfg, ok := c.(config.Configuration)
@ -241,7 +227,8 @@ func buildLuaSharedDictionaries(c interface{}, s interface{}, disableLuaRestyWAF
klog.Errorf("expected a 'config.Configuration' type but %T was returned", c) klog.Errorf("expected a 'config.Configuration' type but %T was returned", c)
return "" return ""
} }
servers, ok := s.([]*ingress.Server)
_, ok = s.([]*ingress.Server)
if !ok { if !ok {
klog.Errorf("expected an '[]*ingress.Server' type but %T was returned", s) klog.Errorf("expected an '[]*ingress.Server' type but %T was returned", s)
return "" return ""
@ -251,23 +238,6 @@ func buildLuaSharedDictionaries(c interface{}, s interface{}, disableLuaRestyWAF
out = append(out, fmt.Sprintf("lua_shared_dict %s %dM", name, size)) out = append(out, fmt.Sprintf("lua_shared_dict %s %dM", name, size))
} }
// TODO: there must be a better place for this
if _, ok := cfg.LuaSharedDicts["waf_storage"]; !ok && !disableLuaRestyWAF {
luaRestyWAFEnabled := func() bool {
for _, server := range servers {
for _, location := range server.Locations {
if len(location.LuaRestyWAF.Mode) > 0 {
return true
}
}
}
return false
}()
if luaRestyWAFEnabled {
out = append(out, "lua_shared_dict waf_storage 64M")
}
}
sort.Strings(out) sort.Strings(out)
return strings.Join(out, ";\n") + ";\n" return strings.Join(out, ";\n") + ";\n"

View file

@ -38,7 +38,6 @@ import (
"k8s.io/ingress-nginx/internal/ingress" "k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations/authreq" "k8s.io/ingress-nginx/internal/ingress/annotations/authreq"
"k8s.io/ingress-nginx/internal/ingress/annotations/influxdb" "k8s.io/ingress-nginx/internal/ingress/annotations/influxdb"
"k8s.io/ingress-nginx/internal/ingress/annotations/luarestywaf"
"k8s.io/ingress-nginx/internal/ingress/annotations/modsecurity" "k8s.io/ingress-nginx/internal/ingress/annotations/modsecurity"
"k8s.io/ingress-nginx/internal/ingress/annotations/ratelimit" "k8s.io/ingress-nginx/internal/ingress/annotations/ratelimit"
"k8s.io/ingress-nginx/internal/ingress/annotations/rewrite" "k8s.io/ingress-nginx/internal/ingress/annotations/rewrite"
@ -189,7 +188,7 @@ func TestBuildLuaSharedDictionaries(t *testing.T) {
"configuration_data": 10, "certificate_data": 20, "configuration_data": 10, "certificate_data": 20,
}, },
} }
actual := buildLuaSharedDictionaries(cfg, invalidType, true) actual := buildLuaSharedDictionaries(cfg, invalidType)
if !reflect.DeepEqual(expected, actual) { if !reflect.DeepEqual(expected, actual) {
t.Errorf("Expected '%v' but returned '%v'", expected, actual) t.Errorf("Expected '%v' but returned '%v'", expected, actual)
@ -198,32 +197,23 @@ func TestBuildLuaSharedDictionaries(t *testing.T) {
servers := []*ingress.Server{ servers := []*ingress.Server{
{ {
Hostname: "foo.bar", Hostname: "foo.bar",
Locations: []*ingress.Location{{Path: "/", LuaRestyWAF: luarestywaf.Config{}}}, Locations: []*ingress.Location{{Path: "/"}},
}, },
{ {
Hostname: "another.host", Hostname: "another.host",
Locations: []*ingress.Location{{Path: "/", LuaRestyWAF: luarestywaf.Config{}}}, Locations: []*ingress.Location{{Path: "/"}},
}, },
} }
// returns value from config // returns value from config
configuration := buildLuaSharedDictionaries(cfg, servers, false) configuration := buildLuaSharedDictionaries(cfg, servers)
if !strings.Contains(configuration, "lua_shared_dict configuration_data 10M;\n") { if !strings.Contains(configuration, "lua_shared_dict configuration_data 10M;\n") {
t.Errorf("expected to include 'configuration_data' but got %s", configuration) t.Errorf("expected to include 'configuration_data' but got %s", configuration)
} }
if !strings.Contains(configuration, "lua_shared_dict certificate_data 20M;\n") { if !strings.Contains(configuration, "lua_shared_dict certificate_data 20M;\n") {
t.Errorf("expected to include 'certificate_data' but got %s", configuration) t.Errorf("expected to include 'certificate_data' but got %s", configuration)
} }
if strings.Contains(configuration, "waf_storage") {
t.Errorf("expected to not include 'waf_storage' but got %s", configuration)
}
servers[1].Locations[0].LuaRestyWAF = luarestywaf.Config{Mode: "ACTIVE"}
configuration = buildLuaSharedDictionaries(cfg, servers, false)
if !strings.Contains(configuration, "lua_shared_dict waf_storage") {
t.Errorf("expected to configure 'waf_storage', but got %s", configuration)
}
// test invalid config // test invalid config
configuration = buildLuaSharedDictionaries(invalidType, servers, false) configuration = buildLuaSharedDictionaries(invalidType, servers)
if configuration != "" { if configuration != "" {
t.Errorf("expected an empty string, but got %s", configuration) t.Errorf("expected an empty string, but got %s", configuration)
} }

View file

@ -31,7 +31,6 @@ import (
"k8s.io/ingress-nginx/internal/ingress/annotations/influxdb" "k8s.io/ingress-nginx/internal/ingress/annotations/influxdb"
"k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist" "k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist"
"k8s.io/ingress-nginx/internal/ingress/annotations/log" "k8s.io/ingress-nginx/internal/ingress/annotations/log"
"k8s.io/ingress-nginx/internal/ingress/annotations/luarestywaf"
"k8s.io/ingress-nginx/internal/ingress/annotations/mirror" "k8s.io/ingress-nginx/internal/ingress/annotations/mirror"
"k8s.io/ingress-nginx/internal/ingress/annotations/modsecurity" "k8s.io/ingress-nginx/internal/ingress/annotations/modsecurity"
"k8s.io/ingress-nginx/internal/ingress/annotations/opentracing" "k8s.io/ingress-nginx/internal/ingress/annotations/opentracing"
@ -308,8 +307,6 @@ type Location struct {
// Logs allows to enable or disable the nginx logs // Logs allows to enable or disable the nginx logs
// By default access logs are enabled and rewrite logs are disabled // By default access logs are enabled and rewrite logs are disabled
Logs log.Config `json:"logs,omitempty"` Logs log.Config `json:"logs,omitempty"`
// LuaRestyWAF contains parameters to configure lua-resty-waf
LuaRestyWAF luarestywaf.Config `json:"luaRestyWAF"`
// InfluxDB allows to monitor the incoming request by sending them to an influxdb database // InfluxDB allows to monitor the incoming request by sending them to an influxdb database
// +optional // +optional
InfluxDB influxdb.Config `json:"influxDB,omitempty"` InfluxDB influxdb.Config `json:"influxDB,omitempty"`

View file

@ -404,9 +404,6 @@ func (l1 *Location) Equal(l2 *Location) bool {
if !(&l1.Logs).Equal(&l2.Logs) { if !(&l1.Logs).Equal(&l2.Logs) {
return false return false
} }
if !(&l1.LuaRestyWAF).Equal(&l2.LuaRestyWAF) {
return false
}
if !(&l1.InfluxDB).Equal(&l2.InfluxDB) { if !(&l1.InfluxDB).Equal(&l2.InfluxDB) {
return false return false

View file

@ -50,16 +50,11 @@ events {
http { http {
lua_package_path "/etc/nginx/lua/?.lua;;"; lua_package_path "/etc/nginx/lua/?.lua;;";
{{ buildLuaSharedDictionaries $cfg $servers $all.Cfg.DisableLuaRestyWAF }} {{ buildLuaSharedDictionaries $cfg $servers }}
init_by_lua_block { init_by_lua_block {
collectgarbage("collect") collectgarbage("collect")
{{ if not $all.Cfg.DisableLuaRestyWAF }}
local lua_resty_waf = require("resty.waf")
lua_resty_waf.init()
{{ end }}
-- init modules -- init modules
local ok, res local ok, res
@ -989,78 +984,20 @@ stream {
plugins.run() plugins.run()
} }
{{ if shouldConfigureLuaRestyWAF $all.Cfg.DisableLuaRestyWAF $location.LuaRestyWAF.Mode }}
# be careful with `access_by_lua_block` and `satisfy any` directives as satisfy any # 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)` # will always succeed when there's `access_by_lua_block` that does not have any lua code doing `ngx.exit(ngx.DECLINED)`
# that means currently `satisfy any` and lua-resty-waf together will potentiall render any
# other authentication method such as basic auth or external auth useless - all requests will be allowed. # other authentication method such as basic auth or external auth useless - all requests will be allowed.
access_by_lua_block { #access_by_lua_block {
local lua_resty_waf = require("resty.waf") #}
local waf = lua_resty_waf:new()
waf:set_option("mode", {{ $location.LuaRestyWAF.Mode | quote }})
waf:set_option("storage_zone", "waf_storage")
{{ if $location.LuaRestyWAF.AllowUnknownContentTypes }}
waf:set_option("allow_unknown_content_types", true)
{{ else }}
waf:set_option("allowed_content_types", { "text/html", "text/json", "application/json" })
{{ end }}
waf:set_option("event_log_level", ngx.WARN)
{{ if gt $location.LuaRestyWAF.ScoreThreshold 0 }}
waf:set_option("score_threshold", {{ $location.LuaRestyWAF.ScoreThreshold }})
{{ end }}
{{ if not $location.LuaRestyWAF.ProcessMultipartBody }}
waf:set_option("process_multipart_body", false)
{{ end }}
{{ if $location.LuaRestyWAF.Debug }}
waf:set_option("debug", true)
waf:set_option("event_log_request_arguments", true)
waf:set_option("event_log_request_body", true)
waf:set_option("event_log_request_headers", true)
waf:set_option("req_tid_header", true)
waf:set_option("res_tid_header", true)
{{ end }}
{{ range $ruleset := $location.LuaRestyWAF.IgnoredRuleSets }}
waf:set_option("ignore_ruleset", {{ $ruleset | quote }})
{{ end }}
{{ if gt (len $location.LuaRestyWAF.ExtraRulesetString) 0 }}
waf:set_option("add_ruleset_string", "10000_extra_rules", {{ $location.LuaRestyWAF.ExtraRulesetString }})
{{ end }}
waf:exec()
}
{{ end }}
header_filter_by_lua_block { header_filter_by_lua_block {
{{ if shouldConfigureLuaRestyWAF $all.Cfg.DisableLuaRestyWAF $location.LuaRestyWAF.Mode }}
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
waf:exec()
{{ end }}
plugins.run() plugins.run()
} }
body_filter_by_lua_block { body_filter_by_lua_block {
{{ if shouldConfigureLuaRestyWAF $all.Cfg.DisableLuaRestyWAF $location.LuaRestyWAF.Mode }}
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
waf:exec()
{{ end }}
} }
log_by_lua_block { log_by_lua_block {
{{ if shouldConfigureLuaRestyWAF $all.Cfg.DisableLuaRestyWAF $location.LuaRestyWAF.Mode }}
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
waf:exec()
{{ end }}
balancer.log() balancer.log()
{{ if $all.EnableMetrics }} {{ if $all.EnableMetrics }}
monitor.call() monitor.call()

View file

@ -1,224 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package annotations
import (
"fmt"
"net/http"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/parnurzeal/gorequest"
"k8s.io/ingress-nginx/test/e2e/framework"
)
var _ = framework.IngressNginxDescribe("Annotations - lua-resty-waf", func() {
f := framework.NewDefaultFramework("luarestywaf")
BeforeEach(func() {
f.NewEchoDeployment()
})
Context("when lua-resty-waf is enabled", func() {
It("should return 403 for a malicious request that matches a default WAF rule and 200 for other requests", func() {
host := "foo"
createIngress(f, host, framework.EchoService, 80, map[string]string{"nginx.ingress.kubernetes.io/lua-resty-waf": "active"})
url := fmt.Sprintf("%s?msg=<A href=\"http://mysite.com/\">XSS</A>", f.GetURL(framework.HTTP))
resp, _, errs := gorequest.New().
Get(url).
Set("Host", host).
End()
Expect(len(errs)).Should(Equal(0))
Expect(resp.StatusCode).Should(Equal(http.StatusForbidden))
})
It("should not apply ignored rulesets", func() {
host := "foo"
createIngress(f, host, framework.EchoService, 80, map[string]string{
"nginx.ingress.kubernetes.io/lua-resty-waf": "active",
"nginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets": "41000_sqli, 42000_xss"})
url := fmt.Sprintf("%s?msg=<A href=\"http://mysite.com/\">XSS</A>", f.GetURL(framework.HTTP))
resp, _, errs := gorequest.New().
Get(url).
Set("Host", host).
End()
Expect(len(errs)).Should(Equal(0))
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
})
It("should apply the score threshold", func() {
host := "foo"
createIngress(f, host, framework.EchoService, 80, map[string]string{
"nginx.ingress.kubernetes.io/lua-resty-waf": "active",
"nginx.ingress.kubernetes.io/lua-resty-waf-score-threshold": "20"})
url := fmt.Sprintf("%s?msg=<A href=\"http://mysite.com/\">XSS</A>", f.GetURL(framework.HTTP))
resp, _, errs := gorequest.New().
Get(url).
Set("Host", host).
End()
Expect(len(errs)).Should(Equal(0))
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
})
It("should not reject request with an unknown content type", func() {
host := "foo"
contenttype := "application/octet-stream"
createIngress(f, host, framework.EchoService, 80, map[string]string{
"nginx.ingress.kubernetes.io/lua-resty-waf-allow-unknown-content-types": "true",
"nginx.ingress.kubernetes.io/lua-resty-waf": "active"})
url := fmt.Sprintf("%s?msg=my-message", f.GetURL(framework.HTTP))
resp, _, errs := gorequest.New().
Get(url).
Set("Host", host).
Set("Content-Type", contenttype).
End()
Expect(len(errs)).Should(Equal(0))
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
})
It("should not fail a request with multipart content type when multipart body processing disabled", func() {
contenttype := "multipart/form-data; boundary=alamofire.boundary.3fc2e849279e18fc"
host := "foo"
createIngress(f, host, framework.EchoService, 80, map[string]string{
"nginx.ingress.kubernetes.io/lua-resty-waf-process-multipart-body": "false",
"nginx.ingress.kubernetes.io/lua-resty-waf": "active"})
url := fmt.Sprintf("%s?msg=my-message", f.GetURL(framework.HTTP))
resp, _, errs := gorequest.New().
Get(url).
Set("Host", host).
Set("Content-Type", contenttype).
End()
Expect(len(errs)).Should(Equal(0))
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
})
It("should fail a request with multipart content type when multipart body processing enabled by default", func() {
contenttype := "multipart/form-data; boundary=alamofire.boundary.3fc2e849279e18fc"
host := "foo"
createIngress(f, host, framework.EchoService, 80, map[string]string{
"nginx.ingress.kubernetes.io/lua-resty-waf": "active"})
url := fmt.Sprintf("%s?msg=my-message", f.GetURL(framework.HTTP))
resp, _, errs := gorequest.New().
Get(url).
Set("Host", host).
Set("Content-Type", contenttype).
End()
Expect(len(errs)).Should(Equal(0))
Expect(resp.StatusCode).Should(Equal(http.StatusBadRequest))
})
It("should apply configured extra rules", func() {
host := "foo"
createIngress(f, host, framework.EchoService, 80, map[string]string{
"nginx.ingress.kubernetes.io/lua-resty-waf": "active",
"nginx.ingress.kubernetes.io/lua-resty-waf-extra-rules": `[=[
{ "access": [
{ "actions": { "disrupt" : "DENY" },
"id": 10001,
"msg": "my custom rule",
"operator": "STR_CONTAINS",
"pattern": "foo",
"vars": [ { "parse": [ "values", 1 ], "type": "REQUEST_ARGS" } ] }
],
"body_filter": [],
"header_filter":[]
}
]=]`,
})
url := fmt.Sprintf("%s?msg=my-message", f.GetURL(framework.HTTP))
resp, _, errs := gorequest.New().
Get(url).
Set("Host", host).
End()
Expect(len(errs)).Should(Equal(0))
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
url = fmt.Sprintf("%s?msg=my-foo-message", f.GetURL(framework.HTTP))
resp, _, errs = gorequest.New().
Get(url).
Set("Host", host).
End()
Expect(len(errs)).Should(Equal(0))
Expect(resp.StatusCode).Should(Equal(http.StatusForbidden))
})
})
Context("when lua-resty-waf is not enabled", func() {
It("should return 200 even for a malicious request", func() {
host := "foo"
createIngress(f, host, framework.EchoService, 80, map[string]string{})
url := fmt.Sprintf("%s?msg=<A href=\"http://mysite.com/\">XSS</A>", f.GetURL(framework.HTTP))
resp, _, errs := gorequest.New().
Get(url).
Set("Host", host).
End()
Expect(len(errs)).Should(Equal(0))
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
})
It("should run in simulate mode", func() {
host := "foo"
createIngress(f, host, framework.EchoService, 80, map[string]string{"nginx.ingress.kubernetes.io/lua-resty-waf": "simulate"})
url := fmt.Sprintf("%s?msg=<A href=\"http://mysite.com/\">XSS</A>", f.GetURL(framework.HTTP))
resp, _, errs := gorequest.New().
Get(url).
Set("Host", host).
End()
Expect(len(errs)).Should(Equal(0))
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
time.Sleep(5 * time.Second)
log, err := f.NginxLogs()
Expect(err).ToNot(HaveOccurred())
Expect(log).To(ContainSubstring("Request score greater than score threshold"))
})
})
})
func createIngress(f *framework.Framework, host, service string, port int, annotations map[string]string) {
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, service, port, &annotations)
f.EnsureIngress(ing)
f.WaitForNginxServer(host,
func(server string) bool {
return Expect(server).Should(ContainSubstring(fmt.Sprintf("server_name %v", host)))
})
time.Sleep(1 * time.Second)
resp, body, errs := gorequest.New().
Get(f.GetURL(framework.HTTP)).
Set("Host", host).
End()
Expect(len(errs)).Should(Equal(0))
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
Expect(body).Should(ContainSubstring(fmt.Sprintf("host=%v", host)))
}