Add Bolt TLS termination as optional feature
This commit is contained in:
1 parent
5f879fd9a4
commit
eb989c9155
12 files changed
+446
-53
No files matched your search
@@ -61,6 +61,38 @@ boltage is configured through environment variables:
|
||||
| `BOLTAGE_ADVERTISED_BOLT_PORT` | `$BOLTAGE_BOLT_PORT` | Bolt port advertised to the browser; set it when clients reach the Bolt port on another port. |
|
||||
| `BOLTAGE_ADVERTISED_HOST` | `localhost` | Host reported in `SHOW DATABASES` and to clients that do not send a routing address. |
|
||||
| `BOLTAGE_LOG_LEVEL` | `INFO` | `DEBUG` logs every generated SQL statement. |
|
||||
| `BOLTAGE_TLS_CERT` | (unset) | PEM certificate (chain) for TLS, see [TLS](#tls). |
|
||||
| `BOLTAGE_TLS_KEY` | (unset) | PEM private key of that certificate. |
|
||||
| `BOLTAGE_BOLT_TLS` | `optional` with a certificate, else `disabled` | TLS on the Bolt port: `disabled`, `optional` or `required`. |
|
||||
| `BOLTAGE_HTTPS` | `true` with a certificate, else `false` | Serve neo4j-browser over HTTPS instead of HTTP. |
|
||||
|
||||
### TLS
|
||||
|
||||
With `BOLTAGE_TLS_CERT` and `BOLTAGE_TLS_KEY` set, boltage accepts TLS on the Bolt
|
||||
port and serves neo4j-browser over HTTPS:
|
||||
|
||||
```sh
|
||||
BOLTAGE_TLS_CERT=/etc/boltage/cert.pem BOLTAGE_TLS_KEY=/etc/boltage/key.pem boltage
|
||||
```
|
||||
|
||||
`BOLTAGE_BOLT_TLS` works like Neo4j's TLS level for Bolt. `optional`, the default
|
||||
when a certificate is set, accepts TLS and plain connections on the same port, so
|
||||
`bolt://` and `bolt+s://` both work. `required` only accepts TLS and makes the
|
||||
discovery document advertise `neo4j+s://`. `disabled` ignores the certificate for
|
||||
Bolt but still uses it for HTTPS unless `BOLTAGE_HTTPS=false`.
|
||||
|
||||
Clients connect with `bolt+s://` or `neo4j+s://` when they trust the certificate, and
|
||||
with `bolt+ssc://` or `neo4j+ssc://` for a self-signed one. neo4j-browser served over
|
||||
HTTPS connects to the Bolt port over a secure WebSocket (`wss://`), which needs the
|
||||
Bolt port to accept TLS and the browser to trust its certificate; with a self-signed
|
||||
certificate, open `https://localhost:7687/` once and accept it. The certificate is
|
||||
read at start-up, so restart boltage after renewing it. For the container images,
|
||||
see [TLS in the containers](#tls-in-the-containers).
|
||||
|
||||
The connection from boltage to PostgreSQL uses libpq, which takes its TLS settings
|
||||
from [its environment
|
||||
variables](https://www.postgresql.org/docs/current/libpq-envars.html), such as
|
||||
`PGSSLMODE=verify-full` and `PGSSLROOTCERT`.
|
||||
|
||||
## How it works
|
||||
|
||||
@@ -375,6 +407,98 @@ is initialised, and pgAdmin comes with the server already registered as "boltage
|
||||
in `.env` too. Data is kept in the `postgres-data` and `pgadmin-data` volumes;
|
||||
`podman compose down -v` removes them.
|
||||
|
||||
### TLS in the containers
|
||||
|
||||
Both images serve plain Bolt and HTTP unless you turn on [TLS](#tls), either with a
|
||||
self-signed certificate that the container generates, or with your own certificate.
|
||||
In both cases the Bolt port keeps accepting plain connections as well, unless you
|
||||
also set `BOLTAGE_BOLT_TLS=required`, and neo4j-browser moves to
|
||||
<https://localhost:7474/>; set `BOLTAGE_HTTPS=false` to keep serving it over HTTP.
|
||||
|
||||
#### A self-signed certificate
|
||||
|
||||
Set `BOLTAGE_TLS_SELF_SIGNED=true`, and mount a volume on `/var/lib/boltage` to keep
|
||||
the certificate when the container is re-created:
|
||||
|
||||
```sh
|
||||
podman run -d --name boltage -e POSTGRES_PASSWORD=secret -e BOLTAGE_TLS_SELF_SIGNED=true \
|
||||
-p 7474:7474 -p 7687:7687 -p 5050:5050 -p 5432:5432 \
|
||||
-v boltage-data:/var/lib/postgresql -v boltage-pgadmin:/var/lib/pgadmin \
|
||||
-v boltage-tls:/var/lib/boltage boltage
|
||||
```
|
||||
|
||||
With compose, put `BOLTAGE_TLS_SELF_SIGNED=true` in `.env`; the certificate is kept
|
||||
in the `boltage-tls` volume.
|
||||
|
||||
The certificate is valid for `localhost`, `127.0.0.1`, `::1` and
|
||||
`BOLTAGE_ADVERTISED_HOST`. List other host names and addresses, comma-separated, in
|
||||
`BOLTAGE_TLS_HOSTNAMES`. A new certificate is generated when that list changes and
|
||||
30 days before the old one expires (it is valid for 825 days). Its SHA-256
|
||||
fingerprint is logged at every start, so you can compare it with the one your
|
||||
browser shows.
|
||||
|
||||
Drivers connect with `neo4j+ssc://localhost:7687`. In a web browser, accept the
|
||||
certificate at <https://localhost:7687/> once, then open <https://localhost:7474/> and
|
||||
accept it there too.
|
||||
|
||||
#### Your own certificate
|
||||
|
||||
Mount the certificate and key, and point `BOLTAGE_TLS_CERT` and `BOLTAGE_TLS_KEY` at
|
||||
them:
|
||||
|
||||
```sh
|
||||
podman run -d --name boltage -e POSTGRES_PASSWORD=secret \
|
||||
-v ./tls:/etc/boltage/tls:ro \
|
||||
-e BOLTAGE_TLS_CERT=/etc/boltage/tls/cert.pem -e BOLTAGE_TLS_KEY=/etc/boltage/tls/key.pem \
|
||||
-p 7474:7474 -p 7687:7687 -p 5050:5050 -p 5432:5432 \
|
||||
-v boltage-data:/var/lib/postgresql -v boltage-pgadmin:/var/lib/pgadmin boltage
|
||||
```
|
||||
|
||||
Both images run boltage as user and group 999, which must be able to read the key.
|
||||
Keep the key private on the host and give it to that user: with rootless Podman,
|
||||
`podman unshare chown 999:999 tls/key.pem`, otherwise `sudo chown 999:999 tls/key.pem`;
|
||||
then `chmod 0400 tls/key.pem`. On hosts with SELinux (Fedora, RHEL), mount with
|
||||
`:ro,Z` instead of `:ro`.
|
||||
|
||||
#### Secrets
|
||||
|
||||
Podman secrets keep the key out of the host's file system and set its owner for you:
|
||||
|
||||
```sh
|
||||
podman secret create boltage-tls-cert tls/cert.pem
|
||||
podman secret create boltage-tls-key tls/key.pem
|
||||
podman run -d --name boltage -e POSTGRES_PASSWORD=secret \
|
||||
--secret boltage-tls-cert,uid=999,gid=999,mode=0444 \
|
||||
--secret boltage-tls-key,uid=999,gid=999,mode=0400 \
|
||||
-e BOLTAGE_TLS_CERT=/run/secrets/boltage-tls-cert \
|
||||
-e BOLTAGE_TLS_KEY=/run/secrets/boltage-tls-key \
|
||||
-p 7474:7474 -p 7687:7687 -p 5050:5050 -p 5432:5432 \
|
||||
-v boltage-data:/var/lib/postgresql -v boltage-pgadmin:/var/lib/pgadmin boltage
|
||||
```
|
||||
|
||||
With compose, add the secrets in a `compose.override.yaml` next to `compose.yaml`,
|
||||
which compose reads automatically:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
boltage:
|
||||
environment:
|
||||
BOLTAGE_TLS_CERT: /run/secrets/boltage-tls-cert
|
||||
BOLTAGE_TLS_KEY: /run/secrets/boltage-tls-key
|
||||
secrets:
|
||||
- boltage-tls-cert
|
||||
- boltage-tls-key
|
||||
|
||||
secrets:
|
||||
boltage-tls-cert:
|
||||
file: ./tls/cert.pem
|
||||
boltage-tls-key:
|
||||
file: ./tls/key.pem
|
||||
```
|
||||
|
||||
Compose mounts file secrets from the host as they are, so the key needs the same
|
||||
owner as above.
|
||||
|
||||
### Build arguments
|
||||
|
||||
`AGE_IMAGE` (base of the full image, default `apache/age:release_PG18_1.8.0`),
|
||||
@@ -396,7 +520,8 @@ addressing it in [`plans/`](plans/README.md):
|
||||
([plan](plans/03-age-unsupported-features.md)).
|
||||
4. User and role management, `SHOW TRANSACTIONS`, `:sysinfo`
|
||||
([plan](plans/04-users-transactions-sysinfo.md)).
|
||||
5. TLS (`bolt+s://`, HTTPS) ([plan](plans/05-tls.md)).
|
||||
5. [TLS](#tls) certificates are only read at start-up, so renewing one needs a
|
||||
restart ([plan](plans/05-tls.md)).
|
||||
6. Each query's full result is fetched from PostgreSQL before it is streamed to the
|
||||
client, so very large results use memory in boltage
|
||||
([plan](plans/06-streaming-results.md)).
|
||||
|
||||
Reference in new issue
Block a user