Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Importer for tls_private_key #7

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions internal/provider/fixtures/fixtures.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ rpxCHbX0xSJh0s8j7exRHMF8W16DHjjkc265YdWPXWo=
-----END RSA PRIVATE KEY-----
`

TestPrivateKeyECDSA = `
-----BEGIN EC PRIVATE KEY-----
MGgCAQEEHJEA3wyFdST8uuJeYAoW1DISVM8sqj/xhk3AJZegBwYFK4EEACGhPAM6
AARnftbJ7ZLuRFxEeYJ8iVWLo45/87Nb4fxijONNCkDIIqOrBJ6LFhiYXZ0AOErw
6eZBkrwPQ2ADQA==
-----END EC PRIVATE KEY-----`

TestPrivateKeyOpenSSHPEM = `
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlwAAAAdzc2gtcn
Expand Down
32 changes: 32 additions & 0 deletions internal/provider/resource_private_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
"os"
"strings"

"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
Expand All @@ -33,6 +35,7 @@ type privateKeyResource struct{}
var (
_ resource.Resource = (*privateKeyResource)(nil)
_ resource.ResourceWithUpgradeState = (*privateKeyResource)(nil)
_ resource.ResourceWithImportState = (*privateKeyResource)(nil)
)

func NewPrivateKeyResource() resource.Resource {
Expand Down Expand Up @@ -367,6 +370,35 @@ func (r *privateKeyResource) Delete(ctx context.Context, _ resource.DeleteReques
tflog.Debug(ctx, "Removing private key from state")
}

func (r *privateKeyResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
bytes, err := os.ReadFile(req.ID)
if err != nil {
resp.Diagnostics.AddError("Could not read file", err.Error())
return
}
key, algo, err := parsePrivateKeyPEM(bytes)
if err != nil {
resp.Diagnostics.AddError("Error parsing private key", err.Error())
}

// Set the default values for the attributes
resp.State.SetAttribute(ctx, path.Root("rsa_bits"), 2048)
resp.State.SetAttribute(ctx, path.Root("ecdsa_curve"), P224.String())

// Set the attributes on the State
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("algorithm"), algo)...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("private_key_pem"), string(bytes))...)
resp.Diagnostics.Append(setPublicKeyAttributes(ctx, &resp.State, key)...)
switch k := key.(type) {
case *rsa.PrivateKey:
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("rsa_bits"), int64(k.N.BitLen()))...)
case *ecdsa.PrivateKey:
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("ecdsa_curve"), strings.Replace(k.Curve.Params().Name, "-", "", -1))...)
case ed25519.PrivateKey:
// Nothing to do
}
}

func (r *privateKeyResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader {
schemaV1 := privateKeyResourceSchemaV1()

Expand Down
99 changes: 99 additions & 0 deletions internal/provider/resource_private_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,3 +434,102 @@ func TestOpenSSHComment(t *testing.T) {
},
})
}

// type keyLens struct {
// algorithm string
// rsa_bits int
// ecdsa_curve string
// }

// var testAccProviders map[string]*schema.Provider
// var testAccProvider *schema.Provider

// func init() {
// testAccProvider = New()
// testAccProviders = map[string]*schema.Provider{
// "tls": testAccProvider,
// }
// }

// func TestAccImportKey(t *testing.T) {
// r.UnitTest(t, r.TestCase{
// PreCheck: func() {},
// Providers: testAccProviders,
// Steps: []r.TestStep{
// {
// Config: testAccResourceKeyConfig,
// Check: r.ComposeTestCheckFunc(
// testAccResourceKeyCheck("tls_private_key.rsa", &keyLens{
// algorithm: "RSA",
// rsa_bits: 2048,
// ecdsa_curve: "P224",
// }),
// testAccResourceKeyCheck("tls_private_key.ecdsa", &keyLens{
// algorithm: "ECDSA",
// rsa_bits: 2048,
// ecdsa_curve: "P224",
// }),
// ),
// },
// {
// ResourceName: "tls_private_key.rsa",
// ImportState: true,
// ImportStateIdFunc: importStateIdFunc(t, fixtures.TestPrivateKeyPEM),
// },
// {
// ResourceName: "tls_private_key.ecdsa",
// ImportState: true,
// ImportStateIdFunc: importStateIdFunc(t, fixtures.TestPrivateKeyECDSA),
// },
// },
// })
// }
// func importStateIdFunc(t *testing.T, key string) func(*terraform.State) (string, error) {
// return func(state *terraform.State) (string, error) {
// file, err := os.CreateTemp(t.TempDir(), state.Lineage)
// file.Write([]byte(key))
// if err != nil {
// return "", fmt.Errorf("could not write file: %w", err)
// }
// return file.Name(), nil
// }
// }
// func testAccResourceKeyCheck(id string, want *keyLens) r.TestCheckFunc {
// return func(s *terraform.State) error {
// rs, ok := s.RootModule().Resources[id]
// if !ok {
// return fmt.Errorf("Not found: %s", id)
// }
// if rs.Primary.ID == "" {
// return fmt.Errorf("No ID is set")
// }

// algorithm := rs.Primary.Attributes["algorithm"]
// rsa_bits := rs.Primary.Attributes["rsa_bits"]
// ecdsa_curve := rs.Primary.Attributes["ecdsa_curve"]

// if got, want := algorithm, want.algorithm; got != want {
// return fmt.Errorf("algorithm is %s; want %s", got, want)
// }
// if got, want := rsa_bits, want.rsa_bits; got != fmt.Sprint(want) {
// return fmt.Errorf("rsa_bits is %v; want %v", got, want)
// }
// if got, want := ecdsa_curve, want.ecdsa_curve; got != want {
// return fmt.Errorf("ecdsa_curve is %s; want %s", got, want)
// }

// return nil
// }
// }

// const (
// testAccResourceKeyConfig = `
// resource "tls_private_key" "rsa" {
// algorithm = "RSA"
// }

// resource "tls_private_key" "ecdsa" {
// algorithm = "ECDSA"
// }
// `
// )
8 changes: 8 additions & 0 deletions templates/resources/private_key.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,11 @@ terraform taint tls_private_key.example
```

A new key will then be generated on the next ``terraform apply``.

## Import

Import is supported for private key files in PEM format using the following syntax:

```shell
terraform import tls_private_key.example key.pem
```