Skip to content

Commit 6dbc3e5

Browse files
committed
CrateDB SSL: Add client programs and enable testing on CI
1 parent 76b01d7 commit 6dbc3e5

14 files changed

+246
-30
lines changed

.github/dependabot.yml

+7
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,13 @@ updates:
172172
schedule:
173173
interval: "daily"
174174

175+
# Operation.
176+
177+
- directory: "/operation/compose/ssl"
178+
package-ecosystem: "docker-compose"
179+
schedule:
180+
interval: "daily"
181+
175182
# Topics.
176183

177184
- directory: "/topic/machine-learning/automl"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: "Compose: CrateDB with SSL"
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- '.github/workflows/operation-compose-ssl.yml'
7+
- 'operation/compose/ssl/**'
8+
- '/requirements.txt'
9+
push:
10+
branches: [ main ]
11+
paths:
12+
- '.github/workflows/operation-compose-ssl.yml'
13+
- 'operation/compose/ssl/**'
14+
- '/requirements.txt'
15+
16+
# Allow job to be triggered manually.
17+
workflow_dispatch:
18+
19+
# Run job each night after CrateDB nightly has been published.
20+
schedule:
21+
- cron: '0 3 * * *'
22+
23+
# Cancel in-progress jobs when pushing to the same branch.
24+
concurrency:
25+
cancel-in-progress: true
26+
group: ${{ github.workflow }}-${{ github.ref }}
27+
28+
jobs:
29+
test:
30+
name: "
31+
Python ${{ matrix.python-version }}
32+
on ${{ matrix.os }}"
33+
runs-on: ${{ matrix.os }}
34+
strategy:
35+
fail-fast: false
36+
matrix:
37+
os: [ 'ubuntu-latest' ]
38+
python-version: [ '3.13' ]
39+
40+
env:
41+
UV_SYSTEM_PYTHON: true
42+
43+
steps:
44+
45+
- name: Acquire sources
46+
uses: actions/checkout@v4
47+
48+
- name: Set up Python
49+
uses: actions/setup-python@v5
50+
with:
51+
python-version: ${{ matrix.python-version }}
52+
53+
- name: Set up uv
54+
uses: astral-sh/setup-uv@v5
55+
with:
56+
cache-dependency-glob: |
57+
requirements.txt
58+
enable-cache: true
59+
version: "latest"
60+
61+
- name: Install utilities
62+
run: |
63+
uv pip install -r requirements.txt
64+
65+
- name: Validate operation/compose/ssl
66+
run: |
67+
cd operation/compose/ssl
68+
make test

operation/compose/ssl/Makefile

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.DEFAULT_GOAL:=help
2+
3+
.PHONY: test
4+
test: ## Run the integration tests.
5+
@\
6+
docker compose up --detach
7+
sh client_crash.sh
8+
sh client_pgsql.sh
9+
uv run client_dbapi.py
10+
uv run client_sqlalchemy.py
11+
uv run client_psycopg.py
12+
docker compose down
13+
14+
.PHONY: help
15+
help: ## Show this help message.
16+
@echo 'usage: make [target]'
17+
@echo
18+
@echo 'targets:'
19+
@grep -E '^[8+a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

