summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorchaosinthecrd <tom@tmlabs.co.uk>2026-03-02 19:26:30 +0000
committerchaosinthecrd <tom@tmlabs.co.uk>2026-03-02 19:34:47 +0000
commita766e00e05015735a567946351a2b08ace73110e (patch)
treed11e0a8294d989da42c8b81a3efb4938e0df0903
parenteeb1fa047bef2896d81eb01ab1a653419c129dc2 (diff)
downloadtailscale-k8s-proxy-l4-tcpforward.tar.xz
tailscale-k8s-proxy-l4-tcpforward.zip
cmd/k8s-proxy: use L4 TCPForward instead of L7 HTTP proxyk8s-proxy-l4-tcpforward
considerable latency was seen when using k8s-proxy with ProxyGroup in the kubernetes operator. Switching to L4 TCPForward solves this. Fixes tailscale#18171 Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
-rw-r--r--cmd/k8s-operator/depaware.txt2
-rw-r--r--cmd/k8s-proxy/k8s-proxy.go22
-rw-r--r--k8s-operator/api-proxy/proxy.go24
3 files changed, 27 insertions, 21 deletions
diff --git a/cmd/k8s-operator/depaware.txt b/cmd/k8s-operator/depaware.txt
index d801c0285..38b8c4679 100644
--- a/cmd/k8s-operator/depaware.txt
+++ b/cmd/k8s-operator/depaware.txt
@@ -160,7 +160,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/
💣 github.com/modern-go/reflect2 from github.com/json-iterator/go
github.com/munnerz/goautoneg from k8s.io/kube-openapi/pkg/handler3+
github.com/opencontainers/go-digest from github.com/distribution/reference
- github.com/pires/go-proxyproto from tailscale.com/ipn/ipnlocal
+ github.com/pires/go-proxyproto from tailscale.com/ipn/ipnlocal+
github.com/pkg/errors from github.com/evanphx/json-patch/v5+
github.com/pmezard/go-difflib/difflib from k8s.io/apimachinery/pkg/util/diff
D github.com/prometheus-community/pro-bing from tailscale.com/wgengine/netstack
diff --git a/cmd/k8s-proxy/k8s-proxy.go b/cmd/k8s-proxy/k8s-proxy.go
index e00d43a94..38a86a5e0 100644
--- a/cmd/k8s-proxy/k8s-proxy.go
+++ b/cmd/k8s-proxy/k8s-proxy.go
@@ -50,6 +50,12 @@ import (
"tailscale.com/tsnet"
)
+const (
+ // proxyProtocolV2 enables PROXY protocol v2 to preserve original client
+ // connection info after TLS termination.
+ proxyProtocolV2 = 2
+)
+
func main() {
encoderCfg := zap.NewProductionEncoderConfig()
encoderCfg.EncodeTime = zapcore.RFC3339TimeEncoder
@@ -441,24 +447,16 @@ func setServeConfig(ctx context.Context, lc *local.Client, cm *certs.CertManager
if err != nil {
return fmt.Errorf("error getting local client status: %w", err)
}
- serviceHostPort := ipn.HostPort(fmt.Sprintf("%s.%s:443", name.WithoutPrefix(), status.CurrentTailnet.MagicDNSSuffix))
+ serviceSNI := fmt.Sprintf("%s.%s", name.WithoutPrefix(), status.CurrentTailnet.MagicDNSSuffix)
serveConfig := ipn.ServeConfig{
- // Configure for the Service hostname.
Services: map[tailcfg.ServiceName]*ipn.ServiceConfig{
name: {
TCP: map[uint16]*ipn.TCPPortHandler{
443: {
- HTTPS: true,
- },
- },
- Web: map[ipn.HostPort]*ipn.WebServerConfig{
- serviceHostPort: {
- Handlers: map[string]*ipn.HTTPHandler{
- "/": {
- Proxy: "http://localhost:80",
- },
- },
+ TCPForward: "localhost:80",
+ TerminateTLS: serviceSNI,
+ ProxyProtocol: proxyProtocolV2,
},
},
},
diff --git a/k8s-operator/api-proxy/proxy.go b/k8s-operator/api-proxy/proxy.go
index c4c651b1f..ff2e033af 100644
--- a/k8s-operator/api-proxy/proxy.go
+++ b/k8s-operator/api-proxy/proxy.go
@@ -12,20 +12,19 @@ import (
"encoding/json"
"errors"
"fmt"
+ "github.com/pires/go-proxyproto"
+ "go.uber.org/zap"
"io"
+ "k8s.io/apimachinery/pkg/util/sets"
+ "k8s.io/apiserver/pkg/endpoints/request"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/transport"
"net"
"net/http"
"net/http/httputil"
"net/netip"
"net/url"
"strings"
- "time"
-
- "go.uber.org/zap"
- "k8s.io/apimachinery/pkg/util/sets"
- "k8s.io/apiserver/pkg/endpoints/request"
- "k8s.io/client-go/rest"
- "k8s.io/client-go/transport"
"tailscale.com/client/local"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/envknob"
@@ -38,6 +37,7 @@ import (
"tailscale.com/util/clientmetric"
"tailscale.com/util/ctxkey"
"tailscale.com/util/set"
+ "time"
)
var (
@@ -163,10 +163,18 @@ func (ap *APIServerProxy) Run(ctx context.Context) error {
}
} else {
var err error
- proxyLn, err = net.Listen("tcp", "localhost:80")
+ baseLn, err := net.Listen("tcp", "localhost:80")
if err != nil {
return fmt.Errorf("could not listen on :80: %w", err)
}
+ proxyLn = &proxyproto.Listener{
+ Listener: baseLn,
+ ReadHeaderTimeout: 10 * time.Second,
+ ConnPolicy: proxyproto.ConnPolicyFunc(func(opts proxyproto.ConnPolicyOptions) (proxyproto.Policy,
+ error) {
+ return proxyproto.REQUIRE, nil
+ }),
+ }
serve = ap.hs.Serve
}