I follow all steps you suggested and it seems work, but i don't know how to ensure. Let me check if on the right way please.
Trying to understand
So, correct me if i'm wrong, i think hmisiemens cointainer actually connects to plcsiemens through the ziti-client router because in compose.yml i've not set hmisiemens as part of testnet, so "the only way to access testnet network" is through the edge-router.
A little doubt
What makes me in doubt is last hint you suggested me. Now i have PLCSIEMENS_ADDRESS=${PLCSIEMENS_ADDRESS:-172.19.1.1} and all works since i've network_mode: service:ziti-client in the compose.yml (if i remove this line, i get Unreachable peer, that's ok).
Where i should see something like PLCSIEMENS_ADDRESS="plcsiemens.ziti.internal" as you suggested?
Server-side tunneler intercepting
Last question: if i set siemensclient as part of testnet network with his own ipaddress, i can quietly connect to plcsiemens byepassing all ziti infrastructure. I thought server-side tunneler could intercept all incoming requests. Is there something else to be done to reach this goal?
When i say "make siemens client part of testnet network" i mean the following configuration:
Ziti will grant access but does not block access in that particular way, i.e. as a firewall. You can isolate the server at the network layer then grant access with Ziti.
"Interception" in the Ziti jargon refers to a client proxy for requests that match a Ziti service address.
Ok, so the only way to reach this behaviour is isolating networks and make ziti being the only access point. There's no built-in option to do so in Ziti, right?
Yes, when using Ziti tunnelers in Docker. If a non-Docker server process listens only on the loopback address, then a tunneler on the same host can host a Ziti service with a host (target) address like 127.0.0.1:4321. The host may be attached to an untrusted network, but only authorized Ziti clients can reach the service.
You could have two Docker networks, "private" for the protected server and "public" for the client and Ziti controller/router. This would complicate the Docker compose project because you would then need to manage firewall rules, and DNS records or IPAM.
I cannot access in this way because the lib which connects to plcsiemen asks for IP address and not DNS name, so i guess i need configure the plc-client-config with the IP address (in this case 172.19.1.1)
Last question! To reach the behaviour we were talking about before, let me know if this idea could make sense:
if i've understood correctly, all the infrastructure we built make communication evolve
from HMI <-->PLC to HMI<-->CLI_TUN<-->SRV_TUN<-->PLC.
So: does it make sense to DROP all incoming requests on PLC execpt for what came from SRV_TUN? Simply with an iptables rule!
I know that formally is horrible (network segmentation is the right way to do so), but it's good in the context of the simulation for my project!
I'm not perfectly understanding the CLI_TUN or SRV_TUN symbols, but the following is accurate and you can make ziti-host container the only access point for the PLC to simulate network isolation.
Yes, sorry i was referring to ZITI_HOST with SRV_TUN, my bad.
So it could be an (horrible) idea in your opinion too? I'll try and eventually refers you my results!
Thanks for all the time you wasted with me until now!
I've tried dropping all packets except for those which arrives from ziti-host (the server-side tunneler), but it began not working.
Basically i run the following commands:
iptables -A INPUT -s ziti-host -j ACCEPT
iptables -A INPUT -j DROP
Then i noticed that packets were arriving from ziti-client, so i changed my iptables rules making only packets from ziti-client being accetped and restart working good.
So, new iptables configuration is:
iptables -A INPUT -s ziti-client -j ACCEPT
iptables -A INPUT -j DROP
But then i start having some doubts...
tcpdumping in my plcsiemens container and sending data from siemensclient i captured this:
and if i run docker compose down ziti-client (the client-side tunneler) the siemensclient container actually lost connection to the plcsiemens container.
For this reason, i guess this part of the communications is working fine!
I tried to understand why accepting only ziti-host packets plcsiemens began receiving nothing from anyone, and to do so i tried to install "things" on ziti-host container to sniff traffic and see if actually something pass through it.
Unfortunately, the image for ziti-host container is very very basic and i was able to install only iftop command and that's the output:
Honestly i don't know exactly how iftop works, but it seems ziti-host container has only one connection with the ziti-ctrl container (ziti-controller).
Is it possible that the following part of the communication doesn't work for an unknown reason?
Just to simplify your research of the error i drop here what i think could be useful tu have.
ziti-client,ziti-host --> ziti-ctrl:1280,3022 (both client and host reach out to the ctrl)
ziti-host --> plc:102
Ensure that only ziti-host has Ziti role attribute "plc-hosts." Then you will know the origin of the Ziti service traffic is from ziti-host --> plc:102
It seems plc-host is the only one identity with "plc-hosts" role attribute.
Since we've run the command below, i guess that if i've used the right token to initialize the ziti-host container, everything should be correctly configured.
Ensure all containers are attached to "testnet" network in your project.
Yes, do try restarting containers in turn. Ensure ziti-client is ready before starting hmi client. In my example I added a Docker health check dependency to order the clients.
I've tried re-configuring all the infrastructur from the beginning and it still not work. It seems like the ziti-host container is completely byepassed.
Here's the output of netstat -t -u run in PLC container
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 3f14bf3d52db:iso-tsap ziti-client.testn:59262 ESTABLISHED
Isn't it supposed to be one connection to ziti-host?
EDIT: running netstat -t -u in the ziti controller both connection to ziti-host and ziti-client are established. The missing part is still the ziti-host --> plc:102 connection. The hmi --> ziti-client i guess is implicit due to the fact that both container are sort of sharing the interface thanks to network_mode: service:ziti-client in the compose.yml.
tcp 0 0 a9e5890c454a:45256 a9e5890c45:pictrography ESTABLISHED
tcp6 0 0 a9e5890c454a:csregagent ziti-host.testnet:33366 ESTABLISHED
tcp6 0 0 a9e5890c45:pictrography ziti-client.testn:44184 ESTABLISHED
tcp6 0 0 a9e5890c45:pictrography a9e5890c454a:45256 ESTABLISHED
tcp6 0 0 a9e5890c454a:csregagent ziti-client.testn:50040 ESTABLISHED
tcp6 0 0 a9e5890c454a:csregagent ziti-client.testn:50030 ESTABLISHED
EDIT2: Should we change strategy? Maybe not using quickstart containers, but some other which requires extra explicit configuration.
EDIT3: Some of ziti-client's log are the following
ziti-client | {"file":"github.com/openziti/ziti/router/state/apiSessionAdded.go:124","func":"github.com/openziti/ziti/router/state.(*apiSessionAddedHandler).applySync","level":"info","msg":"finished synchronizing api sessions [count: 10, syncId: cm0l6zjuj003101lbtdsv6j0b, duration: 127.195ยตs]","time":"2024-09-02T16:05:37.191Z"}
ziti-client | {"file":"github.com/openziti/ziti/tunnel/dns/server.go:119","func":"github.com/openziti/ziti/tunnel/dns.NewDnsServer","level":"info","msg":"dns server running at 127.0.0.1:53","time":"2024-09-02T16:05:38.184Z"}
ziti-client | {"file":"github.com/openziti/ziti/tunnel/dns/server.go:271","func":"github.com/openziti/ziti/tunnel/dns.(*resolver).AddHostname","level":"info","msg":"adding ziti-tunnel.resolver.test = 19.65.28.94 to resolver","time":"2024-09-02T16:05:38.184Z"}
ziti-client | {"file":"github.com/openziti/ziti/tunnel/dns/server.go:300","func":"github.com/openziti/ziti/tunnel/dns.(*resolver).RemoveHostname","level":"info","msg":"removing ziti-tunnel.resolver.test from resolver","time":"2024-09-02T16:05:38.229Z"}
ziti-client | {"file":"github.com/openziti/ziti/tunnel/intercept/iputils.go:51","func":"github.com/openziti/ziti/tunnel/intercept.SetDnsInterceptIpRange","level":"info","msg":"dns intercept IP range: 100.64.0.1 - 100.127.255.255","time":"2024-09-02T16:05:38.229Z"}
ziti-client | {"file":"github.com/openziti/ziti/tunnel/intercept/svcpoll.go:155","func":"github.com/openziti/ziti/tunnel/intercept.(*ServiceListener).HandleServicesChange","level":"info","msg":"adding service","service":"plc-siemens-service","time":"2024-09-02T16:05:38.234Z"}
ziti-client | {"file":"github.com/openziti/ziti/tunnel/intercept/svcpoll.go:226","func":"github.com/openziti/ziti/tunnel/intercept.(*ServiceListener).addService","level":"info","msg":"starting tunnel for newly available service plc-siemens-service","serviceId":"WLtDWbS6auakI1TitWeKF","serviceName":"plc-siemens-service","time":"2024-09-02T16:05:38.235Z"}
ziti-client | {"file":"github.com/openziti/ziti/tunnel/intercept/svcpoll.go:228","func":"github.com/openziti/ziti/tunnel/intercept.(*ServiceListener).addService","level":"error","msg":"failed to intercept service: can not intercept services in host mode","serviceId":"WLtDWbS6auakI1TitWeKF","serviceName":"plc-siemens-service","time":"2024-09-02T16:05:38.235Z"}
I am mobile and will offer a quick answer with more detailed follow up on Tuesday or Thursday this week.
My hypothesis was the intercept had a lower precedence than the real IP because the real address'es network is directly attached.
To test this, I suggest a fictitious intercept (meaning from a subnet that is not attached to the client container).
I take it you tried inventing an intercept IP address in the same subnet that is attached to the client, but that would suffer from the same problem if the hypothesis is correct.
Assuming there are no networks in 10.0.0.0/8 attached to the client you can safely us an intercept address like 10.11.12.13.