Skip to content

Commit 5c5e1d9

Browse files
authored
Implement basic file fetcher (#3577)
Problem: As a user I want NGF to fetch my NAP WAF Policy bundle from a remote location So that this bundle can be applied by the data plane to protect my traffic Solution: Create a Policy Fetcher utility in framework which can pull files from a remote location, as configured in the WafPolicy resource. Implement policy validation via Checksum validation (compute checksum locally and compare to remote provided checksum).
1 parent d3c3c8d commit 5c5e1d9

File tree

5 files changed

+732
-8
lines changed

5 files changed

+732
-8
lines changed

docs/proposals/nap-waf.md

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,9 @@ sha256sum compiled-policy.tgz > compiled-policy.tgz.sha256
296296
aws s3 cp compiled-policy.tgz s3://company-policies/prod-policy.tgz
297297
aws s3 cp compiled-policy.tgz.sha256 s3://company-policies/prod-policy.tgz.sha256
298298

299+
# Note: In WAFPolicy, reference S3 objects using HTTPS URLs:
300+
# fileLocation: "https://company-policies.s3.amazonaws.com/prod-policy.tgz"
301+
299302
# No Kubernetes resource changes needed - NGF automatically detects the update
300303
echo "Policy updated. NGF will detect changes within polling interval."
301304
```
@@ -427,6 +430,8 @@ spec:
427430

428431
### WAFPolicy Custom Resource with Policy Attachment
429432

433+
**Note**: When referencing S3 objects, use HTTPS URLs (e.g., `https://bucket.s3.amazonaws.com/path/file.tgz`) rather than S3 protocol URLs (`s3://bucket/path/file.tgz`).
434+
430435
```yaml
431436
apiVersion: gateway.nginx.org/v1alpha1
432437
kind: WAFPolicy
@@ -442,7 +447,7 @@ spec:
442447
namespace: applications
443448

444449
policySource:
445-
fileLocation: "s3://ngf-waf-policies/production/gateway-policy-v1.2.3.tgz"
450+
fileLocation: "https://ngf-waf-policies.s3.amazonaws.com/production/gateway-policy-v1.2.3.tgz"
446451
authSecret:
447452
name: "policy-store-credentials"
448453
validation:
@@ -456,7 +461,7 @@ spec:
456461
interval: "5m" # Check every 5 minutes
457462
# Optional: explicit checksum location
458463
# If not specified, defaults to <fileLocation>.sha256
459-
checksumLocation: "s3://ngf-waf-policies/production/gateway-policy-v1.2.3.tgz"
464+
checksumLocation: "https://ngf-waf-policies.s3.amazonaws.com/production/gateway-policy-v1.2.3.tgz.sha256"
460465

461466
# Retry configuration for policy fetch failures
462467
retryPolicy:
@@ -480,7 +485,7 @@ spec:
480485
# Custom logging profile bundle (similar to policy bundle)
481486
# logProfile and logProfileBundle are mutually exclusive per security log configuration entry
482487
logProfileBundle:
483-
fileLocation: "s3://ngf-waf-policies/logging/custom-log-profile.tgz"
488+
fileLocation: "https://ngf-waf-policies.s3.amazonaws.com/logging/custom-log-profile.tgz"
484489
authSecret:
485490
name: "policy-store-credentials"
486491
validation:
@@ -527,7 +532,7 @@ spec:
527532

528533
# Stricter policy for admin endpoints
529534
policySource:
530-
fileLocation: "s3://ngf-waf-policies/production/admin-strict-policy-v1.0.0.tgz"
535+
fileLocation: "https://ngf-waf-policies.s3.amazonaws.com/production/admin-strict-policy-v1.0.0.tgz"
531536
authSecret:
532537
name: "policy-store-credentials"
533538
polling:
@@ -664,7 +669,7 @@ metadata:
664669
# NGF service account in nginx-gateway namespace provides IRSA authentication
665670
spec:
666671
policySource:
667-
fileLocation: "s3://company-waf-policies/policy.tgz"
672+
fileLocation: "https://company-waf-policies.s3.amazonaws.com/policy.tgz"
668673
# No authSecret needed - uses IRSA automatically
669674
```
670675

@@ -1009,7 +1014,7 @@ spec:
10091014
namespace: applications
10101015
10111016
policySource:
1012-
fileLocation: "s3://company-waf-policies/production/base-policy.tgz"
1017+
fileLocation: "https://company-waf-policies.s3.amazonaws.com/production/base-policy.tgz"
10131018
# Secret referenced for fallback - NGF will use IRSA if available, secret if not
10141019
authSecret:
10151020
name: "policy-store-credentials"
@@ -1020,7 +1025,7 @@ spec:
10201025
interval: "5m"
10211026
# Optional explicit checksum location
10221027
# If not specified, defaults to base-policy.tgz.sha256
1023-
checksumLocation: "s3://company-waf-policies/production/base-policy.tgz.sha256"
1028+
checksumLocation: "https://company-waf-policies.s3.amazonaws.com/production/base-policy.tgz.sha256"
10241029
10251030
securityLogs:
10261031
- name: "gateway-logging"
@@ -1044,7 +1049,7 @@ spec:
10441049
namespace: applications
10451050
10461051
policySource:
1047-
fileLocation: "s3://company-waf-policies/production/admin-strict-policy.tgz"
1052+
fileLocation: "https://company-waf-policies.s3.amazonaws.com/production/admin-strict-policy.tgz"
10481053
polling:
10491054
enabled: true
10501055

internal/framework/fetch/errors.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package fetch
2+
3+
import "fmt"
4+
5+
// ChecksumMismatchError represents an error when the calculated checksum doesn't match the expected checksum.
6+
// This type of error should not trigger retries as it indicates data corruption or tampering.
7+
type ChecksumMismatchError struct {
8+
Expected string
9+
Actual string
10+
}
11+
12+
func (e *ChecksumMismatchError) Error() string {
13+
return fmt.Sprintf("checksum mismatch: expected %s, got %s", e.Expected, e.Actual)
14+
}
15+
16+
// HTTPStatusError represents an HTTP status code error for retry logic.
17+
type HTTPStatusError struct {
18+
StatusCode int
19+
}
20+
21+
func (e *HTTPStatusError) Error() string {
22+
return fmt.Sprintf("unexpected status code: %d", e.StatusCode)
23+
}

0 commit comments

Comments
 (0)