tailscale/tailscale · error
failed to clean up cert resources: %w
Error message
failed to clean up cert resources: %w
What it means
Thrown by HAIngressReconciler.maybeCleanupProxyGroup when cleanupCertResources fails to delete the per-domain TLS Secret and its Role/RoleBinding (label-selected on ProxyGroup and domain) for an orphaned Tailscale Service. It wraps dnsNameForService failing because no ProxyGroup node metadata exists (Pods already deleted: deriving the MagicDNS domain needs a live proxy's DNS name), or DeleteAllOf on RoleBinding/Role/Secret failing (RBAC, apiserver).
Source
Thrown at cmd/k8s-operator/ingress-for-pg.go:526
// 3. Delete the Tailscale Service from the control plane.
tsService, err := tsClient.VIPServices().Get(ctx, tsSvcName.String())
switch {
case tailscale.IsNotFound(err):
// Already gone at the control plane; continue with cluster
// cleanup rather than aborting the sweep.
case err != nil:
return svcsChanged, fmt.Errorf("getting Tailscale Service %q: %w", tsSvcName, err)
default:
updated, err := r.cleanupTailscaleService(ctx, tsService, logger, tsClient)
if err != nil {
return svcsChanged, fmt.Errorf("deleting Tailscale Service %q: %w", tsSvcName, err)
}
svcsChanged = svcsChanged || updated
}
// 4. Clean up cluster cert resources.
if err := cleanupCertResources(ctx, r.Client, r.tsNamespace, tsSvcName, pg); err != nil {
return svcsChanged, fmt.Errorf("failed to clean up cert resources: %w", err)
}
}
return svcsChanged, nil
}
// maybeCleanup ensures that any resources, such as a Tailscale Service created for this Ingress, are cleaned up when the
// Ingress is being deleted or is unexposed. The cleanup is safe for a multi-cluster setup- the Tailscale Service is only
// deleted if it does not contain any other owner references. If it does the cleanup only removes the owner reference
// corresponding to this Ingress.
//
// Steps are ordered so the proxy cancels its cert loop (via serve config
// removal) before the VIPService is deleted; otherwise the loop retries
// against a domain the control plane no longer recognises.
func (r *HAIngressReconciler) maybeCleanup(ctx context.Context, hostname string, ing *networkingv1.Ingress, logger *zap.SugaredLogger, tsClient tsclient.Client, pg *tsapi.ProxyGroup) (svcChanged bool, err error) {
logger.Debugf("Ensuring any resources for Ingress are cleaned up")
ix := slices.Index(ing.Finalizers, FinalizerNamePG)
if ix < 0 {View on GitHub (pinned to cfe32b8be6)
Solutions
- Order teardown: delete Ingresses and wait for finalizers to clear before deleting the ProxyGroup or operator.
- Reapply full RBAC if 'forbidden' appears on the DeleteAllOf calls.
- If the ProxyGroup is already gone: verify no control-plane VIPService remains, then manually remove the operator finalizer from the stuck Ingress and delete leftover cert Secrets, Roles, and RoleBindings by label.
Defensive patterns
Strategy: validation
Validate before calling
// teardown precondition: DNS name must be derivable, which needs live proxy state
if _, err := dnsNameForService(ctx, cl, serviceName, pg, tsNamespace); err != nil {
// postpone ProxyGroup deletion until Ingress finalizers have cleared
} Try / catch
if err := cleanupCertResources(ctx, r.Client, r.tsNamespace, tsSvcName, pg); err != nil {
if strings.Contains(err.Error(), "dns name") {
logger.Error("ProxyGroup metadata is gone; remove cert Secrets, Roles, RoleBindings by label and the Ingress finalizer manually")
}
return svcsChanged, fmt.Errorf("failed to clean up cert resources: %w", err)
} Prevention
- Delete Ingresses before the ProxyGroup; cleanup derives DNS names from live proxy state.
- Keep operator RBAC (roles, rolebindings, secrets delete) intact until teardown completes.
- After manual cleanup, delete leftover resources by the operator's labels, not by guesswork.
When it happens
Trigger: ProxyGroup or its Pods deleted before its Ingresses finished cleanup, so the DNS name cannot be derived; operator RBAC missing delete on roles/rolebindings/secrets; apiserver errors during teardown.
Common situations: Uninstalling the operator and ProxyGroup in one shot, leaving Ingress finalizers stuck; RBAC pruned during teardown; version skew between operators.
Related errors
- failed to update tailscaled config services: %w
- user is not an admin
- error retrieving state secret: %w
- error retrieving state Secret: %w
- error patching state Secret: %w
AI-assisted analysis of tailscale/tailscale@cfe32b8be6 (2026-08-15).
Data as JSON: /api/errors/0cae6d6db7dc441a.
Report an issue: GitHub.