Сообщение об ошибке
Could not parse PKey (OpenSSL::PKey::PKeyError)
Также выводится как
- OpenSSL::PKey::PKeyError: Could not parse PKey
- Neither PUB key nor PRIV key (OpenSSL::PKey::RSAError)
- invalid curve name (OpenSSL::PKey::ECError)
Если исключение не перехвачено, Ruby выводит «…: Could not parse PKey (OpenSSL::PKey::PKeyError)». Конструкторы отдельных классов выбрасывают `OpenSSL::PKey::RSAError` / `ECError` со своими текстами.
Ruby openssl gem — OpenSSL::PKey.read / OpenSSL::PKey::RSA.new / OpenSSL::PKey::EC.new
Что это означает
`OpenSSL::PKey.read` перепробовал все форматы ключей, известные OpenSSL (PEM и DER, открытые и закрытые, зашифрованные заданным паролем), и ни один не подошёл. Ruby не передаёт конкретную причину от OpenSSL, поэтому один и тот же текст выводится и для испорченного PEM, и для неверной парольной фразы, и для данных, которые вовсе не ключ. Конструкторы для конкретных алгоритмов выдают похожие ошибки: `RSA.new` — «Neither PUB key nor PRIV key», `EC.new` — «invalid curve name» (он принимает неразбираемые входные данные за имя кривой).
Почему это происходит
Переводы строк заменены на буквальные \n
частоМногострочные ключи в переменных окружения, переменных конфигурации Heroku/Render или строках YAML часто превращаются в одну строку с последовательностями `\n`.
Зашифрованный ключ без пароля или с неверным паролем
часто`PKey.read(data)` без второго аргумента не может расшифровать зашифрованный ключ; неверный пароль даёт ту же ошибку, а не отдельную ошибку о пароле.
Не ключ в формате, понятном OpenSSL
иногдаОткрытый ключ OpenSSH (`ssh-ed25519 AAAA…`), JSON-документ JWK или файл с цепочкой сертификатов, в котором перед блоком PEM есть посторонний текст.
Как исправить
- 1.
Восстановите переводы строк и проверьте, что вы загрузили
Преобразуйте последовательности `\n` обратно в переводы строк, прочитайте ключ один раз при запуске и проверьте его тип и то, закрытый ли он.
ruby pem = ENV.fetch("JWT_PUBLIC_KEY").gsub("\\n", "\n") # restore real newlines key = OpenSSL::PKey.read(pem) raise "expected a public EC key" if key.private? || !key.is_a?(OpenSSL::PKey::EC) - 2.
Храните многострочные ключи там, где они не портятся
Зашифрованные учётные данные Rails или смонтированный файл секрета сохраняют PEM в точности, в отличие от однострочных переменных окружения.
ruby # Rails: keep multi-line keys in encrypted credentials instead of ENV # bin/rails credentials:edit # jwt: # public_key: | # -----BEGIN PUBLIC KEY----- # ... key = OpenSSL::PKey.read(Rails.application.credentials.dig(:jwt, :public_key))