Skip to content

Commit 9230d64

Browse files
Mutual TLS (#445)
1 parent 0e07199 commit 9230d64

File tree

4 files changed

+297
-0
lines changed

4 files changed

+297
-0
lines changed

go-manual/modules/ROOT/pages/connect-advanced.adoc

+75
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,81 @@ You can switch users at both xref:query-simple.adoc#impersonation[query level] a
101101
`TokenManager` implementations and providers must not interact with the driver in any way, as this can cause deadlocks and undefined behavior.
102102

103103

104+
[#mtls]
105+
[role=label--new-5.27 label--not-on-aura]
106+
== Mutual TLS (client-side certificates as 2FA)
107+
108+
Mutual TLS (mTLS) allows you to use a client certificate as second factor for authenticating with the server.
109+
The certificate can only be used together with an authentication token and is not a replacement of regular authentication, unless authentication is disabled on the server.
110+
111+
The client's certificate and public key must be placed in the server's `<NEO4J_HOME>/certificates/bolt/trusted` directory. For more information on server setup, see link:https://neo4j.com/docs/operations-manual/current/security/ssl-framework/#ssl-bolt-config[Configure SSL over Bolt].
112+
113+
[NOTE]
114+
For mTLS to work, the driver's connection with the server must be encrypted, i.e. the xref:_connection_protocols_and_security[connection URI scheme] must be either `+s` or `+ssc` (ex. `neo4j+s://example.com:7687`).
115+
116+
[.tabbed-example]
117+
=====
118+
[.include-with-static-certificate]
119+
======
120+
Use link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth#NewStaticClientCertificateProvider[`auth.NewStaticClientCertificateProvider()`] for static certificates. +
121+
The method takes a link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth#ClientCertificate[`ClientCertificate`] instance.
122+
123+
[source, go, test-skip]
124+
----
125+
certProvider, err := auth.NewStaticClientCertificateProvider(auth.ClientCertificate {
126+
CertFile: "path/to/cert.pem",
127+
KeyFile: "path/to/key.pem",
128+
Password: "theCertPassword",
129+
})
130+
if err != nil {
131+
log.Fatalf("Failed to load certificate: %v", err)
132+
}
133+
_, _ = neo4j.NewDriverWithContext(dbUri, neo4j.BasicAuth(dbUser, dbPassword, ""), func(config *config.Config) {
134+
config.ClientCertificateProvider = certProvider
135+
})
136+
----
137+
138+
======
139+
[.include-with-rotating-certificate]
140+
======
141+
142+
Use link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth#NewRotatingClientCertificateProvider[`auth.NewRotatingClientCertificateProvider()`] for rotating certificates. +
143+
The method takes a link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth#ClientCertificate[`ClientCertificate`] instance.
144+
145+
[source, go, test-skip]
146+
----
147+
password := "theCertPassword"
148+
certProvider, err := auth.NewRotatingClientCertificateProvider(auth.ClientCertificate {
149+
CertFile: "path/to/cert.pem",
150+
KeyFile: "path/to/key.pem",
151+
Password: &password,
152+
})
153+
if err != nil {
154+
log.Fatalf("Failed to load certificate: %v", err)
155+
}
156+
_, _ = neo4j.NewDriverWithContext(dbUri, neo4j.BasicAuth(dbUser, dbPassword, ""), func(config *config.Config) {
157+
config.ClientCertificateProvider = certProvider
158+
})
159+
// use the driver a bit...
160+
// when it's time to rotate the certificate...
161+
err = provider.UpdateCertificate(auth.ClientCertificate {
162+
CertFile: "path/to/new_cert.pem",
163+
KeyFile: "path/to/new_key.pem",
164+
Password: &password,
165+
})
166+
if err != nil {
167+
log.Fatalf("Failed to update certificate: %v", err)
168+
}
169+
// use the driver again...
170+
----
171+
172+
======
173+
=====
174+
175+
176+
For more information, see link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth#ClientCertificateProvider[API docs -> `ClientCertificateProvider`].
177+
178+
104179
== Custom address resolver
105180

106181
When creating a `DriverWithContext` object, you can specify a _resolver_ function to resolve the connection address the driver is initialized with.

java-manual/modules/ROOT/pages/connect-advanced.adoc

+62
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,68 @@ You can switch users at both xref:query-simple.adoc#impersonation[query level] a
118118
`AuthTokenManager` objects must not interact with the driver in any way, as this can cause deadlocks and undefined behavior.
119119

120120

121+
[#mtls]
122+
[role=label--new-5.27 label--not-on-aura]
123+
== Mutual TLS (client-side certificates as 2FA)
124+
125+
Mutual TLS (mTLS) allows you to use a client certificate as second factor for authenticating with the server.
126+
The certificate can only be used together with an authentication token and is not a replacement of regular authentication, unless authentication is disabled on the server.
127+
128+
The client's certificate and public key must be placed in the server's `<NEO4J_HOME>/certificates/bolt/trusted` directory. For more information on server setup, see link:https://neo4j.com/docs/operations-manual/current/security/ssl-framework/#ssl-bolt-config[Configure SSL over Bolt].
129+
130+
[NOTE]
131+
For mTLS to work, the driver's connection with the server must be encrypted, i.e. the xref:_connection_protocols_and_security[connection URI scheme] must be either `+s` or `+ssc` (ex. `neo4j+s://example.com:7687`).
132+
133+
Use link:https://neo4j.com/docs/api/java-driver/current/org.neo4j.driver/org/neo4j/driver/ClientCertificateManagers.html[`ClientCertificateManagers.rotating()`] for both static and rotating certificates. +
134+
The method takes a link:https://neo4j.com/docs/api/java-driver/current/org.neo4j.driver/org/neo4j/driver/ClientCertificates.html[`ClientCertificate`] instance. +
135+
For rotating certificates, use the `.rotate()` method; static certificates don't need to be updated.
136+
137+
[.tabbed-example]
138+
=====
139+
[.include-with-static-certificate]
140+
======
141+
142+
[source, java, test-skip]
143+
----
144+
var certificateFile = new File("/path/to/cert.pem");
145+
var privateKeyFile = new File("/path/to/key.pem");
146+
var keyPassword = "password"; // optional
147+
var certificate = ClientCertificates.of(certificateFile, privateKeyFile, keyPassword);
148+
var certificateManager = ClientCertificateManagers.rotating(certificate);
149+
try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword), certificateManager)) {
150+
// use the driver
151+
}
152+
----
153+
154+
======
155+
[.include-with-rotating-certificate]
156+
======
157+
158+
[source, java, test-skip]
159+
----
160+
var certificateFile = new File("/path/to/cert.pem");
161+
var privateKeyFile = new File("/path/to/key.pem");
162+
var keyPassword = "password"; // optional
163+
var certificate = ClientCertificates.of(certificateFile, privateKeyFile, keyPassword);
164+
// instantiate the rotating certificate with an initial one
165+
var certificateManager = ClientCertificateManagers.rotating(certificate);
166+
try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword), certificateManager)) {
167+
// use the driver...
168+
// ... until it's time to rotate the certificate
169+
var updatedCertificate = ClientCertificates.of(
170+
new File("/path/to/new/cert.pem")
171+
new File("/path/to/new/key.pem"),
172+
"newPassword" // optional
173+
);
174+
certificateManager.rotate(updatedCertificate);
175+
// use the driver some more - new connections are opened with the new certificate
176+
}
177+
----
178+
179+
======
180+
=====
181+
182+
121183
== Logging
122184

