Skip to content

Commit dd53f2f

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

14 files changed

+237
-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

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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+
## Usage
14+
15+
```shell
16+
docker compose up
17+
```
18+
19+
## Clients
20+
21+
Client examples adjusted to disable certificate validation, allowing
22+
connections to the server with self-signed certificates.
23+
24+
- [crash] » [client_crash.sh]
25+
- [DB API] » [client_dbapi.py]
26+
- [SQLAlchemy] » [client_sqlalchemy.py]
27+
28+
## Tests
29+
30+
```shell
31+
make test
32+
```
33+
34+
## Rationale
35+
36+
When not disabling host name verification, clients will bail out with
37+
`SSLError`/`SSLCertVerificationError`:
38+
```text
39+
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed
40+
certificate in certificate chain (_ssl.c:1010).
41+
```
42+
43+
## Backlog
44+
45+
- Documentation is currently void of relevant ready-to-run examples
46+
- <https://cratedb.com/docs/guide/install/container/>
47+
- <https://cratedb.com/docs/guide/install/container/docker.html>
48+
- <https://cratedb.com/docs/crate/reference/en/latest/admin/ssl.html>
49+
- Possibly synchronize with `crate-pdo`, where this is derived from
50+
<https://github.com/crate/crate-pdo/tree/2.2.2/test/provisioning>
51+
52+
53+
[client_crash.sh]: ./client_crash.sh
54+
[client_dbapi.py]: ./client_dbapi.py
55+
[client_sqlalchemy.py]: ./client_sqlalchemy.py
56+
[crash]: https://cratedb.com/docs/crate/crash/
57+
[DB API]: https://cratedb.com/docs/python/
58+
[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)