Skip to content

Commit 91c0726

Browse files
authored
feat(secretsmanager): add support for kms keys (#1312)
relates to STACKITTPR-539
1 parent e41d37a commit 91c0726

File tree

8 files changed

+396
-33
lines changed

8 files changed

+396
-33
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,12 @@ Terraform acceptance tests are run using the command `make test-acceptance-tf`.
222222

223223
Additionally:
224224

225-
| Env var | Value | Example value | needed for Acc tests of the following services |
226-
|---------------------------------------------|---------------------------------------------------------------------------------------------------------|----------------------------------------|------------------------------------------------|
227-
| `TF_ACC_ORGANIZATION_ID` | ID of the STACKIT test organization | `5353ccfa-a984-4b96-a71d-b863dd2b7087` | `authorization`, `iaas` |
228-
| `TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL` | Email of the STACKIT service account | `abc-serviceaccount@sa.stackit.cloud` | `authorization`, `resourcemanager` | |
229-
| `TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID` | Container ID of the project parent container (folder within an organization or the organization itself) | `organization-d2b7087` | `resourcemanager` |
230-
| `TF_ACC_TEST_PROJECT_PARENT_UUID` | UUID ID of the project parent container (folder within an organization or the organization itself) | `5353ccfa-a984-4b96-a71d-b863dd2b7087` | `resourcemanager` |
225+
| Env var | Value | Example value | needed for Acc tests of the following services |
226+
|---------------------------------------------|---------------------------------------------------------------------------------------------------------|----------------------------------------|--------------------------------------------------------------|
227+
| `TF_ACC_ORGANIZATION_ID` | ID of the STACKIT test organization | `5353ccfa-a984-4b96-a71d-b863dd2b7087` | `authorization`, `iaas` |
228+
| `TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL` | Email of the STACKIT service account | `abc-serviceaccount@sa.stackit.cloud` | `authorization`, `iaas`, `resourcemanager`, `secretsmanager` |
229+
| `TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID` | Container ID of the project parent container (folder within an organization or the organization itself) | `organization-d2b7087` | `resourcemanager` |
230+
| `TF_ACC_TEST_PROJECT_PARENT_UUID` | UUID ID of the project parent container (folder within an organization or the organization itself) | `5353ccfa-a984-4b96-a71d-b863dd2b7087` | `resourcemanager` |
231231

232232
### Run Acceptance Tests of a single service
233233

docs/data-sources/secretsmanager_instance.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,15 @@ data "stackit_secretsmanager_instance" "example" {
3131

3232
- `acls` (Set of String) The access control list for this instance. Each entry is an IP or IP range that is permitted to access, in CIDR notation
3333
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`instance_id`".
34+
- `kms_key` (Attributes) The STACKIT-KMS key for secret encryption and decryption. (see [below for nested schema](#nestedatt--kms_key))
3435
- `name` (String) Instance name.
36+
37+
<a id="nestedatt--kms_key"></a>
38+
### Nested Schema for `kms_key`
39+
40+
Read-Only:
41+
42+
- `key_id` (String) UUID of the key within the STACKIT-KMS to use for the encryption.
43+
- `key_ring_id` (String) UUID of the keyring where the key is located within the STACKTI-KMS.
44+
- `key_version` (Number) Version of the key within the STACKIT-KMS to use for the encryption.
45+
- `service_account_email` (String) Service-Account linked to the Key within the STACKIT-KMS.

docs/resources/secretsmanager_instance.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,19 @@ import {
3737
### Optional
3838

3939
- `acls` (Set of String) The access control list for this instance. Each entry is an IP or IP range that is permitted to access, in CIDR notation
40+
- `kms_key` (Attributes) The STACKIT-KMS key for secret encryption and decryption. (see [below for nested schema](#nestedatt--kms_key))
4041

4142
### Read-Only
4243

4344
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`instance_id`".
4445
- `instance_id` (String) ID of the Secrets Manager instance.
46+
47+
<a id="nestedatt--kms_key"></a>
48+
### Nested Schema for `kms_key`
49+
50+
Required:
51+
52+
- `key_id` (String) UUID of the key within the STACKIT-KMS to use for the encryption.
53+
- `key_ring_id` (String) UUID of the keyring where the key is located within the STACKTI-KMS.
54+
- `key_version` (Number) Version of the key within the STACKIT-KMS to use for the encryption.
55+
- `service_account_email` (String) Service-Account linked to the Key within the STACKIT-KMS.

stackit/internal/services/secretsmanager/instance/datasource.go

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,17 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi
5858
// Schema defines the schema for the data source.
5959
func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
6060
descriptions := map[string]string{
61-
"main": "Secrets Manager instance data source schema. Must have a `region` specified in the provider configuration.",
62-
"id": "Terraform's internal resource ID. It is structured as \"`project_id`,`instance_id`\".",
63-
"instance_id": "ID of the Secrets Manager instance.",
64-
"project_id": "STACKIT project ID to which the instance is associated.",
65-
"name": "Instance name.",
66-
"acls": "The access control list for this instance. Each entry is an IP or IP range that is permitted to access, in CIDR notation",
61+
"main": "Secrets Manager instance data source schema. Must have a `region` specified in the provider configuration.",
62+
"id": "Terraform's internal resource ID. It is structured as \"`project_id`,`instance_id`\".",
63+
"instance_id": "ID of the Secrets Manager instance.",
64+
"project_id": "STACKIT project ID to which the instance is associated.",
65+
"name": "Instance name.",
66+
"acls": "The access control list for this instance. Each entry is an IP or IP range that is permitted to access, in CIDR notation",
67+
"kms_key": "The STACKIT-KMS key for secret encryption and decryption.",
68+
"kms_key.key_id": "UUID of the key within the STACKIT-KMS to use for the encryption.",
69+
"kms_key.key_ring_id": "UUID of the keyring where the key is located within the STACKTI-KMS.",
70+
"kms_key.key_version": "Version of the key within the STACKIT-KMS to use for the encryption.",
71+
"kms_key.service_account_email": "Service-Account linked to the Key within the STACKIT-KMS.",
6772
}
6873

6974
resp.Schema = schema.Schema{
@@ -98,6 +103,28 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques
98103
ElementType: types.StringType,
99104
Computed: true,
100105
},
106+
"kms_key": schema.SingleNestedAttribute{
107+
Description: descriptions["kms_key"],
108+
Computed: true,
109+
Attributes: map[string]schema.Attribute{
110+
"key_id": schema.StringAttribute{
111+
Description: descriptions["kms_key.key_id"],
112+
Computed: true,
113+
},
114+
"key_ring_id": schema.StringAttribute{
115+
Description: descriptions["kms_key.key_ring_id"],
116+
Computed: true,
117+
},
118+
"key_version": schema.Int64Attribute{
119+
Description: descriptions["kms_key.key_version"],
120+
Computed: true,
121+
},
122+
"service_account_email": schema.StringAttribute{
123+
Description: descriptions["kms_key.service_account_email"],
124+
Computed: true,
125+
},
126+
},
127+
},
101128
},
102129
}
103130
}

stackit/internal/services/secretsmanager/instance/resource.go

Lines changed: 104 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ type Model struct {
4242
ProjectId types.String `tfsdk:"project_id"`
4343
Name types.String `tfsdk:"name"`
4444
ACLs types.Set `tfsdk:"acls"`
45+
KmsKey *KmsKeyModel `tfsdk:"kms_key"`
46+
}
47+
48+
type KmsKeyModel struct {
49+
KeyId types.String `tfsdk:"key_id"`
50+
KeyRingId types.String `tfsdk:"key_ring_id"`
51+
KeyVersion types.Int64 `tfsdk:"key_version"`
52+
ServiceAccountEmail types.String `tfsdk:"service_account_email"`
4553
}
4654

4755
// NewInstanceResource is a helper function to simplify the provider implementation.
@@ -77,12 +85,17 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure
7785
// Schema defines the schema for the resource.
7886
func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
7987
descriptions := map[string]string{
80-
"main": "Secrets Manager instance resource schema. Must have a `region` specified in the provider configuration.",
81-
"id": "Terraform's internal resource ID. It is structured as \"`project_id`,`instance_id`\".",
82-
"instance_id": "ID of the Secrets Manager instance.",
83-
"project_id": "STACKIT project ID to which the instance is associated.",
84-
"name": "Instance name.",
85-
"acls": "The access control list for this instance. Each entry is an IP or IP range that is permitted to access, in CIDR notation",
88+
"main": "Secrets Manager instance resource schema. Must have a `region` specified in the provider configuration.",
89+
"id": "Terraform's internal resource ID. It is structured as \"`project_id`,`instance_id`\".",
90+
"instance_id": "ID of the Secrets Manager instance.",
91+
"project_id": "STACKIT project ID to which the instance is associated.",
92+
"name": "Instance name.",
93+
"acls": "The access control list for this instance. Each entry is an IP or IP range that is permitted to access, in CIDR notation",
94+
"kms_key": "The STACKIT-KMS key for secret encryption and decryption.",
95+
"kms_key.key_id": "UUID of the key within the STACKIT-KMS to use for the encryption.",
96+
"kms_key.key_ring_id": "UUID of the keyring where the key is located within the STACKTI-KMS.",
97+
"kms_key.key_version": "Version of the key within the STACKIT-KMS to use for the encryption.",
98+
"kms_key.service_account_email": "Service-Account linked to the Key within the STACKIT-KMS.",
8699
}
87100

88101
resp.Schema = schema.Schema{
@@ -118,11 +131,9 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
118131
},
119132
},
120133
"name": schema.StringAttribute{
121-
Description: descriptions["name"],
122-
Required: true,
123-
PlanModifiers: []planmodifier.String{
124-
stringplanmodifier.RequiresReplace(),
125-
},
134+
Description: descriptions["name"],
135+
Required: true,
136+
PlanModifiers: []planmodifier.String{},
126137
Validators: []validator.String{
127138
stringvalidator.LengthAtLeast(1),
128139
},
@@ -137,6 +148,28 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
137148
),
138149
},
139150
},
151+
"kms_key": schema.SingleNestedAttribute{
152+
Description: descriptions["kms_key"],
153+
Optional: true,
154+
Attributes: map[string]schema.Attribute{
155+
"key_id": schema.StringAttribute{
156+
Description: descriptions["kms_key.key_id"],
157+
Required: true,
158+
},
159+
"key_ring_id": schema.StringAttribute{
160+
Description: descriptions["kms_key.key_ring_id"],
161+
Required: true,
162+
},
163+
"key_version": schema.Int64Attribute{
164+
Description: descriptions["kms_key.key_version"],
165+
Required: true,
166+
},
167+
"service_account_email": schema.StringAttribute{
168+
Description: descriptions["kms_key.service_account_email"],
169+
Required: true,
170+
},
171+
},
172+
},
140173
},
141174
}
142175
}
@@ -284,6 +317,21 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
284317
ctx = tflog.SetField(ctx, "project_id", projectId)
285318
ctx = tflog.SetField(ctx, "instance_id", instanceId)
286319

