Working on my demo to access AKS API servers in multiregional deployment, I was able to use addressable terminator service config options and dial a specific API server per region. But when I wanted to extend that to more than one Cluster per region, it was not possible. If there is no access to the host hosting the API Server (i.e. service managed by the cloud provider), then deploying ZET on it would not be possible, and deploying one edge router with tunneler option per API is not practical. The service fits into ZTNA model, where a region would need to be dialed by subnet/wildcard name. Is this feature under consideration or approved? I did not file this issue under ZET or Edge Router Tunneler, because I think both would need this feature if approved?
Thanks, @dariuszSki. @scareything and @plorenz have seen this post and I expect will follow up with you. If not here then in person (with notes posted here afterwards).
Your post did inspire some discussion about the need for a periodic (monthly?) forum to discuss issues/ideas live with community members. @TheLumberjack has brought this up in the past, and we’re at the point where starting those probably makes sense. But we won’t wait for that to get started before working with you on this…
Hi @dariuszSki,
I’m not 100% clear on what you need to do, so maybe sharing your configs and showing an example of what you want would help me get a better picture? How are you using addressable terminators in your demo, and how is it falling short of what you need?
If I just consider the title of this thread, my first thought is that it feels not quite right to use wildcards and/or CIDRs for listen identities… But maybe we could come at it another way… Could you solve your problem if the dialOptions.identity
field supported some additional variables? For example:
variable | meaning |
---|---|
$dst_domain |
the root domain of the hostname that was intercepted. if the intercepted hostname matched a wildcard domain, this would be the shortest matching portion of the wildcard. e.g. for an intercept address of “*.ziti.io”, $dst_domain would resolve to “ziti.io” |
$dst_subdomain |
the subdomain of the intercepted hostname. continuing the “*.ziti.io” example, assuming “host1.cluster2.ziti.io” was intercepted, $dst_subdomain would resolve to “cluster2” |
$dst_short_hostname |
the hostname only, with anything after the first . removed. e.g. “host1” |
We could have analogous variables for IP/CIDR address too, but let’s make sure we are on the same page before going further.
@scareything sorry for the late response, but I needed to finish something else. The service configs are:
host.v1
{
"forwardPort": true,
"listenOptions": {
"identity": "$tunneler_id.appData[fqdn]"
},
"forwardAddress": true,
"forwardProtocol": true,
"allowedAddresses": [
"akssand-b2922463.4d542dfb-fd9c-4f2d-89c7-ad73b0e3adfb.privatelink.eastus2.azmk8s.io",
"aksprod-cae02995.39fe6dad-7f05-4382-bbe0-29fc8e666015.privatelink.eastus2.azmk8s.io"
],
"allowedProtocols": [
"tcp"
],
"allowedPortRanges": [
{
"low": 443,
"high": 443
}
]
}
intercept.v1
{
"addresses": [
"akssand-b2922463.4d542dfb-fd9c-4f2d-89c7-ad73b0e3adfb.privatelink.eastus2.azmk8s.io",
"aksprod-cae02995.39fe6dad-7f05-4382-bbe0-29fc8e666015.privatelink.eastus2.azmk8s.io"
],
"protocols": [
"tcp"
],
"portRanges": [
{
"low": 443,
"high": 443
}
],
"dialOptions": {
"identity": "$dst_hostname"
}
}
on egress router’s identity config - run this command to update update app data if I want to switch another cluster’s private control plane using fqdn.
ziti edge update identity YiFh92K0N --app-data "fqdn"="akssand-b2922463.4d542dfb-fd9c-4f2d-89c7-ad73b0e3adfb.privatelink.eastus2.azmk8s.io"
ziti edge update identity YiFh92K0N --app-data "fqdn"="aksprod-cae02995.39fe6dad-7f05-4382-bbe0-29fc8e666015.privatelink.eastus2.azmk8s.io"
As you can see that the up to the second subdomain is the same per region, so yes the dial by $dst_subdomain = privatelink.eastus2.azmk8s.io
should work but one would want to define with 2 subdomains, $dst.subdomain.subdomain
?
another region for this service would be address like this privatelink.westus.azmk8s.io
I guess in this instance just $dst_subdomain
would work.
How would the host.v1 look like?
"listenOptions": {
"identity": "$tunneler_id.appData[subdomain]"
}
ziti edge update identity YiFh92K0N --app-data "subdomain"="privatelink.eastus2.azmk8s.io"
or more like
"subdomain"="eastus2.azmk8s.io"
So your configuration is intercepting specific hostname addresses, but really each hostname represents a remote network (in this case in a different AWS region)? I may be wrong on that though, because I don’t understand why you’d update the app data on the edge router’s identity?
I would think you want one ER per remote network (region), and the ER/tunneler identity app data for each ER is fixed. Were those ziti edge update identity
commands a side effect of running a single ER for some reason that I don’t see?
Assuming that you’re ok with an ER in each region, and that I’m not missing the point (which is very possible!), would something like this work?
host.v1
{
"forwardPort": true,
"listenOptions": { "identity": "$tunneler_id.appData[domain]" },
"forwardAddress": true,
"forwardProtocol": true,
"allowedAddresses": [
"*.eastus2.azmk8s.io",
"*.westus.azmk8s.io"
],
"allowedProtocols": [ "tcp" ],
"allowedPortRanges": [ { "low": 443, "high": 443 } ]
}
intercept.v1
{
"addresses": [
"*.eastus2.azmk8s.io",
"*.westus.azmk8s.io"
],
"protocols": [ "tcp" ],
"portRanges": [ { "low": 443, "high": 443 } ],
"dialOptions": { "identity": "$dst_domain" }
}
And you’d set each ER identity’s app data to represent the domain that the ER is running in:
ziti edge update identity er-in-eastus2 --app-data "domain"="eastus2.azmk8s.io"
ziti edge update identity er-in-westus --app-data "domain"="westus.azmk8s.io"
So assuming the underlay client app connects using a fqdn like “akssand-b2922463.4d542dfb-fd9c-4f2d-89c7-ad73b0e3adfb.privatelink.eastus2.azmk8s.io”, the intercepting tunneler will resolve $dst_domain
to “eastus2.azmk8s.io” which would select the ER that completes the ziti connection.
And the fqdn that was intercepted will be passed to the ER in the connection metadata, so the forwardAddress
setting in the host.v1configuration will cause the ER to connect whatever hostname the original client connected to (and I’m assuming the hosts running the ERs can resolve those hostnames).
So, would this application of $dst_domain
fulfill your need?
My example configuration shows two FQDNs from the same subdomain. i.e.
“akssand-b2922463.4d542dfb-fd9c-4f2d-89c7-ad73b0e3adfb.privatelink.eastus2.azmk8s.io”
“aksprod-cae02995.39fe6dad-7f05-4382-bbe0-29fc8e666015.privatelink.eastus2.azmk8s.io”
That is why I needed to update appData. Yes, one router per region is correct.
I would think that “eastus2.azmk8s.io” be the first subdomain, and “azmk8s.io” would be the domain. Anyways, that would work, but if one wanted to dial by “azmk8s.io”, would the config be still $dst_domain?
I was thinking that $dst_domain
would be the wildcard domain (everything to the right of the “*.”) when the intercepted hostname matches a wildcard. Maybe this could be called call $dst_matched_domain
to be more accurate.
If this checks out with you, the variables we’d be talking about could be as follows
variable | description | example value |
---|---|---|
$dst_hostname |
the fqdn that was intercepted. we already have this. btw we might consider renaming this to $dst_fqdn
|
“host1.region1.dc1.openziti.io” |
$dst_short_hostname |
the hostname portion of the intercepted fqdn | “host1” |
$dst_domain |
the domain portion of the intercepted fqdn | “openziti.io” |
$dst_subdomain |
the subdomain portion of $dst_hostname
|
“region1.dc1” |
$dst_matched_domain |
the wildcard domain if $dst_hostname matches an intercepted wildcard domain |
e.g. if wildcard is “*.dc1.openziti.io” then $dst_matched_domain == “dc1.openziti.io” |
fwiw $dst_domain
may be of limited value as-is, particularly when the fqdn has multiple subdomains. Maybe we could add an index reference - e.g. $dst_subdomain[N]
but that would probably require more clever parsing.
I like this. The only thing I would use $dst_matched_wildcard instead of $dst_matched_domain. Perhaps more self-explanatory this way? Just a suggestion.
In $dst_subdomain[N], string parsing would need take into account how many periods after the domain, which would equal to N or N+1, something along those lines?
Ok, I captured most of this in support domain substitutions · Issue #540 · openziti/ziti-tunnel-sdk-c · GitHub.
Looks good. Thank you!