How can I create a service for ssh and add identities with the least amount of policies/configs/etc?

Hello, this is a great question!

Here’s a setup that I think comes really close to your request. The one major difference between what I’ll describe here and your request is that the mechanism for access control with this setup will use service policies and role attributes rather than tags.

  • Identities with the “ssh” role will make their sshd server available
  • Identities with the “admin” role will be able to initiate connections to the ssh service

You mentioned the possibility of multitenancy, and I’m assuming other tenants might have an ssh service that is accessed by “admins”. FYI my personal convention is to name these roles so that it’s easy to tell at a glance which service and context the role specifies; e.g. “jptech.ssh.clients”, and “jptech.ssh.servers”. This is just my convention though. For this post I’ll stick with “ssh” and “admin” (and a separate “jptech” role that signifies the tenant).

By the way, all of what follows assumes that you will not restrict your tenants or services to specific edge routers. In other words, all of your edge routers will carry connections for any tenant and any service. So for this to work you’ll need open router policies:

ziti edge create service-edge-router-policy all --service-roles '#all' --edge-router-roles '#all'
ziti edge create edge-router-policy all --edge-router-roles '#all'  --identity-roles '#all'

You could deploy routers that will only be used by specific tenants and/or services. In that case you’d define your router policies accordingly, and the service policies that I show below could omit the “tenant” role. That last sentence might not make sense until you’ve seen the service policies, so read on if it isn’t

The service configuration is pretty easy, so let’s get that out of the way first. We’ll intercept the *.jptech.ziti" domain and the terminating side of the connection will always connect to 127.0.0.1:

ziti edge create config jptech.ssh.cfg.intercept intercept.v1 '{
    "addresses": ["*.jptech.ziti"],
    "protocols": ["tcp"],
    "portRanges": [ {"low":22,"high":22} ],
    "dialOptions": { "identity": "$dst_hostname" }
}'
ziti edge create config jptech.ssh.cfg.host host.v1 '{
    "address": "127.0.0.1",
    "protocol": "tcp",
    "port": 22,
    "listenOptions": { "identity": "$tunneler_id.name" }
}'

These configurations assume the identity names will match the intercept address wildcard.

We pull those configurations together into a service that specifies the roles that may access it:

ziti edge create service jptech.ssh \
    --configs jptech.ssh.cfg.intercept,jptech.ssh.cfg.host \
    --role-attributes admin,ssh

So the “jptech.ssh” service may be accessed by identities that have either or both of the role attributes “admin” and/or “ssh”. I’ll explain how to assign an identity to a role shortly.

First we need the service policies that give the role attributes their meaning. This is where the dial or bind (connect or serve) permission is mapped to the roles (there is a separate policy for dial/connect and bind/serve)

ziti edge create service-policy jptech.ssh.dial Dial --identity-roles "#jptech,#admin" --service-roles "@jptech.ssh"
ziti edge create service-policy jptech.ssh.bind Bind --identity-roles "#jptech,#ssh" --service-roles "@jptech.ssh"

These policies specify that identities with roles “jptech” AND “admin” may dial (a.k.a connect to) the “jptech.ssh” service, and identities with roles “jptech” AND “ssh” may bind (a.k.a. host) the “jptech.ssh” service. By the way, the comma-separated roles are AND’ed together by default. You could OR a list of roles together by passing --semantic AnyOf when creating a service policy.

Finally we can create the identities with role assignments as appropriate. For demonstration, I’ll create one identity that has “admin” access and one that does not. I’ll also create one that is a “jptech” tenant with no ssh access of any kind (probably wouldn’t want that, but just to illustrate the policies), and one identity that isn’t a “jptech” tenant at all:

ziti edge create identity device linux.jptech.ziti --role-attributes jptech,ssh,admin -o linux.jptech.ziti.jwt
ziti edge create identity device mac1.jptech.ziti --role-attributes jptech,admin -o mac1.jptech.ziti.jwt
ziti edge create identity device mac2.jptech.ziti --role-attributes jptech,ssh -o mac2.jptech.ziti.jwt
ziti edge create identity device win.jptech.ziti --role-attributes jptech -o win.jptech.ziti.jwt
ziti edge create identity device ios.notech.ziti --role-attributes notech,ssh,admin -o ios.notech.ziti.jwt

Note that it is possible to update an identities role attributes after it has been created.

It should look like this after the identities are enrolled:

ziti edge list identities
╭────────────┬───────────────────┬────────┬──────────────────┬─────────────╮
│ ID         │ NAME              │ TYPE   │ ATTRIBUTES       │ AUTH-POLICY │
├────────────┼───────────────────┼────────┼──────────────────┼─────────────┤
│ FgtJ-2309K │ mac1.jptech.ziti  │ Device │ admin,jptech     │ Default     │
│ Wul7VL0y8  │ Default Admin     │ User   │                  │ Default     │
│ ZSd4I2mXg  │ win.jptech.ziti   │ Device │ jptech           │ Default     │
│ gZdhILmX9K │ mac2.jptech.ziti  │ Device │ jptech,ssh       │ Default     │
│ jKExIL309K │ ios.notech.ziti   │ Device │ admin,notech,ssh │ Default     │
│ oqIQIL3XgK │ linux.jptech.ziti │ Device │ admin,jptech,ssh │ Default     │
╰────────────┴───────────────────┴────────┴──────────────────┴─────────────╯

And the policy-advisor shows us who can access what:

ziti edge policy-advisor identities
...
Output format: STATUS: ID (ID ROUTERS) -> SVC (SVC ROUTERS) Common Routers: (ONLINE COMMON ROUTERS/COMMON ROUTERS) Dial: DIAL_OK Bind: BIND_OK. ERROR_LIST
-------------------------------------------------------------------------------
OKAY : mac1.jptech.ziti (1) -> jptech.ssh (1) Common Routers: (1/1) Dial: Y Bind: N 

ERROR: Default Admin 
  - Identity does not have access to any services. Adjust service policies.

ERROR: win.jptech.ziti 
  - Identity does not have access to any services. Adjust service policies.

OKAY : mac2.jptech.ziti (1) -> jptech.ssh (1) Common Routers: (1/1) Dial: N Bind: Y 

ERROR: ios.notech.ziti 
  - Identity does not have access to any services. Adjust service policies.

OKAY : linux.jptech.ziti (1) -> jptech.ssh (1) Common Routers: (1/1) Dial: Y Bind: Y 
2 Likes