{"record":{"id":"f31e5cad11a75381","repo":"hashicorp/nomad","slug":"error-parsing-rsa-key-w","errorCode":null,"errorMessage":"error parsing rsa key: %w","messagePattern":"error parsing rsa key: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/encrypter.go","lineNumber":691,"sourceCode":"\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid algorithm %s\", rootKey.Meta.Algorithm)\n\t}\n\n\ted25519Key := ed25519.NewKeyFromSeed(rootKey.Key)\n\n\tcs := cipherSet{\n\t\trootKey:         rootKey,\n\t\twrapper:         wrapper,\n\t\teddsaPrivateKey: ed25519Key,\n\t}\n\n\t// Unmarshal RSAKey for Workload Identity JWT signing if one exists. Prior to\n\t// 1.7 only the ed25519 key was used.\n\tif len(rootKey.RSAKey) > 0 {\n\t\trsaKey, err := x509.ParsePKCS1PrivateKey(rootKey.RSAKey)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error parsing rsa key: %w\", err)\n\t\t}\n\n\t\tcs.rsaPrivateKey = rsaKey\n\t\tcs.rsaPKCS1PublicKey = x509.MarshalPKCS1PublicKey(&rsaKey.PublicKey)\n\t}\n\n\treturn &cs, nil\n}\n\n// waitForKey retrieves the key material by ID from the keyring, retrying with\n// geometric backoff until the context expires.\nfunc (e *Encrypter) waitForKey(ctx context.Context, keyID string) (*cipherSet, error) {\n\tvar ks *cipherSet\n\n\terr := helper.WithBackoffFunc(ctx, 50*time.Millisecond, 100*time.Millisecond,\n\t\tfunc() error {\n\t\t\te.keyringLock.RLock()\n\t\t\tdefer e.keyringLock.RUnlock()","sourceCodeStart":673,"sourceCodeEnd":709,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/encrypter.go#L673-L709","documentation":"If the root key stores an RSA key (used for Workload Identity JWT signing since Nomad 1.7), generateCipher parses it as PKCS#1 DER via x509.ParsePKCS1PrivateKey. A non-empty RSAKey blob that isn't valid PKCS#1 DER produces \"error parsing rsa key\".","triggerScenarios":"rootKey.RSAKey has len > 0 but its bytes are not a valid PKCS1 private key — corrupted storage, wrong encoding (e.g. PKCS8 or PEM-wrapped bytes stored raw), or bytes from the wrong key.","commonSituations":"Snapshot restores that mangled binary columns; tooling that stored a PEM or PKCS8 encoding where Nomad expects raw PKCS1 DER; partial writes during crash.","solutions":["Check the wrapped x509 error; 'asn1: structure error' confirms malformed DER bytes","Rotate the root key to regenerate a correctly encoded RSA key","If migrating keys manually, ensure the bytes are x509.MarshalPKCS1PrivateKey DER, not PEM or PKCS8","Restore a known-good keyring snapshot if state corruption is suspected"],"exampleFix":"// before: storing PEM bytes in RSAKey\nrootKey.RSAKey = pemBytes\n// after: store raw PKCS1 DER\nder, _ := x509.MarshalPKCS1PrivateKey(priv), error check\nrootKey.RSAKey = x509.MarshalPKCS1PrivateKey(priv)","handlingStrategy":"validation","validationCode":"if len(rootKey.RSAKey) > 0 {\n    if _, err := x509.ParsePKCS1PrivateKey(rootKey.RSAKey); err != nil {\n        return fmt.Errorf(\"RSAKey is not PKCS1 DER: %w\", err)\n    }\n}","typeGuard":"func isPKCS1DER(b []byte) bool { _, err := x509.ParsePKCS1PrivateKey(b); return len(b) > 0 && err == nil }","tryCatchPattern":"if err != nil && strings.HasPrefix(err.Error(), \"error parsing rsa key\") { /* rotate key to regenerate RSA material */ }","preventionTips":["Store RSA keys as raw PKCS1 DER (x509.MarshalPKCS1PrivateKey), not PEM or PKCS8","Rotate keys after any storage-layer corruption event","Verify binary fields survive snapshot export/import"],"tags":["rsa","x509","keyring","key-parsing"],"backgroundTag":"rsa-key-parse-error","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}