Сообщение об ошибке
ssh: this private key is passphrase protected
Также выводится как
- ssh: no key found
«ssh: no key found» (указана здесь как псевдоним) — другая ситуация, о которой сообщает тот же парсер: в байтах нет блока ключа PEM, например это открытый ключ, файл PuTTY `.ppk` или пустой файл.
golang.org/x/crypto/ssh (Go) — *ssh.PassphraseMissingError from ssh.ParsePrivateKey
Что это означает
Функция `ssh.ParsePrivateKey` распознала зашифрованный закрытый ключ и остановилась: парольной фразы, чтобы его расшифровать, у неё нет. Возвращаемая ошибка `*ssh.PassphraseMissingError` даже содержит открытый ключ, но для подписи нужен расшифрованный закрытый ключ: вызовите `ssh.ParsePrivateKeyWithPassphrase` или поручите подпись SSH-агенту. Родственная ошибка «ssh: no key found» означает, что во входных данных вообще нет распознаваемого ключа.
Почему это происходит
Ключ создан с парольной фразой
часто`ssh-keygen` запрашивает парольную фразу и шифрует ею файл ключа. OpenSSH в интерактивном режиме спрашивает её или использует агент; программа на Go должна передать её явно.
Инструмент рассчитывал, что агент разблокирует ключ
иногдаНа рабочей станции расшифрованный ключ держит `ssh-add`, а `ssh` файл вообще не читает. Коду на Go, который читает файл напрямую, агент ничем не помогает.
Личный зашифрованный ключ скопирован в CI
иногдаКлючи развёртывания (deploy keys) для автоматизации обычно не зашифрованы и имеют узкие права; если повторно использовать в CI личный зашифрованный ключ, возникает эта ошибка.
Как исправить
- 1.
Распознайте ошибку и передайте парольную фразу
`errors.As` определяет, что не хватает парольной фразы; читайте её из хранилища секретов и никогда не берите из исходного кода.
go signer, err := ssh.ParsePrivateKey(keyBytes) var missing *ssh.PassphraseMissingError if errors.As(err, &missing) { passphrase := []byte(os.Getenv("SSH_KEY_PASSPHRASE")) signer, err = ssh.ParsePrivateKeyWithPassphrase(keyBytes, passphrase) } if err != nil { return err } - 2.
Подписывайте через SSH-агент
С `golang.org/x/crypto/ssh/agent` закрытый ключ никогда не попадает в ваш процесс, а парольной фразой занимается агент.
go import "golang.org/x/crypto/ssh/agent" conn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")) if err != nil { return err } agentClient := agent.NewClient(conn) auth := ssh.PublicKeysCallback(agentClient.Signers) // the agent holds the decrypted key