Connect Desktop Tunneler to Docker Quickstart on seperate host

Probably an RTFM error, if the answer is already clearly laid out I’d appreciate if someone can point me in the right direction.

I tried to spin up the Docker quick-start with the goal to connect to it via the windows Desktop edge client. (referenced Setting Up Oracle Cloud To Host OpenZiti) As far as I can tell Everything in the Docker quick-start is working properly but I have not been able to figure out how to generate a config for an edge client that will connect.

After using the docker quick-start to get my containers spun up on a remote VM, and confirmed I could log into ZAC and see my basic config, I then followed the first bit of Wildcard DNS with OpenZiti using Ziti Desktop Edge for Windows - YouTube to get the edge routers publicly accessible and generate a client jwt.

When I try to use the jwt to create a new identity in the windows app, it says “failed to enroll”. I’m pretty sure the issue is that the ziti controller does not know an IP or hostname that is routeable from my computer, and I’m having trouble figuring out where this would be configured.

Ideally the way I envisioned building this out, I was hoping to have the admin interfaces only accessible via docker exec into the controller and have the ZAC set up but only accessible when using a desktop edge client. When I tried to configure the rout-able domain name via the .env file then the docker-compose up hung waiting fore https://routable-controller-hostname.com:1280 to come up, but from the docs I read I didn’t think 1280 should need to be publicly exposed.

Anyway I hope that is helpful context and someone can help fill in the detail whereever I’m missing how this should work.

thanks

Hi @jrdnr, welcome to OpenZiti and the community!

We’ve known this day would come for a while, but we currently do not have a solid guide for exactly what you’re looking for. There is another community member doing just this and I think I can dig up his old forum posts that cover “how-to” do this… I’ll do that, but let me explain what the problem is here, then I’ll go dig up the steps…

When you run an OpenZiti overlay network, there are four types of connections that get made:

  • connections to the controller by edge clients
  • connections to the controller from edge routers
  • connections to edge routers from other edge routers
  • connections to edge routers from edge clients

For things to work properly, each of those types of connections need to be addressable by the things connecting. That’s probably obvious, but what’s not obvious is that when the docker files start up, they were originally intended for “local-only” type of development, developer up-and-running type things for “local learning”. It was later that we (well, me) learned that people will want to run externally addressable services, within docker! (which tbh, makes perfect sense in retrospect)…

Anyway, let me continue… The problem is that all the configuration in the config files living inside docker right now are going to all use “docker-addressable” names… ziti-controller, ziti-edge-router etc. So the “advertised addresses” of those will not be routable from anywhere outside of docker. You can “get it to work” locally using hosts files, local dns etc, but it’s not really what I consider ‘easy’…

So, what we need to do is influence docker so that when it starts up, the configuration files “advertise” some externally addressable host, thereby allowing edge clients wherever they are to connect, and allowing other routers to form links, etc.

I hope that’s clear, but if not I’ll clarify whatever isn’t clear (it’s hard to tell if that’s enough detail or not).

Let me go find the old discourse posts from our good friend mr @gooseleggs and I’ll follow up in a bit (and i’ll try them out to make sure they still work)

I’ll follow up in a bit

Hi @jrdnr,

I’ve spent time tonight getting this to a state that I think makes sense and works and I think represents what you’re looking for. You should be able to take this exact docker-compose.yml file and save it, then make a .env file and put it into the same directory as docker-compose.yml.

.env file

EDIT: Hopefully, it’s clear, but to make it explicit, you would want to change any ports you desire, but you must change the EXTERNAL_DNS.

ZITI_IMAGE=openziti/quickstart
ZITI_VERSION=latest
ZITI_CONTROLLER_RAWNAME=ziti-controller

ZITI_CTRL_PORT=8440
ZITI_EDGE_CONTROLLER_PORT=8441
ZITI_EDGE_ROUTER_PORT=8442
ZITI_EDGE_ROUTER_LISTENER_BIND_PORT=10080
ZITI_ZAC_PORTTLS=8448

EXTERNAL_DNS=ec2-3-134-108-218.us-east-2.compute.amazonaws.com
ZITI_NETWORK_NAME=${EXTERNAL_DNS}
ZITI_CONTROLLER_HOSTNAME=${EXTERNAL_DNS}

ZITI_EDGE_ROUTER_RAWNAME=${EXTERNAL_DNS}
ZITI_EDGE_ROUTER_DESIRED_RAWNAME=${EXTERNAL_DNS}
ZITI_EDGE_ROUTER_HOSTNAME=${EXTERNAL_DNS}

ZITI_EDGE_ROUTER_ROLES=public

docker-compose.yml

