Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mutual TLS #445

Merged
merged 2 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions go-manual/modules/ROOT/pages/connect-advanced.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,81 @@ You can switch users at both xref:query-simple.adoc#impersonation[query level] a
`TokenManager` implementations and providers must not interact with the driver in any way, as this can cause deadlocks and undefined behavior.


[#mtls]
[role=label--new-5.27 label--not-on-aura]
== Mutual TLS (client-side certificates as 2FA)

Mutual TLS (mTLS) allows you to use a client certificate as second factor for authenticating with the server.
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.

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].

[NOTE]
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`).

[.tabbed-example]
=====
[.include-with-static-certificate]
======
Use link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth#NewStaticClientCertificateProvider[`auth.NewStaticClientCertificateProvider()`] for static certificates. +
The method takes a link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth#ClientCertificate[`ClientCertificate`] instance.

[source, go, test-skip]
----
certProvider, err := auth.NewStaticClientCertificateProvider(auth.ClientCertificate {
CertFile: "path/to/cert.pem",
KeyFile: "path/to/key.pem",
Password: "theCertPassword",
})
if err != nil {
log.Fatalf("Failed to load certificate: %v", err)
}
_, _ = neo4j.NewDriverWithContext(dbUri, neo4j.BasicAuth(dbUser, dbPassword, ""), func(config *config.Config) {
config.ClientCertificateProvider = certProvider
})
----

======
[.include-with-rotating-certificate]
======

Use link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth#NewRotatingClientCertificateProvider[`auth.NewRotatingClientCertificateProvider()`] for rotating certificates. +
The method takes a link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth#ClientCertificate[`ClientCertificate`] instance.

[source, go, test-skip]
----
password := "theCertPassword"
certProvider, err := auth.NewRotatingClientCertificateProvider(auth.ClientCertificate {
CertFile: "path/to/cert.pem",
KeyFile: "path/to/key.pem",
Password: &password,
})
if err != nil {
log.Fatalf("Failed to load certificate: %v", err)
}
_, _ = neo4j.NewDriverWithContext(dbUri, neo4j.BasicAuth(dbUser, dbPassword, ""), func(config *config.Config) {
config.ClientCertificateProvider = certProvider
})
// use the driver a bit...
// when it's time to rotate the certificate...
err = provider.UpdateCertificate(auth.ClientCertificate {
CertFile: "path/to/new_cert.pem",
KeyFile: "path/to/new_key.pem",
Password: &password,
})
if err != nil {
log.Fatalf("Failed to update certificate: %v", err)
}
// use the driver again...
----

======
=====


For more information, see link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth#ClientCertificateProvider[API docs -> `ClientCertificateProvider`].


== Custom address resolver

When creating a `DriverWithContext` object, you can specify a _resolver_ function to resolve the connection address the driver is initialized with.
Expand Down
62 changes: 62 additions & 0 deletions java-manual/modules/ROOT/pages/connect-advanced.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,68 @@ You can switch users at both xref:query-simple.adoc#impersonation[query level] a
`AuthTokenManager` objects must not interact with the driver in any way, as this can cause deadlocks and undefined behavior.


[#mtls]
[role=label--new-5.27 label--not-on-aura]
== Mutual TLS (client-side certificates as 2FA)

Mutual TLS (mTLS) allows you to use a client certificate as second factor for authenticating with the server.
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.

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].

[NOTE]
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`).

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. +
The method takes a link:https://neo4j.com/docs/api/java-driver/current/org.neo4j.driver/org/neo4j/driver/ClientCertificates.html[`ClientCertificate`] instance. +
For rotating certificates, use the `.rotate()` method; static certificates don't need to be updated.

[.tabbed-example]
=====
[.include-with-static-certificate]
======

[source, java, test-skip]
----
var certificateFile = new File("/path/to/cert.pem");
var privateKeyFile = new File("/path/to/key.pem");
var keyPassword = "password"; // optional
var certificate = ClientCertificates.of(certificateFile, privateKeyFile, keyPassword);
var certificateManager = ClientCertificateManagers.rotating(certificate);
try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword), certificateManager)) {
// use the driver
}
----

======
[.include-with-rotating-certificate]
======

[source, java, test-skip]
----
var certificateFile = new File("/path/to/cert.pem");
var privateKeyFile = new File("/path/to/key.pem");
var keyPassword = "password"; // optional
var certificate = ClientCertificates.of(certificateFile, privateKeyFile, keyPassword);
// instantiate the rotating certificate with an initial one
var certificateManager = ClientCertificateManagers.rotating(certificate);
try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword), certificateManager)) {
// use the driver...
// ... until it's time to rotate the certificate
var updatedCertificate = ClientCertificates.of(
new File("/path/to/new/cert.pem")
new File("/path/to/new/key.pem"),
"newPassword" // optional
);
certificateManager.rotate(updatedCertificate);
// use the driver some more - new connections are opened with the new certificate
}
----

======
=====


== Logging

