Skip to content

Commit 9d31719

Browse files
Add Neo4j TLS (#220)
Signed-off-by: Fazle Rabbi Sarker <fazlerabbi@appscode.com> Signed-off-by: souravbiswassanto <saurov@appscode.com> Co-authored-by: souravbiswassanto <saurov@appscode.com>
1 parent 3cbe874 commit 9d31719

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+6018
-98
lines changed

go.mod

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ require (
4444
k8s.io/klog/v2 v2.130.1
4545
kmodules.xyz/client-go v0.34.2
4646
kmodules.xyz/custom-resources v0.34.0
47-
kubedb.dev/apimachinery v0.61.0-rc.0
47+
kubedb.dev/apimachinery v0.61.0-rc.0.0.20260220081356-913319e2ecb3
4848
sigs.k8s.io/controller-runtime v0.22.4
4949
xorm.io/xorm v1.3.11
5050
)
@@ -71,10 +71,11 @@ require (
7171
)
7272

7373
require (
74-
filippo.io/edwards25519 v1.1.0 // indirect
74+
filippo.io/edwards25519 v1.1.1 // indirect
7575
github.com/ClickHouse/ch-go v0.69.0 // indirect
7676
github.com/Masterminds/semver v1.5.0 // indirect
7777
github.com/andybalholm/brotli v1.2.0 // indirect
78+
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 // indirect
7879
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
7980
github.com/beorn7/perks v1.0.1 // indirect
8081
github.com/blang/semver/v4 v4.0.0 // indirect
@@ -85,6 +86,7 @@ require (
8586
github.com/cockroachdb/errors v1.9.1 // indirect
8687
github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f // indirect
8788
github.com/cockroachdb/redact v1.1.3 // indirect
89+
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
8890
github.com/containerd/cgroups/v3 v3.0.3 // indirect
8991
github.com/coreos/go-semver v0.3.1 // indirect
9092
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
@@ -242,8 +244,10 @@ require (
242244
golang.org/x/time v0.14.0 // indirect
243245
golang.org/x/tools v0.40.0 // indirect
244246
gomodules.xyz/clock v0.0.0-20200817085942-06523dba733f // indirect
247+
gomodules.xyz/go-sh v0.2.0 // indirect
245248
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
246249
gomodules.xyz/mergo v0.3.13 // indirect
250+
gomodules.xyz/restic v0.1.0 // indirect
247251
gomodules.xyz/sync v0.1.0 // indirect
248252
gomodules.xyz/wait v0.2.0 // indirect
249253
gomodules.xyz/x v0.0.17 // indirect
@@ -269,7 +273,7 @@ require (
269273
kubeops.dev/operator-shard-manager v0.0.5 // indirect
270274
kubeops.dev/petset v0.0.15 // indirect
271275
kubeops.dev/sidekick v0.0.12 // indirect
272-
kubestash.dev/apimachinery v0.23.1-0.20260209084525-80db980e861f // indirect
276+
kubestash.dev/apimachinery v0.24.0-rc.0 // indirect
273277
open-cluster-management.io/api v1.1.1-0.20251222023835-510285203ee6 // indirect
274278
sigs.k8s.io/gateway-api v1.4.0 // indirect
275279
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect

go.sum

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2-
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
3-
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
2+
filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw=
3+
filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
44
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
55
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
66
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
@@ -46,6 +46,8 @@ github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwTo
4646
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
4747
github.com/apache/thrift v0.14.1 h1:Yh8v0hpCj63p5edXOLaqTJW0IJ1p+eMW6+YSOqw1d6s=
4848
github.com/apache/thrift v0.14.1/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
49+
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloDxZfhMm0xrLXZS8+COSu2bXmEQs=
50+
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
4951
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
5052
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
5153
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
@@ -101,6 +103,7 @@ github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f h1:6jduT9Hfc0n
101103
github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
102104
github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ=
103105
github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
106+
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
104107
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
105108
github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0=
106109
github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0=
@@ -1009,12 +1012,16 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
10091012
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
10101013
gomodules.xyz/clock v0.0.0-20200817085942-06523dba733f h1:hTyhR4r+tj1Uq7/PpFxLTzbeA0LhMVp7bEYfhkzFjdY=
10111014
gomodules.xyz/clock v0.0.0-20200817085942-06523dba733f/go.mod h1:K3m7N+nBOlf91/tpv8REUGwsAgaKFwElQCuiLhm12AQ=
1015+
gomodules.xyz/go-sh v0.2.0 h1:DMQHTsnhrcFDFAIpuFq+ThGNvWjB/NYrsFZLv5RPcUs=
1016+
gomodules.xyz/go-sh v0.2.0/go.mod h1:N8IrjNiYppUI/rxENYrWD6FOrSxSyEZnIekPEWM7LP0=
10121017
gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
10131018
gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
10141019
gomodules.xyz/mergo v0.3.13 h1:q6cL/MMXZH/MrR2+yjSihFFq6UifXqjwaqI48B6cMEM=
10151020
gomodules.xyz/mergo v0.3.13/go.mod h1:F/2rKC7j0URTnHUKDiTiLcGdLMhdv8jK2Za3cRTUVmc=
10161021
gomodules.xyz/pointer v0.1.0 h1:sG2UKrYVSo6E3r4itAjXfPfe4fuXMi0KdyTHpR3vGCg=
10171022
gomodules.xyz/pointer v0.1.0/go.mod h1:sPLsC0+yLTRecUiC5yVlyvXhZ6LAGojNCRWNNqoplvo=
1023+
gomodules.xyz/restic v0.1.0 h1:CWf2yxPqM6VeNj57ao1QSxrUDEjziv9ewl7YnKe3eB8=
1024+
gomodules.xyz/restic v0.1.0/go.mod h1:Api8DksK5irIRJGjnxt7wSxsJ6AsSu3i97bQVRaQ5zs=
10181025
gomodules.xyz/sync v0.1.0 h1:Y7vHOtMrqN9FojRwkCQdC17dKL1fVx+6xb7WdfnXX58=
10191026
gomodules.xyz/sync v0.1.0/go.mod h1:kv570yCdknyiZ8Y94uaRFGBC5E47TV/5A7PD9jlnJoQ=
10201027
gomodules.xyz/wait v0.2.0 h1:HnRIh+cvIrrKIFaXoYznCVVirv2/2xu3KzjSzsQmYAY=
@@ -1124,16 +1131,16 @@ kmodules.xyz/prober v0.34.0 h1:ElZkZYCjLaytAA0M8EH42To7i9gh1IIX+d0qfaIohys=
11241131
kmodules.xyz/prober v0.34.0/go.mod h1:rsu/fxxfNxY70GDbH6Ju8G66459hi7AhWSSBoiIp8ic=
11251132
kmodules.xyz/resource-metadata v0.42.1 h1:RxAi354cKOeCVLoZI+WjR+tooU4lEq/axIafm1SYa20=
11261133
kmodules.xyz/resource-metadata v0.42.1/go.mod h1:xntcQko2QLbLEHwGE4TQ7I/80fcBQzcexbep97Akstk=
1127-
kubedb.dev/apimachinery v0.61.0-rc.0 h1:jxmBu5wndg2hj2vFDLoYrdbat1fYApLV571tNsV1f6I=
1128-
kubedb.dev/apimachinery v0.61.0-rc.0/go.mod h1:2zrZDkZyxlEcRaFqQlQLpXSwlDFoYgLQcCy4jY6vU6Q=
1134+
kubedb.dev/apimachinery v0.61.0-rc.0.0.20260220081356-913319e2ecb3 h1:/N+z8e8QIDW6cCtpBe9MyYLTq36KePq0X3j7vqhnpTI=
1135+
kubedb.dev/apimachinery v0.61.0-rc.0.0.20260220081356-913319e2ecb3/go.mod h1:zI/nWwbrBNEcB9pTGOJVG83BiOPbwXas4CsCWLzzX7Y=
11291136
kubeops.dev/operator-shard-manager v0.0.5 h1:i7VnyUfIa9u3RQhSTVWNsooXcgmrWWxJyI9gJ10onE8=
11301137
kubeops.dev/operator-shard-manager v0.0.5/go.mod h1:NE6GzlhwLRiwiUUpqi4Uf+J7e/gniITM0uJnE5r1mzY=
11311138
kubeops.dev/petset v0.0.15 h1:iwTRFAp0RNw0A87sw2c97UZ6WIA9H/nhJBpDhXLa7fk=
11321139
kubeops.dev/petset v0.0.15/go.mod h1:sw96WiXfzhpmKpXj4a5AdmEHs0Bx4QMhf+iW15zY4Gg=
11331140
kubeops.dev/sidekick v0.0.12 h1:pmUjQLZDKxgREiM6z0PogLR1aDbgvkE9jRjbxG6dEt0=
11341141
kubeops.dev/sidekick v0.0.12/go.mod h1:RU7QH3E8DOLw15rBYlOOJSyczuwAnVVtYyZjJb00UB8=
1135-
kubestash.dev/apimachinery v0.23.1-0.20260209084525-80db980e861f h1:nti4U+hCA4VH4+Fc9D9/AEpw2/nHkUgyAhZrLkpfMfQ=
1136-
kubestash.dev/apimachinery v0.23.1-0.20260209084525-80db980e861f/go.mod h1:zJEjHjd/nYcXFSW+RfGbLxZMJK41IOWjQGosoAWZDRg=
1142+
kubestash.dev/apimachinery v0.24.0-rc.0 h1:JRVGCjDvJo0qEQLpuP6gNKmFEgBbp+e20qUsnhYNA+c=
1143+
kubestash.dev/apimachinery v0.24.0-rc.0/go.mod h1:Y+/8u+3kPWBuaVchmUn4/AlaGW0nLUZh57JWwvNiDlE=
11371144
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
11381145
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
11391146
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=

neo4j/kubedb_client_builder.go

Lines changed: 71 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@ package neo4j
1818

1919
import (
2020
"context"
21+
"crypto/tls"
22+
"crypto/x509"
2123
"errors"
2224
"fmt"
2325
"strings"
2426
"time"
2527

2628
"kubedb.dev/apimachinery/apis/kubedb"
29+
v1api "kubedb.dev/apimachinery/apis/kubedb/v1"
2730
api "kubedb.dev/apimachinery/apis/kubedb/v1alpha2"
2831
apiutils "kubedb.dev/apimachinery/pkg/utils"
2932

@@ -34,6 +37,7 @@ import (
3437
kerr "k8s.io/apimachinery/pkg/api/errors"
3538
"k8s.io/apimachinery/pkg/types"
3639
"k8s.io/klog/v2"
40+
ctrl "sigs.k8s.io/controller-runtime"
3741
"sigs.k8s.io/controller-runtime/pkg/client"
3842
)
3943

@@ -53,6 +57,11 @@ func NewKubeDBClientBuilder(kc client.Client, db *api.Neo4j) *KubeDBClientBuilde
5357
}
5458
}
5559

60+
func (o *KubeDBClientBuilder) WithPodName(podName string) *KubeDBClientBuilder {
61+
o.podName = podName
62+
return o
63+
}
64+
5665
func (o *KubeDBClientBuilder) WithContext(ctx context.Context) *KubeDBClientBuilder {
5766
o.ctx = ctx
5867
return o
@@ -64,32 +73,8 @@ func (o *KubeDBClientBuilder) WithLog(log logr.Logger) *KubeDBClientBuilder {
6473
}
6574

6675
func (o *KubeDBClientBuilder) GetNeo4jClient() (*Client, error) {
67-
// Guard against nil receiver or missing required fields to avoid nil deref
68-
if o == nil {
69-
return nil, fmt.Errorf("KubeDBClientBuilder is nil")
70-
}
71-
if o.db == nil {
72-
return nil, fmt.Errorf("neo4j object is nil")
73-
}
74-
if o.kc == nil {
75-
return nil, fmt.Errorf("kubernetes client is nil")
76-
}
77-
// Ensure context is non-nil
78-
if o.ctx == nil {
79-
o.ctx = context.TODO()
80-
}
81-
// Get domain and fallback to cluster.local if not found
82-
domain := apiutils.FindDomain()
83-
if domain == "" {
84-
domain = "cluster.local"
85-
}
86-
8776
// Construct URL - use default service if podName not provided
88-
if o.podName != "" {
89-
o.url = fmt.Sprintf("neo4j://%s.%s.%s.svc.%s:%d", o.podName, o.db.GoverningServiceName(), o.db.Namespace, domain, kubedb.Neo4jBoltPort)
90-
} else {
91-
o.url = fmt.Sprintf("neo4j://%s.%s.svc.%s:%d", o.db.ServiceName(), o.db.Namespace, domain, kubedb.Neo4jBoltPort)
92-
}
77+
o.url = o.buildConnectionURL()
9378

9479
klog.V(3).Infof("Attempting to connect to Neo4j at: %s", o.url)
9580

@@ -128,13 +113,53 @@ func (o *KubeDBClientBuilder) GetNeo4jClient() (*Client, error) {
128113
klog.Info("Security is disabled for Neo4j, no credentials will be used.")
129114
}
130115

116+
tlsConfig := &tls.Config{}
117+
118+
if o.db.Spec.TLS != nil && o.db.Spec.TLS.Bolt.Mode != api.TLSModeDisabled {
119+
certSecret := &core.Secret{}
120+
err := o.kc.Get(o.ctx, types.NamespacedName{
121+
Namespace: o.db.Namespace,
122+
Name: o.db.GetCertSecretName(api.Neo4jCertificateTypeClient),
123+
}, certSecret)
124+
if err != nil {
125+
if kerr.IsNotFound(err) {
126+
klog.Error(err, "Client certificate secret not found")
127+
return nil, errors.New("client certificate secret is not found")
128+
}
129+
klog.Error(err, "Failed to get client certificate Secret")
130+
return nil, err
131+
}
132+
133+
// get tls cert, clientCA and rootCA for tls config
134+
clientCA := x509.NewCertPool()
135+
rootCA := x509.NewCertPool()
136+
137+
crt, err := tls.X509KeyPair(certSecret.Data[core.TLSCertKey], certSecret.Data[core.TLSPrivateKeyKey])
138+
if err != nil {
139+
klog.Error(err, "Failed to parse private key pair")
140+
return nil, err
141+
}
142+
clientCA.AppendCertsFromPEM(certSecret.Data[v1api.TLSCACertFileName])
143+
rootCA.AppendCertsFromPEM(certSecret.Data[v1api.TLSCACertFileName])
144+
tlsConfig = &tls.Config{
145+
Certificates: []tls.Certificate{crt},
146+
ClientAuth: tls.RequireAndVerifyClientCert,
147+
ClientCAs: clientCA,
148+
RootCAs: rootCA,
149+
MaxVersion: tls.VersionTLS13,
150+
}
151+
}
152+
131153
// Create driver and check for errors immediately
132154
driver, err := neo4j.NewDriverWithContext(o.url, neo4j.BasicAuth(dbUser, dbPassword, ""), func(c *config.Config) {
133155
c.SocketConnectTimeout = 60 * time.Second
134156
c.ConnectionAcquisitionTimeout = 60 * time.Second
135157
c.MaxTransactionRetryTime = 60 * time.Second
136158
c.MaxConnectionLifetime = 30 * time.Minute
137-
c.MaxConnectionPoolSize = 100
159+
c.MaxConnectionPoolSize = 20
160+
if o.db.Spec.TLS != nil {
161+
c.TlsConfig = tlsConfig
162+
}
138163
})
139164
if o.db.Spec.DisableSecurity {
140165
driver, err = neo4j.NewDriverWithContext(o.url, neo4j.NoAuth())
@@ -152,7 +177,12 @@ func (o *KubeDBClientBuilder) GetNeo4jClient() (*Client, error) {
152177
return nil, err
153178
}
154179

155-
fmt.Println("Connection established.")
180+
log := ctrl.Log.WithValues(api.ResourceSingularNeo4j, types.NamespacedName{
181+
Namespace: o.db.Namespace,
182+
Name: o.db.OffshootName(),
183+
})
184+
185+
log.V(2).Info("Connection established successfully to Neo4j at: %s", o.url)
156186

157187
return &Client{
158188
DriverWithContext: driver,
@@ -163,3 +193,17 @@ func (c *Client) ExecuteQuery(ctx context.Context, query string, params map[stri
163193
return neo4j.ExecuteQuery(ctx, c, query, params, neo4j.EagerResultTransformer,
164194
neo4j.ExecuteQueryWithDatabase(dbName))
165195
}
196+
197+
func (o *KubeDBClientBuilder) buildConnectionURL() string {
198+
scheme := "neo4j"
199+
200+
if o.db.Spec.TLS != nil && o.db.Spec.TLS.Bolt.Mode != api.TLSModeDisabled {
201+
scheme = "neo4j+s"
202+
}
203+
204+
if o.podName != "" {
205+
return fmt.Sprintf("%s://%s.%s.%s.svc.%s:%d", scheme, o.podName, o.db.OffshootName(), o.db.Namespace, apiutils.FindDomain(), kubedb.Neo4jBoltPort)
206+
}
207+
208+
return fmt.Sprintf("%s://%s.%s.svc.%s:%d", scheme, o.db.ServiceName(), o.db.Namespace, apiutils.FindDomain(), kubedb.Neo4jBoltPort)
209+
}

vendor/filippo.io/edwards25519/extra.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/armon/circbuf/.gitignore

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

vendor/github.com/armon/circbuf/LICENSE

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

vendor/github.com/armon/circbuf/README.md

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

0 commit comments

Comments
 (0)