Single identity for many services

Hi everybody,

I'd like to know if this can be achieved. I like to has the minimum amount of objects to manage (this is a personal preference), so in a ziti network a dialer has to use the name of the identity who binds to a specific service in order to connect to that service, but i'd want to has only one identity representing a host (PC) who can offer many services (ssh, http, sql, etc), so how the controller will know that i want to connect to http instead of ssh?

For example, the identity name will be server240.ziti, and this is used in my server host who binds to 2 services ssh.svc and http.svc, each of them has a intercept config with the address like the below:

//only one config for ssh services
ziti edge create config ssh.cfg.intercept intercept.v1 '{
    "addresses": ["*.ssh.ziti"],
    "protocols": ["tcp"],
    "portRanges": [ {"low":22,"high":22} ],
    "dialOptions": { "identity": "$dst_hostname" }
}'

//only one config fot http services
ziti edge create config http.cfg.intercept intercept.v1 '{
    "addresses": ["*.http.ziti"],
    "protocols": ["tcp"],
    "portRanges": [ {"low":80,"high":80} ],
    "dialOptions": { "identity": "$dst_hostname" }
}'

Since the client who dials has to indicate the name of the identity as the target host, for example ssh user@server240.ziti or http://server240.ziti, none of them apply for the dns pattern in the addresses property of the intercept config, so this wont work rigth?

The question is, there is a way to use a unique identity per host or i have to use a identity per service per host? for example i manage 3 services on each host: ssh, postgresql and https, i would have to create 9 identities, 3 per every host?

Thanks in advance

Hello and welcome to the OpenZiti community!

Thanks for the interesting question! I like how you've named your identities to match the hostnames that you want to access them by, and your service intercepts a wildcard domain that matches the hostnames. That's exactly the technique I use to represent a service that is provided by multiple identities/hosts. Nice work!

Let me know if I'm not getting at what you're looking for here, but I think you want to push this idea of an identity-per-host to expose multiple apps. So for example each host provides ssh and http. There may be more than these two apps but I think two is enough to sketch the idea.

The intercept configurations that you've shown are close, but you don't need to use unique "addresses" in the each of the service configurations because your apps use different port ranges, and that is enough for the intercepting tunneler to distinguish one service from another. So I think the simplest way to achieve multiple identities that expose multiple apps is to make a single service configuration that covers all of your hostnames and all of the port ranges for your apps:

ziti edge create config all.cfg.intercept intercept.v1 '{
    "addresses": ["*.ziti"],
    "protocols": ["tcp"],
    "portRanges": [ {"low":22,"high":22}, {"low":80,"high":80} ],
    "dialOptions": { "identity": "$dst_hostname" }
}'

The key trick to making this work is to ensure that whatever port was intercepted is also used on the far side of the tunnel, when the hosting tunneler connects to the app server. This can be done by setting forwardPort to true in the associated host.v1 configuration:

ziti edge create config all.cfg.host host.v1 '{
    "address": "127.0.0.1",
    "protocol": "tcp",
    "forwardPort": true,
    "allowedPortRanges": [ {"low":22,"high":22}, {"low":80,"high":80} ],
    "listenOptions": { "bindUsingEdgeIdentity": true }
}'

You could also create a separate OpenZiti service for each of your apps if you really wanted to. This might make sense if you wanted to use service policies to control exactly which identities could access/provide the various apps. You'd just use the same "addresses" in all configurations, and set the port range appropriately for the app:

ziti edge create config ssh.cfg.intercept intercept.v1 '{
    "addresses": ["*.ziti"],
    "protocols": ["tcp"],
    "portRanges": [ {"low":22,"high":22} ],
    "dialOptions": { "identity": "$dst_hostname" }
}'
ziti edge create config http.cfg.intercept intercept.v1 '{
    "addresses": ["*.ziti"],
    "protocols": ["tcp"],
    "portRanges": [ {"low":80,"high":80} ],
    "dialOptions": { "identity": "$dst_hostname" }
}'
1 Like

What @scareything describes above are called "Addressable Terminators" in OpenZiti lingo

Thanks for your response.

I learn 2 things with this answer:

  1. The intercept config compares at least 3 data: address pattern, protocol and port, so if you have many intercept config you just must be sure they are unique using this 3 fields.
  2. I read the ziti/tunnel/entities/host.v1.json at main · openziti/ziti · GitHub schema, but i miss a lot of things, i assumed the properties used in the guides/examples were required but they are not, so in you host config are using what i will call advanced properties. If you use forwardPort i could also use forwardProtocol, this will make the Binder work as the same protocol the dialer is using. Moreover in your example you just using in listenOptions: "bindUsingEdgeIdentity": true instead of "identity": "$tunneler_id.name", any reason why one above the another?

One thing i wanted to avoid was let the config more open, for example using *.ziti, but as it is gonna be applyed only if port matches, i guess there is no security problem.

In general its being more clear to me, thank you so much for your help. =)

"bindUsingEdgeIdentity": true and "identity": "$tunneler_id.name" are exactly equivalent. In fact I considered using the "identity:" form in my example but changed my mind at the last moment. :smiley:

You can be more specific with your intercept addresses if you'd like. For example you could simply spell out the list of hostnames that you want to use in a list instead of using the wildcard notation:

ziti edge create config all.cfg.intercept intercept.v1 '{
    "addresses": ["server240.ziti", "server241.ziti", "server999.ziti"],
    "protocols": ["tcp"],
    "portRanges": [ {"low":22,"high":22}, {"low":80,"high":80} ],
    "dialOptions": { "identity": "$dst_hostname" }
}'

Hi @scareything , thanks for your support

I ended up writing a intercept config for my ssh severs, one for postgres servers and one for apache servers but just one host config with 4 port ranges for ports: 22, 5432 80 y 443, this is because as you suggest be able to delimit clients to access the services by a role attribute in service policies, so when a client wants to connect the target is is server240.ziti, server241.ziti, and depending on the tcp port, it uses routes to the correct endpoint, and the best of all, with just one identity per server. That's amazing.

Thanks again for your help.

3 Likes