8000 Add handling of mutiple log destinations · nginx/kubernetes-ingress@e93d010 · GitHub
[go: up one dir, main page]

Skip to content

Commit e93d010

Browse files
author
Rafal Wegrzycki
committed
Add handling of mutiple log destinations
1 parent 8791d41 commit e93d010

File tree

16 files changed

+434
-39
lines changed

16 files changed

+434
-39
lines changed

deployments/common/crds/k8s.nginx.org_policies.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,18 @@ spec:
156156
type: boolean
157157
logDest:
158158
type: string
159+
securityLogs:
160+
type: array
161+
items:
162+
description: SecurityLog defines the security log of a WAF policy.
163+
type: object
164+
properties:
165+
apLogConf:
166+
type: string
167+
enable:
168+
type: boolean
169+
logDest:
170+
type: string
159171
status:
160172
description: PolicyStatus is the status of the policy resource
161173
type: object

deployments/helm-chart/crds/k8s.nginx.org_policies.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,18 @@ spec:
156156
type: boolean
157157
logDest:
158158
type: string
159+
securityLogs:
160+
type: array
161+
items:
162+
description: SecurityLog defines the security log of a WAF policy.
163+
type: object
164+
properties:
165+
apLogConf:
166+
type: string
167+
enable:
168+
type: boolean
169+
logDest:
170+
type: string
159171
status:
160172
description: PolicyStatus is the status of the policy resource
161173
type: object

docs/content/configuration/policy-resource.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,17 +362,20 @@ For `kubectl get` and similar commands, you can also use the short name `pol` in
362362

363363
The WAF policy configures NGINX Plus to secure client requests using App Protect policies.
364364

