Skip to content

Commit 40667ce

Browse files
chore: validate tls-name and auth-config-file in xdr config [KO-606]
1 parent 7d97c07 commit 40667ce

3 files changed

Lines changed: 198 additions & 0 deletions

File tree

pkg/utils/utils.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
ls "k8s.io/apimachinery/pkg/labels"
1414
"k8s.io/apimachinery/pkg/selection"
1515
"k8s.io/apimachinery/pkg/types"
16+
"k8s.io/apimachinery/pkg/util/sets"
1617
"sigs.k8s.io/controller-runtime/pkg/client"
1718

1819
asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/v4/api/v1"
@@ -296,6 +297,27 @@ func GetRackIdentifier(rackID int, rackRevision string) string {
296297
return rackIDStr
297298
}
298299

300+
// GetNetworkTLSNames returns the set of TLS configuration names defined in network.tls,
301+
// used to check that xdr.dcs[].tls-name references an existing entry.
302+
func GetNetworkTLSNames(networkConf map[string]interface{}) sets.Set[string] {
303+
tlsNames := sets.Set[string]{}
304+
305+
tlsConfList, ok := networkConf["tls"].([]interface{})
306+
if !ok {
307+
return tlsNames
308+
}
309+
310+
for _, tlsConfInt := range tlsConfList {
311+
if tlsConf, ok := tlsConfInt.(map[string]interface{}); ok {
312+
if tlsName, ok := tlsConf["name"].(string); ok {
313+
tlsNames.Insert(tlsName)
314+
}
315+
}
316+
}
317+
318+
return tlsNames
319+
}
320+
299321
func IsOwnedBy(obj, parent client.Object) bool {
300322
for _, o := range obj.GetOwnerReferences() {
301323
if o.UID == parent.GetUID() {

pkg/validation/validate.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"k8s.io/apimachinery/pkg/util/sets"
1111

1212
asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/v4/api/v1"
13+
"github.com/aerospike/aerospike-kubernetes-operator/v4/pkg/utils"
1314
"github.com/aerospike/aerospike-management-lib/asconfig"
1415
)
1516

@@ -58,6 +59,10 @@ func ValidateAerospikeConfig(
5859
return err
5960
}
6061

62+
if err := validateXDRConfig(config); err != nil {
63+
return err
64+
}
65+
6166
// namespace conf
6267
nsListInterface, ok := config[asdbv1.ConfKeyNamespace]
6368
if !ok {
@@ -167,6 +172,62 @@ func validateNetworkConfig(networkConf map[string]interface{}) error {
167172
return nil
168173
}
169174

175+
// validateXDRConfig validates the xdr section of aerospikeConfig.
176+
func validateXDRConfig(config map[string]interface{}) error {
177+
xdrConfInterface, exists := config[asdbv1.ConfKeyXdr]
178+
if !exists || xdrConfInterface == nil {
179+
return nil
180+
}
181+
182+
xdrConf, ok := xdrConfInterface.(map[string]interface{})
183+
if !ok {
184+
return fmt.Errorf("aerospikeConfig.xdr not a valid map %v", xdrConfInterface)
185+
}
186+
187+
networkConf, _ := config["network"].(map[string]interface{})
188+
tlsNames := utils.GetNetworkTLSNames(networkConf)
189+
190+
dcListInterface, exists := xdrConf["dcs"]
191+
if !exists {
192+
return nil
193+
}
194+
195+
dcList, ok := dcListInterface.([]interface{})
196+
if !ok {
197+
return fmt.Errorf("aerospikeConfig.xdr.dcs not a valid list %v", dcListInterface)
198+
}
199+
200+
for _, dcConfInterface := range dcList {
201+
dcConf, ok := dcConfInterface.(map[string]interface{})
202+
if !ok {
203+
return fmt.Errorf("aerospikeConfig.xdr.dcs entry not a valid map %v", dcConfInterface)
204+
}
205+
206+
dcName := dcConf[asdbv1.ConfKeyName]
207+
208+
if tlsName, tlsNameExists := dcConf[asdbv1.ConfKeyTLSName]; tlsNameExists {
209+
if !tlsNames.Has(tlsName.(string)) {
210+
return fmt.Errorf(
211+
"xdr.dcs[%v].tls-name '%s' must refer the TLS configuration defined in network.tls",
212+
dcName, tlsName,
213+
)
214+
}
215+
}
216+
217+
isConnectorDC, _ := dcConf["connector"].(bool)
218+
authPasswordFile, _ := dcConf["auth-password-file"].(string)
219+
220+
if isConnectorDC && authPasswordFile != "" {
221+
return fmt.Errorf(
222+
"xdr.dcs[%v]: auth-password-file is not allowed for 'connector' datacenters",
223+
dcName,
224+
)
225+
}
226+
}
227+
228+
return nil
229+
}
230+
170231
// ValidateTLSAuthenticateClient validate the tls-authenticate-client field in the service configuration.
171232
func ValidateTLSAuthenticateClient(serviceConf map[string]interface{}) (
172233
[]string, error,

pkg/validation/validate_test.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package validation
2+
3+
import "testing"
4+
5+
// networkConfWithTLS returns a network config declaring a single TLS
6+
// configuration named "dc1-tls", used as the xdr.dcs tls-name reference target.
7+
func networkConfWithTLS() map[string]any {
8+
return map[string]any{
9+
"tls": []any{
10+
map[string]any{"name": "dc1-tls"},
11+
},
12+
}
13+
}
14+
15+
func TestValidateXdrConfig(t *testing.T) {
16+
tests := []struct {
17+
config map[string]any
18+
name string
19+
wantErr bool
20+
}{
21+
{
22+
name: "no xdr section",
23+
config: map[string]any{},
24+
wantErr: false,
25+
},
26+
{
27+
name: "tls-name references a configured network.tls entry",
28+
config: map[string]any{
29+
"network": networkConfWithTLS(),
30+
"xdr": map[string]any{
31+
"dcs": []any{
32+
map[string]any{
33+
"name": "dc1",
34+
"tls-name": "dc1-tls",
35+
},
36+
},
37+
},
38+
},
39+
wantErr: false,
40+
},
41+
{
42+
name: "tls-name does not reference a configured network.tls entry",
43+
config: map[string]any{
44+
"network": networkConfWithTLS(),
45+
"xdr": map[string]any{
46+
"dcs": []any{
47+
map[string]any{
48+
"name": "dc1",
49+
"tls-name": "unknown-tls",
50+
},
51+
},
52+
},
53+
},
54+
wantErr: true,
55+
},
56+
{
57+
name: "connector true with auth-password-file set",
58+
config: map[string]any{
59+
"network": networkConfWithTLS(),
60+
"xdr": map[string]any{
61+
"dcs": []any{
62+
//nolint:gosec // G101 test config path, not real credentials
63+
map[string]any{
64+
"name": "dc1",
65+
"connector": true,
66+
"auth-password-file": "/etc/aerospike/secret/password.txt",
67+
},
68+
},
69+
},
70+
},
71+
wantErr: true,
72+
},
73+
{
74+
name: "connector true without auth-password-file",
75+
config: map[string]any{
76+
"network": networkConfWithTLS(),
77+
"xdr": map[string]any{
78+
"dcs": []any{
79+
map[string]any{
80+
"name": "dc1",
81+
"connector": true,
82+
},
83+
},
84+
},
85+
},
86+
wantErr: false,
87+
},
88+
{
89+
name: "connector false (default) with auth-password-file set",
90+
config: map[string]any{
91+
"network": networkConfWithTLS(),
92+
"xdr": map[string]any{
93+
"dcs": []any{
94+
//nolint:gosec // G101 test config path, not real credentials
95+
map[string]any{
96+
"name": "dc1",
97+
"auth-user": "admin",
98+
"auth-password-file": "/etc/aerospike/secret/password.txt",
99+
},
100+
},
101+
},
102+
},
103+
wantErr: false,
104+
},
105+
}
106+
107+
for _, tt := range tests {
108+
t.Run(tt.name, func(t *testing.T) {
109+
err := validateXDRConfig(tt.config)
110+
if (err != nil) != tt.wantErr {
111+
t.Errorf("validateXdrConfig() error = %v, wantErr %v", err, tt.wantErr)
112+
}
113+
})
114+
}
115+
}

0 commit comments

Comments
 (0)