Skip to content

Commit

Permalink
r/private_key: Add private_key_openssh attribute
Browse files Browse the repository at this point in the history
This commit adds private_key_openssh attribute, which always contains
private key in format, which is compatible with OpenSSH.

This allows to produce ED25519 private key in OpenSSL compatible format
in private_key_pem attribute and OpenSSH-compatible format in this new
attribute.

Other key types are the same in private_key_pem and private_key_openssh,
as OpenSSH can read them. In the future, this could be changed to produce
all private keys OpenSSH native format.

Refs #26

Signed-off-by: Mateusz Gozdek <mgozdekof@gmail.com>
  • Loading branch information
invidian committed Nov 22, 2020
1 parent 924e3b1 commit 5181615
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 6 deletions.
24 changes: 22 additions & 2 deletions internal/provider/resource_private_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ func resourcePrivateKey() *schema.Resource {
Sensitive: true,
},

"private_key_openssh": {
Type: schema.TypeString,
Computed: true,
Sensitive: true,
},

"public_key_pem": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -125,6 +131,7 @@ func CreatePrivateKey(d *schema.ResourceData, meta interface{}) error {
}

var keyPemBlock *pem.Block
var openSSHKeyPemBlock *pem.Block
switch k := key.(type) {
case *rsa.PrivateKey:
keyPemBlock = &pem.Block{
Expand All @@ -141,16 +148,29 @@ func CreatePrivateKey(d *schema.ResourceData, meta interface{}) error {
Bytes: keyBytes,
}
case *ed25519.PrivateKey:
keyBytes, err := x509.MarshalPKCS8PrivateKey(*k)
if err != nil {
return fmt.Errorf("error encoding key to PEM: %s", err)
}

keyPemBlock = &pem.Block{
Type: "PRIVATE KEY",
Bytes: keyBytes,
}
openSSHKeyPemBlock = &pem.Block{
Type: "OPENSSH PRIVATE KEY",
Bytes: marshalED25519PrivateKey(*k),
}
default:
return fmt.Errorf("unsupported private key type")
}
keyPem := string(pem.EncodeToMemory(keyPemBlock))
d.Set("private_key_pem", string(pem.EncodeToMemory(keyPemBlock)))

if openSSHKeyPemBlock == nil {
openSSHKeyPemBlock = keyPemBlock
}

d.Set("private_key_pem", keyPem)
d.Set("private_key_openssh", string(pem.EncodeToMemory(openSSHKeyPemBlock)))

return readPublicKey(d, key)
}
Expand Down
17 changes: 15 additions & 2 deletions internal/provider/resource_private_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ func TestPrivateKeyED25519(t *testing.T) {
output "private_key_pem" {
value = "${tls_private_key.test.private_key_pem}"
}
output "private_key_openssh" {
value = "${tls_private_key.test.private_key_openssh}"
}
output "public_key_pem" {
value = "${tls_private_key.test.public_key_pem}"
}
Expand All @@ -252,8 +255,18 @@ func TestPrivateKeyED25519(t *testing.T) {
return fmt.Errorf("output for \"private_key_pem\" is not a string")
}

if !strings.HasPrefix(gotPrivate, "-----BEGIN OPENSSH PRIVATE KEY----") {
return fmt.Errorf("private key is missing RSA key PEM preamble")
if !strings.HasPrefix(gotPrivate, "-----BEGIN PRIVATE KEY----") {
return fmt.Errorf("private key is missing ED25519 key PEM preamble")
}

gotPrivateOpenSSHUntyped := s.RootModule().Outputs["private_key_openssh"].Value
gotPrivateOpenSSH, ok := gotPrivateOpenSSHUntyped.(string)
if !ok {
return fmt.Errorf("output for \"private_key_openssh\" is not a string")
}

if !strings.HasPrefix(gotPrivateOpenSSH, "-----BEGIN OPENSSH PRIVATE KEY----") {
return fmt.Errorf("private key is missing OPENSSH key PEM preamble")
}

gotPublicUntyped := s.RootModule().Outputs["public_key_pem"].Value
Expand Down
4 changes: 2 additions & 2 deletions website/docs/r/private_key.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ default.
The following attributes are exported:

* `algorithm` - The algorithm that was selected for the key.
* `private_key_pem` - The private key data in PEM format. For "ED25519" keys,
the key is in OpenSSH-compatible format.
* `private_key_pem` - The private key data in PEM format.
* `private_key_openssh` - The private key data in OpenSSH-compatible format.
* `public_key_pem` - The public key data in PEM format.
* `public_key_openssh` - The public key data in OpenSSH `authorized_keys`
format, if the selected private key format is compatible. All RSA and ED25519
Expand Down

0 comments on commit 5181615

Please sign in to comment.