cmd/k8s-operator: validate Service tags, catch duplicate Tailscale Services (#16058)

Validate that any tags that users have specified via tailscale.com/tags
annotation are valid Tailscale ACL tags.
Validate that no more than one HA Tailscale Kubernetes Services in a single cluster refer
to the same Tailscale Service.

Updates tailscale/tailscale#16054
Updates tailscale/tailscale#16035

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
This commit is contained in:
Irbe Krumina
2025-05-23 12:23:58 +01:00
committed by GitHub
parent 7a5af6e6e7
commit 00a7dd180a
6 changed files with 122 additions and 25 deletions
+26 -6
View File
@@ -169,12 +169,9 @@ func (r *HAServiceReconciler) maybeProvision(ctx context.Context, hostname strin
return false, nil
}
// Validate Service configuration
if violations := validateService(svc); len(violations) > 0 {
msg := fmt.Sprintf("unable to provision proxy resources: invalid Service: %s", strings.Join(violations, ", "))
r.recorder.Event(svc, corev1.EventTypeWarning, "INVALIDSERVICE", msg)
r.logger.Error(msg)
tsoperator.SetServiceCondition(svc, tsapi.IngressSvcValid, metav1.ConditionFalse, reasonIngressSvcInvalid, msg, r.clock, logger)
if err := r.validateService(ctx, svc, pg); err != nil {
r.recorder.Event(svc, corev1.EventTypeWarning, reasonIngressSvcInvalid, err.Error())
tsoperator.SetServiceCondition(svc, tsapi.IngressSvcValid, metav1.ConditionFalse, reasonIngressSvcInvalid, err.Error(), r.clock, logger)
return false, nil
}
@@ -857,3 +854,26 @@ func (r *HAServiceReconciler) checkEndpointsReady(ctx context.Context, svc *core
logger.Debugf("could not find any ready Endpoints in EndpointSlice")
return false, nil
}
func (r *HAServiceReconciler) validateService(ctx context.Context, svc *corev1.Service, pg *tsapi.ProxyGroup) error {
var errs []error
if pg.Spec.Type != tsapi.ProxyGroupTypeIngress {
errs = append(errs, fmt.Errorf("ProxyGroup %q is of type %q but must be of type %q",
pg.Name, pg.Spec.Type, tsapi.ProxyGroupTypeIngress))
}
if violations := validateService(svc); len(violations) > 0 {
errs = append(errs, fmt.Errorf("invalid Service: %s", strings.Join(violations, ", ")))
}
svcList := &corev1.ServiceList{}
if err := r.List(ctx, svcList); err != nil {
errs = append(errs, fmt.Errorf("[unexpected] error listing Services: %w", err))
return errors.Join(errs...)
}
svcName := nameForService(svc)
for _, s := range svcList.Items {
if r.shouldExpose(&s) && nameForService(&s) == svcName && s.UID != svc.UID {
errs = append(errs, fmt.Errorf("found duplicate Service %q for hostname %q - multiple HA Services for the same hostname in the same cluster are not allowed", client.ObjectKeyFromObject(&s), svcName))
}
}
return errors.Join(errs...)
}