Skip to content

Commit a7f003f

Browse files
committed
Implement WAFPolicy controller
1 parent e11a235 commit a7f003f

File tree

38 files changed

+3027
-25
lines changed

38 files changed

+3027
-25
lines changed

apis/v1alpha1/wafpolicy_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ type WAFPolicySpec struct {
5959
}
6060

6161
// WAFPolicySource defines the source location and configuration for fetching WAF policy bundles.
62+
//
63+
// +kubebuilder:validation:XValidation:message="policySource is required when securityLogs are specified",rule="!has(self.securityLogs) || has(self.policySource)"
64+
//
65+
//nolint:lll
6266
type WAFPolicySource struct {
6367
// AuthSecret is the Secret containing authentication credentials for the WAF policy source.
6468
//

charts/nginx-gateway-fabric/templates/clusterrole.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ rules:
109109
- clientsettingspolicies
110110
- observabilitypolicies
111111
- upstreamsettingspolicies
112+
- wafpolicies
112113
{{- if .Values.nginxGateway.snippetsFilters.enable }}
113114
- snippetsfilters
114115
{{- end }}
@@ -122,6 +123,7 @@ rules:
122123
- clientsettingspolicies/status
123124
- observabilitypolicies/status
124125
- upstreamsettingspolicies/status
126+
- wafpolicies/status
125127
{{- if .Values.nginxGateway.snippetsFilters.enable }}
126128
- snippetsfilters/status
127129
{{- end }}

config/crd/bases/gateway.nginx.org_wafpolicies.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ spec:
151151
required:
152152
- fileLocation
153153
type: object
154+
x-kubernetes-validations:
155+
- message: policySource is required when securityLogs are specified
156+
rule: '!has(self.securityLogs) || has(self.policySource)'
154157
securityLogs:
155158
description: |-
156159
SecurityLogs defines the security logging configuration for app_protect_security_log directives.
@@ -331,6 +334,9 @@ spec:
331334
required:
332335
- fileLocation
333336
type: object
337+
x-kubernetes-validations:
338+
- message: policySource is required when securityLogs are specified
339+
rule: '!has(self.securityLogs) || has(self.policySource)'
334340
name:
335341
description: Name is the name of the security log configuration.
336342
maxLength: 63

deploy/azure/deploy.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ rules:
145145
- clientsettingspolicies
146146
- observabilitypolicies
147147
- upstreamsettingspolicies
148+
- wafpolicies
148149
verbs:
149150
- list
150151
- watch
@@ -155,6 +156,7 @@ rules:
155156
- clientsettingspolicies/status
156157
- observabilitypolicies/status
157158
- upstreamsettingspolicies/status
159+
- wafpolicies/status
158160
verbs:
159161
- update
160162
- apiGroups:

deploy/default/deploy.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ rules:
145145
- clientsettingspolicies
146146
- observabilitypolicies
147147
- upstreamsettingspolicies
148+
- wafpolicies
148149
verbs:
149150
- list
150151
- watch
@@ -155,6 +156,7 @@ rules:
155156
- clientsettingspolicies/status
156157
- observabilitypolicies/status
157158
- upstreamsettingspolicies/status
159+
- wafpolicies/status
158160
verbs:
159161
- update
160162
- apiGroups:

deploy/experimental-nginx-plus/deploy.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ rules:
149149
- clientsettingspolicies
150150
- observabilitypolicies
151151
- upstreamsettingspolicies
152+
- wafpolicies
152153
verbs:
153154
- list
154155
- watch
@@ -159,6 +160,7 @@ rules:
159160
- clientsettingspolicies/status
160161
- observabilitypolicies/status
161162
- upstreamsettingspolicies/status
163+
- wafpolicies/status
162164
verbs:
163165
- update
164166
- apiGroups:

deploy/experimental/deploy.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ rules:
149149
- clientsettingspolicies
150150
- observabilitypolicies
151151
- upstreamsettingspolicies
152+
- wafpolicies
152153
verbs:
153154
- list
154155
- watch
@@ -159,6 +160,7 @@ rules:
159160
- clientsettingspolicies/status
160161
- observabilitypolicies/status
161162
- upstreamsettingspolicies/status
163+
- wafpolicies/status
162164
verbs:
163165
- update
164166
- apiGroups:

deploy/nginx-plus/deploy.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ rules:
145145
- clientsettingspolicies
146146
- observabilitypolicies
147147
- upstreamsettingspolicies
148+
- wafpolicies
148149
verbs:
149150
- list
150151
- watch
@@ -155,6 +156,7 @@ rules:
155156
- clientsettingspolicies/status
156157
- observabilitypolicies/status
157158
- upstreamsettingspolicies/status
159+
- wafpolicies/status
158160
verbs:
159161
- update
160162
- apiGroups:

deploy/nodeport/deploy.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ rules:
145145
- clientsettingspolicies
146146
- observabilitypolicies
147147
- upstreamsettingspolicies
148+
- wafpolicies
148149
verbs:
149150
- list
150151
- watch
@@ -155,6 +156,7 @@ rules:
155156
- clientsettingspolicies/status
156157
- observabilitypolicies/status
157158
- upstreamsettingspolicies/status
159+
- wafpolicies/status
158160
verbs:
159161
- update
160162
- apiGroups:

deploy/openshift/deploy.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ rules:
145145
- clientsettingspolicies
146146
- observabilitypolicies
147147
- upstreamsettingspolicies
148+
- wafpolicies
148149
verbs:
149150
- list
150151
- watch
@@ -155,6 +156,7 @@ rules:
155156
- clientsettingspolicies/status
156157
- observabilitypolicies/status
157158
- upstreamsettingspolicies/status
159+
- wafpolicies/status
158160
verbs:
159161
- update
160162
- apiGroups:

deploy/snippets-filters-nginx-plus/deploy.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ rules:
145145
- clientsettingspolicies
146146
- observabilitypolicies
147147
- upstreamsettingspolicies
148+
- wafpolicies
148149
- snippetsfilters
149150
verbs:
150151
- list
@@ -156,6 +157,7 @@ rules:
156157
- clientsettingspolicies/status
157158
- observabilitypolicies/status
158159
- upstreamsettingspolicies/status
160+
- wafpolicies/status
159161
- snippetsfilters/status
160162
verbs:
161163
- update

deploy/snippets-filters/deploy.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ rules:
145145
- clientsettingspolicies
146146
- observabilitypolicies
147147
- upstreamsettingspolicies
148+
- wafpolicies
148149
- snippetsfilters
149150
verbs:
150151
- list
@@ -156,6 +157,7 @@ rules:
156157
- clientsettingspolicies/status
157158
- observabilitypolicies/status
158159
- upstreamsettingspolicies/status
160+
- wafpolicies/status
159161
- snippetsfilters/status
160162
verbs:
161163
- update

internal/controller/manager.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import (
4848
"github.com/nginx/nginx-gateway-fabric/internal/controller/nginx/config/policies/clientsettings"
4949
"github.com/nginx/nginx-gateway-fabric/internal/controller/nginx/config/policies/observability"
5050
"github.com/nginx/nginx-gateway-fabric/internal/controller/nginx/config/policies/upstreamsettings"
51+
"github.com/nginx/nginx-gateway-fabric/internal/controller/nginx/config/policies/wafsettings"
5152
ngxvalidation "github.com/nginx/nginx-gateway-fabric/internal/controller/nginx/config/validation"
5253
"github.com/nginx/nginx-gateway-fabric/internal/controller/provisioner"
5354
"github.com/nginx/nginx-gateway-fabric/internal/controller/state"
@@ -326,6 +327,10 @@ func createPolicyManager(
326327
GVK: mustExtractGVK(&ngfAPIv1alpha1.UpstreamSettingsPolicy{}),
327328
Validator: upstreamsettings.NewValidator(validator),
328329
},
330+
{
331+
GVK: mustExtractGVK(&ngfAPIv1alpha1.WAFPolicy{}),
332+
Validator: wafsettings.NewValidator(validator),
333+
},
329334
}
330335

331336
return policies.NewManager(mustExtractGVK, cfgs...)
@@ -507,6 +512,12 @@ func registerControllers(
507512
controller.WithK8sPredicate(k8spredicate.GenerationChangedPredicate{}),
508513
},
509514
},
515+
{
516+
objectType: &ngfAPIv1alpha1.WAFPolicy{},
517+
options: []controller.Option{
518+
controller.WithK8sPredicate(k8spredicate.GenerationChangedPredicate{}),
519+
},
520+
},
510521
}
511522