365-
For example, the following policy will enable the referenced APPolicy and APLogConf with the configured log destination:
365+
For example, the following policy will enable the referenced APPolicy. You can configure multiple APLogConfs with log destinations:
366366
```yaml
367367
waf:
368368
enable: true
369369
apPolicy: "default/dataguard-alarm"
370-
securityLog:
371-
enable: true
370+
securityLogs:
371+
- enable: true
372372
apLogConf: "default/logconf"
373373
logDest: "syslog:server=syslog-svc.default:514"
374+
- enable: true
375+
apLogConf: "default/logconf"
376+
logDest: "syslog:server=syslog-svc-secondary.default:514"
374377
```
375-
378+
> Note: The field `waf.securityLog` is supported but will be ignored if `waf.securityLogs` is populated.
376379
> Note: The feature is implemented using the NGINX Plus [NGINX App Protect Module](https://docs.nginx.com/nginx-app-protect/configuration/).
377380

378381
{{% table %}}

examples/custom-resources/waf/waf.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ spec:
66
waf:
77
enable: true
88
apPolicy: "default/dataguard-alarm"
9-
securityLog:
10-
enable: true
9+
securityLogs:
10+
- enable: true
1111
apLogConf: "default/logconf"
1212
logDest: "syslog:server=syslog-svc.default:514"

internal/configs/version2/http.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ type WAF struct {
123123
Enable string
124124
ApPolicy string
125125
ApSecurityLogEnable bool
126-
ApLogConf string
126+
ApLogConf []string
127127
}
128128

129129
// Dos defines Dos configuration.

internal/configs/version2/nginx-plus.virtualserver.tmpl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,9 @@ server {
189189

190190
{{ if .ApSecurityLogEnable }}
191191
app_protect_security_log_enable on;
192-
app_protect_security_log {{ .ApLogConf }};
192+
{{ range $logconf := .ApLogConf }}
193+
app_protect_security_log {{ $logconf }};
194+
{{ end }}
193195
{{ end }}
194196
{{ end }}
195197

internal/configs/version2/templates_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ var virtualServerCfg = VirtualServerConfig{
150150
WAF: &WAF{
151151
ApPolicy: "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
152152
ApSecurityLogEnable: true,
153-
ApLogConf: "/etc/nginx/waf/nac-logconfs/default-logconf",
153+
ApLogConf: []string{"/etc/nginx/waf/nac-logconfs/default-logconf"},
154154
},
155155
Snippets: []string{"# server snippet"},
156156
InternalRedirectLocations: []InternalRedirectLocation{

internal/configs/virtualserver.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,7 +1041,7 @@ func (p *policiesCfg) addWAFConfig(
10411041
}
10421042
}
10431043

1044-
if waf.SecurityLog != nil {
1044+
if waf.SecurityLog != nil && waf.SecurityLogs == nil {
10451045
p.WAF.ApSecurityLogEnable = true
10461046

10471047
logConfKey := waf.SecurityLog.ApLogConf
@@ -1052,13 +1052,31 @@ func (p *policiesCfg) addWAFConfig(
10521052

10531053
if logConfPath, ok := apResources.LogConfs[logConfKey]; ok {
10541054
logDest := generateString(waf.SecurityLog.LogDest, "syslog:server=localhost:514")
1055-
p.WAF.ApLogConf = fmt.Sprintf("%s %s", logConfPath, logDest)
1055+
p.WAF.ApLogConf = []string{fmt.Sprintf("%s %s", logConfPath, logDest)}
10561056
} else {
10571057
res.addWarningf("WAF policy %s references an invalid or non-existing log config %s", polKey, logConfKey)
10581058
res.isError = true
10591059
}
10601060
}
10611061

1062+
if waf.SecurityLogs != nil {
1063+
p.WAF.ApSecurityLogEnable = true
1064+
p.WAF.ApLogConf = []string{}
1065+
for _, loco := range waf.SecurityLogs {
1066+
logConfKey := loco.ApLogConf
1067+
hasNamepace := strings.Contains(logConfKey, "/")
1068+
if !hasNamepace {
1069+
logConfKey = fmt.Sprintf("%v/%v", polNamespace, logConfKey)
1070+
}
1071+
if logConfPath, ok := apResources.LogConfs[logConfKey]; ok {
1072+
logDest := generateString(loco.LogDest, "syslog:server=localhost:514")
1073+
p.WAF.ApLogConf = append(p.WAF.ApLogConf, fmt.Sprintf("%s %s", logConfPath, logDest))
1074+
} else {
1075+
res.addWarningf("WAF policy %s references an invalid or non-existing log config %s", polKey, logConfKey)
1076+
res.isError = true
1077+
}
1078+
}
1079+
}
10621080
return res
10631081
}
10641082

internal/configs/virtualserver_test.go

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2924,7 +2924,7 @@ func TestGeneratePolicies(t *testing.T) {
29242924
Enable: "on",
29252925
ApPolicy: "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
29262926
ApSecurityLogEnable: true,
2927-
ApLogConf: "/etc/nginx/waf/nac-logconfs/default-logconf syslog:server=127.0.0.1:514",
2927+
ApLogConf: []string{"/etc/nginx/waf/nac-logconfs/default-logconf syslog:server=127.0.0.1:514"},
29282928
},
29292929
},
29302930
msg: "WAF reference",
@@ -6673,7 +6673,6 @@ func TestGenerateHealthCheck(t *testing.T) {
66736673
msg string
66746674
}{
66756675
{
6676-
66776676
upstream: conf_v1.Upstream{
66786677
HealthCheck: &conf_v1.HealthCheck{
66796678
Enable: true,
@@ -6854,7 +6853,6 @@ func TestGenerateGrpcHealthCheck(t *testing.T) {
68546853
msg string
68556854
}{
68566855
{
6857-
68586856
upstream: conf_v1.Upstream{
68596857
HealthCheck: &conf_v1.HealthCheck{
68606858
Enable: true,
@@ -8174,7 +8172,6 @@ func TestAddWafConfig(t *testing.T) {
81748172
msg string
81758173
}{
81768174
{
8177-
81788175
wafInput: &conf_v1.WAF{
81798176
Enable: true,
81808177
},
@@ -8191,7 +8188,6 @@ func TestAddWafConfig(t *testing.T) {
81918188
msg: "valid waf config, default App Protect config",
81928189
},
81938190
{
8194-
81958191
wafInput: &conf_v1.WAF{
81968192
Enable: true,
81978193
ApPolicy: "dataguard-alarm",
@@ -8214,13 +8210,42 @@ func TestAddWafConfig(t *testing.T) {
82148210
wafConfig: &version2.WAF{
82158211
ApPolicy: "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
82168212
ApSecurityLogEnable: true,
8217-
ApLogConf: "/etc/nginx/waf/nac-logconfs/default-logconf",
8213+
ApLogConf: []string{"/etc/nginx/waf/nac-logconfs/default-logconf"},
8214+
},
8215+
expected: &validationResults{isError: false},
8216+
msg: "valid waf config",
8217+
},
8218+
{
8219+
wafInput: &conf_v1.WAF{
8220+
Enable: true,
8221+
ApPolicy: "dataguard-alarm",
8222+
SecurityLogs: []*conf_v1.SecurityLog{
8223+
{
8224+
Enable: true,
8225+
ApLogConf: "logconf",
8226+
LogDest: "syslog:server=127.0.0.1:514",
8227+
},
8228+
},
8229+
},
8230+
polKey: "default/waf-policy",
8231+
polNamespace: "default",
8232+
apResources: &appProtectResourcesForVS{
8233+
Policies: map[string]string{
8234+
"default/dataguard-alarm": "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
8235+
},
8236+
LogConfs: map[string]string{
8237+
"default/logconf": "/etc/nginx/waf/nac-logconfs/default-logconf",
8238+
},
8239+
},
8240+
wafConfig: &version2.WAF{
8241+
ApPolicy: "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
8242+
ApSecurityLogEnable: true,
8243+
ApLogConf: []string{"/etc/nginx/waf/nac-logconfs/default-logconf"},
82188244
},
82198245
expected: &validationResults{isError: false},
82208246
msg: "valid waf config",
82218247
},
82228248
{
8223-
82248249
wafInput: &conf_v1.WAF{
82258250
Enable: true,
82268251
ApPolicy: "default/dataguard-alarm",
@@ -8241,7 +8266,7 @@ func TestAddWafConfig(t *testing.T) {
82418266
wafConfig: &version2.WAF{
82428267
ApPolicy: "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
82438268
ApSecurityLogEnable: true,
8244-
ApLogConf: "/etc/nginx/waf/nac-logconfs/default-logconf",
8269+
ApLogConf: []string{"/etc/nginx/waf/nac-logconfs/default-logconf"},
82458270
},
82468271
expected: &validationResults{
82478272
isError: true,
@@ -8252,7 +8277,6 @@ func TestAddWafConfig(t *testing.T) {
82528277
msg: "invalid waf config, apLogConf references non-existing log conf",
82538278
},
82548279
{
8255-
82568280
wafInput: &conf_v1.WAF{
82578281
Enable: true,
82588282
ApPolicy: "default/dataguard-alarm",
@@ -8272,7 +8296,7 @@ func TestAddWafConfig(t *testing.T) {
82728296
wafConfig: &version2.WAF{
82738297
ApPolicy: "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
82748298
ApSecurityLogEnable: true,
8275-
ApLogConf: "/etc/nginx/waf/nac-logconfs/default-logconf",
8299+
ApLogConf: []string{"/etc/nginx/waf/nac-logconfs/default-logconf"},
82768300
},
82778301
expected: &validationResults{
82788302
isError: true,
@@ -8283,7 +8307,6 @@ func TestAddWafConfig(t *testing.T) {
82838307
msg: "invalid waf config, apLogConf references non-existing ap conf",
82848308
},
82858309
{
8286-
82878310
wafInput: &conf_v1.WAF{
82888311
Enable: true,
82898312
ApPolicy: "ns1/dataguard-alarm",
@@ -8306,13 +8329,12 @@ func TestAddWafConfig(t *testing.T) {
83068329
wafConfig: &version2.WAF{
83078330
ApPolicy: "/etc/nginx/waf/nac-policies/ns1-dataguard-alarm",
83088331
ApSecurityLogEnable: true,
8309-
ApLogConf: "/etc/nginx/waf/nac-logconfs/ns2-logconf",
8332+
ApLogConf: []string{"/etc/nginx/waf/nac-logconfs/ns2-logconf"},
83108333
},
83118334
expected: &validationResults{},
83128335
msg: "valid waf config, cross ns reference",
83138336
},
83148337
{
8315-
83168338
wafInput: &conf_v1.WAF{
83178339
Enable: false,
83188340
ApPolicy: "dataguard-alarm",

internal/k8s/controller.go

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2786,19 +2786,37 @@ func (lbc *LoadBalancerController) addWAFPolicyRefs(
27862786
apPolRef[apPolKey] = apPolicy
27872787
}
27882788

2789-
if pol.Spec.WAF.SecurityLog != nil && pol.Spec.WAF.SecurityLog.ApLogConf != "" {
2790-
logConfKey := pol.Spec.WAF.SecurityLog.ApLogConf
2791-
if !strings.Contains(pol.Spec.WAF.SecurityLog.ApLogConf, "/") {
2792-
logConfKey = fmt.Sprintf("%v/%v", pol.Namespace, logConfKey)
2793-
}
2789+
if pol.Spec.WAF.SecurityLog != nil && pol.Spec.WAF.SecurityLogs == nil {
2790+
if pol.Spec.WAF.SecurityLog.ApLogConf != "" {
2791+
logConfKey := pol.Spec.WAF.SecurityLog.ApLogConf
2792+
if !strings.Contains(pol.Spec.WAF.SecurityLog.ApLogConf, "/") {
2793+
logConfKey = fmt.Sprintf("%v/%v", pol.Namespace, logConfKey)
2794+
}
27942795

2795-
logConf, err := lbc.appProtectConfiguration.GetAppResource(appprotect.LogConfGVK.Kind, logConfKey)
2796-
if err != nil {
2797-
return fmt.Errorf("WAF policy %q is invalid: %w", logConfKey, err)
2796+
logConf, err := lbc.appProtectConfiguration.GetAppResource(appprotect.LogConfGVK.Kind, logConfKey)
2797+
if err != nil {
2798+
return fmt.Errorf("WAF policy %q is invalid: %w", logConfKey, err)
2799+
}
2800+
logConfRef[logConfKey] = logConf
27982801
}
2799-
logConfRef[logConfKey] = logConf
28002802
}
28012803

2804+
if pol.Spec.WAF.SecurityLogs != nil {
2805+
for _, SecLog := range pol.Spec.WAF.SecurityLogs {
2806+
if SecLog.ApLogConf != "" {
2807+
logConfKey := SecLog.ApLogConf
2808+
if !strings.Contains(SecLog.ApLogConf, "/") {
2809+
logConfKey = fmt.Sprintf("%v/%v", pol.Namespace, logConfKey)
2810+
}
2811+
2812+
logConf, err := lbc.appProtectConfiguration.GetAppResource(appprotect.LogConfGVK.Kind, logConfKey)
2813+
if err != nil {
2814+
return fmt.Errorf("WAF policy %q is invalid: %w", logConfKey, err)
2815+
}
2816+
logConfRef[logConfKey] = logConf
2817+
}
2818+
}
2819+
}
28022820
}
28032821
return nil
28042822
}
@@ -2846,6 +2864,13 @@ func getWAFPoliciesForAppProtectLogConf(pols []*conf_v1.Policy, key string) []*c
28462864
if pol.Spec.WAF != nil && pol.Spec.WAF.SecurityLog != nil && isMatchingResourceRef(pol.Namespace, pol.Spec.WAF.SecurityLog.ApLogConf, key) {
28472865
policies = append(policies, pol)
28482866
}
2867+
if pol.Spec.WAF != nil && pol.Spec.WAF.SecurityLogs != nil {
2868+
for _, logConf := range pol.Spec.WAF.SecurityLogs {
2869+
if isMatchingResourceRef(pol.Namespace, logConf.ApLogConf, key) {
2870+
policies = append(policies, pol)
2871+
}
2872+
}
2873+
}
28492874
}
28502875

28512876
return policies

0 commit comments

Comments
 (0)
0