Skip to content

Commit 7ab34c5

Browse files
Feat(event-gateway): SNI routing (#3736)
* create includes * replace text with includes * draft * fixes * fixes * Update configure-sni-routing.md * update validation * links * update includes * Update create-virtual-cluster.md * Update productize-kafka-topics.md * create topics * add copy * remove dns alternative names * fix * Apply suggestions from code review Co-authored-by: Cora <[email protected]> * apply feedback --------- Co-authored-by: Cora <[email protected]>
1 parent 1fcef98 commit 7ab34c5

File tree

7 files changed

+402
-124
lines changed

7 files changed

+402
-124
lines changed
Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
---
2+
title: Configure SNI routing with {{site.event_gateway}}
3+
content_type: how_to
4+
breadcrumbs:
5+
- /event-gateway/
6+
7+
permalink: /event-gateway/configure-sni-routing/
8+
9+
products:
10+
- event-gateway
11+
12+
works_on:
13+
- konnect
14+
15+
tags:
16+
- event-gateway
17+
- kafka
18+
19+
description: Set up SNI routing to send traffic to multiple virtual clusters in the same Event Gateway control plane without opening more ports on the data plane.
20+
21+
tldr:
22+
q: How can I route traffic to multiple virtual clusters via a single port?
23+
a: |
24+
To send traffic to multiple virtual clusters with a single port and certificate:
25+
1. Generate a certificate and use a wildcard for the virtual cluster prefix in the subject.
26+
1. Create an OpenSSL extension file to set the subject alternative names for the certificate.
27+
1. Create a listener that listens on a single port.
28+
1. Create a TLS server listener policy using your certificate and key.
29+
1. Create a Forward to virtual cluster policy with the port ans SNI suffix.
30+
31+
32+
tools:
33+
- konnect-api
34+
35+
related_resources:
36+
- text: Event Gateway
37+
url: /event-gateway/
38+
- text: Productize Kafka topics with {{site.event_gateway}}
39+
url: /event-gateway/productize-kafka-topics/
40+
41+
prereqs:
42+
inline:
43+
- title: Install kafkactl
44+
position: before
45+
include_content: knep/kafkactl
46+
- title: Start a local Kafka cluster
47+
position: before
48+
include_content: knep/docker-compose-start
49+
---
50+
51+
In this guide we'll set up SNI routing to send traffic to more two virtual clusters in the same Event Gateway without opening more ports on the data plane. For more details, see [Hostname mapping](/event-gateway/architecture/#hostname-mapping).
52+
53+
For testing purposes, this guide generates self-signed certificates and points to hostnames that resolve to `127.0.0.1`. In production, you should use real hostnames, manage the DNS entries, and sign your certificates with a real, trusted CA.
54+
55+
## Create a backend cluster
56+
57+
{% include knep/create-backend-cluster.md insecure=true %}
58+
59+
## Create an analytics virtual cluster
60+
61+
{% include knep/create-virtual-cluster.md name="analytics" auth=false %}
62+
63+
## Create a payments virtual cluster
64+
65+
{% include knep/create-virtual-cluster.md name="payments" auth=false %}
66+
67+
## Define the kafkactl context
68+
69+
Configure kafkactl to use TLS but ignore certificate verification:
70+
71+
```sh
72+
cat <<EOF > kafkactl.yaml
73+
contexts:
74+
backend:
75+
brokers:
76+
- localhost:9094
77+
analytics:
78+
brokers:
79+
- bootstrap.analytics.127-0-0-1.sslip.io:19092
80+
tls:
81+
enabled: true
82+
ca: ./rootCA.crt
83+
insecure: true
84+
payments:
85+
brokers:
86+
- bootstrap.payments.127-0-0-1.sslip.io:19092
87+
tls:
88+
enabled: true
89+
ca: ./rootCA.crt
90+
insecure: true
91+
EOF
92+
```
93+
94+
## Create Kafka topics
95+
96+
Create sample topics in the Kafka cluster that we created in the [prerequisites](#start-a-local-kakfa-cluster):
97+
98+
<!--vale off-->
99+
{% validation custom-command %}
100+
command: |
101+
kafkactl -C kafkactl.yaml --context backend create topic \
102+
analytics_pageviews analytics_clicks analytics_orders \
103+
payments_transactions payments_refunds payments_orders \
104+
user_actions
105+
expected:
106+
return_code: 0
107+
render_output: false
108+
{% endvalidation %}
109+
<!--vale on-->
110+
111+
## Generate certificates
112+
113+
Generate the certificates we'll need to enable TLS:
114+
115+
1. Generate the root key and certificate:
116+
117+
```sh
118+
openssl genrsa -out ./rootCA.key 4096
119+
openssl req -x509 -new -nodes -key ./rootCA.key \
120+
-sha256 -days 3650 \
121+
-subj "/C=US/ST=Local/L=Local/O=Dev CA/CN=Dev Root CA" \
122+
-out ./rootCA.crt
123+
```
124+
125+
1. Generate the gateway key and certificate signing request:
126+
127+
```sh
128+
openssl genrsa -out ./tls.key 2048
129+
openssl req -new -key ./tls.key \
130+
-subj "/C=US/ST=Local/L=Local/O=Dev/CN=*.127-0-0-1.sslip.io" \
131+
-out ./tls.csr
132+
```
133+
134+
We're setting the subject in the certificate signing request to `*.127-0-0-1.sslip.io`:
135+
* `*` is used for the virtual cluster prefixes, which are the `analytics` and `payments` DNS labels we configured when creating the virtual clusters.
136+
* `.127-0-0-1.sslip.io` is the SNI suffix, which we'll use in the TLS listener policy configuration. In this example, we're using [sslip.io](https://sslip.io/) to resolve `127-0-0-1.sslip.io` to `127.0.0.1`.
137+
138+
1. To explicitly set the subject alternative names for the certificate, create an OpenSSL extension file:
139+
140+
```sh
141+
cat << EOF > ./tls.ext
142+
basicConstraints = CA:FALSE
143+
keyUsage = digitalSignature, keyEncipherment
144+
extendedKeyUsage = serverAuth, clientAuth
145+
subjectAltName = @alt_names
146+
authorityKeyIdentifier = keyid,issuer
147+
148+
[alt_names]
149+
DNS.1 = *.analytics.127-0-0-1.sslip.io
150+
DNS.2 = *.payments.127-0-0-1.sslip.io
151+
EOF
152+
```
153+
154+
1. To generate the certificate we'll need for the TLS listener policy, sign the gateway certificate signing request:
155+
156+
```sh
157+
openssl x509 -req -in ./tls.csr \
158+
-CA ./rootCA.crt -CAkey ./rootCA.key -CAcreateserial \
159+
-out ./tls.crt -days 825 -sha256 \
160+
-extfile ./tls.ext
161+
```
162+
163+
1. Export the key and certificate to your environment:
164+
```sh
165+
export CERTIFICATE=$(awk '{printf "%s\\n", $0}' tls.crt)
166+
export KEY=$(cat tls.key | base64)
167+
```
168+
169+
## Create a listener
170+
171+
Create a listener that listens on port `19092`:
172+
173+
<!--vale off-->
174+
{% konnect_api_request %}
175+
url: /v1/event-gateways/$EVENT_GATEWAY_ID/listeners
176+
status_code: 201
177+
method: POST
178+
body:
179+
name: gateway_listener
180+
addresses:
181+
- 0.0.0.0
182+
ports:
183+
- 19092
184+
extract_body:
185+
- name: id
186+
variable: LISTENER_ID
187+
capture: LISTENER_ID
188+
jq: ".id"
189+
{% endkonnect_api_request %}
190+
<!--vale on-->
191+
192+
## Create a TLS server listener policy
193+
194+
Create a TLS server policy:
195+
196+
<!--vale off-->
197+
{% konnect_api_request %}
198+
url: /v1/event-gateways/$EVENT_GATEWAY_ID/listeners/$LISTENER_ID/policies
199+
status_code: 201
200+
method: POST
201+
body:
202+
type: tls_server
203+
name: tls_server
204+
config:
205+
certificates:
206+
- certificate: $CERTIFICATE
207+
key: $KEY
208+
{% endkonnect_api_request %}
209+
<!--vale on-->
210+
211+
## Create a Forward to virtual cluster policy
212+
213+
Create a Forward to virtual cluster policy that configures SNI and defines a suffix to expose on the listener:
214+
215+
<!--vale off-->
216+
{% konnect_api_request %}
217+
url: /v1/event-gateways/$EVENT_GATEWAY_ID/listeners/$LISTENER_ID/policies
218+
status_code: 201
219+
method: POST
220+
body:
221+
type: forward_to_virtual_cluster
222+
name: forward_to_virtual_cluster
223+
config:
224+
type: sni
225+
advertised_port: 19092
226+
sni_suffix: .127-0-0-1.sslip.io
227+
{% endkonnect_api_request %}
228+
<!--vale on-->
229+
230+
This policy enables routing to each virtual cluster and mapping brokers:
231+
232+
* Bootstrap server to `bootstrap.analytics.127-0-0-1.sslip.io:19092` or `bootstrap.payments.127-0-0-1.sslip.io:19092`
233+
* Broker 1 to `broker-0.analytics.127-0-0-1.sslip.io:19092` or `broker-0.payments.127-0-0-1.sslip.io:19092`
234+
* Broker 2 to `broker-1.analytics.127-0-0-1.sslip.io:19092` or `broker-1.payments.127-0-0-1.sslip.io:19092`
235+
* Broker 3 to `broker-2.analytics.127-0-0-1.sslip.io:19092` or `broker-2.payments.127-0-0-1.sslip.io:19092`
236+
237+
## Validate
238+
239+
Get a list of topics from the `analytics` virtual cluster:
240+
241+
<!--vale off-->
242+
{% validation custom-command %}
243+
command: |
244+
kafkactl -C kafkactl.yaml --context analytics list topics
245+
expected:
246+
return_code: 0
247+
message: |
248+
TOPIC PARTITIONS REPLICATION FACTOR
249+
clicks 1 1
250+
orders 1 1
251+
pageviews 1 1
252+
user_actions 1 1
253+
render_output: false
254+
{% endvalidation %}
255+
256+
You should see the following result:
257+
```sh
258+
TOPIC PARTITIONS REPLICATION FACTOR
259+
clicks 1 1
260+
orders 1 1
261+
pageviews 1 1
262+
user_actions 1 1
263+
```
264+
{:.no-copy-code}
265+
<!--vale on-->
266+
267+
Get a list of topics from the `payments` virtual cluster:
268+
<!--vale off-->
269+
{% validation custom-command %}
270+
command: |
271+
kafkactl -C kafkactl.yaml --context payments list topics
272+
expected:
273+
return_code: 0
274+
message: |
275+
TOPIC PARTITIONS REPLICATION FACTOR
276+
orders 1 1
277+
refunds 1 1
278+
transactions 1 1
279+
user_actions 1 1
280+
render_output: false
281+
{% endvalidation %}
282+
283+
You should see the following result:
284+
```sh
285+
TOPIC PARTITIONS REPLICATION FACTOR
286+
orders 1 1
287+
refunds 1 1
288+
transactions 1 1
289+
user_actions 1 1
290+
```
291+
{:.no-copy-code}
292+
293+
<!--vale on-->
294+
295+
You can reach both virtual clusters with a single certificate and through a single port.

0 commit comments

Comments
 (0)