cmd/k8s-operator: add support for taiscale.com/http-redirect (#17596)

* cmd/k8s-operator: add support for taiscale.com/http-redirect

The k8s-operator now supports a tailscale.com/http-redirect annotation
on Ingress resources. When enabled, this automatically creates port 80
handlers that automatically redirect to the equivalent HTTPS location.

Fixes #11252

Signed-off-by: Fernando Serboncini <fserb@tailscale.com>

* Fix for permanent redirect

Signed-off-by: Fernando Serboncini <fserb@tailscale.com>

* lint

Signed-off-by: Fernando Serboncini <fserb@tailscale.com>

* warn for redirect+endpoint

Signed-off-by: Fernando Serboncini <fserb@tailscale.com>

* tests

Signed-off-by: Fernando Serboncini <fserb@tailscale.com>

---------

Signed-off-by: Fernando Serboncini <fserb@tailscale.com>
This commit is contained in:
Fernando Serboncini
2025-11-28 09:16:18 -05:00
committed by GitHub
parent 411cee0dc9
commit 7c5c02b77a
5 changed files with 429 additions and 36 deletions
+22 -3
View File
@@ -290,6 +290,25 @@ func (r *HAIngressReconciler) maybeProvision(ctx context.Context, hostname strin
ingCfg.Web[epHTTP] = &ipn.WebServerConfig{
Handlers: handlers,
}
if isHTTPRedirectEnabled(ing) {
logger.Warnf("Both HTTP endpoint and HTTP redirect flags are enabled: ignoring HTTP redirect.")
}
} else if isHTTPRedirectEnabled(ing) {
logger.Infof("HTTP redirect enabled, setting up port 80 redirect handlers")
epHTTP := ipn.HostPort(fmt.Sprintf("%s:80", dnsName))
ingCfg.TCP[80] = &ipn.TCPPortHandler{HTTP: true}
ingCfg.Web[epHTTP] = &ipn.WebServerConfig{
Handlers: map[string]*ipn.HTTPHandler{},
}
web80 := ingCfg.Web[epHTTP]
for mountPoint := range handlers {
// We send a 301 - Moved Permanently redirect from HTTP to HTTPS
redirectURL := "301:https://${HOST}${REQUEST_URI}"
logger.Debugf("Creating redirect handler: %s -> %s", mountPoint, redirectURL)
web80.Handlers[mountPoint] = &ipn.HTTPHandler{
Redirect: redirectURL,
}
}
}
var gotCfg *ipn.ServiceConfig
@@ -316,7 +335,7 @@ func (r *HAIngressReconciler) maybeProvision(ctx context.Context, hostname strin
}
tsSvcPorts := []string{"tcp:443"} // always 443 for Ingress
if isHTTPEndpointEnabled(ing) {
if isHTTPEndpointEnabled(ing) || isHTTPRedirectEnabled(ing) {
tsSvcPorts = append(tsSvcPorts, "tcp:80")
}
@@ -346,7 +365,7 @@ func (r *HAIngressReconciler) maybeProvision(ctx context.Context, hostname strin
// 5. Update tailscaled's AdvertiseServices config, which should add the Tailscale Service
// IPs to the ProxyGroup Pods' AllowedIPs in the next netmap update if approved.
mode := serviceAdvertisementHTTPS
if isHTTPEndpointEnabled(ing) {
if isHTTPEndpointEnabled(ing) || isHTTPRedirectEnabled(ing) {
mode = serviceAdvertisementHTTPAndHTTPS
}
if err = r.maybeUpdateAdvertiseServicesConfig(ctx, pg.Name, serviceName, mode, logger); err != nil {
@@ -377,7 +396,7 @@ func (r *HAIngressReconciler) maybeProvision(ctx context.Context, hostname strin
Port: 443,
})
}
if isHTTPEndpointEnabled(ing) {
if isHTTPEndpointEnabled(ing) || isHTTPRedirectEnabled(ing) {
ports = append(ports, networkingv1.IngressPortStatus{
Protocol: "TCP",
Port: 80,