kubernetes/kops · error

unknown private key type: %T

Error message

unknown private key type: %T

What it means

PrivateKey.WriteTo only supports *rsa.PrivateKey and *ecdsa.PrivateKey. If Key holds any other crypto.Signer implementation, the type switch falls to default and returns 'unknown private key type: %T' naming the concrete Go type. Callers AsString, AsBytes, MarshalJSON, and WriteToFile all surface this.

Source

Thrown at pkg/pki/privatekey.go:168

	}

	var data bytes.Buffer

	switch pk := k.Key.(type) {
	case *rsa.PrivateKey:
		if err := pem.Encode(&data, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(pk)}); err != nil {
			return 0, fmt.Errorf("error encoding RSA private key: %w", err)
		}
	case *ecdsa.PrivateKey:
		b, err := x509.MarshalECPrivateKey(pk)
		if err != nil {
			return 0, fmt.Errorf("error encoding ECDSA private key: %w", err)
		}
		if err := pem.Encode(&data, &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}); err != nil {
			return 0, fmt.Errorf("error encoding ECDSA private key: %w", err)
		}
	default:
		return 0, fmt.Errorf("unknown private key type: %T", k.Key)
	}

	return data.WriteTo(w)
}

func (k *PrivateKey) WriteToFile(filename string, perm os.FileMode) error {
	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
	if err != nil {
		return err
	}
	_, err = k.WriteTo(f)
	if err1 := f.Close(); err == nil {
		err = err1
	}
	return err
}

func parsePEMPrivateKey(pemData []byte) (crypto.Signer, error) {

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Read the %T in the message to identify the actual key type stored in Key.
  2. Regenerate the key as RSA or ECDSA using pki.GeneratePrivateKey() or ecdsa.GenerateKey().
  3. If the key must be reused, convert it: for ed25519 there is no conversion — create a new RSA/ECDSA key and reissue certificates.
  4. Add a type check before serializing: only proceed when Key is *rsa.PrivateKey or *ecdsa.PrivateKey.

Example fix

// before
parsed, _ := x509.ParsePKCS8PrivateKey(der) // ed25519
k := &pki.PrivateKey{Key: parsed.(crypto.Signer)}
b, err := k.AsBytes() // error: unknown private key type: ed25519.PrivateKey
// after
key, err := pki.GeneratePrivateKey() // RSA, supported by WriteTo
b, err := key.AsBytes()
Defensive patterns

Strategy: type-guard

Validate before calling

switch key.Key.(type) {
case *rsa.PrivateKey, *ecdsa.PrivateKey:
    // supported
default:
    return fmt.Errorf("unsupported key algorithm %T; use RSA or ECDSA", key.Key)
}

Type guard

func isSupportedSigner(k *pki.PrivateKey) bool {
    if k == nil || k.Key == nil { return false }
    switch k.Key.(type) {
    case *rsa.PrivateKey, *ecdsa.PrivateKey:
        return true
    default:
        return false
    }
}

Try / catch

out, err := key.AsBytes()
if err != nil {
    if strings.Contains(err.Error(), "unknown private key type") {
        // extract %T from message, regenerate as RSA/ECDSA
    }
    return err
}

Prevention

When it happens

Trigger: Placing a signer of another algorithm into PrivateKey.Key — typically ed25519.PrivateKey (or ed25519.PublicKey by mistake) obtained from x509.ParsePKCS8PrivateKey on a 'PRIVATE KEY' PEM block, then serializing with AsBytes/AsString/MarshalJSON/WriteToFile.

Common situations: Adopting modern Ed25519 keys from external tooling (openssl genpkey -algorithm ED25519) and importing them into kops structures; keys parsed by parsePEMPrivateKey's PKCS8 branch whose type assertion to crypto.Signer succeeds but which WriteTo cannot encode.

Related errors


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