kubernetes/kops · error

callback challenge returned wrong result

Error message

callback challenge returned wrong result

What it means

After a successful RPC, the client compares the server's response bytes to the locally computed expected challenge response using a constant-time comparison. A mismatch means the server returned a different response than the HMAC derived from the ChallengeSecret — indicating the server did not hold the same secret or the challenge data was tampered with.

Source

Thrown at pkg/bootstrap/challenge_client.go:126

	expectedChallengeResponse := buildChallengeResponse(challenge.ChallengeSecret, kospControllerNonce)

	var opts []grpc.DialOption
	opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)))
	conn, err := grpc.DialContext(ctx, targetEndpoint, opts...)
	if err != nil {
		return fmt.Errorf("error dialing target %q: %w", targetEndpoint, err)
	}
	defer conn.Close()
	client := pb.NewCallbackServiceClient(conn)

	response, err := client.Challenge(ctx, req)
	if err != nil {
		return fmt.Errorf("error from callback challenge: %w", err)
	}

	if subtle.ConstantTimeCompare(response.GetChallengeResponse(), expectedChallengeResponse) != 1 {
		return fmt.Errorf("callback challenge returned wrong result")
	}
	return nil
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Re-run the challenge/bootstrap flow to obtain a fresh challenge and secret from kops-controller
  2. Verify the ChallengeID and ChallengeSecret pair matches what the server currently holds
  3. Ensure you are dialing the genuine kops-controller endpoint, not a stale or spoofed address

Example fix

null
Defensive patterns

Strategy: validation

Validate before calling

if len(ch.ChallengeID) == 0 || len(ch.ChallengeSecret) == 0 {
	return fmt.Errorf("stale/empty challenge; request a fresh challenge first")
}

Try / catch

if err := client.DoCallbackChallenge(ctx, clusterName, ch); err != nil {
	if strings.Contains(err.Error(), "wrong result") {
		// discard cached challenge, re-request a fresh one, retry once
	}
	return err
}

Prevention

When it happens

Trigger: Calling DoCallbackChallenge when response.GetChallengeResponse() differs from buildChallengeResponse(ChallengeSecret, nonce): wrong/rotated secret on the server, stale challenge ID, or a man-in-the-middle/buggy server returning unexpected bytes.

Common situations: The challenge secret was rotated on the server after issuance to the node; the node cached an old challenge; a misconfigured or malicious callback endpoint answering with wrong material.

Related errors


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