Ingress for VIP

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
This commit is contained in:
Irbe Krumina 2024-02-23 16:14:18 +00:00
parent ab1eb428d9
commit 350d37286d
3 changed files with 33 additions and 16 deletions

View File

@ -155,6 +155,16 @@ func (a *IngressReconciler) maybeProvision(ctx context.Context, logger *zap.Suga
// magic443 is a fake hostname that we can use to tell containerboot to swap
// out with the real hostname once it's known.
const magic443 = "${TS_CERT_DOMAIN}:443"
tlsHostname := ""
if ing.Spec.TLS != nil && len(ing.Spec.TLS) > 0 && len(ing.Spec.TLS[0].Hosts) > 0 {
tlsHostname = ing.Spec.TLS[0].Hosts[0]
}
tlsHost := ipn.HostPort(fmt.Sprintf("%s:443", tlsHostname))
if tlsHostname == "" {
tlsHost = magic443
}
sc := &ipn.ServeConfig{
TCP: map[uint16]*ipn.TCPPortHandler{
443: {
@ -162,18 +172,18 @@ func (a *IngressReconciler) maybeProvision(ctx context.Context, logger *zap.Suga
},
},
Web: map[ipn.HostPort]*ipn.WebServerConfig{
magic443: {
tlsHost: {
Handlers: map[string]*ipn.HTTPHandler{},
},
},
}
if opt.Bool(ing.Annotations[AnnotationFunnel]).EqualBool(true) {
sc.AllowFunnel = map[ipn.HostPort]bool{
magic443: true,
tlsHost: true,
}
}
web := sc.Web[magic443]
web := sc.Web[tlsHost]
addIngressBackend := func(b *networkingv1.IngressBackend, path string) {
if b == nil {
return
@ -216,14 +226,10 @@ func (a *IngressReconciler) maybeProvision(ctx context.Context, logger *zap.Suga
}
addIngressBackend(ing.Spec.DefaultBackend, "/")
var tlsHost string // hostname or FQDN or empty
if ing.Spec.TLS != nil && len(ing.Spec.TLS) > 0 && len(ing.Spec.TLS[0].Hosts) > 0 {
tlsHost = ing.Spec.TLS[0].Hosts[0]
}
for _, rule := range ing.Spec.Rules {
// Host is optional, but if it's present it must match the TLS host
// otherwise we ignore the rule.
if rule.Host != "" && rule.Host != tlsHost {
if rule.Host != "" && rule.Host != tlsHostname {
a.recorder.Eventf(ing, corev1.EventTypeWarning, "InvalidIngressBackend", "rule with host %q ignored, unsupported", rule.Host)
continue
}
@ -253,10 +259,9 @@ func (a *IngressReconciler) maybeProvision(ctx context.Context, logger *zap.Suga
tags = strings.Split(tstr, ",")
}
hostname := ing.Namespace + "-" + ing.Name + "-ingress"
if tlsHost != "" {
hostname, _, _ = strings.Cut(tlsHost, ".")
}
// if tlsHost != "" {
// hostname, _, _ = strings.Cut(tlsHost, ".")
// }
sts := &tailscaleSTSConfig{
Hostname: hostname,
ParentResourceName: ing.Name,
@ -265,6 +270,7 @@ func (a *IngressReconciler) maybeProvision(ctx context.Context, logger *zap.Suga
Tags: tags,
ChildResourceLabels: crl,
ProxyClass: proxyClass,
TSVIP: a.tailnetVIPForIngress(ing),
}
if val := ing.GetAnnotations()[AnnotationExperimentalForwardClusterTrafficViaL7IngresProxy]; val == "true" {
@ -307,6 +313,13 @@ func (a *IngressReconciler) maybeProvision(ctx context.Context, logger *zap.Suga
return nil
}
func (a *IngressReconciler) tailnetVIPForIngress(ing *networkingv1.Ingress) string {
if !a.shouldExpose(ing) || ing.Annotations == nil {
return ""
}
return ing.GetAnnotations()[AnnotationTSVIP]
}
func (a *IngressReconciler) shouldExpose(ing *networkingv1.Ingress) bool {
return ing != nil &&
ing.Spec.IngressClassName != nil &&

View File

@ -428,7 +428,7 @@ var userspaceProxyYaml []byte
func (a *tailscaleSTSReconciler) reconcileSTS(ctx context.Context, logger *zap.SugaredLogger, sts *tailscaleSTSConfig, headlessSvc *corev1.Service, proxySecret, tsConfigHash string) (*appsv1.StatefulSet, error) {
ss := new(appsv1.StatefulSet)
if sts.ServeConfig != nil && sts.ForwardClusterTrafficViaL7IngressProxy != true { // If forwarding cluster traffic via is required we need non-userspace + NET_ADMIN + forwarding
if sts.ServeConfig != nil && sts.ForwardClusterTrafficViaL7IngressProxy != true && sts.TSVIP == "" { // If forwarding cluster traffic via is required we need non-userspace + NET_ADMIN + forwarding
if err := yaml.Unmarshal(userspaceProxyYaml, &ss); err != nil {
return nil, fmt.Errorf("failed to unmarshal userspace proxy spec: %v", err)
}

View File

@ -3299,9 +3299,13 @@ func (b *LocalBackend) handlePeerAPIConn(remote, local netip.AddrPort, c net.Con
return
}
func (b *LocalBackend) isLocalIP(ip netip.Addr) bool {
func (b *LocalBackend) isLocallyAvailable(ip netip.Addr) bool {
nm := b.NetMap()
return nm != nil && views.SliceContains(nm.GetAddresses(), netip.PrefixFrom(ip, ip.BitLen()))
if nm == nil {
return false
}
pfx := netip.PrefixFrom(ip, ip.BitLen())
return views.SliceContains(nm.SelfNode.AllowedIPs(), pfx)
}
var (
@ -3319,7 +3323,7 @@ func (b *LocalBackend) TCPHandlerForDst(src, dst netip.AddrPort) (handler func(c
}
return b.HandleQuad100Port80Conn, opts
}
if !b.isLocalIP(dst.Addr()) {
if !b.isLocallyAvailable(dst.Addr()) {
return nil, nil
}
if dst.Port() == 22 && b.ShouldRunSSH() {