Skip to content

Commit 7617648

Browse files
authored
Add SSL options to configuration (#114)
* Add development guide for schema registry * Bump version to 0.28.0
1 parent 5fe9b71 commit 7617648

File tree

10 files changed

+407
-99
lines changed

10 files changed

+407
-99
lines changed

CHANGELOG.md

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,42 @@
11
# Changelog
22

3-
## [0.27.0] - 2023-07-14 <sup>([notes][0.27.0-n])</sup>
3+
## [0.28.0] - 2024-04-18
4+
5+
- Add new `Avrora.Config` SSL options `registry_ssl_cacerts` and `registry_ssl_cacert_path` (#114 @strech)
6+
7+
## [0.27.0] - 2023-07-14
48

59
- Replace `Logger.warn/1` with `Logger.warning/2` (#107 @trbngr, @strech)
610
- Drop support for Elixir lower than 1.12 (#107 @strech)
711

8-
## [0.26.0] - 2023-01-11 <sup>([notes][0.26.0-n])</sup>
12+
## [0.26.0] - 2023-01-11
913

1014
- Add `--appconfig` argument to schema registration mix task (#102 @emilianobovetti, @strech)
1115

12-
## [0.25.0] - 2023-01-03 <sup>([notes][0.25.0-n])</sup>
16+
## [0.25.0] - 2023-01-03
1317

14-
- Add User-Agent header when communicating with Schema Registry (#100 @azeemchauhan, @strech)
18+
- Add `User-Agent` header when communicating with Schema Registry (#100 @azeemchauhan, @strech)
1519

16-
## [0.24.2] - 2022-09-13 <sup>([notes][0.24.2-n])</sup>
20+
## [0.24.2] - 2022-09-13
1721

18-
- Fix Avrora.Config.registry_schemas_autoreg/0 to return configured `false` value (#99 @ankhers)
22+
- Fix `Avrora.Config.registry_schemas_autoreg/0` to return configured `false` value (#99 @ankhers)
1923

20-
## [0.24.1] - 2022-09-12 <sup>([notes][0.24.1-n])</sup>
24+
## [0.24.1] - 2022-09-12
2125

22-
- Add SSL option `[verify: :verify_none]` to Avrora.HttpClient (#97, @goozzik)
26+
- Add SSL option `[verify: :verify_none]` to `Avrora.HttpClient` (#97, @goozzik)
2327

24-
## [0.24.0] - 2022-03-16 <sup>([notes][0.24.0-n])</sup>
28+
## [0.24.0] - 2022-03-16
2529

26-
- Add new Avrora.Config option decoder_hook (#94, @strech)
30+
- Add new `Avrora.Config` option decoder_hook (#94, @strech)
2731

28-
## [0.23.0] - 2021-07-06 <sup>([notes][0.23.0-n])</sup>
32+
## [0.23.0] - 2021-07-06
2933

3034
- Add runtime config resolution for Avrora.Client (#92, @strech)
3135

32-
[0.27.0]: https://github.com/Strech/avrora/compare/v0.26.0...v0.27.0
33-
[0.27.0-n]: https://github.com/Strech/avrora/releases/tag/v0.27.0
34-
[0.26.0]: https://github.com/Strech/avrora/compare/v0.25.0...v0.26.0
35-
[0.26.0-n]: https://github.com/Strech/avrora/releases/tag/v0.26.0
36-
[0.25.0]: https://github.com/Strech/avrora/compare/v0.24.2...v0.25.0
37-
[0.25.0-n]: https://github.com/Strech/avrora/releases/tag/v0.25.0
38-
[0.24.2]: https://github.com/Strech/avrora/compare/v0.24.1...v0.24.2
39-
[0.24.2-n]: https://github.com/Strech/avrora/releases/tag/v0.24.2
40-
[0.24.1]: https://github.com/Strech/avrora/compare/v0.24.0...v0.24.1
41-
[0.24.1-n]: https://github.com/Strech/avrora/releases/tag/v0.24.1
42-
[0.24.0]: https://github.com/Strech/avrora/compare/v0.23.0...v0.24.0
43-
[0.24.0-n]: https://github.com/Strech/avrora/releases/tag/v0.24.0
44-
[0.23.0]: https://github.com/Strech/avrora/compare/v0.22.0...v0.23.0
45-
[0.23.0-n]: https://github.com/Strech/avrora/releases/tag/v0.23.0
36+
[0.27.0]: https://github.com/Strech/avrora/releases/tag/v0.27.0
37+
[0.26.0]: https://github.com/Strech/avrora/releases/tag/v0.26.0
38+
[0.25.0]: https://github.com/Strech/avrora/releases/tag/v0.25.0
39+
[0.24.2]: https://github.com/Strech/avrora/releases/tag/v0.24.2
40+
[0.24.1]: https://github.com/Strech/avrora/releases/tag/v0.24.1
41+
[0.24.0]: https://github.com/Strech/avrora/releases/tag/v0.24.0
42+
[0.23.0]: https://github.com/Strech/avrora/releases/tag/v0.23.0

DEVELOPMENT.md

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
# Development
2+
3+
To test `Avrora` with real Confluent Schema Registry it is recommended to use
4+
official demo project.
5+
6+
## 1. Setup Confluent demo project
7+
8+
```console
9+
$ git clone git clone git@github.com:confluentinc/cp-demo.git
10+
$ cd cp-demo
11+
$ git checkout -b 7.5.1-post origin/7.5.1-post
12+
```
13+
14+
Apply the following patch to minimize the setup and keep the bare-minimum.
15+
16+
> [!NOTE]
17+
> You may see some errors and warnings, but you could ignore them, for example:
18+
>
19+
> Error response from daemon: No such container: connect
20+
> WARNING: Expected to find at least 6 subjects in Schema Registry but found...
21+
22+
```diff
23+
diff --git a/scripts/start.sh b/scripts/start.sh
24+
index 50b5b41a..535b7a0e 100755
25+
--- a/scripts/start.sh
26+
+++ b/scripts/start.sh
27+
@@ -5,6 +5,8 @@ source ${DIR}/helper/functions.sh
28+
source ${DIR}/env.sh
29+
30+
#-------------------------------------------------------------------------------
31+
+# Disable visualization by default
32+
+VIZ=false
33+
34+
# Do preflight checks
35+
preflight_checks || exit
36+
@@ -15,7 +17,7 @@ ${DIR}/stop.sh
37+
CLEAN=${CLEAN:-false}
38+
39+
# Build Kafka Connect image with connector plugins
40+
-build_connect_image
41+
+# build_connect_image
42+
43+
# Set the CLEAN variable to true if cert doesn't exist
44+
if ! [[ -f "${DIR}/security/controlCenterAndKsqlDBServer-ca1-signed.crt" ]] || ! check_num_certs; then
45+
@@ -86,75 +88,82 @@ docker-compose exec kafka1 kafka-configs \
46+
47+
48+
# Bring up more containers
49+
-docker-compose up --no-recreate -d schemaregistry connect control-center
50+
+# FIXME
51+
+# docker-compose up --no-recreate -d schemaregistry connect control-center
52+
+docker-compose up --no-recreate -d schemaregistry
53+
54+
echo
55+
echo -e "Create topics in Kafka cluster:"
56+
docker-compose exec tools bash -c "/tmp/helper/create-topics.sh" || exit 1
57+
58+
# Verify Kafka Connect Worker has started
59+
-MAX_WAIT=240
60+
-echo -e "\nWaiting up to $MAX_WAIT seconds for Connect to start"
61+
-retry $MAX_WAIT host_check_up connect || exit 1
62+
+# FIXME
63+
+# MAX_WAIT=240
64+
+# echo -e "\nWaiting up to $MAX_WAIT seconds for Connect to start"
65+
+# retry $MAX_WAIT host_check_up connect || exit 1
66+
67+
#-------------------------------------------------------------------------------
68+
69+
-echo -e "\nStart streaming from the Wikipedia SSE source connector:"
70+
-${DIR}/connectors/submit_wikipedia_sse_config.sh || exit 1
71+
+# FIXME
72+
+# echo -e "\nStart streaming from the Wikipedia SSE source connector:"
73+
+# ${DIR}/connectors/submit_wikipedia_sse_config.sh || exit 1
74+
75+
-# Verify connector is running
76+
-MAX_WAIT=120
77+
-echo
78+
-echo "Waiting up to $MAX_WAIT seconds for connector to be in RUNNING state"
79+
-retry $MAX_WAIT check_connector_status_running "wikipedia-sse" || exit 1
80+
+# # Verify connector is running
81+
+# MAX_WAIT=120
82+
+# echo
83+
+# echo "Waiting up to $MAX_WAIT seconds for connector to be in RUNNING state"
84+
+# retry $MAX_WAIT check_connector_status_running "wikipedia-sse" || exit 1
85+
86+
-# Verify wikipedia.parsed topic is populated and schema is registered
87+
-MAX_WAIT=120
88+
-echo
89+
-echo -e "Waiting up to $MAX_WAIT seconds for subject wikipedia.parsed-value (for topic wikipedia.parsed) to be registered in Schema Registry"
90+
-retry $MAX_WAIT host_check_schema_registered || exit 1
91+
+# # Verify wikipedia.parsed topic is populated and schema is registered
92+
+# MAX_WAIT=120
93+
+# echo
94+
+# echo -e "Waiting up to $MAX_WAIT seconds for subject wikipedia.parsed-value (for topic wikipedia.parsed) to be registered in Schema Registry"
95+
+# retry $MAX_WAIT host_check_schema_registered || exit 1
96+
97+
#-------------------------------------------------------------------------------
98+
99+
-# Verify Confluent Control Center has started
100+
-MAX_WAIT=300
101+
-echo
102+
-echo "Waiting up to $MAX_WAIT seconds for Confluent Control Center to start"
103+
-retry $MAX_WAIT host_check_up control-center || exit 1
104+
+# # Verify Confluent Control Center has started
105+
+# FIXME
106+
+# MAX_WAIT=300
107+
+# echo
108+
+# echo "Waiting up to $MAX_WAIT seconds for Confluent Control Center to start"
109+
+# retry $MAX_WAIT host_check_up control-center || exit 1
110+
111+
-echo -e "\nConfluent Control Center modifications:"
112+
-${DIR}/helper/control-center-modifications.sh
113+
-echo
114+
+# echo -e "\nConfluent Control Center modifications:"
115+
+# ${DIR}/helper/control-center-modifications.sh
116+
+# echo
117+
118+
119+
#-------------------------------------------------------------------------------
120+
121+
-# Start more containers
122+
-docker-compose up --no-recreate -d ksqldb-server ksqldb-cli restproxy
123+
+# FIXME
124+
+# # Start more containers
125+
+# docker-compose up --no-recreate -d ksqldb-server ksqldb-cli restproxy
126+
127+
-# Verify ksqlDB server has started
128+
-echo
129+
-echo
130+
-MAX_WAIT=120
131+
-echo -e "\nWaiting up to $MAX_WAIT seconds for ksqlDB server to start"
132+
-retry $MAX_WAIT host_check_up ksqldb-server || exit 1
133+
+# # Verify ksqlDB server has started
134+
+# echo
135+
+# echo
136+
+# MAX_WAIT=120
137+
+# echo -e "\nWaiting up to $MAX_WAIT seconds for ksqlDB server to start"
138+
+# retry $MAX_WAIT host_check_up ksqldb-server || exit 1
139+
140+
-echo -e "\nRun ksqlDB queries:"
141+
-${DIR}/ksqlDB/run_ksqlDB.sh
142+
+# echo -e "\nRun ksqlDB queries:"
143+
+# ${DIR}/ksqlDB/run_ksqlDB.sh
144+
145+
if [[ "$VIZ" == "true" ]]; then
146+
build_viz || exit 1
147+
fi
148+
149+
-echo -e "\nStart additional consumers to read from topics WIKIPEDIANOBOT, WIKIPEDIA_COUNT_GT_1"
150+
-${DIR}/consumers/listen_WIKIPEDIANOBOT.sh
151+
-${DIR}/consumers/listen_WIKIPEDIA_COUNT_GT_1.sh
152+
+# FIXME
153+
+# echo -e "\nStart additional consumers to read from topics WIKIPEDIANOBOT, WIKIPEDIA_COUNT_GT_1"
154+
+# ${DIR}/consumers/listen_WIKIPEDIANOBOT.sh
155+
+# ${DIR}/consumers/listen_WIKIPEDIA_COUNT_GT_1.sh
156+
157+
-echo
158+
-echo
159+
-echo "Start the Kafka Streams application wikipedia-activity-monitor"
160+
-docker-compose up --no-recreate -d streams-demo
161+
-echo "..."
162+
+# echo
163+
+# echo
164+
+# echo "Start the Kafka Streams application wikipedia-activity-monitor"
165+
+# docker-compose up --no-recreate -d streams-demo
166+
+# echo "..."
167+
168+
169+
#-------------------------------------------------------------------------------
170+
```
171+
172+
Save it with name `cp-demo.patch` and run the following command.
173+
174+
```console
175+
$ git apply cp-demo.patch
176+
```
177+
178+
To ensure HTTP(S) connectivity with the generated certificate,
179+
add the schema registry to your system's hosts file:
180+
181+
```console
182+
$ sudo sh -c 'echo "0.0.0.0 schemaregistry" >> /etc/hosts'
183+
```
184+
185+
## 2. Get certificates
186+
187+
Copy the certificate from the Docker container to your local machine and
188+
convert the PEM certificate to a DER-encoded format.
189+
190+
```console
191+
$ docker cp schemaregistry:/etc/kafka/secrets/snakeoil-ca-1.crt .
192+
$ openssl x509 -in snakeoil-ca-1.crt -outform DER -out snakeoil-ca-1.der
193+
```
194+
195+
## 3. Check Schema Registry connectivity
196+
197+
Test the connection to the Schema Registry using the `Avrora.HTTPClient`
198+
with the converted certificate. Run the following code in your console.
199+
200+
```elixir
201+
# Setup the URL and read the certificate
202+
url = "https://superUser:superUser@schemaregistry:8085/subjects"
203+
cert = File.read!(Path.expand("./snakeoil-ca-1.der"))
204+
205+
# Make a get request to the Schema Registry it should output `{:ok, []}`
206+
# (because no data was populated in patched `start.sh` script)
207+
Avrora.HTTPClient.get(url, [ssl_options: [verify: :verify_peer, cacerts: [cert]]])
208+
```

README.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
[v0.24]: https://github.com/Strech/avrora/releases/tag/v0.24.0
2424
[v0.25]: https://github.com/Strech/avrora/releases/tag/v0.25.0
2525
[v0.26]: https://github.com/Strech/avrora/releases/tag/v0.26.0
26+
[v0.28]: https://github.com/Strech/avrora/releases/tag/v0.28.0
2627
[1]: https://avro.apache.org/
2728
[2]: https://www.confluent.io/confluent-schema-registry
2829
[3]: https://docs.confluent.io/current/schema-registry/serializer-formatter.html#wire-format
@@ -34,6 +35,7 @@
3435
[9]: https://github.com/Strech/avrora/wiki/Schema-name-resolution
3536
[10]: https://github.com/Strech/avrora/pull/70
3637
[11]: https://github.com/klarna/erlavro#decoder-hooks
38+
[12]: https://www.erlang.org/docs/26/man/ssl#type-client_cacerts
3739

3840
# Getting Started
3941

@@ -62,7 +64,7 @@ Add Avrora to `mix.exs` as a dependency
6264
```elixir
6365
def deps do
6466
[
65-
{:avrora, "~> 0.21"}
67+
{:avrora, "~> 0.27"}
6668
]
6769
end
6870
```
@@ -83,10 +85,12 @@ Create your private Avrora client module
8385
defmodule MyClient do
8486
use Avrora.Client,
8587
otp_app: :my_application,
88+
schemas_path: "./priv/schemas",
8689
registry_url: "http://localhost:8081",
8790
registry_auth: {:basic, ["username", "password"]},
8891
registry_user_agent: "Avrora/0.25.0 Elixir",
89-
schemas_path: "./priv/schemas",
92+
registry_ssl_cacerts: File.read!("./priv/trusted.der"),
93+
registry_ssl_cacert_path: "./priv/trusted.crt",
9094
registry_schemas_autoreg: false,
9195
convert_null_values: false,
9296
convert_map_to_proplist: false,
@@ -104,10 +108,12 @@ Configure the `Avrora` shared client in `config/config.exs`
104108
```elixir
105109
config :avrora,
106110
otp_app: :my_application, # optional, if you want to use it as a root folder for `schemas_path`
111+
schemas_path: "./priv/schemas",
107112
registry_url: "http://localhost:8081",
108113
registry_auth: {:basic, ["username", "password"]}, # optional
109114
registry_user_agent: "Avrora/0.24.2 Elixir", # optional: if you want to return previous behaviour, set it to `nil`
110-
schemas_path: "./priv/schemas",
115+
registry_ssl_cacerts: File.read!("./priv/trusted.der"), # optional: if you have DER-encoded certificate
116+
registry_ssl_cacert_path: "./priv/trusted.crt", # optional: if you have PEM-encoded certificate file
111117
registry_schemas_autoreg: false, # optional: if you want manually register schemas
112118
convert_null_values: false, # optional: if you want to keep decoded `:null` values as is
113119
convert_map_to_proplist: false, # optional: if you want to restore the old behavior for decoding map-type
@@ -116,10 +122,12 @@ config :avrora,
116122
```
117123

118124
- `otp_app`<sup>[v0.22]</sup> - Name of the OTP application to use for runtime configuration via env, default `nil`
125+
- `schemas_path` - Base path for locally stored schema files, default `./priv/schemas`
119126
- `registry_url` - URL for the Schema Registry, default `nil`
120127
- `registry_auth` – Credentials to authenticate in the Schema Registry, default `nil`
121128
- `registry_user_agent`<sup>[v0.25]</sup> - HTTP `User-Agent` header for Schema Registry requests, default `Avrora/<version> Elixir`
122-
- `schemas_path` - Base path for locally stored schema files, default `./priv/schemas`
129+
- `registry_ssl_cacerts`<sup>[v0.28]</sup> - DER-encoded certificates, but [without combined support][12], default `nil`
130+
- `registry_ssl_cacert_path`<sup>[v0.28]</sup> - Path to a file containing PEM-encoded CA certificates, default `nil`
123131
- `registry_schemas_autoreg`<sup>[v0.13]</sup> - Flag for automatic schemas registration in the Schema Registry, default `true`
124132
- `convert_null_values`<sup>[v0.14]</sup> - Flag for automatic conversion of decoded `:null` values into `nil`, default `true`
125133
- `convert_map_to_proplist`<sup>[v0.15]</sup> restore old behaviour and confiugre decoding map-type to proplist, default `false`
@@ -146,6 +154,9 @@ recommended to set `otp_app` which will point to your OTP applications. This wil
146154
to have a per-client runtime resolution for all configuration options (i.e. `schemas_path`)
147155
with a fallback to staticly defined in a client itself.<sup>[v0.23]</sup>
148156

157+
:bulb: If both `registry_ssl_cacerts` and `registry_ssl_cacert_path` given, then
158+
`registry_ssl_cacerts` has a priority.
159+
149160
## Start cache process
150161

151162
Avrora uses an in-memory cache to speed up schema lookup.

lib/avrora/client.ex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,16 @@ defmodule Avrora.Client do
109109
if is_nil(@otp_app), do: Path.expand(path), else: Application.app_dir(@otp_app, path)
110110
end
111111

112+
def registry_ssl_cacert_path do
113+
path = get(@opts, :registry_ssl_cacert_path, nil)
114+
115+
if is_nil(path), do: nil, else: Path.expand(path)
116+
end
117+
112118
def registry_url, do: get(@opts, :registry_url, nil)
113119
def registry_auth, do: get(@opts, :registry_auth, nil)
114120
def registry_user_agent, do: get(@opts, :registry_user_agent, "Avrora/#{version()} Elixir")
121+
def registry_ssl_cacerts, do: get(@opts, :registry_ssl_cacerts, nil)
115122
def registry_schemas_autoreg, do: get(@opts, :registry_schemas_autoreg, true)
116123
def convert_null_values, do: get(@opts, :convert_null_values, true)
117124
def convert_map_to_proplist, do: get(@opts, :convert_map_to_proplist, false)

0 commit comments

Comments
 (0)