Skip to content

Commit 9f23cae

Browse files
authored
feat!: Support both inline and secret-ref based auth for http file rules (#270)
## Issue Resolves #263 ## Description - Adds an `Auth` struct which contains both a `*BasicAuthSecretReference` and a `*BasicAuth` - Modifies `Validate` func to take in a `map[string][]string` instead of a `[][][]byte`. The key for the auth for each rule is the `rule.Name()`. This addresses a TODO thats found in validatorctl: https://github.com/validator-labs/validatorctl/blob/c7408a6254238c174deb005f4ac98c1ec2f25c99/pkg/components/validator.go#L450
1 parent 4b8314e commit 9f23cae

13 files changed

+323
-70
lines changed

.gitignore

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# Binaries for programs and plugins
32
*.exe
43
*.exe~
@@ -15,14 +14,17 @@ Dockerfile.cross
1514
*.out
1615

1716
# Kubernetes Generated files - skip generated files, except for vendored files
18-
1917
!vendor/**/zz_generated.*
2018

21-
# editor and IDE paraphernalia
19+
# Editor and IDE paraphernalia
2220
.devspace
2321
.idea
2422
.vscode
2523
!.vscode/launch.json
2624
*.swp
2725
*.swo
2826
*~
27+
28+
# Misc
29+
.DS_Store
30+
tmp/*

api/v1alpha1/networkvalidator_types.go

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,32 @@ type NetworkValidatorSpec struct {
3333
// +kubebuilder:validation:MaxItems=5
3434
// +kubebuilder:validation:XValidation:message="DNSRules must have unique names",rule="self.all(e, size(self.filter(x, x.name == e.name)) == 1)"
3535
DNSRules []DNSRule `json:"dnsRules,omitempty" yaml:"dnsRules,omitempty"`
36+
3637
// ICMPRules validate ICMP pings to network hosts
3738
// +kubebuilder:validation:MaxItems=5
3839
// +kubebuilder:validation:XValidation:message="ICMPRules must have unique names",rule="self.all(e, size(self.filter(x, x.name == e.name)) == 1)"
3940
ICMPRules []ICMPRule `json:"icmpRules,omitempty" yaml:"icmpRules,omitempty"`
41+
4042
// IPRangeRules validate that all IPs in a given CIDR range are free (unallocated)
4143
// +kubebuilder:validation:MaxItems=5
4244
// +kubebuilder:validation:XValidation:message="IPRangeRules must have unique names",rule="self.all(e, size(self.filter(x, x.name == e.name)) == 1)"
4345
IPRangeRules []IPRangeRule `json:"ipRangeRules,omitempty" yaml:"ipRangeRules,omitempty"`
46+
4447
// MTURules validate that the default NIC has an MTU of at least X, where X is the provided MTU
4548
// +kubebuilder:validation:MaxItems=5
4649
// +kubebuilder:validation:XValidation:message="MTURules must have unique names",rule="self.all(e, size(self.filter(x, x.name == e.name)) == 1)"
4750
MTURules []MTURule `json:"mtuRules,omitempty" yaml:"mtuRules,omitempty"`
51+
4852
// TCPConnRules validate arbitrary TCP connections, including proxied connections
4953
// +kubebuilder:validation:MaxItems=5
5054
// +kubebuilder:validation:XValidation:message="TCPConnRules must have unique names",rule="self.all(e, size(self.filter(x, x.name == e.name)) == 1)"
5155
TCPConnRules []TCPConnRule `json:"tcpConnRules,omitempty" yaml:"tcpConnRules,omitempty"`
56+
5257
// HTTPFileRules validate that files are available via HTTP HEAD requests
5358
// +kubebuilder:validation:MaxItems=5
5459
// +kubebuilder:validation:XValidation:message="HTTPFileRules must have unique names",rule="self.all(e, size(self.filter(x, x.name == e.name)) == 1)"
5560
HTTPFileRules []HTTPFileRule `json:"httpFileRules,omitempty" yaml:"httpFileRules,omitempty"`
61+
5662
// CACerts allow additional CA certificates to be used for TLS. Applies to TCPConnRules and HTTPFileRules.
5763
CACerts CACertificates `json:"caCerts,omitempty" yaml:"caCerts,omitempty"`
5864
}
@@ -76,6 +82,7 @@ type CACertificates struct {
7682
// Certs is a list of certificates to use.
7783
// +kubebuilder:validation:MaxItems=500
7884
Certs []Certificate `json:"certs,omitempty" yaml:"certs,omitempty"`
85+
7986
// SecretRefs is a list of CA secret references to use.
8087
// +kubebuilder:validation:MaxItems=500
8188
SecretRefs []CASecretReference `json:"secretRefs,omitempty" yaml:"secretRefs,omitempty"`
@@ -100,6 +107,7 @@ type CASecretReference struct {
100107
// Name is the name of the secret.
101108
// +kubebuilder:validation:MinLength=1
102109
Name string `json:"name" yaml:"name"`
110+
103111
// Key is the key in the secret data.
104112
// +kubebuilder:validation:MinLength=1
105113
Key string `json:"key" yaml:"key"`
@@ -187,6 +195,7 @@ type MTURule struct {
187195
RuleName string `json:"name" yaml:"name"`
188196
Host string `json:"host" yaml:"host"`
189197
MTU int `json:"mtu" yaml:"mtu"`
198+
190199
// Optionally specify the size in bytes of the packet headers for the MTU ping packet.
191200
// This varies by medium, e.g. Ethernet, WiFi, etc.) and defaults to 28 bytes
192201
// (20 bytes IP header + 8 bytes ICMP header)
@@ -214,9 +223,11 @@ type TCPConnRule struct {
214223
RuleName string `json:"name" yaml:"name"`
215224
Host string `json:"host" yaml:"host"`
216225
Ports []int `json:"ports" yaml:"ports"`
226+
217227
// InsecureSkipTLSVerify controls whether the HTTP client used validate the rule skips TLS certificate verification.
218228
// Defaults to false.
219229
InsecureSkipTLSVerify bool `json:"insecureSkipTlsVerify,omitempty" yaml:"insecureSkipTlsVerify,omitempty"`
230+
220231
// Timeout is the duration to wait, in seconds, for a connection to be established. Defaults to 5 seconds.
221232
// +kubebuilder:default=5
222233
Timeout int `json:"timeout,omitempty" yaml:"timeout,omitempty"`
@@ -241,11 +252,16 @@ type HTTPFileRule struct {
241252
// RuleName is a unique identifier for the rule in the validator. Used to ensure conditions do not overwrite each other.
242253
// +kubebuilder:validation:MaxLength=500
243254
RuleName string `json:"name" yaml:"name"`
255+
244256
// Paths is a list of file paths to check. When performing HTTP requests, if any of the paths result in a non-200 OK response code, the rule fails validation.
245257
// +kubebuilder:validation:MaxItems=1000
246258
Paths []string `json:"paths" yaml:"paths"`
247-
// AuthSecretRef is an optional basic auth secret reference.
248-
AuthSecretRef *BasicAuthSecretReference `json:"authSecretRef,omitempty" yaml:"authSecretRef,omitempty"`
259+
260+
// Auth contains optional basic authentication details.
261+
// If a SecretRef is provided, the secret is used to retrieve the credentials and the inline auth is ignored.
262+
// If a SecretRef is not provided but Basic is, the inline credentials within Basic are used directly.
263+
Auth Auth `json:"auth,omitempty" yaml:"auth,omitempty"`
264+
249265
// InsecureSkipTLSVerify controls whether the HTTP client used validate the rule skips TLS certificate verification.
250266
// Defaults to false.
251267
InsecureSkipTLSVerify bool `json:"insecureSkipTlsVerify,omitempty" yaml:"insecureSkipTlsVerify,omitempty"`
@@ -263,19 +279,41 @@ func (r *HTTPFileRule) SetName(name string) {
263279
r.RuleName = name
264280
}
265281

282+
// Auth contains optional basic authentication details.
283+
type Auth struct {
284+
// SecretRef is an optional basic auth secret reference.
285+
SecretRef *BasicAuthSecretReference `json:"secretRef,omitempty" yaml:"secretRef,omitempty"`
286+
287+
// Basic provides optional basic auth credentials inline.
288+
Basic *BasicAuth `json:"basic,omitempty" yaml:"basic,omitempty"`
289+
}
290+
266291
// BasicAuthSecretReference is a reference to a secret containing HTTP basic authentication credentials.
267292
type BasicAuthSecretReference struct {
268293
// Name is the name of the secret.
269294
// +kubebuilder:validation:MinLength=1
270295
Name string `json:"name" yaml:"name"`
296+
271297
// UsernameKey is the username key in the secret data.
272298
// +kubebuilder:validation:MinLength=1
273299
UsernameKey string `json:"usernameKey" yaml:"usernameKey"`
300+
274301
// PasswordKey is the password key in the secret data.
275302
// +kubebuilder:validation:MinLength=1
276303
PasswordKey string `json:"passwordKey" yaml:"passwordKey"`
277304
}
278305

306+
// BasicAuth contains basic authentication credentials.
307+
type BasicAuth struct {
308+
// Username is the username used to authenticate to the OCI Registry.
309+
// +kubebuilder:validation:MinLength=1
310+
Username string `json:"username" yaml:"username"`
311+
312+
// Password is the password used to authenticate to the OCI Registry.
313+
// +kubebuilder:validation:MinLength=1
314+
Password string `json:"password" yaml:"password"`
315+
}
316+
279317
// Keys returns the keys in a BasicAuthSecretReference.
280318
func (r BasicAuthSecretReference) Keys() []string {
281319
return []string{r.UsernameKey, r.PasswordKey}
@@ -323,3 +361,20 @@ type NetworkValidatorList struct {
323361
func init() {
324362
SchemeBuilder.Register(&NetworkValidator{}, &NetworkValidatorList{})
325363
}
364+
365+
// HTTPFileAuthBytesDirect converts all of the inline basic authentication details in a NetworkValidatorSpec
366+
// to a map of rule names to basic auth details.
367+
func (s *NetworkValidatorSpec) HTTPFileAuthBytesDirect() map[string][]string {
368+
auths := make(map[string][]string)
369+
for _, rule := range s.HTTPFileRules {
370+
if rule.Auth.Basic == nil {
371+
continue
372+
}
373+
374+
auths[rule.Name()] = []string{
375+
rule.Auth.Basic.Username,
376+
rule.Auth.Basic.Password,
377+
}
378+
}
379+
return auths
380+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package v1alpha1
2+
3+
import (
4+
"github.com/stretchr/testify/assert"
5+
"testing"
6+
)
7+
8+
func TestHTTPFileAuthBytesDirect(t *testing.T) {
9+
tests := []struct {
10+
name string
11+
spec NetworkValidatorSpec
12+
expected map[string][]string
13+
}{
14+
{
15+
name: "No HTTPFileRules",
16+
spec: NetworkValidatorSpec{
17+
HTTPFileRules: []HTTPFileRule{},
18+
},
19+
expected: map[string][]string{},
20+
},
21+
{
22+
name: "HTTPFileRule without basic auth",
23+
spec: NetworkValidatorSpec{
24+
HTTPFileRules: []HTTPFileRule{
25+
{
26+
RuleName: "rule1",
27+
},
28+
},
29+
},
30+
expected: map[string][]string{},
31+
},
32+
{
33+
name: "Single HTTPFileRule with basic auth",
34+
spec: NetworkValidatorSpec{
35+
HTTPFileRules: []HTTPFileRule{
36+
{
37+
RuleName: "rule1",
38+
Auth: Auth{
39+
Basic: &BasicAuth{
40+
Username: "user1",
41+
Password: "pass1",
42+
},
43+
},
44+
},
45+
},
46+
},
47+
expected: map[string][]string{
48+
"rule1": {"user1", "pass1"},
49+
},
50+
},
51+
{
52+
name: "Multiple HTTPFileRules with and without basic auth",
53+
spec: NetworkValidatorSpec{
54+
HTTPFileRules: []HTTPFileRule{
55+
{
56+
RuleName: "rule1",
57+
Auth: Auth{
58+
Basic: &BasicAuth{
59+
Username: "user1",
60+
Password: "pass1",
61+
},
62+
},
63+
},
64+
{
65+
RuleName: "rule2",
66+
Auth: Auth{
67+
Basic: &BasicAuth{
68+
Username: "user2",
69+
Password: "pass2",
70+
},
71+
},
72+
},
73+
{
74+
RuleName: "rule3",
75+
},
76+
},
77+
},
78+
expected: map[string][]string{
79+
"rule1": {"user1", "pass1"},
80+
"rule2": {"user2", "pass2"},
81+
},
82+
},
83+
}
84+
85+
for _, tt := range tests {
86+
t.Run(tt.name, func(t *testing.T) {
87+
actual := tt.spec.HTTPFileAuthBytesDirect()
88+
assert.Equal(t, tt.expected, actual)
89+
})
90+
}
91+
}

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 41 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)