123185
By default, the driver logs `INFO` messages through the Java logging framework `java.util.logging`.

javascript-manual/modules/ROOT/pages/connect-advanced.adoc

+62
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,68 @@ You can switch users at both xref:query-simple.adoc#impersonation[query level] a
120120
`AuthManagers` (including provider functions passed to `expirationBasedAuthTokenManager()`) must not interact with the driver in any way, as this can cause deadlocks and undefined behavior.
121121

122122

123+
[#mtls]
124+
[role=label--new-5.27 label--not-on-aura]
125+
== Mutual TLS (client-side certificates as 2FA)
126+
127+
Mutual TLS (mTLS) allows you to use a client certificate as second factor for authenticating with the server.
128+
The certificate can only be used together with an authentication token and is not a replacement of regular authentication, unless authentication is disabled on the server.
129+
130+
The client's certificate and public key must be placed in the server's `<NEO4J_HOME>/certificates/bolt/trusted` directory. For more information on server setup, see link:https://neo4j.com/docs/operations-manual/current/security/ssl-framework/#ssl-bolt-config[Configure SSL over Bolt].
131+
132+
[NOTE]
133+
For mTLS to work, the driver's connection with the server must be encrypted, i.e. the xref:_connection_protocols_and_security[connection URI scheme] must be either `+s` or `+ssc` (ex. `neo4j+s://example.com:7687`).
134+
135+
[.tabbed-example]
136+
=====
137+
[.include-with-static-certificate]
138+
======
139+
Use the driver configuration option link:https://neo4j.com/docs/api/javascript-driver/current/class/lib6/types.js~Config.html#instance-member-clientCertificate[`clientCertificate`] to provide the certificate information as an object.
140+
141+
[source, javascript, test-skip]
142+
----
143+
const driver = neo4j.driver(URI, neo4j.auth.basic(USER, PASSWORD), {
144+
clientCertificate: {
145+
certfile: '/path/to/cert.cert',
146+
keyfile: '/path/to/cert.pem',
147+
password: 'the_key_password' // optional
148+
}
149+
})
150+
----
151+
152+
======
153+
[.include-with-rotating-certificate]
154+
======
155+
156+
Instantiate the certificate object via link:https://neo4j.com/docs/api/javascript-driver/current/class/lib6/client-certificate.js~ClientCertificateProviders.html[`clientCertificateProviders.rotating`] and provide it when instantiating the driver via the configuration option link:https://neo4j.com/docs/api/javascript-driver/current/class/lib6/types.js~Config.html#instance-member-clientCertificate[`clientCertificate`].
157+
158+
[source, javascript, test-skip]
159+
----
160+
const initialClientCertificate: {
161+
certfile: '/path/to/cert.cert',
162+
keyfile: '/path/to/cert.pem',
163+
password: 'the_key_password' // optional
164+
}
165+
const clientCertificateProvider = neo4j.clientCertificateProviders.rotating({
166+
initialCertificate: initialClientCertificate
167+
})
168+
const driver = neo4j.driver(URI, MY_CREDENTIALS, {
169+
clientCertificate: clientCertificateProvider
170+
})
171+
// use the driver...
172+
// ... until it's time to update the certificate
173+
clientCertificateProvider.updateCertificate({
174+
certfile: '/path/to/new_cert.cert',
175+
keyfile: '/path/to/new_cert.pem',
176+
password: 'the_new_key_password' // optional
177+
})
178+
// use the driver some more
179+
----
180+
181+
======
182+
=====
183+
184+
123185
== Custom address resolver
124186

125187
When creating a `Driver` object, you can specify a _resolver_ function to resolve the connection address the driver is initialized with.

python-manual/modules/ROOT/pages/connect-advanced.adoc

+98
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,104 @@ You can switch users at both xref:query-simple.adoc#impersonation[query level] a
107107
`AuthManagers` (including provider functions passed to `AuthManagers.expiration_based()`) must not interact with the driver in any way, as this can cause deadlocks and undefined behavior.
108108

109109

110+
[#mtls]
111+
[role=label--new-5.27 label--not-on-aura]
112+
== Mutual TLS (client-side certificates as 2FA)
113+
114+
Mutual TLS (mTLS) allows you to use a client certificate as second factor for authenticating with the server.
115+
The certificate can only be used together with an authentication token and is not a replacement of regular authentication, unless authentication is disabled on the server.
116+
117+
The client's certificate and public key must be placed in the server's `<NEO4J_HOME>/certificates/bolt/trusted` directory. For more information on server setup, see link:https://neo4j.com/docs/operations-manual/current/security/ssl-framework/#ssl-bolt-config[Configure SSL over Bolt].
118+
119+
[NOTE]
120+
For mTLS to work, the driver's connection with the server must be encrypted, i.e. the xref:_connection_protocols_and_security[connection URI scheme] must be either `+s` or `+ssc` (ex. `neo4j+s://example.com:7687`).
121+
122+
[.tabbed-example]
123+
=====
124+
[.include-with-static-certificate]
125+
======
126+
Use link:https://neo4j.com/docs/api/python-driver/current/api.html#neo4j.auth_management.ClientCertificateProviders.static[`ClientCertificateProviders.static()`] for static certificates. +
127+
The method takes a link:https://neo4j.com/docs/api/python-driver/current/api.html#neo4j.auth_management.ClientCertificate[`ClientCertificate`] instance, which takes the same parameters as Python's link:https://docs.python.org/3/library/ssl.html#ssl.SSLContext.load_cert_chain[`ssl.SSLContext.load_cert_chain()`].
128+
129+
[source, python, test-skip]
130+
----
131+
import neo4j
132+
from neo4j.auth_management import (
133+
ClientCertificate,
134+
ClientCertificateProviders,
135+
)
136+
URI = "<URI for Neo4j database>"
137+
AUTH = ("<Username>", "<Password>")
138+
cert_provider = ClientCertificateProviders.static(
139+
ClientCertificate(
140+
# path to certificate
141+
"path/to/cert.pem",
142+
# path to private key (optional; needed if certificate does not contain private key too)
143+
"path/to/key.pem",
144+
# password to decrypt private key (can be function or string) (optional)
145+
lambda: "password",
146+
)
147+
)
148+
with neo4j.GraphDatabase.driver(
149+
URI,
150+
auth=AUTH,
151+
client_certificate=cert_provider,
152+
) as driver:
153+
...
154+
----
155+
156+
======
157+
[.include-with-rotating-certificate]
158+
======
159+
160+
Use link:https://neo4j.com/docs/api/python-driver/current/api.html#neo4j.auth_management.ClientCertificateProviders.rotating[`ClientCertificateProviders.rotating()`] for rotating certificates. +
161+
The method takes a link:https://neo4j.com/docs/api/python-driver/current/api.html#neo4j.auth_management.ClientCertificate[`ClientCertificate`] instance.
162+
163+
[source, python, test-skip]
164+
----
165+
import neo4j
166+
from neo4j.auth_management import (
167+
ClientCertificate,
168+
ClientCertificateProviders,
169+
)
170+
URI = "<URI for Neo4j database>"
171+
AUTH = ("<Username>", "<Password>")
172+
cert_provider = ClientCertificateProviders.rotating(
173+
ClientCertificate(
174+
# path to public certificate to load
175+
"path/to/cert.pem",
176+
# path to private key to load
177+
"path/to/key.pem",
178+
# password to decrypt private key (can be a function or string)
179+
# see also Python's ssl.SSLContext.load_cert_chain()
180+
lambda: "password",
181+
)
182+
)
183+
driver = neo4j.GraphDatabase.driver(
184+
URI
185+
auth=(USERNAME, PASSWORD),
186+
client_certificate=cert_provider
187+
)
188+
# use the driver...
189+
# ... until the certificate needs to be rotated
190+
cert_provider.update_certificate(
191+
ClientCertificate(
192+
certfile="path/to/new/cert.pem",
193+
keyfile="path/to/new/key.pem",
194+
password=lambda: "new_super_secret_password"
195+
)
196+
)
197+
# use the driver again, until the certificate needs to be
198+
# rotated again
199+
# ...
200+
----
201+
202+
======
203+
=====
204+
205+
For more information, see link:https://neo4j.com/docs/api/python-driver/current/api.html#neo4j.auth_management.ClientCertificateProvider[API docs -> `ClientCertificateProvider`].
206+
207+
110208
== Custom address resolver
111209

112210
When creating a `Driver` object, you can specify a _resolver_ function to resolve any addresses the driver receives ahead of DNS resolution.

0 commit comments

Comments
 (0)