From b76429c37e7369e28ee452c62328a7096231ebe9 Mon Sep 17 00:00:00 2001 From: Ruben Costa Date: Fri, 15 Nov 2024 15:28:02 +0100 Subject: [PATCH 1/4] add key type param --- docs/resources/nkey.md | 4 ++++ go.mod | 2 +- internal/provider/nkey_resource.go | 28 ++++++++++++++++++++++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/docs/resources/nkey.md b/docs/resources/nkey.md index ae040b9..22d1ac8 100644 --- a/docs/resources/nkey.md +++ b/docs/resources/nkey.md @@ -15,6 +15,10 @@ An nkey is an ed25519 key pair formatted for use with NATS. ## Schema +### Optional + +- `type` (String) The type of nkey to generate. Must be one of user|account|server|cluster|operator|curve + ### Read-Only - `private_key` (String, Sensitive) Private key of the nkey to be given to the client for authentication diff --git a/go.mod b/go.mod index 6536afc..e979bdf 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.21 require ( github.com/hashicorp/terraform-plugin-docs v0.19.4 github.com/hashicorp/terraform-plugin-framework v1.11.0 - github.com/hashicorp/terraform-plugin-go v0.23.0 github.com/hashicorp/terraform-plugin-log v0.9.0 github.com/nats-io/nkeys v0.4.7 ) @@ -38,6 +37,7 @@ require ( github.com/hashicorp/hc-install v0.8.0 // indirect github.com/hashicorp/terraform-exec v0.21.0 // indirect github.com/hashicorp/terraform-json v0.22.1 // indirect + github.com/hashicorp/terraform-plugin-go v0.23.0 // indirect github.com/hashicorp/terraform-registry-address v0.2.3 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect github.com/hashicorp/yamux v0.1.1 // indirect diff --git a/internal/provider/nkey_resource.go b/internal/provider/nkey_resource.go index 477b23c..22abf22 100644 --- a/internal/provider/nkey_resource.go +++ b/internal/provider/nkey_resource.go @@ -5,10 +5,12 @@ package provider import ( "context" + "strings" "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/stringdefault" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" @@ -29,6 +31,7 @@ type Nkey struct { // NkeyModel describes the resource data model. type NkeyModel struct { + KeyType types.String `tfsdk:"type"` Public_key types.String `tfsdk:"public_key"` Private_key types.String `tfsdk:"private_key"` } @@ -43,6 +46,12 @@ func (r *Nkey) Schema(ctx context.Context, req resource.SchemaRequest, resp *res MarkdownDescription: "An nkey is an ed25519 key pair formatted for use with NATS.", Attributes: map[string]schema.Attribute{ + "type": schema.StringAttribute{ + Optional: true, + Computed: true, + Default: stringdefault.StaticString("account"), + Description: "The type of nkey to generate. Must be one of user|account|server|cluster|operator|curve", + }, "public_key": schema.StringAttribute{ Computed: true, MarkdownDescription: "Public key of the nkey to be given in config to the nats server", @@ -70,12 +79,27 @@ func (r *Nkey) Create(ctx context.Context, req resource.CreateRequest, resp *res return } - keys, err := nkeys.CreateAccount() + var keys nkeys.KeyPair + var err error + switch strings.ToLower(data.KeyType.ValueString()) { + case "user": + keys, err = nkeys.CreateUser() + case "account": + keys, err = nkeys.CreateAccount() + case "server": + keys, err = nkeys.CreateServer() + case "cluster": + keys, err = nkeys.CreateCluster() + case "operator": + keys, err = nkeys.CreateOperator() + case "curve": + keys, err = nkeys.CreateCurveKeys() + } + if err != nil { resp.Diagnostics.AddError("generating nkey", err.Error()) return } - pubKey, err := keys.PublicKey() if err != nil { resp.Diagnostics.AddError("accessing public nkey", err.Error()) From 95b0ccc7fcf9a53f480652356b9d53a2f0b4e5df Mon Sep 17 00:00:00 2001 From: Ruben Costa Date: Fri, 15 Nov 2024 17:36:27 +0100 Subject: [PATCH 2/4] handle key type updates --- .../provider-install-verification/main.tf | 3 +- internal/provider/nkey_resource.go | 101 ++++++++++-------- 2 files changed, 61 insertions(+), 43 deletions(-) diff --git a/examples/provider-install-verification/main.tf b/examples/provider-install-verification/main.tf index 16bcdbe..ebbee6c 100644 --- a/examples/provider-install-verification/main.tf +++ b/examples/provider-install-verification/main.tf @@ -9,4 +9,5 @@ terraform { provider "nkey" { } -resource "nkey_nkey" "verify" {} \ No newline at end of file +resource "nkey_nkey" "verify" { +} diff --git a/internal/provider/nkey_resource.go b/internal/provider/nkey_resource.go index 22abf22..66ca265 100644 --- a/internal/provider/nkey_resource.go +++ b/internal/provider/nkey_resource.go @@ -31,9 +31,9 @@ type Nkey struct { // NkeyModel describes the resource data model. type NkeyModel struct { - KeyType types.String `tfsdk:"type"` - Public_key types.String `tfsdk:"public_key"` - Private_key types.String `tfsdk:"private_key"` + KeyType types.String `tfsdk:"type"` + PublicKey types.String `tfsdk:"public_key"` + PrivateKey types.String `tfsdk:"private_key"` } func (r *Nkey) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -79,43 +79,10 @@ func (r *Nkey) Create(ctx context.Context, req resource.CreateRequest, resp *res return } - var keys nkeys.KeyPair - var err error - switch strings.ToLower(data.KeyType.ValueString()) { - case "user": - keys, err = nkeys.CreateUser() - case "account": - keys, err = nkeys.CreateAccount() - case "server": - keys, err = nkeys.CreateServer() - case "cluster": - keys, err = nkeys.CreateCluster() - case "operator": - keys, err = nkeys.CreateOperator() - case "curve": - keys, err = nkeys.CreateCurveKeys() - } - - if err != nil { + if err := data.generateKeys(); err != nil { resp.Diagnostics.AddError("generating nkey", err.Error()) return } - pubKey, err := keys.PublicKey() - if err != nil { - resp.Diagnostics.AddError("accessing public nkey", err.Error()) - return - } - - data.Public_key = types.StringValue(pubKey) - - privKey, err := keys.PrivateKey() - if err != nil { - resp.Diagnostics.AddError("accessing private nkey", err.Error()) - return - } - - data.Private_key = types.StringValue(string(privKey)) - tflog.Trace(ctx, "created nkey resource") // Save data into Terraform state @@ -137,17 +104,31 @@ func (r *Nkey) Read(ctx context.Context, req resource.ReadRequest, resp *resourc } func (r *Nkey) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var data NkeyModel - - // Read Terraform plan data into the model - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + var plan NkeyModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + var state NkeyModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) if resp.Diagnostics.HasError() { return } + if !plan.KeyType.Equal(state.KeyType) { + tflog.Debug(ctx, "key type changed. generating new key") + if err := plan.generateKeys(); err != nil { + resp.Diagnostics.AddError("generating nkey", err.Error()) + return + } + } + // Save updated data into Terraform state - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } } func (r *Nkey) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { @@ -164,3 +145,39 @@ func (r *Nkey) Delete(ctx context.Context, req resource.DeleteRequest, resp *res func (r *Nkey) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } + +func (m *NkeyModel) generateKeys() (err error) { + var keys nkeys.KeyPair + + switch strings.ToLower(m.KeyType.ValueString()) { + case "user": + keys, err = nkeys.CreateUser() + case "account": + keys, err = nkeys.CreateAccount() + case "server": + keys, err = nkeys.CreateServer() + case "cluster": + keys, err = nkeys.CreateCluster() + case "operator": + keys, err = nkeys.CreateOperator() + case "curve": + keys, err = nkeys.CreateCurveKeys() + } + if err != nil { + return err + } + + pubKey, err := keys.PublicKey() + if err != nil { + return err + } + privKey, err := keys.PrivateKey() + if err != nil { + return err + } + + m.PublicKey = types.StringValue(pubKey) + m.PrivateKey = types.StringValue(string(privKey)) + + return nil +} From 81c80905bb99a1b9008ba41a74180399f4b1dc61 Mon Sep 17 00:00:00 2001 From: Ruben Costa Date: Fri, 15 Nov 2024 19:06:46 +0100 Subject: [PATCH 3/4] recreate keys on type change --- internal/provider/nkey_resource.go | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/internal/provider/nkey_resource.go b/internal/provider/nkey_resource.go index 66ca265..6bf34f4 100644 --- a/internal/provider/nkey_resource.go +++ b/internal/provider/nkey_resource.go @@ -10,7 +10,9 @@ import ( "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/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" @@ -51,6 +53,9 @@ func (r *Nkey) Schema(ctx context.Context, req resource.SchemaRequest, resp *res Computed: true, Default: stringdefault.StaticString("account"), Description: "The type of nkey to generate. Must be one of user|account|server|cluster|operator|curve", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, }, "public_key": schema.StringAttribute{ Computed: true, @@ -110,20 +115,6 @@ func (r *Nkey) Update(ctx context.Context, req resource.UpdateRequest, resp *res return } - var state NkeyModel - resp.Diagnostics.Append(req.State.Get(ctx, &state)...) - if resp.Diagnostics.HasError() { - return - } - - if !plan.KeyType.Equal(state.KeyType) { - tflog.Debug(ctx, "key type changed. generating new key") - if err := plan.generateKeys(); err != nil { - resp.Diagnostics.AddError("generating nkey", err.Error()) - return - } - } - // Save updated data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) if resp.Diagnostics.HasError() { @@ -132,14 +123,6 @@ func (r *Nkey) Update(ctx context.Context, req resource.UpdateRequest, resp *res } func (r *Nkey) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - var data NkeyModel - - // Read Terraform prior state data into the model - resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } } func (r *Nkey) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { @@ -162,6 +145,8 @@ func (m *NkeyModel) generateKeys() (err error) { keys, err = nkeys.CreateOperator() case "curve": keys, err = nkeys.CreateCurveKeys() + default: + keys, err = nkeys.CreateAccount() } if err != nil { return err From 375e16f59603a82cf08bc3bf9843d8f57790d9d8 Mon Sep 17 00:00:00 2001 From: Ruben Costa Date: Mon, 18 Nov 2024 09:49:53 +0100 Subject: [PATCH 4/4] return nkey seed --- docs/resources/nkey.md | 1 + internal/provider/nkey_resource.go | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/docs/resources/nkey.md b/docs/resources/nkey.md index 22d1ac8..9298efe 100644 --- a/docs/resources/nkey.md +++ b/docs/resources/nkey.md @@ -23,3 +23,4 @@ An nkey is an ed25519 key pair formatted for use with NATS. - `private_key` (String, Sensitive) Private key of the nkey to be given to the client for authentication - `public_key` (String) Public key of the nkey to be given in config to the nats server +- `seed` (String, Sensitive) Seed of the nkey to be given to the client for authentication diff --git a/internal/provider/nkey_resource.go b/internal/provider/nkey_resource.go index 6bf34f4..3cf3059 100644 --- a/internal/provider/nkey_resource.go +++ b/internal/provider/nkey_resource.go @@ -36,6 +36,7 @@ type NkeyModel struct { KeyType types.String `tfsdk:"type"` PublicKey types.String `tfsdk:"public_key"` PrivateKey types.String `tfsdk:"private_key"` + Seed types.String `tfsdk:"seed"` } func (r *Nkey) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -66,6 +67,11 @@ func (r *Nkey) Schema(ctx context.Context, req resource.SchemaRequest, resp *res MarkdownDescription: "Private key of the nkey to be given to the client for authentication", Sensitive: true, }, + "seed": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "Seed of the nkey to be given to the client for authentication", + Sensitive: true, + }, }, } } @@ -160,9 +166,14 @@ func (m *NkeyModel) generateKeys() (err error) { if err != nil { return err } + seed, err := keys.Seed() + if err != nil { + return err + } m.PublicKey = types.StringValue(pubKey) m.PrivateKey = types.StringValue(string(privKey)) + m.Seed = types.StringValue(string(seed)) return nil }