Is it possible to bind to service without host config and still have TLS?

Context:

  1. a go app that binds to a service

  2. intercept config for myapi.ziti on port 443

  3. chrome browser that opens(host running a tunneler) https://myapi.ziti

The api part, without TLS works great, but it would be better for api to use TLS(get rid of chrome warning - this site is not secure).

Heres my code:

package main

import (
	"context"
	"fmt"
	"log"
	"net"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/openziti/sdk-golang/ziti"
	"github.com/openziti/sdk-golang/ziti/edge"
)

func main() {
	// load identity
	cfg, err := ziti.NewConfigFromFile("api-binder.json")
	if err != nil {
		panic(err)
	}
	ctx, err := ziti.NewContext(cfg)
	if err != nil {
		panic(err)
	}

	// listen on a Ziti service (instead of a TCP port)
	listener, err := ctx.Listen("api")
	if err != nil {
		panic(err)
	}
	defer listener.Close()

	// create Gin router
	r := gin.Default()
	r.GET("/", CheckAuth, func(c *gin.Context) {
		log.Print(c.Get("zitiIdentity"))
		log.Print(c.Get("AppData"))
		c.JSON(200, gin.H{"msg": "hello over ziti"})
	})
	r.POST("/echo", func(c *gin.Context) {
		body, _ := c.GetRawData()
		c.Data(200, "application/octet-stream", body)
	})

	srv := &http.Server{
		Handler: r,
		ConnContext: func(ctx context.Context, c net.Conn) context.Context {
			if edge, ok := c.(edge.Conn); ok {
				return context.WithValue(ctx, "zitiConn", edge)
			}
			return ctx
		},
	}

	fmt.Println("Gin HTTP server is running over Ziti service: my-http-service")
	if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed {
		panic(err)
	}
}

func CheckAuth(c *gin.Context) {
	val := c.Request.Context().Value("zitiConn")
	if val != nil {
		if edge, ok := val.(edge.Conn); ok {
			c.Set("zitiIdentity", edge.SourceIdentifier())
			c.Set("AppData", string(edge.GetAppData()))
		}
	}
	c.Next()
}


If i do

if err := srv.ServeTLS(listener, "server.crt", "server.key"); err != nil && err != http.ErrServerClosed {

I get errors in logs:

2025/10/01 15:02:17 http: TLS handshake error from ziti-edge-router connId=2147483648, logical=ziti-sdk[router=tls:ziti-edge-router:80]: remote error: tls: unknown certificate

Is it possible to still use https for an api when binding to service?

I got it working(getting ziti data in middleware), but still get errors in logs:

package main

import (
	"context"
	"crypto/tls"
	"fmt"
	"log"
	"net"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/openziti/sdk-golang/ziti"
	"github.com/openziti/sdk-golang/ziti/edge"
)

func main() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	// load identity
	cfg, err := ziti.NewConfigFromFile("api-binder.json")
	if err != nil {
		panic(err)
	}
	ctx, err := ziti.NewContext(cfg)
	if err != nil {
		panic(err)
	}

	// listen on a Ziti service (instead of a TCP port)
	listener, err := ctx.Listen("api")
	if err != nil {
		panic(err)
	}
	defer listener.Close()

	// create Gin router
	r := gin.Default()
	r.GET("/", CheckAuth, func(c *gin.Context) {
		log.Print(c.Get("zitiIdentity"))
		log.Print(c.Get("AppData"))
		c.JSON(200, gin.H{"msg": "hello over ziti"})
	})
	r.POST("/echo", func(c *gin.Context) {
		body, _ := c.GetRawData()
		c.Data(200, "application/octet-stream", body)
	})

	srv := &http.Server{
		Handler: r,
		ConnContext: func(ctx context.Context, c net.Conn) context.Context {
			// If TLS, unwrap it
			if tlsConn, ok := c.(*tls.Conn); ok {
				if underlying := tlsConn.NetConn(); underlying != nil {
					if edgeConn, ok := underlying.(edge.Conn); ok {
						return context.WithValue(ctx, "zitiConn", edgeConn)
					}
				}
			}

			// If it’s a direct Ziti connection (no TLS)
			if edgeConn, ok := c.(edge.Conn); ok {
				return context.WithValue(ctx, "zitiConn", edgeConn)
			}

			log.Print("connection was neither edge.Conn nor tls->edge.Conn")
			return ctx
		},
	}

	fmt.Println("Gin HTTP server is running over Ziti service: my-http-service")
	if err := srv.ServeTLS(listener, "server.crt", "server.key"); err != nil {
		panic(err)
	}
}

func CheckAuth(c *gin.Context) {
	val := c.Request.Context().Value("zitiConn")
	if val != nil {
		if edge, ok := val.(edge.Conn); ok {
			c.Set("zitiIdentity", edge.SourceIdentifier())
			c.Set("AppData", string(edge.GetAppData()))
		} else {
			log.Print("not okey")
		}
	}
	c.Next()
}

logs:

INFO[0000] new service session                           session token=f48603bd-af8f-4346-a32a-5946e10d4ec0
2025/10/01 18:47:01 server.go:3640: http: TLS handshake error from ziti-edge-router connId=2147483648, logical=ziti-sdk[router=tls:ziti-edge-router:80]: remote error: tls: unknown certificate
2025/10/01 18:47:01 server.go:3640: http: TLS handshake error from ziti-edge-router connId=2147483649, logical=ziti-sdk[router=tls:ziti-edge-router:80]: remote error: tls: unknown certificate
2025/10/01 18:47:01 main.go:39: admin1@gmail.comtrue
2025/10/01 18:47:01 main.go:40: {"connType":null,"dst_protocol":"tcp","dst_hostname":"myapi.ziti","dst_ip":"100.64.0.7","dst_port":"443","src_protocol":"tcp","src_ip":"100.64.0.1","src_port":"44278"}true
[GIN] 2025/10/01 - 18:47:01 | 200 |     144.125µs |                 | GET      "/"

More info on the TLS handshake errors, they only show up on the first request, any subsequent request dont have those warnings. And they show up only when called from chrome(if i curl from terminal they dont show up)

Yes it's certainly possible as you discovered. You just need to make a tls listener in some fashion (as you showed in your code)

As for a TLS handshake error, if you are presenting a correct certificate, you won't have that problem. Unfortunately, I don't believe this is an OpenZiti-related issue so it's kinda hard for us to help you. I think this is just a "regular ol tls-related" issue. OpenZiti won't impact that at all.

If you curl from the terminal and don't see the problem, that smells to me like the go library doesn't use the same ca store possibly, but unfortunattely this doesn't seem like an OpenZiti issue to me.

1 Like