kubernetes/kops · critical

failed to verify claim signature for node: %w

Error message

failed to verify claim signature for node: %w

What it means

The TPM claim signature over the token data did not verify against the instance's GCE Shielded VM signing key. Note the code wraps err which is nil at that point, so the message carries no underlying cause — the RSA-PKCS verification simply returned false.

Source

Thrown at upup/pkg/fi/cloudup/gce/tpm/gcetpmverifier/tpmverifier.go:188

		}
		capiMachine = m
	}

	// Check if this is a CAPG managed instance
	if instanceGroupName == "" && capiMachine == nil {
		return nil, fmt.Errorf("could not determine ownership for instance %s", instance.SelfLink)
	}

	// Verify the token has a valid GCE TPM signature.
	{
		// Note - we might be able to avoid this call by including the attestation certificate (signed by GCE) in the claim.
		tpmSigningKey, err := v.getTPMSigningKey(ctx, &tokenData)
		if err != nil {
			return nil, err
		}

		if !verifySignature(tpmSigningKey, token.Data, token.Signature) {
			return nil, fmt.Errorf("failed to verify claim signature for node: %w", err)
		}
	}

	sans, err := GetInstanceCertificateAlternateNames(instance)
	if err != nil {
		return nil, err
	}

	challengeEndpoint := instance.NetworkInterfaces[0].NetworkIP + ":" + strconv.Itoa(wellknownports.NodeupChallenge)

	result := &bootstrap.VerifyResult{
		NodeName:          instance.Name,
		InstanceGroupName: instanceGroupName,
		CAPIMachine:       capiMachine,
		CertificateNames:  sans,
		ChallengeEndpoint: challengeEndpoint,
	}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Investigate the source node for tampering or a compromised token — treat as a security signal if unexpected
  2. Recreate/replace the node so it generates a fresh TPM-signed token
  3. Align the node-side gcetpm token producer version with the verifier
  4. Check for proxy/middleware modifying the request body between signing and verification
Defensive patterns

Strategy: try-catch

Validate before calling

// confirm the token is well-formed and unmodified before sending
if sha256.Sum256(body) != tokenData.RequestHash {
    return errors.New("request body does not match signed hash — body was modified")
}

Try / catch

result, err := verifier.VerifyToken(ctx, req, authToken, body)
if err != nil && strings.Contains(err.Error(), "failed to verify claim signature") {
    log.SecurityEvent("TPM signature mismatch for node", err) // investigate node for tampering
    return nil, err // never retry-sign; treat as untrusted
}

Prevention

When it happens

Trigger: verifySignature(tpmSigningKey, token.Data, token.Signature) returns false: the token's signature doesn't match token.Data when checked against the key fetched from GetShieldedInstanceIdentity.

Common situations: Tampered or forged token (potential attack — investigate); node software and verifier using mismatched token formats/versions; signing key rotated by GCE between token creation and verification; corrupted request body altering signed content.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/66f72438d7660551. Report an issue: GitHub.