Skip to content

Commit c195bba

Browse files
authored
refactor: support direct rule evaluation (#239)
## Issue N/A ## Description Refactor to support direct, in-process evaluation of network rules. Required by: - validator-labs/validatorctl#102 Related: - validator-labs/validator-plugin-aws#450 --------- Signed-off-by: Tyler Gillson <tyler.gillson@gmail.com>
1 parent c280e89 commit c195bba

File tree

13 files changed

+144
-123
lines changed

13 files changed

+144
-123
lines changed

api/v1alpha1/networkvalidator_types.go

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ package v1alpha1
1818

1919
import (
2020
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
22+
"github.com/validator-labs/validator-plugin-network/pkg/constants"
2123
)
2224

2325
// NetworkValidatorSpec defines the desired state of NetworkValidator
@@ -50,6 +52,16 @@ type NetworkValidatorSpec struct {
5052
CACerts CACertificates `json:"caCerts,omitempty" yaml:"caCerts,omitempty"`
5153
}
5254

55+
// PluginCode returns the network validator's plugin code.
56+
func (s NetworkValidatorSpec) PluginCode() string {
57+
return constants.PluginCode
58+
}
59+
60+
// ResultCount returns the number of validation results expected for a NetworkValidatorSpec.
61+
func (s NetworkValidatorSpec) ResultCount() int {
62+
return len(s.DNSRules) + len(s.ICMPRules) + len(s.IPRangeRules) + len(s.MTURules) + len(s.TCPConnRules) + len(s.HTTPFileRules)
63+
}
64+
5365
// CACertificates contains configuration for additional CA certificates to use for TLS. Can be certs
5466
// provided inline or secret references. Secrets are assumed to be in the same namespace as the
5567
// NetworkValidator.
@@ -62,6 +74,16 @@ type CACertificates struct {
6274
SecretRefs []CASecretReference `json:"secretRefs,omitempty" yaml:"secretRefs,omitempty"`
6375
}
6476

77+
// RawCerts returns the raw certificates included in a CACertificates.
78+
// SecretRefs are not included.
79+
func (c CACertificates) RawCerts() [][]byte {
80+
certs := make([][]byte, 0, len(c.Certs))
81+
for _, cert := range c.Certs {
82+
certs = append(certs, []byte(cert))
83+
}
84+
return certs
85+
}
86+
6587
// Certificate is a certificate specified inline.
6688
// +kubebuilder:validation:MinLength=1
6789
type Certificate string
@@ -81,11 +103,6 @@ func (r CASecretReference) Keys() []string {
81103
return []string{r.Key}
82104
}
83105

84-
// ResultCount returns the number of validation results expected for a NetworkValidatorSpec.
85-
func (s NetworkValidatorSpec) ResultCount() int {
86-
return len(s.DNSRules) + len(s.ICMPRules) + len(s.IPRangeRules) + len(s.MTURules) + len(s.TCPConnRules) + len(s.HTTPFileRules)
87-
}
88-
89106
// DNSRule defines a DNS validation rule.
90107
type DNSRule struct {
91108
// RuleName is a unique identifier for the rule in the validator. Used to ensure conditions do not overwrite each other.
@@ -218,6 +235,16 @@ type NetworkValidator struct {
218235
Status NetworkValidatorStatus `json:"status,omitempty"`
219236
}
220237

238+
// PluginCode returns the network validator's plugin code.
239+
func (v NetworkValidator) PluginCode() string {
240+
return v.Spec.PluginCode()
241+
}
242+
243+
// ResultCount returns the number of validation results expected for a NetworkValidator.
244+
func (v NetworkValidator) ResultCount() int {
245+
return v.Spec.ResultCount()
246+
}
247+
221248
//+kubebuilder:object:root=true
222249

223250
// NetworkValidatorList contains a list of NetworkValidator

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ require (
66
github.com/go-logr/logr v1.4.2
77
github.com/onsi/ginkgo/v2 v2.19.1
88
github.com/onsi/gomega v1.34.1
9-
github.com/validator-labs/validator v0.0.50
9+
github.com/validator-labs/validator v0.1.1
1010
k8s.io/api v0.30.3
1111
k8s.io/apimachinery v0.30.3
1212
k8s.io/client-go v0.30.3
@@ -72,3 +72,5 @@ require (
7272
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
7373
sigs.k8s.io/yaml v1.4.0 // indirect
7474
)
75+
76+
// replace github.com/validator-labs/validator => ../validator

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
132132
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
133133
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
134134
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
135-
github.com/validator-labs/validator v0.0.50 h1:8h0Dy1Hl0818WuTF8hgZ3HaNxUtGSm130Zrp7f7vjGw=
136-
github.com/validator-labs/validator v0.0.50/go.mod h1:YxUKAXuSR6fIAi7WCQV/Wbrzf9szf8aCTeYWEA+JyIY=
135+
github.com/validator-labs/validator v0.1.1 h1:BzUWeSAP5eGHX2oOulJWZxXr+Zz6Uh6ZqP5sYudnv3I=
136+
github.com/validator-labs/validator v0.1.1/go.mod h1:to8CMM+LlTcEzbqxVyHND9/uJO2+ORTFk9ovqVOnCU8=
137137
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
138138
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
139139
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=

internal/controller/networkvalidator_controller.go

Lines changed: 16 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,20 @@ package controller
1919

2020
import (
2121
"context"
22-
"fmt"
2322
"time"
2423

2524
"github.com/go-logr/logr"
2625
apierrs "k8s.io/apimachinery/pkg/api/errors"
27-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2826
"k8s.io/apimachinery/pkg/runtime"
2927
ktypes "k8s.io/apimachinery/pkg/types"
3028
"sigs.k8s.io/cluster-api/util/patch"
3129
ctrl "sigs.k8s.io/controller-runtime"
3230
"sigs.k8s.io/controller-runtime/pkg/client"
3331

3432
"github.com/validator-labs/validator-plugin-network/api/v1alpha1"
35-
"github.com/validator-labs/validator-plugin-network/internal/constants"
36-
"github.com/validator-labs/validator-plugin-network/internal/http"
37-
"github.com/validator-labs/validator-plugin-network/internal/secrets"
38-
"github.com/validator-labs/validator-plugin-network/internal/validators"
33+
"github.com/validator-labs/validator-plugin-network/pkg/secrets"
34+
"github.com/validator-labs/validator-plugin-network/pkg/validate"
3935
vapi "github.com/validator-labs/validator/api/v1alpha1"
40-
"github.com/validator-labs/validator/pkg/types"
41-
"github.com/validator-labs/validator/pkg/util"
4236
vres "github.com/validator-labs/validator/pkg/validationresult"
4337
)
4438

@@ -74,16 +68,16 @@ func (r *NetworkValidatorReconciler) Reconcile(ctx context.Context, req ctrl.Req
7468
return ctrl.Result{}, err
7569
}
7670
nn := ktypes.NamespacedName{
77-
Name: validationResultName(validator),
71+
Name: vres.Name(validator),
7872
Namespace: req.Namespace,
7973
}
8074
if err := r.Get(ctx, nn, vr); err == nil {
81-
vres.HandleExistingValidationResult(vr, r.Log)
75+
vres.HandleExisting(vr, r.Log)
8276
} else {
8377
if !apierrs.IsNotFound(err) {
8478
l.Error(err, "unexpected error getting ValidationResult")
8579
}
86-
if err := vres.HandleNewValidationResult(ctx, r.Client, p, buildValidationResult(validator), r.Log); err != nil {
80+
if err := vres.HandleNew(ctx, r.Client, p, vres.Build(validator), r.Log); err != nil {
8781
return ctrl.Result{}, err
8882
}
8983
return ctrl.Result{RequeueAfter: time.Millisecond}, nil
@@ -92,18 +86,9 @@ func (r *NetworkValidatorReconciler) Reconcile(ctx context.Context, req ctrl.Req
9286
// Always update the expected result count in case the validator's rules have changed
9387
vr.Spec.ExpectedResults = validator.Spec.ResultCount()
9488

95-
resp := types.ValidationResponse{
96-
ValidationRuleResults: make([]*types.ValidationRuleResult, 0, vr.Spec.ExpectedResults),
97-
ValidationRuleErrors: make([]error, 0, vr.Spec.ExpectedResults),
98-
}
99-
100-
networkService := validators.NewNetworkService(r.Log)
89+
// Fetch additional CAs to augment the system cert pool
90+
caPems := validator.Spec.CACerts.RawCerts()
10191

102-
// If CACert config provided, use the inline certs and secret refs.
103-
caPems := make([][]byte, 0)
104-
for _, cert := range validator.Spec.CACerts.Certs {
105-
caPems = append(caPems, []byte(cert))
106-
}
10792
for _, secretRef := range validator.Spec.CACerts.SecretRefs {
10893
caPem, err := secrets.ReadKeys(secretRef.Name, req.Namespace, []string{secretRef.Key}, r.Client)
10994
if err != nil {
@@ -113,57 +98,25 @@ func (r *NetworkValidatorReconciler) Reconcile(ctx context.Context, req ctrl.Req
11398
caPems = append(caPems, caPem[0])
11499
}
115100

116-
// DNS rules
117-
for _, rule := range validator.Spec.DNSRules {
118-
vrr := networkService.ReconcileDNSRule(rule)
119-
resp.AddResult(vrr, err)
120-
}
121-
122-
// ICMP rules
123-
for _, rule := range validator.Spec.ICMPRules {
124-
vrr := networkService.ReconcileICMPRule(rule)
125-
resp.AddResult(vrr, err)
126-
}
127-
128-
// IP range rules
129-
for _, rule := range validator.Spec.IPRangeRules {
130-
vrr := networkService.ReconcileIPRangeRule(rule)
131-
resp.AddResult(vrr, err)
132-
}
133-
134-
// MTU rules
135-
for _, rule := range validator.Spec.MTURules {
136-
vrr := networkService.ReconcileMTURule(rule)
137-
resp.AddResult(vrr, err)
138-
}
139-
140-
// TCP connection rules
141-
for _, rule := range validator.Spec.TCPConnRules {
142-
tlsConfig := http.TLSConfig(caPems, rule.InsecureSkipTLSVerify, r.Log)
143-
ruleSvc := validators.NewNetworkService(r.Log, validators.WithTLSConfig(tlsConfig))
144-
vrr := ruleSvc.ReconcileTCPConnRule(rule)
145-
resp.AddResult(vrr, err)
146-
}
147-
148-
// HTTP file rules
101+
// Fetch HTTP basic auth credentials
102+
auths := make([][][]byte, len(validator.Spec.HTTPFileRules))
149103
for _, rule := range validator.Spec.HTTPFileRules {
150104
var auth [][]byte
151105
if rule.AuthSecretRef != nil {
152106
auth, err = secrets.ReadKeys(rule.AuthSecretRef.Name, req.Namespace, rule.AuthSecretRef.Keys(), r.Client)
153107
if err != nil {
154-
vrr := validators.BuildValidationResult(rule, constants.ValidationTypeHTTPFile)
155-
resp.AddResult(vrr, fmt.Errorf("failed to parse HTTP basic auth: %w", err))
156-
continue
108+
r.Log.Error(err, "failed to parse HTTP basic auth", "rule", rule.RuleName)
109+
return ctrl.Result{}, err
157110
}
158111
}
159-
transport := http.Transport(caPems, auth, rule.InsecureSkipTLSVerify, r.Log)
160-
ruleSvc := validators.NewNetworkService(r.Log, validators.WithTransport(transport))
161-
vrr := ruleSvc.ReconcileHTTPFileRule(rule)
162-
resp.AddResult(vrr, err)
112+
auths = append(auths, auth)
163113
}
164114

115+
// Validate the rules
116+
resp := validate.Validate(validator.Spec, caPems, auths, r.Log)
117+
165118
// Patch the ValidationResult with the latest ValidationRuleResults
166-
if err := vres.SafeUpdateValidationResult(ctx, p, vr, resp, r.Log); err != nil {
119+
if err := vres.SafeUpdate(ctx, p, vr, resp, r.Log); err != nil {
167120
return ctrl.Result{}, err
168121
}
169122

@@ -177,29 +130,3 @@ func (r *NetworkValidatorReconciler) SetupWithManager(mgr ctrl.Manager) error {
177130
For(&v1alpha1.NetworkValidator{}).
178131
Complete(r)
179132
}
180-
181-
func buildValidationResult(validator *v1alpha1.NetworkValidator) *vapi.ValidationResult {
182-
return &vapi.ValidationResult{
183-
ObjectMeta: metav1.ObjectMeta{
184-
Name: validationResultName(validator),
185-
Namespace: validator.Namespace,
186-
OwnerReferences: []metav1.OwnerReference{
187-
{
188-
APIVersion: validator.APIVersion,
189-
Kind: validator.Kind,
190-
Name: validator.Name,
191-
UID: validator.UID,
192-
Controller: util.Ptr(true),
193-
},
194-
},
195-
},
196-
Spec: vapi.ValidationResultSpec{
197-
Plugin: constants.PluginCode,
198-
ExpectedResults: validator.Spec.ResultCount(),
199-
},
200-
}
201-
}
202-
203-
func validationResultName(validator *v1alpha1.NetworkValidator) string {
204-
return fmt.Sprintf("validator-plugin-network-%s", validator.Name)
205-
}

internal/controller/networkvalidator_controller_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515

1616
"github.com/validator-labs/validator-plugin-network/api/v1alpha1"
1717
vapi "github.com/validator-labs/validator/api/v1alpha1"
18+
vres "github.com/validator-labs/validator/pkg/validationresult"
1819
//+kubebuilder:scaffold:imports
1920
)
2021

@@ -95,7 +96,7 @@ var _ = Describe("NetworkValidator controller", Ordered, func() {
9596
}
9697

9798
vr := &vapi.ValidationResult{}
98-
vrKey := types.NamespacedName{Name: validationResultName(val), Namespace: validatorNamespace}
99+
vrKey := types.NamespacedName{Name: vres.Name(val), Namespace: validatorNamespace}
99100

100101
It("Should create a ValidationResult and update its Status", func() {
101102
By("By creating a new NetworkValidator")
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)