By default, the driver logs `INFO` messages through the Java logging framework `java.util.logging`.
Expand Down
62 changes: 62 additions & 0 deletions javascript-manual/modules/ROOT/pages/connect-advanced.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,68 @@ You can switch users at both xref:query-simple.adoc#impersonation[query level] a
`AuthManagers` (including provider functions passed to `expirationBasedAuthTokenManager()`) must not interact with the driver in any way, as this can cause deadlocks and undefined behavior.


[#mtls]
[role=label--new-5.27 label--not-on-aura]
== Mutual TLS (client-side certificates as 2FA)

Mutual TLS (mTLS) allows you to use a client certificate as second factor for authenticating with the server.
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.

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].

[NOTE]
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`).

[.tabbed-example]
=====
[.include-with-static-certificate]
======
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.

[source, javascript, test-skip]
----
const driver = neo4j.driver(URI, neo4j.auth.basic(USER, PASSWORD), {
clientCertificate: {
certfile: '/path/to/cert.cert',
keyfile: '/path/to/cert.pem',
password: 'the_key_password' // optional
}
})
----

======
[.include-with-rotating-certificate]
======

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`].

[source, javascript, test-skip]
----
const initialClientCertificate: {
certfile: '/path/to/cert.cert',
keyfile: '/path/to/cert.pem',
password: 'the_key_password' // optional
}
const clientCertificateProvider = neo4j.clientCertificateProviders.rotating({
initialCertificate: initialClientCertificate
})
const driver = neo4j.driver(URI, MY_CREDENTIALS, {
clientCertificate: clientCertificateProvider
})
// use the driver...
// ... until it's time to update the certificate
clientCertificateProvider.updateCertificate({
certfile: '/path/to/new_cert.cert',
keyfile: '/path/to/new_cert.pem',
password: 'the_new_key_password' // optional
})
// use the driver some more
----

======
=====


== Custom address resolver

When creating a `Driver` object, you can specify a _resolver_ function to resolve the connection address the driver is initialized with.
Expand Down
98 changes: 98 additions & 0 deletions python-manual/modules/ROOT/pages/connect-advanced.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,104 @@ You can switch users at both xref:query-simple.adoc#impersonation[query level] a
`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.


[#mtls]
[role=label--new-5.27 label--not-on-aura]
== Mutual TLS (client-side certificates as 2FA)

Mutual TLS (mTLS) allows you to use a client certificate as second factor for authenticating with the server.
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.

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].

[NOTE]
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`).

[.tabbed-example]
=====
[.include-with-static-certificate]
======
Use link:https://neo4j.com/docs/api/python-driver/current/api.html#neo4j.auth_management.ClientCertificateProviders.static[`ClientCertificateProviders.static()`] for static certificates. +
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()`].

[source, python, test-skip]
----
import neo4j
from neo4j.auth_management import (
ClientCertificate,
ClientCertificateProviders,
)
URI = "<URI for Neo4j database>"
AUTH = ("<Username>", "<Password>")
cert_provider = ClientCertificateProviders.static(
ClientCertificate(
# path to certificate
"path/to/cert.pem",
# path to private key (optional; needed if certificate does not contain private key too)
"path/to/key.pem",
# password to decrypt private key (can be function or string) (optional)
lambda: "password",
)
)
with neo4j.GraphDatabase.driver(
URI,
auth=AUTH,
client_certificate=cert_provider,
) as driver:
...
----

======
[.include-with-rotating-certificate]
======

Use link:https://neo4j.com/docs/api/python-driver/current/api.html#neo4j.auth_management.ClientCertificateProviders.rotating[`ClientCertificateProviders.rotating()`] for rotating certificates. +
The method takes a link:https://neo4j.com/docs/api/python-driver/current/api.html#neo4j.auth_management.ClientCertificate[`ClientCertificate`] instance.

[source, python, test-skip]
----
import neo4j
from neo4j.auth_management import (
ClientCertificate,
ClientCertificateProviders,
)
URI = "<URI for Neo4j database>"
AUTH = ("<Username>", "<Password>")
cert_provider = ClientCertificateProviders.rotating(
ClientCertificate(
# path to public certificate to load
"path/to/cert.pem",
# path to private key to load
"path/to/key.pem",
# password to decrypt private key (can be a function or string)
# see also Python's ssl.SSLContext.load_cert_chain()
lambda: "password",
)
)
driver = neo4j.GraphDatabase.driver(
URI
auth=(USERNAME, PASSWORD),
client_certificate=cert_provider
)
# use the driver...
# ... until the certificate needs to be rotated
cert_provider.update_certificate(
ClientCertificate(
certfile="path/to/new/cert.pem",
keyfile="path/to/new/key.pem",
password=lambda: "new_super_secret_password"
)
)
# use the driver again, until the certificate needs to be
# rotated again
# ...
----

======
=====

For more information, see link:https://neo4j.com/docs/api/python-driver/current/api.html#neo4j.auth_management.ClientCertificateProvider[API docs -> `ClientCertificateProvider`].


== Custom address resolver

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