extra waf rules per ingress (#2315)
* extra waf rules per ingress * document annotation nginx.ingress.kubernetes.io/lua-resty-waf-extra-rules * regenerate internal/file/bindata.go
This commit is contained in:
parent
16faf309ca
commit
bad8295a42
5 changed files with 67 additions and 8 deletions
|
@ -69,6 +69,7 @@ The following annotations are supported:
|
||||||
|[nginx.ingress.kubernetes.io/lua-resty-waf](#lua-resty-waf)|"true" or "false"|
|
|[nginx.ingress.kubernetes.io/lua-resty-waf](#lua-resty-waf)|"true" or "false"|
|
||||||
|[nginx.ingress.kubernetes.io/lua-resty-waf-debug](#lua-resty-waf)|"true" or "false"|
|
|[nginx.ingress.kubernetes.io/lua-resty-waf-debug](#lua-resty-waf)|"true" or "false"|
|
||||||
|[nginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets](#lua-resty-waf)|string|
|
|[nginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets](#lua-resty-waf)|string|
|
||||||
|
|[nginx.ingress.kubernetes.io/lua-resty-waf-extra-rules](#lua-resty-waf)|string|
|
||||||
|
|
||||||
**Note:** all the values must be a string. In case of booleans or number it must be quoted.
|
**Note:** all the values must be a string. In case of booleans or number it must be quoted.
|
||||||
|
|
||||||
|
@ -486,3 +487,13 @@ nginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets: "41000_sqli, 42000_xs
|
||||||
```
|
```
|
||||||
|
|
||||||
will ignore the two mentioned rulesets.
|
will ignore the two mentioned rulesets.
|
||||||
|
|
||||||
|
It is also possible to configure custom WAF rules per ingress using `nginx.ingress.kubernetes.io/lua-resty-waf-extra-rules` annotation. For an example the following snippet will
|
||||||
|
configure a WAF rule to deny requests with query string value that contains word `foo`:
|
||||||
|
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
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":[] } ]=]'
|
||||||
|
```
|
||||||
|
|
||||||
|
For details on how to write WAF rules, please refer to https://github.com/p0pr0ck5/lua-resty-waf.
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -28,9 +28,10 @@ import (
|
||||||
|
|
||||||
// Config returns lua-resty-waf configuration for an Ingress rule
|
// Config returns lua-resty-waf configuration for an Ingress rule
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Debug bool `json:"debug"`
|
Debug bool `json:"debug"`
|
||||||
IgnoredRuleSets []string `json: "ignored-rulesets"`
|
IgnoredRuleSets []string `json: "ignored-rulesets"`
|
||||||
|
ExtraRulesetString string `json: "extra-ruleset-string"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equal tests for equality between two Config types
|
// Equal tests for equality between two Config types
|
||||||
|
@ -50,6 +51,9 @@ func (e1 *Config) Equal(e2 *Config) bool {
|
||||||
if !reflect.DeepEqual(e1.IgnoredRuleSets, e2.IgnoredRuleSets) {
|
if !reflect.DeepEqual(e1.IgnoredRuleSets, e2.IgnoredRuleSets) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if e1.ExtraRulesetString != e2.ExtraRulesetString {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -80,9 +84,13 @@ func (a luarestywaf) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||||
return strC == "," || strC == " "
|
return strC == "," || strC == " "
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// TODO(elvinefendi) maybe validate the ruleset string here
|
||||||
|
extraRulesetString, _ := parser.GetStringAnnotation("lua-resty-waf-extra-rules", ing)
|
||||||
|
|
||||||
return &Config{
|
return &Config{
|
||||||
Enabled: enabled,
|
Enabled: enabled,
|
||||||
Debug: debug,
|
Debug: debug,
|
||||||
IgnoredRuleSets: ignoredRuleSets,
|
IgnoredRuleSets: ignoredRuleSets,
|
||||||
|
ExtraRulesetString: extraRulesetString,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -839,6 +839,10 @@ stream {
|
||||||
waf:set_option("ignore_ruleset", "{{ $ruleset }}")
|
waf:set_option("ignore_ruleset", "{{ $ruleset }}")
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if gt (len $location.LuaRestyWAF.ExtraRulesetString) 0 }}
|
||||||
|
waf:set_option("add_ruleset_string", "10000_extra_rules", {{ $location.LuaRestyWAF.ExtraRulesetString }})
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
waf:exec()
|
waf:exec()
|
||||||
}
|
}
|
||||||
header_filter_by_lua_block {
|
header_filter_by_lua_block {
|
||||||
|
|
|
@ -68,8 +68,44 @@ var _ = framework.IngressNginxDescribe("Annotations - lua-resty-waf", func() {
|
||||||
Expect(len(errs)).Should(Equal(0))
|
Expect(len(errs)).Should(Equal(0))
|
||||||
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
|
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
|
||||||
})
|
})
|
||||||
})
|
It("should apply configured extra rules", func() {
|
||||||
|
host := "foo"
|
||||||
|
createIngress(f, host, map[string]string{
|
||||||
|
"nginx.ingress.kubernetes.io/lua-resty-waf": "true",
|
||||||
|
"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.NginxHTTPURL)
|
||||||
|
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.NginxHTTPURL)
|
||||||
|
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() {
|
Context("when lua-resty-waf is not enabled", func() {
|
||||||
It("should return 200 even for a malicious request", func() {
|
It("should return 200 even for a malicious request", func() {
|
||||||
host := "foo"
|
host := "foo"
|
||||||
|
|
Loading…
Reference in a new issue