version: '2.4'
services:
  ziti-controller:
    image: "${ZITI_IMAGE}:${ZITI_VERSION}"
    env_file:
      - ./.env
    restart: always
    ports:
      - "${ZITI_EDGE_CONTROLLER_PORT}:${ZITI_EDGE_CONTROLLER_PORT}"
      - "${ZITI_CTRL_PORT}:${ZITI_CTRL_PORT}"
    networks:
      ziti:
        aliases:
          - ziti-edge-controller
    volumes:
      - ziti-fs:/persistent
    entrypoint:
      - "/var/openziti/scripts/run-controller.sh"

  ziti-controller-init-container:
    image: "${ZITI_IMAGE}:${ZITI_VERSION}"
    depends_on:
      - ziti-controller
    environment:
      - ZITI_CONTROLLER_RAWNAME="${ZITI_CONTROLLER_RAWNAME}"
      - ZITI_EDGE_CONTROLLER_RAWNAME="${EXTERNAL_DNS}"
    env_file:
      - ./.env
    networks:
      ziti:
        aliases:
          - ziti-edge-controller-init-container
    volumes:
      - ziti-fs:/persistent
    entrypoint:
      - "/var/openziti/scripts/run-with-ziti-cli.sh"
    command:
      - "/var/openziti/scripts/access-control.sh"

  ziti-edge-router:
    image: "${ZITI_IMAGE}:${ZITI_VERSION}"
    environment:
      - ZITI_EDGE_ROUTER_RAWNAME=${ZITI_EDGE_ROUTER_RAWNAME}
    depends_on:
      - ziti-controller
    ports:
      - "${ZITI_EDGE_ROUTER_PORT}:${ZITI_EDGE_ROUTER_PORT}"
      - "${ZITI_EDGE_ROUTER_LISTENER_BIND_PORT}:${ZITI_EDGE_ROUTER_LISTENER_BIND_PORT}"
    restart: always
    networks:
      - ziti
    volumes:
       - ziti-fs:/persistent
    entrypoint: /bin/bash
    command: "/var/openziti/scripts/run-router.sh edge"

  ziti-console:
    image: openziti/zac
    environment:
      - ZAC_SERVER_CERT_CHAIN=/persistent/pki/${EXTERNAL_DNS}-intermediate/certs/${EXTERNAL_DNS}-server.cert
      - ZAC_SERVER_KEY=/persistent/pki/${EXTERNAL_DNS}-intermediate/keys/${EXTERNAL_DNS}-server.key
      - PORTTLS=${ZITI_ZAC_PORTTLS}
    depends_on:
      - ziti-controller
    restart: always
    ports:
      - "1408:1408"
      - "${ZITI_ZAC_PORTTLS}:${ZITI_ZAC_PORTTLS}"
    volumes:
      - ziti-fs:/persistent
    networks:
      - ziti

  web-test-blue:
    image: crccheck/hello-world
    #ports:
    #  - 80:8000
    networks:
      ziti:
        aliases:
          - web-test-ziti
          - web-test.ziti
          - web.test.ziti

networks:
  ziti:

volumes:
  ziti-fs:

Seeing it in action - walkthrough video

Here’s a video of me demonstrating starting everything from docker. I’ve already setup the security group to allow the ports through the web ACL (obviously)

2 Likes

Wow that’s awesome thank you, I’ll give it a go here when I get a chance and report back

I got really close, following the instructions Zero Trust Host Access | OpenZiti as you mentioned in your walkthrough I got as far as step 7, but there is still something I’m missing about what the http_server_id is.

It seems like off screen you were able to get http_server and http_server_id to be set but I’m missing something about how the server is fits in.

Cool, glad to hear.

http_server_id is the name of the identity which is going to be responsible for offloading traffic from the overlay, back into the underlay network. Since you’re using the docker file, it’ll have a router inside docker that has “tunneling mode” enabled. That means when it enrolls (done during the docker compose up process) it also gets an identity provisioned, representing the router.

In OpenZiti, to authorize an identity offload traffic like this, you need a service and the service needs to be “bound” or “hosted” by an identity. That variable, represents that identity name. You can list all the identities in your system by logging into the cli and running ziti edge list identities. You’ll see an identity which is the name of your edge router.

As for http_server, that’s the name of the web server to send traffic to. Since you used the compose file above that could be any of these:

aliases:
          - web-test-ziti
          - web-test.ziti
          - web.test.ziti

I used the first entry when I did the video. So I had set http_server=web-test-ziti

That make sense?

Thanks I was trying the web-test-blue rather than one of the aliases, and for the http_server_id I ran ziti edge list identities which shows the default admin account and the EXTERNAL_DNS address specified in the .env file. All commands run w/o error, when I load of the identity in the tunneler it shows the connection with one service, but when I try to curl it from my local machine with the tunneler running I get:
curl: (7) Failed to connect to http.ziti port 80 after 21 ms: Bad access

At this point I’m not sure if there is something I’m still not understanding or if the web-test-ziti container is not coming up right or something. If I get a chance later I’ll probably try to work back through the docker quickstart to do the network validation and make sure I can get connected into the web test container from w/in the docker environment first then try to trace my steps through to see where I am losing access.

