Hi,
we are deploying a self hosted ziti network to connect our platform with its extensions.
Extensions are web application (rest apis) exposed on the ziti network and we use zrok frontend to route call to the right extension (group of instances each of them binding to the same ziti service) based on the hostname.
We would like ziti client api and router to offer a certificate issued by a public ca (like let’s encrypt) while still using internal ziti CA for client authentication.
This is because there are corporate firewall like Fortigate, Checkpoint etc that have their own list of trusted CAs so they don’t allow connections if the server certificate is not signed by one of their ca.
According to the helm charts for deploying ziti, looks like it’s possible but I had issues with that:
opened 05:48PM - 17 Oct 25 UTC
Hi,
I configured my client api to use a Let's Encrypt certificate, and I deploy… ed a router with an alternative TLS listener to use also Let's Encrypt certificate (via Helm chart).
I included the Let's Encrypt chain within the identity (in the ca chain).
When I try to bind to a service looks like the handshake with the client api succeeds, but the handshake with the router fails.
```
(44854)[ 0.000] INFO ziti-sdk:utils.c:196 ziti_log_set_level() set log level: root=4/DEBUG
(44854)[ 0.000] INFO ziti-sdk:utils.c:165 ziti_log_init() Ziti C SDK version 1.9.1 @g872c073(HEAD) starting at (2025-10-17T17:38:33.123)
(44854)[ 0.000] DEBUG ziti-sdk:zitilib.c:1154 looper() loop is starting
(44854)[ 0.001] DEBUG ziti-sdk:zitilib.c:273 load_ziti_ctx() loading identity from idnew.json
(44854)[ 0.001] INFO ziti-sdk:ziti.c:512 ziti_start_internal() ztx[1] enabling Ziti Context
(44854)[ 0.001] INFO ziti-sdk:ziti.c:528 ziti_start_internal() ztx[1] using tlsuv[v0.38.1/OpenSSL 3.5.1 1 Jul 2025]
(44854)[ 0.001] INFO ziti-sdk:ziti_ctrl.c:637 ziti_ctrl_init() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] controller initialized
(44854)[ 0.001] DEBUG ziti-sdk:ziti_ctrl.c:648 ziti_ctrl_init() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] ziti controller client initialized
(44854)[ 0.001] INFO ziti-sdk:ziti.c:606 ztx_init_controller() ztx[1] Loading ziti context with controller[https://api.ziti.s1.today:8444/edge/client/v1]
(44854)[ 0.001] DEBUG ziti-sdk:ziti.c:537 ziti_start_internal() ztx[1] using metrics interval: 0
(44854)[ 0.001] DEBUG ziti-sdk:ziti.c:226 ziti_set_unauthenticated() ztx[1] setting auth_state[0] to 0
(44854)[ 0.001] DEBUG ziti-sdk:ziti_ctrl.c:380 ziti_ctrl_clear_api_session() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] clearing api session token for ziti_controller
(44854)[ 0.001] DEBUG ziti-sdk:ziti_ctrl.c:1106 ctrl_paging_req() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] starting paging request GET[/external-jwt-signers]
(44854)[ 0.349] DEBUG ziti-sdk:ziti_ctrl.c:502 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] completed GET[/version] in 0.345 s
(44854)[ 0.349] INFO ziti-sdk:ziti.c:2046 version_pre_auth_cb() ztx[1] connected to Legacy controller https://api.ziti.s1.today:8444/edge/client/v1 version v1.6.8(04048e4d05eb 2025-09-04T19:31:30Z)
(44854)[ 0.349] DEBUG ziti-sdk:legacy_auth.c:238 auth_timer_cb() refreshing session[(nil)]
(44854)[ 0.415] DEBUG ziti-sdk:ziti_ctrl.c:487 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] received 0/0 for paging request GET[/external-jwt-signers]
(44854)[ 0.415] DEBUG ziti-sdk:ziti_ctrl.c:497 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] completed paging request GET[/external-jwt-signers] in 0.411 s
(44854)[ 0.415] DEBUG ziti-sdk:ziti.c:663 ext_jwt_singers_cb() ztx[1] 0 external auth providers available
(44854)[ 0.518] DEBUG ziti-sdk:ziti_ctrl.c:502 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] completed POST[/authenticate?method=cert] in 0.168 s
(44854)[ 0.518] DEBUG ziti-sdk:ziti_ctrl.c:394 ctrl_login_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] authenticated successfully session[cmgv4ucsq017l0ec21h5zheeh]
(44854)[ 0.518] DEBUG ziti-sdk:legacy_auth.c:170 login_cb() logged in successfully => api_session[cmgv4ucsq017l0ec21h5zheeh]
(44854)[ 0.518] DEBUG ziti-sdk:ziti.c:381 ziti_set_fully_authenticated() ztx[1] setting auth_state[0] to 3
(44854)[ 0.518] DEBUG ziti-sdk:ziti.c:1704 do_ztx_set_deadline() ztx[1] expire_cb[ziti.c:refresh_cb] timeout[0]
(44854)[ 0.518] DEBUG ziti-sdk:ziti.c:1704 do_ztx_set_deadline() ztx[1] expire_cb[posture.c:ziti_pr_ticker_cb] timeout[1]
(44854)[ 0.518] DEBUG ziti-sdk:legacy_auth.c:309 refresh_delay() api session set based on session->expireSeconds, next refresh in 1740s
(44854)[ 0.518] DEBUG ziti-sdk:ziti.c:1747 ztx_process_deadlines() ztx[1] calling ziti.c:refresh_cb(0xffff90005f40)
(44854)[ 0.518] DEBUG ziti-sdk:ziti_ctrl.c:1106 ctrl_paging_req() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] starting paging request GET[/current-identity/edge-routers]
(44854)[ 0.520] DEBUG ziti-sdk:ziti.c:1747 ztx_process_deadlines() ztx[1] calling posture.c:ziti_pr_ticker_cb(0xffff90005f40)
(44854)[ 0.520] INFO ziti-sdk:posture.c:206 ziti_send_posture_data() ztx[1] first run or potential controller restart detected
(44854)[ 0.520] DEBUG ziti-sdk:posture.c:210 ziti_send_posture_data() ztx[1] posture checks must_send set to TRUE, new_session_id[TRUE], must_send_every_time[TRUE], new_controller_instance[TRUE]
(44854)[ 0.520] DEBUG ziti-sdk:ziti.c:1704 do_ztx_set_deadline() ztx[1] expire_cb[posture.c:ziti_pr_ticker_cb] timeout[20000]
(44854)[ 0.722] DEBUG ziti-sdk:ziti_ctrl.c:502 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] completed GET[/current-api-session] in 0.204 s
(44854)[ 0.722] DEBUG ziti-sdk:ziti_ctrl.c:394 ctrl_login_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] authenticated successfully session[cmgv4ucsq017l0ec21h5zheeh]
(44854)[ 0.722] DEBUG ziti-sdk:ziti.c:2243 api_session_cb() ztx[1] app is not requiring expiration check
(44854)[ 0.765] DEBUG ziti-sdk:ziti_ctrl.c:502 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] completed GET[/current-identity] in 0.246 s
(44854)[ 0.765] DEBUG ziti-sdk:zitilib.c:1003 do_ziti_bind() requesting bind fd[19] to service[@ext-0000-0000]
(44854)[ 0.824] DEBUG ziti-sdk:ziti_ctrl.c:502 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] completed GET[/current-identity] in 0.306 s
(44854)[ 0.866] DEBUG ziti-sdk:ziti_ctrl.c:487 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] received 1/1 for paging request GET[/current-identity/edge-routers]
(44854)[ 0.866] DEBUG ziti-sdk:ziti_ctrl.c:497 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] completed paging request GET[/current-identity/edge-routers] in 0.347 s
(44854)[ 0.866] INFO ziti-sdk:channel.c:265 new_ziti_channel() ch[0] (public-router) new channel for ztx[1] identity[ins-0000-0000-0001.ext-0000-0000]
(44854)[ 0.866] DEBUG ziti-sdk:channel.c:316 ziti_channel_set_url() ch[0] setting channel[public-router] url[tls://router.ziti.s1.today:8445]
(44854)[ 0.866] INFO ziti-sdk:channel.c:836 reconnect_channel() ch[0] reconnecting NOW
(44854)[ 0.866] DEBUG ziti-sdk:ziti.c:1704 do_ztx_set_deadline() ztx[1] expire_cb[channel.c:reconnect_cb] timeout[0]
(44854)[ 0.866] DEBUG ziti-sdk:ziti.c:1747 ztx_process_deadlines() ztx[1] calling channel.c:reconnect_cb(0xffff90077990)
(44854)[ 0.866] DEBUG ziti-sdk:channel.c:802 reconnect_cb() ch[0] connecting to tls://router.ziti.s1.today:8445
(44854)[ 0.866] DEBUG ziti-sdk:ziti.c:1704 do_ztx_set_deadline() ztx[1] expire_cb[channel.c:ch_connect_timeout] timeout[20000]
(44854)[ 0.931] DEBUG ziti-sdk:ziti_ctrl.c:502 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] completed GET[/current-api-session/service-updates] in 0.412 s
(44854)[ 0.931] DEBUG ziti-sdk:ziti_ctrl.c:1106 ctrl_paging_req() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] starting paging request GET[/services?configTypes=all]
(44854)[ 0.973] DEBUG ziti-sdk:ziti_ctrl.c:502 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] completed GET[/services] in 0.207 s
(44854)[ 1.044] DEBUG ziti-sdk:ziti_ctrl.c:487 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] received 1/1 for paging request GET[/services?configTypes=all]
(44854)[ 1.044] DEBUG ziti-sdk:ziti_ctrl.c:497 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] completed paging request GET[/services?configTypes=all] in 0.113 s
(44854)[ 1.044] DEBUG ziti-sdk:ziti.c:1704 do_ztx_set_deadline() ztx[1] expire_cb[ziti.c:refresh_cb] timeout[60000]
(44854)[ 1.044] DEBUG ziti-sdk:ziti.c:1391 update_services() ztx[1] sending service event initial[true] 0 added, 0 removed, 1 changed
(44854)[ 1.133] DEBUG ziti-sdk:ziti_ctrl.c:502 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] completed GET[/services/3jf30eoIMS4CxTWjv82CxU/edge-routers] in 0.160 s
(44854)[ 1.133] DEBUG ziti-sdk:bind.c:273 list_routers_cb() server[1.0](ext-0000-0000) public-router/tls://router.ziti.s1.today:8445
(44854)[ 1.240] ERROR tlsuv:engine.c:868 openssl: handshake was terminated: SSL routines
(44854)[ 1.240] ERROR tlsuv:tlsuv.c:267 TLS handshake failed: certificate verify failed
(44854)[ 1.240] ERROR ziti-sdk:channel.c:976 on_tls_connect() ch[0] failed to connect to ER[public-router] [-103/certificate verify failed]
(44854)[ 1.240] DEBUG ziti-sdk:deadline.h:38 clear_deadline() expire_cb[channel.c:ch_connect_timeout]
(44854)[ 1.240] DEBUG ziti-sdk:channel.c:100 close_connection() ch[0] closing TLS[0xffff900a48d0]
(44854)[ 1.240] INFO ziti-sdk:channel.c:834 reconnect_channel() ch[0] reconnecting in 4048ms (attempt = 1)
(44854)[ 1.240] DEBUG ziti-sdk:ziti.c:1704 do_ztx_set_deadline() ztx[1] expire_cb[channel.c:reconnect_cb] timeout[4048]
(44854)[ 1.240] DEBUG ziti-sdk:ziti_ctrl.c:502 ctrl_body_cb() ctrl[https://api.ziti.s1.today:8444/edge/client/v1] completed POST[/sessions] in 0.270 s
(44854)[ 1.240] DEBUG ziti-sdk:bind.c:136 process_bindings() server[1.0](ext-0000-0000) checking router[public-router]
(44854)[ 1.240] DEBUG ziti-sdk:bind.c:139 process_bindings() server[1.0](ext-0000-0000) router[public-router] is not connected
(44854)[ 1.240] DEBUG ziti-sdk:zitilib.c:979 on_ziti_bind() successfully bound fd[19] to service[ext-0000-0000]
```
Am I doing something wrong, or is it a bug?
Thanks!
Am I wrong in thinking that it can be done?
Thank you!
Mmmmm. OpenZIti really wants to manage its own PKI at this time. I believe this is the feature you would need Enable 3rd Party CA Router Enrollment · Issue #2110 · openziti/ziti · GitHub but I'm not 100% sure
I'll see if anyone else on the team has any additional thoughts until then, it'll be easier to get the root ca added to those troublesome firewalls?
I don’t understand why the certificate presented to clients must be signed by the same CA that signs identities. Trust a new CA in a big corporate firewall, it’s always a bureaucratic pain. Anyway, looking forward to the team feedback. Thank you!