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
- Investigate the source node for tampering or a compromised token — treat as a security signal if unexpected
- Recreate/replace the node so it generates a fresh TPM-signed token
- Align the node-side gcetpm token producer version with the verifier
- 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
- Never modify the request body between client signing and server verification (no mutating proxies)
- Keep node-side token producer and verifier versions in lockstep
- Monitor for repeated signature failures — they indicate tampering or compromised nodes
- Ensure node clock/config is sane so fresh, correctly signed tokens are produced
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
- incorrect Audience
- could not determine ownership for instance %s
- verifying PKCS7 signature: %w
- validating PKCS7 signer SAN: %w
- empty attested document signature
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/66f72438d7660551.
Report an issue: GitHub.