feat(tsconnect): add getCert, listenTLS, setFunnel + fix TLS cert for WASM
Enable ACME TLS certificates on js/wasm by dropping the !js build tag from cert.go and routing storage through the state store. Add getCert, listenTLS, and setFunnel WASM bindings with a combinedTLSListener that merges Funnel ingress and direct tailnet connections. Notify the control plane immediately after serve config changes to accelerate Funnel DNS provisioning. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -122,6 +122,25 @@ type extension struct {
|
||||
// that periodically pokes [LocalBackend.GetCertPEM] so renewals
|
||||
// happen on idle nodes. Non-nil while the loop is running.
|
||||
certRefreshCancel context.CancelFunc
|
||||
|
||||
// httpClient, if non-nil, is used for all ACME HTTP requests instead of
|
||||
// http.DefaultClient. Set via [SetHTTPClient] before first cert use.
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
// SetHTTPClient sets a custom HTTP client for ACME certificate operations on
|
||||
// b. On js/wasm this can route requests through the Tailscale network stack to
|
||||
// bypass browser CORS if Let's Encrypt endpoints fail preflight. A nil value
|
||||
// (the default) uses http.DefaultClient.
|
||||
func SetHTTPClient(b *ipnlocal.LocalBackend, c *http.Client) error {
|
||||
e, err := extFor(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
e.httpClient = c
|
||||
return nil
|
||||
}
|
||||
|
||||
// lockDomain returns the mutex for domain, creating it on first use.
|
||||
|
||||
@@ -82,6 +82,10 @@ func certDir(b *ipnlocal.LocalBackend) (string, error) {
|
||||
|
||||
func (e *extension) getCertStore(b *ipnlocal.LocalBackend) (certStore, error) {
|
||||
st := b.Sys().StateStore.Get()
|
||||
if runtime.GOOS == "js" {
|
||||
// No filesystem to hold a cert directory; the state store is all we have.
|
||||
return certStateStore{StateStore: st}, nil
|
||||
}
|
||||
switch st.(type) {
|
||||
case *store.FileStore:
|
||||
case *mem.Store:
|
||||
@@ -396,10 +400,14 @@ func (e *extension) acmeClient(cs certStore) (*xacme.Client, error) {
|
||||
// Note: if we add support for additional ACME providers (other than
|
||||
// LetsEncrypt), we should make sure that they support ARI extension (see
|
||||
// shouldStartDomainRenewalARI).
|
||||
e.mu.Lock()
|
||||
httpClient := e.httpClient
|
||||
e.mu.Unlock()
|
||||
return &xacme.Client{
|
||||
Key: key,
|
||||
UserAgent: "tailscaled/" + version.Long(),
|
||||
DirectoryURL: envknob.String("TS_DEBUG_ACME_DIRECTORY_URL"),
|
||||
HTTPClient: httpClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !js && !ts_omit_acme
|
||||
//go:build !ts_omit_acme
|
||||
|
||||
package condregister
|
||||
|
||||
|
||||
Reference in New Issue
Block a user