8000 AP: add support for multiple log configs (#1513) · nginx/kubernetes-ingress@6c02b96 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6c02b96

Browse files
rafwegvRafal Wegrzyckivepatel
authored
AP: add support for multiple log configs (#1513)
* AP: add support for multiple log configs Co-authored-by: Rafal Wegrzycki <r.wegrzycki@f5.com> Co-authored-by: Venktesh Patel <ve.patel@f5.com>
1 parent d711e7d commit 6c02b96

20 files changed

+647
-289
lines changed

docs-web/configuration/ingress-resources/advanced-configuration-with-annotations.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,12 +415,12 @@ The table below summarizes the available annotations.
415415
- `Example for App Protect <https://github.com/nginxinc/kubernetes-ingress/tree/v1.11.3/examples/appprotect>`_.
416416
* - ``appprotect.f5.com/app-protect-security-log``
417417
- N/A
418-
- The App Protect log configuration for the Ingress Resource. Format is ``namespace/name``. If no namespace is specified, the same namespace as the Ingress Resource is used. If not specified the default is used which is: filter: ``illegal``, format: ``default``
418+
- The App Protect log configuration for the Ingress Resource. Format is ``namespace/name``. If no namespace is specified, the same namespace as the Ingress Resource is used. If not specified the default is used which is: filter: ``illegal``, format: ``default``. Multiple configurations can be specified in a comma seperated list. Both log configurations and destinations list (see below) must be of equal length. Configs and destinations are paired by the list indices.
419419
- N/A
420420
- `Example for App Protect <https://github.com/nginxinc/kubernetes-ingress/tree/v1.11.3/examples/appprotect>`_.
421421
* - ``appprotect.f5.com/app-protect-security-log-destination``
422422
- N/A
423-
- The destination of the security log. For more information check the `DESTINATION argument </nginx-app-protect/troubleshooting/#app-protect-security-log>`_.
423+
- The destination of the security log. For more information check the `DESTINATION argument </nginx-app-protect/troubleshooting/#app-protect-security-log>`_. Multiple destinations can be specified in a coma seperated list. Both log configurations and destinations list (see above) must be of equal length. Configs and destinations are paired by the list indices.
424424
- ``syslog:server=localhost:514``
425425
- `Example for App Protect <https://github.com/nginxinc/kubernetes-ingress/tree/v1.11.3/examples/appprotect>`_.
426426
```

internal/configs/configurator.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,20 +1221,19 @@ func createSpiffeCert(certs []*x509.Certificate) []byte {
12211221
return pemData
12221222
}
12231223

1224-
func (cnf *Configurator) updateApResources(ingEx *IngressEx) map[string]string {
1225-
apRes := make(map[string]string)
1224+
func (cnf *Configurator) updateApResources(ingEx *IngressEx) (apRes AppProtectResources) {
12261225
if ingEx.AppProtectPolicy != nil {
12271226
policyFileName := appProtectPolicyFileNameFromUnstruct(ingEx.AppProtectPolicy)
12281227
policyContent := generateApResourceFileContent(ingEx.AppProtectPolicy)
12291228
cnf.nginxManager.CreateAppProtectResourceFile(policyFileName, policyContent)
1230-
apRes[appProtectPolicyKey] = policyFileName
1229+
apRes.AppProtectPolicy = policyFileName
12311230
}
12321231

1233-
if ingEx.AppProtectLogConf != nil {
1234-
logConfFileName := appProtectLogConfFileNameFromUnstruct(ingEx.AppProtectLogConf)
1235-
logConfContent := generateApResourceFileContent(ingEx.AppProtectLogConf)
1232+
for _, logConf := range ingEx.AppProtectLogs {
1233+
logConfFileName := appProtectLogConfFileNameFromUnstruct(logConf.LogConf)
1234+
logConfContent := generateApResourceFileContent(logConf.LogConf)
12361235
cnf.nginxManager.CreateAppProtectResourceFile(logConfFileName, logConfContent)
1237-
apRes[appProtectLogConfKey] = logConfFileName + " " + ingEx.AppProtectLogDst
1236+
apRes.AppProtectLogconfs = append(apRes.AppProtectLogconfs, logConfFileName+" "+logConf.Dest)
12381237
}
12391238

12401239
return apRes

internal/configs/configurator_test.go

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,7 @@ func TestUpdateApResources(t *testing.T) {
10911091

10921092
tests := []struct {
10931093
ingEx *IngressEx
1094-
expected map[string]string
1094+
expected AppProtectResources
10951095
msg string
10961096
}{
10971097
{
@@ -1100,7 +1100,7 @@ func TestUpdateApResources(t *testing.T) {
11001100
ObjectMeta: meta_v1.ObjectMeta{},
11011101
},
11021102
},
1103-
expected: map[string]string{},
1103+
expected: AppProtectResources{},
11041104
msg: "no app protect resources",
11051105
},
11061106
{
@@ -1110,8 +1110,8 @@ func TestUpdateApResources(t *testing.T) {
11101110
},
11111111
AppProtectPolicy: appProtectPolicy,
11121112
},
1113-
expected: map[string]string{
1114-
"policy": "/etc/nginx/waf/nac-policies/test-ns_test-name",
1113+
expected: AppProtectResources{
1114+
AppProtectPolicy: "/etc/nginx/waf/nac-policies/test-ns_test-name",
11151115
},
11161116
msg: "app protect policy",
11171117
},
@@ -1120,11 +1120,15 @@ func TestUpdateApResources(t *testing.T) {
11201120
Ingress: &networking.Ingress{
11211121
ObjectMeta: meta_v1.ObjectMeta{},
11221122
},
1123-
AppProtectLogConf: appProtectLogConf,
1124-
AppProtectLogDst: appProtectLogDst,
1123+
AppProtectLogs: []AppProtectLog{
1124+
{
1125+
LogConf: appProtectLogConf,
1126+
Dest: appProtectLogDst,
1127+
},
1128+
},
11251129
},
1126-
expected: map[string]string{
1127-
"logconf": "/etc/nginx/waf/nac-logconfs/test-ns_test-name test-dst",
1130+
expected: AppProtectResources{
1131+
AppProtectLogconfs: []string{"/etc/nginx/waf/nac-logconfs/test-ns_test-name test-dst"},
11281132
},
11291133
msg: "app protect log conf",
11301134
},
@@ -1133,13 +1137,17 @@ func TestUpdateApResources(t *testing.T) {
11331137
Ingress: &networking.Ingress{
11341138
ObjectMeta: meta_v1.ObjectMeta{},
11351139
},
1136-
AppProtectPolicy: appProtectPolicy,
1137-
AppProtectLogConf: appProtectLogConf,
1138-
AppProtectLogDst: appProtectLogDst,
1140+
AppProtectPolicy: appProtectPolicy,
1141+
AppProtectLogs: []AppProtectLog{
1142+
{
1143+
LogConf: appProtectLogConf,
1144+
Dest: appProtectLogDst,
1145+
},
1146+
},
11391147
},
1140-
expected: map[string]string{
1141-
"policy": "/etc/nginx/waf/nac-policies/test-ns_test-name",
1142-
"logconf": "/etc/nginx/waf/nac-logconfs/test-ns_test-name test-dst",
1148+
expected: AppProtectResources{
1149+
AppProtectPolicy: "/etc/nginx/waf/nac-policies/test-ns_test-name",
1150+
AppProtectLogconfs: []string{"/etc/nginx/waf/nac-logconfs/test-ns_test-name test-dst"},
11431151
},
11441152
msg: "app protect policy and log conf",
11451153
},

internal/configs/ingress.go

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,30 @@ const emptyHost = ""
2020
const appProtectPolicyKey = "policy"
2121
const appProtectLogConfKey = "logconf"
2222

23+
// AppProtectResources holds namespace names of App Protect resources relavant to an Ingress
24+
type AppProtectResources struct {
25+
AppProtectPolicy string
26+
AppProtectLogconfs []string
27+
}
28+
29+
// AppProtectLog holds a single pair of log config and log destination
30+
type AppProtectLog struct {
31+
LogConf *unstructured.Unstructured
32+
Dest string
33+
}
34+
2335
// IngressEx holds an Ingress along with the resources that are referenced in this Ingress.
2436
type IngressEx struct {
25-
Ingress *networking.Ingress
26-
Endpoints map[string][]string
27-
HealthChecks map[string]*api_v1.Probe
28-
ExternalNameSvcs map[string]bool
29-
PodsByIP map[string]PodInfo
30-
ValidHosts map[string]bool
31-
ValidMinionPaths map[string]bool
32-
AppProtectPolicy *unstructured.Unstructured
33-
AppProtectLogConf *unstructured.Unstructured
34-
AppProtectLogDst string
35-
SecretRefs map[string]*secrets.SecretReference
37+
Ingress *networking.Ingress
38+
Endpoints map[string][]string
39+
HealthChecks map[string]*api_v1.Probe
40+
ExternalNameSvcs map[string]bool
41+
PodsByIP map[string]PodInfo
42+
ValidHosts map[string]bool
43+
ValidMinionPaths map[string]bool
44+
AppProtectPolicy *unstructured.Unstructured
45+
AppProtectLogs []AppProtectLog
46+
SecretRefs map[string]*secrets.SecretReference
3647
}
3748

3849
// JWTKey represents a secret that holds JSON Web Key.
@@ -55,7 +66,7 @@ type MergeableIngresses struct {
5566
Minions []*IngressEx
5667
}
5768

58-
func generateNginxCfg(ingEx *IngressEx, apResources map[string]string, isMinion bool, baseCfgParams *ConfigParams, isPlus bool,
69+
func generateNginxCfg(ingEx *IngressEx, apResources AppProtectResources, isMinion bool, baseCfgParams *ConfigParams, isPlus bool,
5970
isResolverConfigured bool, staticParams *StaticConfigParams, isWildcardEnabled bool) (version1.IngressNginxConfig, Warnings) {
6071
hasAppProtect := staticParams.MainAppProtectLoadModule
6172
cfgParams := parseAnnotations(ingEx, baseCfgParams, isPlus, hasAppProtect, staticParams.EnableInternalRoutes)
@@ -139,8 +150,8 @@ func generateNginxCfg(ingEx *IngressEx, apResources map[string]string, isMinion
139150
allWarnings.Add(warnings)
140151

141152
if hasAppProtect {
142-
server.AppProtectPolicy = apResources[appProtectPolicyKey]
143-
server.AppProtectLogConf = apResources[appProtectLogConfKey]
153+
server.AppProtectPolicy = apResources.AppProtectPolicy
154+
server.AppProtectLogConfs = apResources.AppProtectLogconfs
144155
}
145156

146157
if !isMinion && cfgParams.JWTKey != "" {
@@ -500,7 +511,7 @@ func upstreamMapToSlice(upstreams map[string]version1.Upstream) []version1.Upstr
500511
return result
501512
}
502513

503-
func generateNginxCfgForMergeableIngresses(mergeableIngs *MergeableIngresses, masterApResources map[string]string,
514+
func generateNginxCfgForMergeableIngresses(mergeableIngs *MergeableIngresses, masterApResources AppProtectResources,
504515
baseCfgParams *ConfigParams, isPlus bool, isResolverConfigured bool, staticParams *StaticConfigParams,
505516
isWildcardEnabled bool) (version1.IngressNginxConfig, Warnings) {
506517

@@ -558,8 +569,8 @@ func generateNginxCfgForMergeableIngresses(mergeableIngs *MergeableIngresses, ma
558569
}
559570

560571
isMinion := true
561-
// App Protect Resources not allowed in minions - pass empty map
562-
dummyApResources := make(map[string]string)
572+
// App Protect Resources not allowed in minions - pass empty struct
573+
dummyApResources := AppProtectResources{}
563574
nginxCfg, minionWarnings := generateNginxCfg(minion, dummyApResources, isMinion, baseCfgParams, isPlus, isResolverConfigured, staticParams, isWildcardEnabled)
564575
warnings.Add(minionWarnings)
565576

internal/configs/ingress_test.go

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ func TestGenerateNginxCfg(t *testing.T) {
2424
isPlus := false
2525
expected := createExpectedConfigForCafeIngressEx(isPlus)
2626

27-
apRes := make(map[string]string)
28-
result, warnings := generateNginxCfg(&cafeIngressEx, apRes, false, configParams, isPlus, false, &StaticConfigParams{}, false)
27+
apRes := AppProtectResources{}
28+
result, warnings := generateNginxCfg(&cafeIngressEx, apRes, false, configParams, false, false, &StaticConfigParams{}, false)
2929

3030
if diff := cmp.Diff(expected, result); diff != "" {
3131
t.Errorf("generateNginxCfg() returned unexpected result (-want +got):\n%s", diff)
@@ -66,8 +66,8 @@ func TestGenerateNginxCfgForJWT(t *testing.T) {
6666
},
6767
}
6868

69-
apRes := make(map[string]string)
70-
result, warnings := generateNginxCfg(&cafeIngressEx, apRes, false, configParams, isPlus, false, &StaticConfigParams{}, false)
69+
apRes := AppProtectResources{}
70+
result, warnings := generateNginxCfg(&cafeIngressEx, apRes, false, configParams, true, false, &StaticConfigParams{}, false)
7171

7272
if !reflect.DeepEqual(result.Servers[0].JWTAuth, expected.Servers[0].JWTAuth) {
7373
t.Errorf("generateNginxCfg returned \n%v, but expected \n%v", result.Servers[0].JWTAuth, expected.Servers[0].JWTAuth)
@@ -85,7 +85,7 @@ func TestGenerateNginxCfgWithMissingTLSSecret(t *testing.T) {
8585
cafeIngressEx.SecretRefs["cafe-secret"].Error = errors.New("secret doesn't exist")
8686
configParams := NewDefaultConfigParams()
8787

88-
apRes := make(map[string]string)
88+
apRes := AppProtectResources{}
8989
result, resultWarnings := generateNginxCfg(&cafeIngressEx, apRes, false, configParams, false, false, &StaticConfigParams{}, false)
9090

9191
expectedSSLRejectHandshake := true
@@ -109,7 +109,7 @@ func TestGenerateNginxCfgWithWildcardTLSSecret(t *testing.T) {
109109
cafeIngressEx.Ingress.Spec.TLS[0].SecretName = ""
110110
configParams := NewDefaultConfigParams()
111111

112-
apRes := make(map[string]string)
112+
apRes := AppProtectResources{}
113113
result, warnings := generateNginxCfg(&cafeIngressEx, apRes, false, configParams, false, false, &StaticConfigParams{}, true)
114114

115115
resultServer := result.Servers[0]
@@ -352,8 +352,8 @@ func TestGenerateNginxCfgForMergeableIngresses(t *testing.T) {
352352

353353
configParams := NewDefaultConfigParams()
354354

355-
masterApRes := make(map[string]string)
356-
result, warnings := generateNginxCfgForMergeableIngresses(mergeableIngresses, masterApRes, configParams, isPlus, false, &StaticConfigParams{}, false)
355+
masterApRes := AppProtectResources{}
356+
result, warnings := generateNginxCfgForMergeableIngresses(mergeableIngresses, masterApRes, configParams, false, false, &StaticConfigParams{}, false)
357357

358358
if diff := cmp.Diff(expected, result); diff != "" {
359359
t.Errorf("generateNginxCfgForMergeableIngresses() returned unexpected result (-want +got):\n%s", diff)
@@ -377,7 +377,7 @@ func TestGenerateNginxConfigForCrossNamespaceMergeableIngresses(t *testing.T) {
377377
expected := createExpectedConfigForCrossNamespaceMergeableCafeIngress()
378378
configParams := NewDefaultConfigParams()
379379

380-
emptyApResources := make(map[string]string)
380+
emptyApResources := AppProtectResources{}
381381
result, warnings := generateNginxCfgForMergeableIngresses(mergeableIngresses, emptyApResources, configParams, false, false, &StaticConfigParams{}, false)
382382

383383
if diff := cmp.Diff(expected, result); diff != "" {
@@ -442,7 +442,7 @@ func TestGenerateNginxCfgForMergeableIngressesForJWT(t *testing.T) {
442442
minionJwtKeyFileNames[objectMetaToFileName(&mergeableIngresses.Minions[0].Ingress.ObjectMeta)] = "/etc/nginx/secrets/default-coffee-jwk"
443443
configParams := NewDefaultConfigParams()
444444

445-
masterApRes := make(map[string]string)
445+
masterApRes := AppProtectResources{}
446446
result, warnings := generateNginxCfgForMergeableIngresses(mergeableIngresses, masterApRes, configParams, isPlus, false, &StaticConfigParams{}, false)
447447

448448
if !reflect.DeepEqual(result.Servers[0].JWTAuth, expected.Servers[0].JWTAuth) {
@@ -837,8 +837,8 @@ func TestGenerateNginxCfgForSpiffe(t *testing.T) {
837837
expected.Servers[0].Locations[i].SSL = true
838838
}
839839

840-
apResources := make(map[string]string)
841-
result, warnings := generateNginxCfg(&cafeIngressEx, apResources, false, configParams, isPlus, false,
840+
apResources := AppProtectResources{}
841+
result, warnings := generateNginxCfg(&cafeIngressEx, apResources, false, configParams, false, false,
842842
&StaticConfigParams{NginxServiceMesh: true}, false)
843843

844844
if diff := cmp.Diff(expected, result); diff != "" {
@@ -861,8 +861,8 @@ func TestGenerateNginxCfgForInternalRoute(t *testing.T) {
861861
expected.Servers[0].SpiffeCerts = true
862862
expected.Ingress.Annotations[internalRouteAnnotation] = "true"
863863

864-
apResources := make(map[string]string)
865-
result, warnings := generateNginxCfg(&cafeIngressEx, apResources, false, configParams, isPlus, false,
864+
apResources := AppProtectResources{}
865+
result, warnings := generateNginxCfg(&cafeIngressEx, apResources, false, configParams, false, false,
866866
&StaticConfigParams{NginxServiceMesh: true, EnableInternalRoutes: true}, false)
867867

868868
if diff := cmp.Diff(expected, result); diff != "" {
@@ -1311,19 +1311,23 @@ func TestGenerateNginxCfgForAppProtect(t *testing.T) {
13111311
},
13121312
},
13131313
}
1314-
cafeIngressEx.AppProtectLogConf = &unstructured.Unstructured{
1315-
Object: map[string]interface{}{
1316-
"metadata": map[string]interface{}{
1317-
"namespace": "default",
1318-
"name": "logconf",
1314+
cafeIngressEx.AppProtectLogs = []AppProtectLog{
1315+
{
1316+
LogConf: &unstructured.Unstructured{
1317+
Object: map[string]interface{}{
1318+
"metadata": map[string]interface{}{
1319+
"namespace": "default",
1320+
"name": "logconf",
1321+
},
1322+
},
13191323
},
13201324
},
13211325
}
13221326

13231327
configParams := NewDefaultConfigParams()
1324-
apRes := map[string]string{
1325-
appProtectPolicyKey: "/etc/nginx/waf/nac-policies/default_dataguard-alarm",
1326-
appProtectLogConfKey: "/etc/nginx/waf/nac-logconfs/default_logconf syslog:server=127.0.0.1:514",
1328+
apRes := AppProtectResources{
1329+
AppProtectPolicy: "/etc/nginx/waf/nac-policies/default_dataguard-alarm",
1330+
AppProtectLogconfs: []string{"/etc/nginx/waf/nac-logconfs/default_logconf syslog:server=127.0.0.1:514"},
13271331
}
13281332
staticCfgParams := &StaticConfigParams{
13291333
MainAppProtectLoadModule: true,
@@ -1334,7 +1338,7 @@ func TestGenerateNginxCfgForAppProtect(t *testing.T) {
13341338
expected := createExpectedConfigForCafeIngressEx(isPlus)
13351339
expected.Servers[0].AppProtectEnable = "on"
13361340
expected.Servers[0].AppProtectPolicy = "/etc/nginx/waf/nac-policies/default_dataguard-alarm"
1337-
expected.Servers[0].AppProtectLogConf = "/etc/nginx/waf/nac-logconfs/default_logconf syslog:server=127.0.0.1:514"
1341+
expected.Servers[0].AppProtectLogConfs = []string{"/etc/nginx/waf/nac-logconfs/default_logconf syslog:server=127.0.0.1:514"}
13381342
expected.Servers[0].AppProtectLogEnable = "on"
13391343
expected.Ingress.Annotations = cafeIngressEx.Ingress.Annotations
13401344

@@ -1359,19 +1363,23 @@ func TestGenerateNginxCfgForMergeableIngressesForAppProtect(t *testing.T) {
13591363
},
13601364
},
13611365
}
1362-
mergeableIngresses.Master.AppProtectLogConf = &unstructured.Unstructured{
1363-
Object: map[string]interface{}{
1364-
"metadata": map[string]interface{}{
1365-
"namespace": "default",
1366-
"name": "logconf",
1366+
mergeableIngresses.Master.AppProtectLogs = []AppProtectLog{
1367+
{
1368+
LogConf: &unstructured.Unstructured{
1369+
Object: map[string]interface{}{
1370+
"metadata": map[string]interface{}{
1371+
"namespace": "default",
1372+
"name": "logconf",
1373+
},
1374+
},
13671375
},
13681376
},
13691377
}
13701378

13711379
configParams := NewDefaultConfigParams()
1372-
apRes := map[string]string{
1373-
appProtectPolicyKey: "/etc/nginx/waf/nac-policies/default_dataguard-alarm",
1374-
appProtectLogConfKey: "/etc/nginx/waf/nac-logconfs/default_logconf syslog:server=127.0.0.1:514",
1380+
apRes := AppProtectResources{
1381+
AppProtectPolicy: "/etc/nginx/waf/nac-policies/default_dataguard-alarm",
1382+
AppProtectLogconfs: []string{"/etc/nginx/waf/nac-logconfs/default_logconf syslog:server=127.0.0.1:514"},
13751383
}
13761384
staticCfgParams := &StaticConfigParams{
13771385
MainAppProtectLoadModule: true,
@@ -1382,7 +1390,7 @@ func TestGenerateNginxCfgForMergeableIngressesForAppProtect(t *testing.T) {
13821390
expected := createExpectedConfigForMergeableCafeIngress(isPlus)
13831391
expected.Servers[0].AppProtectEnable = "on"
13841392
expected.Servers[0].AppProtectPolicy = "/etc/nginx/waf/nac-policies/default_dataguard-alarm"
1385-
expected.Servers[0].AppProtectLogConf = "/etc/nginx/waf/nac-logconfs/default_logconf syslog:server=127.0.0.1:514"
1393+
expected.Servers[0].AppProtectLogConfs = []string{"/etc/nginx/waf/nac-logconfs/default_logconf syslog:server=127.0.0.1:514"}
13861394
expected.Servers[0].AppProtectLogEnable = "on"
13871395
expected.Ingress.Annotations = mergeableIngresses.Master.Ingress.Annotations
13881396

internal/configs/version1/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ type Server struct {
9797
SSLPorts []int
9898
AppProtectEnable string
9999
AppProtectPolicy string
100-
AppProtectLogConf string
100+
AppProtectLogConfs []string
101101
AppProtectLogEnable string
102102

103103
SpiffeCerts bool

internal/configs/version1/nginx-plus.ingress.tmpl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ server {
7070
{{- end}}
7171
{{- if $server.AppProtectLogEnable}}
7272
app_protect_security_log_enable {{$server.AppProtectLogEnable}};
73-
{{if $server.AppProtectLogConf}}app_protect_security_log {{$server.AppProtectLogConf}};{{end}}
73+
{{range $AppProtectLogConf := $server.AppProtectLogConfs}}app_protect_security_log {{$AppProtectLogConf}};
74+
{{end}}
7475
{{- end}}
7576

7677
{{if not $server.GRPCOnly}}

0 commit comments

Comments
 (0)
0