hashicorp/terraform · error

failed to create signer from raw private key %q: %s

Error message

failed to create signer from raw private key %q: %s

What it means

Raised in signCertWithPrivateKey when ssh.NewSignerFromKey(rawPk) fails. The private key was successfully parsed by ParseRawPrivateKey, but converting the resulting crypto.PrivateKey into an ssh.Signer failed. This typically indicates the parsed key is of an unsupported or degenerate type for signer creation.

Source

Thrown at internal/communicator/ssh/provisioner.go:410

	return conf, nil
}

// Create a Cert Signer and return ssh.AuthMethod
func signCertWithPrivateKey(pk string, certificate string) (ssh.AuthMethod, error) {
	rawPk, err := ssh.ParseRawPrivateKey([]byte(pk))
	if err != nil {
		return nil, fmt.Errorf("failed to parse private key %q: %s", pk, err)
	}

	pcert, _, _, _, err := ssh.ParseAuthorizedKey([]byte(certificate))
	if err != nil {
		return nil, fmt.Errorf("failed to parse certificate %q: %s", certificate, err)
	}

	usigner, err := ssh.NewSignerFromKey(rawPk)
	if err != nil {
		return nil, fmt.Errorf("failed to create signer from raw private key %q: %s", rawPk, err)
	}

	ucertSigner, err := ssh.NewCertSigner(pcert.(*ssh.Certificate), usigner)
	if err != nil {
		return nil, fmt.Errorf("failed to create cert signer %q: %s", usigner, err)
	}

	return ssh.PublicKeys(ucertSigner), nil
}

func readPrivateKey(pk string) (ssh.AuthMethod, error) {
	// We parse the private key on our own first so that we can
	// show a nicer error if the private key has a password.
	block, _ := pem.Decode([]byte(pk))
	if block == nil {
		return nil, errors.New("Failed to read ssh private key: no key found")
	}
	if block.Headers["Proc-Type"] == "4,ENCRYPTED" {

View on GitHub (pinned to c9def3e214)

Solutions

  1. Regenerate the key pair using a standard supported type: RSA (>=2048), ECDSA (P-256/P-384/P-521), or Ed25519.
  2. Update terraform to a newer version that bundles a newer x/crypto/ssh with broader key support.
  3. Verify the key file contains a single private key, not a bundle.
  4. Test the key with ssh-keygen -y -f keyfile to confirm it produces a valid public key.

Example fix

// before
connection {
  private_key  = file("~/.ssh/exotic_key")
  certificate  = file("~/.ssh/exotic_key-cert.pub")
}

// after
connection {
  private_key  = file("~/.ssh/id_ed25519")
  certificate  = file("~/.ssh/id_ed25519-cert.pub")
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the private key can produce a signer before use
func validateKeyCanSign(pk string) error {
    rawPk, err := ssh.ParseRawPrivateKey([]byte(pk))
    if err != nil {
        return fmt.Errorf("cannot parse private key: %w", err)
    }
    if _, err := ssh.NewSignerFromKey(rawPk); err != nil {
        return fmt.Errorf("key type does not support signing: %w", err)
    }
    return nil
}

Prevention

When it happens

Trigger: ParseRawPrivateKey succeeded (the key is valid PEM) but the resulting key type is not suitable for signing — for example an unsupported curve, a key type the SSH signer does not handle, or a malformed key structure that parses but cannot sign.

Common situations: The private key uses an exotic or very new key type not yet supported by the Go x/crypto/ssh version bundled with terraform, or the key file contains a multi-key bundle where ParseRawPrivateKey returned an unexpected type.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/213503b22cfbe5e7. Report an issue: GitHub.