Skip to content

Commit

Permalink
certs: update tscert dialer to connect to tsnet server
Browse files Browse the repository at this point in the history
This provides an alternate implementation for tscert.TailscaledDialer
that tries to find a tsnet server for the requested certificate.
This allows caddy-tailscale to be used with caddy's auto_https support.

Fixes #19

Signed-off-by: Will Norris <will@tailscale.com>
  • Loading branch information
willnorris committed May 17, 2024
1 parent ff64dc8 commit 653a702
Showing 1 changed file with 46 additions and 0 deletions.
46 changes: 46 additions & 0 deletions module.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@ import (
"strings"

"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/modules/caddytls"
"github.com/caddyserver/certmagic"
"github.com/tailscale/tscert"
"go.uber.org/zap"
"tailscale.com/tsnet"
)

func init() {
caddy.RegisterNetwork("tailscale", getPlainListener)
caddy.RegisterNetwork("tailscale+tls", getTLSListener)

tscert.TailscaledDialer = localAPIDialer
}

func getPlainListener(c context.Context, _ string, addr string, _ net.ListenConfig) (any, error) {
Expand Down Expand Up @@ -262,3 +267,44 @@ func (t *tsnetServerListener) Close() error {
_, err := nodes.Delete(t.name)
return err
}

// localAPIDialer finds the node that matches the requested certificate in ctx
// and dials that node's local API.
// If no matching node is found, the default dailer is used,
// which tries to connect to a local tailscaled on the machine.
func localAPIDialer(ctx context.Context, network, addr string) (net.Conn, error) {
if addr != "local-tailscaled.sock:80" {
return nil, fmt.Errorf("unexpected URL address %q", addr)
}

serverName, ok := ctx.Value(caddytls.SNIServerNameCtxKey).(string)
if !ok {
return tscert.DefaultDialer(ctx, network, addr)
}

var tn *tailscaleNode
nodes.Range(func(key, value any) bool {
n, ok := value.(*tailscaleNode)
if !ok || n == nil {
return true
}
for _, d := range n.CertDomains() {
// MatchWildcard is not really necessary since Tailscale doesn't do wildcard certs,
// but caddy uses it for the built-in Tailscale CertGetter, so we do so here as well.
if certmagic.MatchWildcard(serverName, d) {
tn = n
return false
}
}

return true
})

if tn != nil {
if lc, err := tn.LocalClient(); err == nil {
return lc.Dial(ctx, network, addr)
}
}

return tscert.DefaultDialer(ctx, network, addr)
}

0 comments on commit 653a702

Please sign in to comment.