Dynamic proxy based on SNI
vk496 opened this issue · 4 comments
Hello.
Related to #240, there are any way to route traffic based on the SNI? For example:
Instead of static configuration like this:
layer4 {
:18000 {
@app1 tls sni app1.internal
route @app1 {
tls
proxy 192.168.1.155:3333
}
@app2 tls sni app2.internal
route @app2 {
tls
proxy 192.168.1.156:3333
}
@app3 tls sni app3.internal
route @app3 {
tls
proxy 192.168.1.157:3333
}
@insecure http
@secure tls
route @insecure @secure {
proxy localhost:443
}
}
}
Have the app routed directly based on the SNI. Maybe similar to this:
layer4 {
:18000 {
#regex or simple wildcard
@app tls sni app[0-9]{1,2}.internal
route @app {
tls
proxy ${sni}:3333 # or maybe object access ${app.tls.sni}
}
@insecure http
@secure tls
route @insecure @secure {
proxy localhost:443
}
}
}
The idea behind is that there will be multiple instances of the app, and the client could route based on the SNI value. Im not sure how ports treatement could be possible (or regex/parser of the sni), but at least using the sni directly could reduce a lot the config redundancy.
So basically the SNI matcher needs to support regex, I guess? Or a new sni_regexp
matcher?
So basically the SNI matcher needs to support regex, I guess? Or a new
sni_regexp
matcher?
That's one of the things. And the other, reference those attributes, so it can be "reused". Even better, if we're able to use basic functions like split or array acces, we could "construct" proxy destination from sni string. Something like:
# sni example: app02_3333_.internal
@app tls sni app[0-9]{1,2}_[0-9]{1,4}_.internal
route @app {
tls
proxy ${app.tls.sni.split("_")[0]}:${app.tls.sni.split("_")[1]}
}
Im not fluent in Go, but the idea is simple: regex on SNI for matching and then accessing what was matched (and if possible, manipulate/parse it)
Hi! My 2 cents:
proxy ${sni}:3333 # or maybe object access ${app.tls.sni}
is already implemented bytls
matcher, use{l4.tls.server_name}
.sni
(sub)matcher is a part of Caddy, not caddy-l4. Whether it is an expanded syntax forsni
matcher or a newsni_regexp
matcher, it would be more logical to put it to modules/caddytls/matchers.go of the mainline.
Even better, if we're able to use basic functions like split or array acces, we could "construct" proxy destination from sni string.
You may also implement your own sni_advanced
matcher with any syntax you like that perfectly satisfies your needs and build Caddy with it.
I'm using something like this in my Caddyfile to perform SRV lookups to identify backends for HTTP:
*.srv.example.com {
map {host} {consul_service} {
~(.*)\.srv\.example\.com$ "${1}.service.consul"
}
reverse_proxy {
dynamic srv {consul_service} {
resolvers "10.10.10.10"
}
}
}
Being able to do the same for L4 would be amazing.