320+
// Generate API request body from model
321+
payload, err := toUpdatePayload(&model)
322+
if err != nil {
323+
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Creating API payload: %v", err))
324+
return
325+
}
326+
// Update instance
327+
err = r.client.UpdateInstance(ctx, projectId, instanceId).UpdateInstancePayload(*payload).Execute()
328+
if err != nil {
329+
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Calling API: %v", err))
330+
return
331+
}
332+
333+
ctx = core.LogResponse(ctx)
334+
287335
var acls []string
288336
if !(model.ACLs.IsNull() || model.ACLs.IsUnknown()) {
289337
diags = model.ACLs.ElementsAs(ctx, &acls, false)
@@ -294,15 +342,15 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
294342
}
295343

296344
// Update ACLs
297-
err := updateACLs(ctx, projectId, instanceId, acls, r.client)
345+
err = updateACLs(ctx, projectId, instanceId, acls, r.client)
298346
if err != nil {
299347
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Updating ACLs: %v", err))
300348
return
301349
}
302350

303351
instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute()
304352
if err != nil {
305-
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Calling API: %v", err))
353+
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance acl", fmt.Sprintf("Calling API: %v", err))
306354
return
307355
}
308356

@@ -398,6 +446,15 @@ func mapFields(instance *secretsmanager.Instance, aclList *secretsmanager.ListAC
398446
model.InstanceId = types.StringValue(instanceId)
399447
model.Name = types.StringPointerValue(instance.Name)
400448

449+
if instance.KmsKey != nil {
450+
model.KmsKey = &KmsKeyModel{
451+
KeyId: types.StringPointerValue(instance.KmsKey.KeyId),
452+
KeyRingId: types.StringPointerValue(instance.KmsKey.KeyRingId),
453+
KeyVersion: types.Int64PointerValue(instance.KmsKey.KeyVersion),
454+
ServiceAccountEmail: types.StringPointerValue(instance.KmsKey.ServiceAccountEmail),
455+
}
456+
}
457+
401458
err := mapACLs(aclList, model)
402459
if err != nil {
403460
return err
@@ -431,9 +488,41 @@ func toCreatePayload(model *Model) (*secretsmanager.CreateInstancePayload, error
431488
if model == nil {
432489
return nil, fmt.Errorf("nil model")
433490
}
434-
return &secretsmanager.CreateInstancePayload{
491+
payload := &secretsmanager.CreateInstancePayload{
435492
Name: conversion.StringValueToPointer(model.Name),
436-
}, nil
493+
}
494+
495+
if model.KmsKey != nil {
496+
payload.KmsKey = &secretsmanager.KmsKeyPayload{
497+
KeyId: conversion.StringValueToPointer(model.KmsKey.KeyId),
498+
KeyRingId: conversion.StringValueToPointer(model.KmsKey.KeyRingId),
499+
KeyVersion: conversion.Int64ValueToPointer(model.KmsKey.KeyVersion),
500+
ServiceAccountEmail: conversion.StringValueToPointer(model.KmsKey.ServiceAccountEmail),
501+
}
502+
}
503+
504+
return payload, nil
505+
}
506+
507+
func toUpdatePayload(model *Model) (*secretsmanager.UpdateInstancePayload, error) {
508+
if model == nil {
509+
return nil, fmt.Errorf("nil model")
510+
}
511+
512+
payload := &secretsmanager.UpdateInstancePayload{
513+
Name: conversion.StringValueToPointer(model.Name),
514+
}
515+
516+
if model.KmsKey != nil {
517+
payload.KmsKey = &secretsmanager.KmsKeyPayload{
518+
KeyId: conversion.StringValueToPointer(model.KmsKey.KeyId),
519+
KeyRingId: conversion.StringValueToPointer(model.KmsKey.KeyRingId),
520+
KeyVersion: conversion.Int64ValueToPointer(model.KmsKey.KeyVersion),
521+
ServiceAccountEmail: conversion.StringValueToPointer(model.KmsKey.ServiceAccountEmail),
522+
}
523+
}
524+
525+
return payload, nil
437526
}
438527

439528
// updateACLs creates and deletes ACLs so that the instance's ACLs are the ones in the model

0 commit comments

Comments
 (0)