We'll try to change this in the future, but that's what it should show. That is the router's name in this setup. It's a bit, well it's not idea, so we'll look to make that better in the future. For now though, that's what you want to use for the http_server_id. So for me when I run it fresh I see:

ubuntu@ip-172-31-47-200:~$ ziti edge list identities
╭───────────┬───────────────────────────────────────────────────┬────────┬────────────╮
│ ID        │ NAME                                              │ TYPE   │ ATTRIBUTES │
├───────────┼───────────────────────────────────────────────────┼────────┼────────────┤
│ Vw2NjHm82 │ ec2-3-134-108-218.us-east-2.compute.amazonaws.com │ Router │            │
│ XBKF1qZv3 │ Default Admin                                     │ User   │            │
╰───────────┴───────────────────────────────────────────────────┴────────┴────────────╯
results: 1-2 of 2

so for me, http_server_id="ec2-3-134-108-218.us-east-2.compute.amazonaws.com"

"Bad access" is something I don't think I've ever actually seen before. Could you look at the logs from the router something-ziti-edge-router-1 and see if it has any clues?

If not, the next place to look is in the tunneler's logs. What OS are you using for the client side tunneler?

I’m running the edge client on windows, I’ll check logs later, might not be able to get back to it today. Thanks for the quick response

Oh no, I think I found the issue… I just went through the steps myself and I left out a VITAL piece of information… The sample web container comes up and listens on port 8000, not port 80 as shown in that example. I bet you that’s “the” issue here…

Here’s EXACTLY the set of steps I ran - notice on step #4 – port 8000. I’m so sorry… :frowning:

http_server_id=$(ziti edge list identities 'type="Router"' -j | jq -r .data[].name)
http_server="web-test-ziti"

# 1. Create an identity for the HTTP client and assign an attribute "http-clients". We'll use this attribute when authorizing the clients to
#  access the HTTP service
ziti edge create identity user http-client -a 'http-clients' -o http.client.jwt 

#2. Create an identity for the HTTP server if you are not using an edge-router with the tunneling option enabled
# SKIPPED - NOT NEEDED IN THIS EXAMPLE

#3. Create an intercept.v1 config. This config is used to instruct the client-side tunneler how to correctly intercept 
#   the targeted traffic and put it onto the overlay.
ziti edge create config http.intercept.v1 intercept.v1 '{"protocols":["tcp"],"addresses":["http.ziti"], "portRanges":[{"low":80, "high":80}]}'
    
#4. Create a host.v1 config. This config is used instruct the server-side tunneler how to offload the traffic from 
#   the overlay, back to the underlay. 
ziti edge create config http.host.v1 host.v1 '{"protocol":"tcp", "address":"'"${http_server}"'", "port":8000}'
    
#5. Create a service to associate the two configs created previously into a service.
ziti edge create service http.svc --configs http.intercept.v1,http.host.v1

#6. Create a service-policy to authorize "HTTP Clients" to "dial" the service representing the HTTP server.
ziti edge create service-policy http.policy.dial Dial --service-roles "@http.svc" --identity-roles '#http-clients'

#7. Create a service-policy to authorize the "HTTP Server" to "bind" the service representing the HTTP server.
ziti edge create service-policy http.policy.bind Bind --service-roles '@http.svc' --identity-roles "@${http_server_id}"

You can “clean up” by running these three commands, then running the ones shown above:

ziti edge delete services where true
ziti edge delete configs where true
ziti edge delete service-policies where true

finally getting back to this, just did

docker compose down -v
docker compose up

I don’t have ziti tools installed on my docker host so I did a docker exec into the controller, ran zitiLogon there and then ran the ziti edge commands you said you used to create the service.

As expected I do get a jwt that I can load up in the edge client which shows the http.ziti with port 80
image
However when I try to curl http.ziti in powershell on my Windows host I get a could not connect… Bad Access error.

I gotta go for now but hopefully I can noodle on this a bit more later. seems like it must be some basic piece of how this works that I’m just missing, but beats me what.

I'm going to go out on a limb and think that it's powershell's version of curl which is really just an alias for Invoke-Web-Request:

alias curl

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           curl -> Invoke-WebRequest

Instead, can you just use your web browser and make sure you go to http://http.ziti:80? Lots of browsers will just convert you from http->https so make sure it doesn't do that.

I'm leery of powershell's 'curl'.

Looks like I didn’t look back far enough for the errors :man_facepalming:

✔ Container docker-web-test-blue-1    Created0.1s
 ! web-test-blue The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested 0.0s

I couldn’t connect to it because it would not run on OCI Arm host vm

Switched to a web test docker image that supports arm and magic.

thanks again for all the help, and sorry for the wild goose chase

Oh interesting! I kinda want to try now. Glad you got it up and running though! Thanks for letting us know