istio/istio · error

registration of WorkloadEntry service account mismatch: %q v

Error message

registration of WorkloadEntry service account mismatch: %q vs %q

What it means

The last ensureProxyCanControlEntry check: if the WorkloadEntry spec sets serviceAccount (non-empty), it must equal the verified identity's service account from the client cert. This binds the resource to one SPIFFE identity, preventing a workload holding a valid cert in the right namespace from hijacking a different service account's WorkloadEntry.

Source

Thrown at pilot/pkg/autoregistration/controller.go:285

	}
	return err
}

// ensureProxyCanControlEntry ensures the connected proxy's identity matches that of the WorkloadEntry it is associating with.
func ensureProxyCanControlEntry(proxy *model.Proxy, wle *config.Config) error {
	if !features.ValidateWorkloadEntryIdentity {
		// Validation disabled, skip
		return nil
	}
	if proxy.VerifiedIdentity == nil {
		return fmt.Errorf("registration of WorkloadEntry requires a verified identity")
	}
	if proxy.VerifiedIdentity.Namespace != wle.Namespace {
		return fmt.Errorf("registration of WorkloadEntry namespace mismatch: %q vs %q", proxy.VerifiedIdentity.Namespace, wle.Namespace)
	}
	spec := wle.Spec.(*v1alpha3.WorkloadEntry)
	if spec.ServiceAccount != "" && proxy.VerifiedIdentity.ServiceAccount != spec.ServiceAccount {
		return fmt.Errorf("registration of WorkloadEntry service account mismatch: %q vs %q", proxy.VerifiedIdentity.ServiceAccount, spec.ServiceAccount)
	}
	return nil
}

// onWorkloadConnect creates/updates WorkloadEntry of the connecting workload.
//
// If workload is using auto-registration, WorkloadEntry will be created automatically.
//
// If workload is not using auto-registration, WorkloadEntry must already exist.
func (c *Controller) onWorkloadConnect(entryName string, proxy *model.Proxy, conTime time.Time, autoCreate bool) error {
	if autoCreate {
		return c.registerWorkload(entryName, proxy, conTime)
	}
	return c.becomeControllerOf(entryName, proxy, conTime)
}

// becomeControllerOf updates an existing WorkloadEntry of a workload that is not using
// auto-registration.

View on GitHub (pinned to 8dc789c5cf)

Solutions

  1. Compare the two quoted service accounts: set WorkloadEntry spec.serviceAccount to the SA in the workload's certificate, or re-issue the workload's identity for the entry's SA
  2. Leave spec.serviceAccount empty if you do not want SA binding (check still enforces namespace)
  3. Automate: generate the WorkloadEntry from the same serviceaccount used to mint the workload's cert

Example fix

# before
WorkloadEntry spec:
  serviceAccount: frontend      # cert SAN: .../ns/web/sa/backend -> mismatch
# after
WorkloadEntry spec:
  serviceAccount: backend       # matches the connecting workload's identity
Defensive patterns

Strategy: validation

Validate before calling

if spec := entry.Spec.(*v1alpha3.WorkloadEntry); spec.ServiceAccount != "" && spec.ServiceAccount != certServiceAccount {
    return fmt.Errorf("WorkloadEntry SA %q != workload cert SA %q", spec.ServiceAccount, certServiceAccount)
}

Prevention

When it happens

Trigger: WorkloadEntry spec.serviceAccount = "frontend" but the connecting proxy's cert SAN says sa/backend (same namespace, different SA) — the %q vs %q mismatch fires. Empty spec.serviceAccount intentionally skips the check.

Common situations: Copying a WorkloadEntry template and forgetting to update serviceAccount; rotating the VM's serviceaccount without updating the entry (or vice versa); onboarding scripts that generate the entry from one config source and the certs from another.

Related errors


AI-assisted analysis of istio/istio@8dc789c5cf (2026-08-15). Data as JSON: /api/errors/d3f55b7704ad63d7. Report an issue: GitHub.