512523
if cfg.ExperimentalFeatures {
@@ -745,6 +756,7 @@ func prepareFirstEventBatchPreparerArgs(cfg config.Config) ([]client.Object, []c
745756
&ngfAPIv1alpha1.ClientSettingsPolicyList{},
746757
&ngfAPIv1alpha2.ObservabilityPolicyList{},
747758
&ngfAPIv1alpha1.UpstreamSettingsPolicyList{},
759+
&ngfAPIv1alpha1.WAFPolicyList{},
748760
partialObjectMetadataList,
749761
}
750762

internal/controller/manager_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ func TestPrepareFirstEventBatchPreparerArgs(t *testing.T) {
6868
&ngfAPIv1alpha1.ClientSettingsPolicyList{},
6969
&ngfAPIv1alpha2.ObservabilityPolicyList{},
7070
&ngfAPIv1alpha1.UpstreamSettingsPolicyList{},
71+
&ngfAPIv1alpha1.WAFPolicyList{},
7172
},
7273
},
7374
{
@@ -97,6 +98,7 @@ func TestPrepareFirstEventBatchPreparerArgs(t *testing.T) {
9798
&ngfAPIv1alpha1.ClientSettingsPolicyList{},
9899
&ngfAPIv1alpha2.ObservabilityPolicyList{},
99100
&ngfAPIv1alpha1.UpstreamSettingsPolicyList{},
101+
&ngfAPIv1alpha1.WAFPolicyList{},
100102
},
101103
},
102104
{
@@ -124,6 +126,7 @@ func TestPrepareFirstEventBatchPreparerArgs(t *testing.T) {
124126
&ngfAPIv1alpha2.ObservabilityPolicyList{},
125127
&ngfAPIv1alpha1.SnippetsFilterList{},
126128
&ngfAPIv1alpha1.UpstreamSettingsPolicyList{},
129+
&ngfAPIv1alpha1.WAFPolicyList{},
127130
},
128131
},
129132
{
@@ -154,6 +157,7 @@ func TestPrepareFirstEventBatchPreparerArgs(t *testing.T) {
154157
&ngfAPIv1alpha2.ObservabilityPolicyList{},
155158
&ngfAPIv1alpha1.SnippetsFilterList{},
156159
&ngfAPIv1alpha1.UpstreamSettingsPolicyList{},
160+
&ngfAPIv1alpha1.WAFPolicyList{},
157161
},
158162
},
159163
}