operation/compose/ssl/README.md

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# CrateDB with SSL
2+
3+
## About
4+
5+
A service composition file (Docker or Podman) for running CrateDB
6+
with SSL enabled, using self-signed certificates.
7+
8+
Accompanied are example client programs that connect to CrateDB/SSL
9+
using the canonical `?sslmode=require` connection option parameter,
10+
to use SSL, but turn off certificate validation. To turn it on,
11+
use `?sslmode=verify-ca` or `?sslmode=verify-full`.
12+
13+
## Caveat
14+
15+
Note this example is not generating fresh self-signed certificates,
16+
but uses the ones uploaded to the repository. In this spirit, anyone
17+
spinning an environment from this example will be using the same
18+
encryption keys. A future iteration might improve this, possibly by
19+
using [minica].
20+
21+
## Usage
22+
23+
```shell
24+
docker compose up
25+
```
26+
27+
## Clients
28+
29+
Client examples adjusted to disable certificate validation, allowing
30+
connections to the server with self-signed certificates.
31+
32+
- [crash] » [client_crash.sh]
33+
- [DB API] » [client_dbapi.py]
34+
- [SQLAlchemy] » [client_sqlalchemy.py]
35+
36+
## Tests
37+
38+
```shell
39+
make test
40+
```
41+
42+
## Rationale
43+
44+
When not disabling host name verification, clients will bail out with
45+
`SSLError`/`SSLCertVerificationError`:
46+
```text
47+
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed
48+
certificate in certificate chain (_ssl.c:1010).
49+
```
50+
51+
## Backlog
52+
53+
- Documentation is currently void of relevant ready-to-run examples
54+
- [Install with containers](https://cratedb.com/docs/guide/install/container/)
55+
- [Docker install guide](https://cratedb.com/docs/guide/install/container/docker.html)
56+
- [SSL Reference](https://cratedb.com/docs/crate/reference/en/latest/admin/ssl.html)
57+
- Possibly synchronize with `crate-pdo`, where this is derived from
58+
<https://github.com/crate/crate-pdo/tree/2.2.2/test/provisioning>
59+
60+
61+
[client_crash.sh]: ./client_crash.sh
62+
[client_dbapi.py]: ./client_dbapi.py
63+
[client_sqlalchemy.py]: ./client_sqlalchemy.py
64+
[crash]: https://cratedb.com/docs/crate/crash/
65+
[DB API]: https://cratedb.com/docs/python/
66+
[minica]: https://github.com/jsha/minica
67+
[SQLAlchemy]: https://cratedb.com/docs/sqlalchemy-cratedb/

operation/compose/ssl/client_crash.sh

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/usr/bin/env sh
2+
3+
# Connect to CrateDB using SSL, with host name verification turned off.
4+
uvx crash -v --hosts https://localhost:4200 \
5+
--user=crate --format=dynamic \
6+
--verify-ssl=false \
7+
--command "SELECT 42"

operation/compose/ssl/client_dbapi.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Connect to CrateDB using SSL, with host name verification turned off.
2+
3+
# /// script
4+
# requires-python = ">=3.9"
5+
# dependencies = [
6+
# "crate",
7+
# ]
8+
# ///
9+
from crate import client
10+
11+
12+
def main():
13+
connection = client.connect("https://localhost:4200", verify_ssl_cert=False)
14+
cursor = connection.cursor()
15+
cursor.execute("SELECT 42")
16+
results = cursor.fetchall()
17+
cursor.close()
18+
connection.close()
19+
20+
print(results)
21+
22+
23+
if __name__ == "__main__":
24+
main()
25+

operation/compose/ssl/client_pgsql.sh

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/usr/bin/env sh
2+
3+
psql "postgresql://crate@localhost:5432/?sslmode=require" -c "SELECT 42"
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Connect to CrateDB using SSL, with host name verification turned off.
2+
3+
# /// script
4+
# requires-python = ">=3.9"
5+
# dependencies = [
6+
# "psycopg[binary]",
7+
# ]
8+
# ///
9+
import psycopg
10+
11+
12+
def main():
13+
connection = psycopg.connect("postgresql://crate@localhost:5432/?sslmode=require")
14+
with connection.cursor(row_factory=psycopg.rows.dict_row) as cursor:
15+
cursor.execute("SELECT 42")
16+
result = cursor.fetchall()
17+
print(result)
18+
connection.close()
19+
20+
21+
if __name__ == "__main__":
22+
main()
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Connect to CrateDB using SSL, with host name verification turned off.
2+
3+
# /// script
4+
# requires-python = ">=3.9"
5+
# dependencies = [
6+
# "sqlalchemy-cratedb>=0.42.0.dev2",
7+
# ]
8+
# ///
9+
import sqlalchemy as sa
10+
11+
12+
def main():
13+
engine = sa.create_engine("crate://localhost/?sslmode=require")
14+
with engine.connect() as connection:
15+
results = connection.execute(sa.text("SELECT 42;"))
16+
print(results.fetchall())
17+
18+
19+
if __name__ == "__main__":
20+
main()

operation/docker/ssl/compose.yml renamed to operation/compose/ssl/compose.yml

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Purpose:
2-
# Start CrateDB with custom parameters and wait for the service being available,
3-
# even when invoked through `docker compose up --detach`.
1+
# CrateDB single-node configuration with SSL (self-signed certificates).
2+
3+
name: cratedb-with-ssl
44

55
services:
66

@@ -9,19 +9,22 @@ services:
99
command: ["crate", "-Cstats.enabled=true"]
1010
ports:
1111
- 4200:4200
12+
- 5432:5432
1213
volumes:
1314
- ./crate.yml:/crate/config/crate.yml
1415
- ./keystore:/crate/config/keystore
1516
- ./truststore:/crate/config/truststore
1617
healthcheck:
1718
test: ["CMD", "curl", "--fail", "--insecure", "https://localhost:4200"]
1819
start_period: 3s
19-
interval: 0.5s
20+
interval: 1.5s
2021
retries: 30
2122
timeout: 30s
2223

24+
# Wait for the service being available, even when
25+
# invoked through `docker compose up --detach`.
2326
# https://marcopeg.com/2019/docker-compose-healthcheck/
24-
start_dependencies:
27+
wait-for-cratedb:
2528
image: dadarek/wait-for-dependencies
2629
depends_on:
2730
cratedb:
File renamed without changes.
File renamed without changes.
File renamed without changes.

operation/docker/ssl/README.md

-25
This file was deleted.

0 commit comments

Comments
 (0)