hashicorp/terraform · error
failed to create cert signer %q: %s
Error message
failed to create cert signer %q: %s
What it means
Raised in signCertWithPrivateKey when ssh.NewCertSigner fails. Both the private key and certificate parsed successfully and a signer was created, but the certificate could not be bound to the signer. The most common cause is a key/cert type mismatch: the certificate was issued for a different public key than the private key supplied.
Source
Thrown at internal/communicator/ssh/provisioner.go:415
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" {
return nil, errors.New(
"Failed to read ssh private key: password protected keys are\n" +
"not supported. Please decrypt the key prior to use.")
}
View on GitHub (pinned to c9def3e214)
Solutions
- Ensure the private_key and certificate come from the same key pair (the cert's public key must match the private key's public key).
- Regenerate both the key pair and certificate together with ssh-keygen -s ca_key -I identity id_ed25519.pub.
- Verify the match: compare ssh-keygen -y -f private_key with the cert's embedded key via ssh-keygen -L -f cert.
- Check for stale certificate files from a previous key rotation.
Example fix
// before
connection {
private_key = file("~/.ssh/id_rsa") # RSA key
certificate = file("~/.ssh/ed25519-cert.pub") # cert for a DIFFERENT key
}
// after
connection {
private_key = file("~/.ssh/id_ed25519")
certificate = file("~/.ssh/id_ed25519-cert.pub")
} Defensive patterns
Strategy: validation
Validate before calling
// Validate that the private key and certificate belong to the same key pair
func validateKeyCertPair(pk, cert string) error {
rawPk, err := ssh.ParseRawPrivateKey([]byte(pk))
if err != nil {
return fmt.Errorf("invalid private key: %w", err)
}
signer, err := ssh.NewSignerFromKey(rawPk)
if err != nil {
return fmt.Errorf("cannot create signer: %w", err)
}
pcert, _, _, _, err := ssh.ParseAuthorizedKey([]byte(cert))
if err != nil {
return fmt.Errorf("invalid certificate: %w", err)
}
sshCert, ok := pcert.(*ssh.Certificate)
if !ok {
return errors.New("not a certificate")
}
if !bytes.Equal(signer.PublicKey().Marshal(), sshCert.Key.Marshal()) {
return errors.New("private key and certificate public keys do not match")
}
return nil
} Prevention
- Always generate the key pair and certificate together from the same base key.
- After rotating keys, regenerate certificates — never mix old certs with new keys.
- Verify the match with ssh-keygen -y -f private_key vs ssh-keygen -L -f cert before use.
When it happens
Trigger: ssh.NewCertSigner validates that the certificate's public key matches the signer's public key. If the private_key and certificate belong to different key pairs, or the certificate type is incompatible with the signer type, this fails.
Common situations: The private_key and certificate were generated from different key pairs (e.g. cert for id_rsa but private_key set to id_ed25519), the certificate was issued for a different key after regeneration, or a stale certificate is paired with a new key.
Related errors
- failed to parse private key %q: %s
- failed to parse certificate %q: %s
- failed to create signer from raw private key %q: %s
- SSH authentication failed (%s@%s): %w
- Error creating new client connection via proxy: %s
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/00e6842f5de6e4d7.
Report an issue: GitHub.