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