internal/controller/nginx/config/generator.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/nginx/nginx-gateway-fabric/internal/controller/nginx/config/policies/clientsettings"
1717
"github.com/nginx/nginx-gateway-fabric/internal/controller/nginx/config/policies/observability"
1818
"github.com/nginx/nginx-gateway-fabric/internal/controller/nginx/config/policies/upstreamsettings"
19+
"github.com/nginx/nginx-gateway-fabric/internal/controller/nginx/config/policies/wafsettings"
1920
"github.com/nginx/nginx-gateway-fabric/internal/controller/state/dataplane"
2021
"github.com/nginx/nginx-gateway-fabric/internal/framework/file"
2122
)
@@ -44,6 +45,9 @@ const (
4445
// includesFolder is the folder where are all include files are stored.
4546
includesFolder = configFolder + "/includes"
4647

48+
// appProtectBundleFolder is the folder where the NGINX App Protect WAF bundles are stored.
49+
appProtectBundleFolder = "/etc/app_protect/bundles"
50+
4751
// httpConfigFile is the path to the configuration file with HTTP configuration.
4852
httpConfigFile = httpFolder + "/http.conf"
4953

@@ -119,10 +123,15 @@ func (g GeneratorImpl) Generate(conf dataplane.Configuration) []agent.File {
119123
policyGenerator := policies.NewCompositeGenerator(
120124
clientsettings.NewGenerator(),
121125
observability.NewGenerator(conf.Telemetry),
126+
wafsettings.NewGenerator(),
122127
)
123128

124129
files = append(files, g.executeConfigTemplates(conf, policyGenerator)...)
125130

131+
for id, bundle := range conf.WAF.WAFBundles {
132+
files = append(files, generateWAFBundle(id, bundle))
133+
}
134+
126135
for id, bundle := range conf.CertBundles {
127136
files = append(files, generateCertBundle(id, bundle))
128137
}
@@ -245,3 +254,19 @@ func generateCertBundle(id dataplane.CertBundleID, cert []byte) agent.File {
245254
func generateCertBundleFileName(id dataplane.CertBundleID) string {
246255
return filepath.Join(secretsFolder, string(id)+".crt")
247256
}
257+
258+
func generateWAFBundle(id dataplane.WAFBundleID, bundle []byte) agent.File {
259+
return agent.File{
260+
Meta: &pb.FileMeta{
261+
Name: GenerateWAFBundleFileName(id),
262+
Hash: filesHelper.GenerateHash(bundle),
263+
Permissions: file.RegularFileMode,
264+
Size: int64(len(bundle)),
265+
},
266+
Contents: bundle,
267+
}
268+
}
269+
270+
func GenerateWAFBundleFileName(id dataplane.WAFBundleID) string {
271+
return filepath.Join(appProtectBundleFolder, string(id)+".tgz")
272+
}

internal/controller/nginx/config/policies/policy.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ type Policy interface {
2626
type GlobalSettings struct {
2727
// TelemetryEnabled is whether telemetry is enabled in the NginxProxy resource.
2828
TelemetryEnabled bool
29+
// WAFEnabled is whether WAF is enabled in the NginxProxy resource.
30+
WAFEnabled bool
2931
}
3032

3133
// ValidateTargetRef validates a policy's targetRef for the proper group and kind.

0 commit comments

Comments
 (0)