{"record":{"id":"c06f991c2b1d3d9c","repo":"kubernetes/kops","slug":"error-parsing-ssh-public-key-q","errorCode":null,"errorMessage":"error parsing SSH public key: %q","messagePattern":"error parsing SSH public key: %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/pki/sshkey.go","lineNumber":37,"sourceCode":"import (\n\t\"bytes\"\n\t\"crypto\"\n\t\"crypto/md5\"\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"golang.org/x/crypto/ssh\"\n)\n\n// parseSSHPublicKey parses the SSH public key string\nfunc parseSSHPublicKey(publicKey string) (ssh.PublicKey, error) {\n\ttokens := strings.Fields(publicKey)\n\tif len(tokens) < 2 {\n\t\treturn nil, fmt.Errorf(\"error parsing SSH public key: %q\", publicKey)\n\t}\n\n\tsshPublicKeyBytes, err := base64.StdEncoding.DecodeString(tokens[1])\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error decoding SSH public key: %q err: %s\", publicKey, err)\n\t}\n\tif len(tokens) < 2 {\n\t\treturn nil, fmt.Errorf(\"error decoding SSH public key: %q\", publicKey)\n\t}\n\n\tsshPublicKey, err := ssh.ParsePublicKey(sshPublicKeyBytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error parsing SSH public key: %v\", err)\n\t}\n\treturn sshPublicKey, nil\n}\n\n// colonSeparatedHex formats the byte slice SSH-fingerprint style: hex bytes separated by colons","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/pki/sshkey.go#L19-L55","documentation":"parseSSHPublicKey splits the public key string on whitespace and requires at least two fields: the key type (e.g. 'ssh-rsa') and the base64 blob. Fewer than two fields means the string is not a valid single-line SSH public key. Callers ComputeAWSKeyFingerprint and ComputeOpenSSHKeyFingerprint pass user-supplied key material here.","triggerScenarios":"Passing an empty string, a passphrase only, a multi-line file's first line being blank, or passing an OpenSSH PRIVATE key block ('-----BEGIN OPENSSH PRIVATE KEY-----') whose first whitespace-delimited token set doesn't include a type+blob pair.","commonSituations":"Users pasting `cat id_rsa` (private key) instead of `id_rsa.pub`, or an empty key field in cluster spec / AWS metadata after a failed kops create secret sshpublickey.","solutions":["Confirm you are passing the .pub public key file contents, e.g. `kops create secret sshpublickey admin -i ~/.ssh/id_rsa.pub`","Ensure the string starts with the key type token ('ssh-rsa', 'ssh-ed25519', etc.) followed by the base64 blob on one line","Check that the key wasn't truncated or whitespace-stripped when stored/passed"],"exampleFix":"// before\nfp, err := pki.ComputeAWSKeyFingerprint(string(privKeyBytes))\n// after\nfp, err := pki.ComputeAWSKeyFingerprint(string(pubKeyBytes)) // contents of id_rsa.pub","handlingStrategy":"validation","validationCode":"func looksLikeSSHPubKey(s string) bool {\n\tf := strings.Fields(s)\n\treturn len(f) >= 2 && strings.HasPrefix(f[0], \"ssh-\")\n}\nif !looksLikeSSHPubKey(pubKey) {\n\treturn fmt.Errorf(\"not an OpenSSH public key line (type + base64 blob expected)\")\n}\nfp, err := pki.ComputeAWSKeyFingerprint(pubKey)","typeGuard":"func isSSHKeyType(token string) bool {\n\tswitch token {\n\tcase \"ssh-rsa\", \"ssh-ed25519\", \"ecdsa-sha2-nistp256\", \"ecdsa-sha2-nistp384\", \"ecdsa-sha2-nistp521\":\n\t\treturn true\n\t}\n\treturn false\n}","tryCatchPattern":"fp, err := pki.ComputeAWSKeyFingerprint(pubKey)\nif err != nil {\n\treturn fmt.Errorf(\"invalid SSH public key supplied: %w\", err)\n}","preventionTips":["Always pass the .pub file, never the private key","Validate keys with `ssh-keygen -l -f key.pub` before importing","Trim leading blank lines when reading key files"],"tags":["ssh","key-parsing","validation"],"backgroundTag":"ssh-public-key-invalid","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}