Zssh service hosting

Any number of Ziti identities can host the zssh service, correct? Then, the zssh client can login to a particular SSH server by specifying the name of the Ziti identity that is hosting the service on that particular device?

1 Like


Any identity configured to ‘host’ a zssh service - can host it. Yes. zssh relies on a relatively new feature of ziti called an “addressable terminator”. An addressable terminator requires an identity be provided the ability to ‘bind’ the service.

Using the ziti cli that might be accomplished by something like:

ziti edge create config zssh-server host.v1 '{"protocol":"tcp", "address":"","port":22, "listenOptions": {"bindUsingEdgeIdentity":true} }'
ziti edge create service-policy bind-all Bind --service-roles '#zssh' --identity-roles '#zsshServerEndpoints'

now any endpoint with the zsshServerEndpoints attribute shoudl be able to ‘host’ ssh via zssh. Does that make sense?

1 Like

It almost makes sense. Clarification: I see you’re creating a hosting config named “zssh-server” with listenOptions.bindUsingEdgeIdentity: true, and a bind SP named “bind-all” to select identities with #zsshServerEndpoints for binding services with #zssh. I’m not sure what the difference is if listenOptions.bindUsingEdgeIdentity is false, though. I think false is the default, but how is the service bound if not by Edge identity?

1 Like

bindUsingEdgeIdentity flag is the basis of addressable terminators. if you set it to false - you will need to make a service for each identity you want to host an ssh service via zssh. You can opt instead to use the built-in variable of tunneler_id.name like this if you don’t want to use bindUsingEdgeIdentity (this is semantically equivalent to the previous example:

ziti edge controller create config zssh-server host.v1 '{"protocol":"tcp", "address":"","port":22, "listenOptions": {"identity":"$tunneler_id.name"} }'
1 Like

Also - if you don’t use an addressable terminator - i would not expect zssh to ‘work’… I didn’t test it that way for sure

Now I think my question is really “How do addressable terminators work?”, using a zssh service as an example.

I think the goal of addressable terminators is to enable a client to access a particular server instance of a service hosted by any one of many Ziti identities that have permission to bind the same Ziti service. Put another way, to make it unnecessary to create many Ziti services for which the configuration is identical and are hosted by many identities in the same way.

With that goal in mind, what is the meaning of bindUsingEdgeIdentity: false? I think that’s the default, and I took your meaning that when false we’re no longer using addressable terminators, and so there’s no way for an edge client to override the load balancing algorithm that determines which hosting identity will fulfill a particular connection request.

Assuming all of that is accurate, I’m only stuck on the name of the property and understanding precisely what it means to “bind using edge identity”. Specifically, what’s the alternative to binding with an edge identity? Would that be binding by the intercept/packet destination?

Reference: Ziti Services | Ziti

1 Like

When you bind, you can set bindUsingEdgeIdentity=true to use the edge identity as the terminator identity. However, if you set that to false you can use something else as the identity. For example, in a voip use case your identity may my-laptop, but you want your terminator identity to be 555-555-5555.

In the SSH use case maybe your edge identity is server1 but you want the terminator identity to be

As an aside, you can have multiple terminators with the same identity. For example, a hosting tunneler or sdk client may connect to multiple edge routers. In this case there would be one terminator for each router and they would all have the same terminator identity. Then when a client connected to the service and used that terminator identity, the controller would pick from the terminators with that identity.

1 Like

Thanks @dovholuknf and @plorenz for explaining that. Now I see what assumptions zssh is making in order to map a Ziti identity name to an addressable terminator. Importantly, that there’s a hosting config with bindUsingEdgeIdentity: true which means the identifier of the terminator is the binding identity.

Do terminators really have identities in the same sense that Edge SDKs have identities i.e. user certificates backed by a private key? It sounds like terminators might rather be known by “identifiers”.

1 Like

Terminators do not ‘have’ identities. Terminators are terminated ‘at’ or ‘by’ a given identity. All ‘terminator’ means is “send this traffic to this identity”. Once at that identity - the application using that identity decides ‘what’ to do with the traffic.

Take a tunneling app (mac, windows, whatever) with an identity called “identity-host”. If you have that identity ‘host’ a service - a terminator is created for that identity/service combo. Now some other identity named “identity-client” uses the service and writes data to the service. Ziti routes the traffic ‘somewhere’. That ‘somewhere’ is determined by terminators, so ziti routes the traffic to “identity-host”.

Once at the identity - the identity decides ‘what’ to do with the traffic… For a tunneler app - it’d send the traffic off the ziti network to the final destination… Make sense?


No, terminators don’t have identities, it’s just an identifier in the sense of a lookup key. If you’ve got a suggestion for a less confusing name, I’ve been looking for something. Maybe dialIdentifier?

I’d disagree with @dovholuknf that terminators are terminated at or by an identity. They can be, if they happen to be terminated by an SDK client, but they don’t need to be. You could use transport binding terminators which have no relation to an edge identity and provide some arbitrary string as the dial identifier.


Thanks again. This is still coming into focus and both responses make sense.

First, a clarification about bindUsingEdgeIdentity: do I understand correctly this functions as a shorthand way of expressing precisely the following in the hosting config?

Is that the only implication of bindUsingEdgeIdentity: true? If so, then I think the most interesting property here is listenOptions. I expect I would infer a wealth of understanding about this config property by reading a few examples, if those are available somewhere.

If I understand correctly I don’t need to use bindUsingEdgeIdentity: true to enable addressable terminators. Rather, I could have any string value for .listenOptions.identity and the sending edge identity may “address” that value to ensure the traffic is algorithmically load balanced (according to configured terminator costs, weights, etc…) across all bindings that have that value.

@plorenz Re: naming
“Yes” to something like “identifier”, “destination”, “target”, or just “terminator” or “terminatorListener” or “terminatorAddress”, since that appears to be how this value is actually used. “identifier” is a mite subtle difference from “identity” but would have been sufficient for me.

1 Like

that is correct. they do the same thing

1 Like

Today I learned that "bindUsingEdgeIdentity": true also means that the terminator’s identifier can only be claimed by a single concurrent Edge identity. Multiple instances of Ziti Edge SDK could be using the same Edge identity and therefore all have a shared terminator, and this distinguishes "identity":"$tunneler_id.name" (synonym for "bindUsingEdgeIdentity": true) from other values for "identity" in that it guarantees uniqueness of the terminator. All other values imply at least the possibility of load-balancing connections across all identical terminator identifiers.

1 Like

Thanks for working through your thinking… along with… all of the great responses from @dovholuknf and @plorenz .

This is my next challenge… working through implementing a zitified ssh.

One question that remains in my mind is… what happens if you close port 22 and then something happens with the controller… causing you to lose access to the server.

how do you re-establish a connection.
you will be unable to ssh… because you will not be able to connect to the server to open port 22

The controller is only 1/2 of the puzzle and is responsible for helping to establish connection. If you are connected when the controller goes down - you’ll never notice it unless you try to make a new connection. If the controller is down when you try to make a new connection you’ll probably receive a “dial” failure until the controller is reestablished. The good news is that starting the controller takes like “a second” so usually you never notice if/when the controller goes down because it’s a very short lived event.

OpenZiti is working towards distributed controllers in an upcoming release which will make this experience even better. stay tuned for that in the coming months

1 Like

That is very exciting news :slight_smile: