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

New Resource: aws_kms_custom_key_store #26997

Merged
merged 5 commits into from Sep 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/26997.txt
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_kms_custom_key_store
```
1 change: 1 addition & 0 deletions internal/provider/provider.go
Expand Up @@ -1660,6 +1660,7 @@ func New(_ context.Context) (*schema.Provider, error) {

"aws_kms_alias": kms.ResourceAlias(),
"aws_kms_ciphertext": kms.ResourceCiphertext(),
"aws_kms_custom_key_store": kms.ResourceCustomKeyStore(),
"aws_kms_external_key": kms.ResourceExternalKey(),
"aws_kms_grant": kms.ResourceGrant(),
"aws_kms_key": kms.ResourceKey(),
Expand Down
158 changes: 158 additions & 0 deletions internal/service/kms/custom_key_store.go
@@ -0,0 +1,158 @@
package kms

import (
"context"
"errors"
"log"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/kms"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/create"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/names"
)

func ResourceCustomKeyStore() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceCustomKeyStoreCreate,
ReadWithoutTimeout: resourceCustomKeyStoreRead,
UpdateWithoutTimeout: resourceCustomKeyStoreUpdate,
DeleteWithoutTimeout: resourceCustomKeyStoreDelete,

Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(15 * time.Minute),
Update: schema.DefaultTimeout(15 * time.Minute),
Delete: schema.DefaultTimeout(15 * time.Minute),
},

Schema: map[string]*schema.Schema{
"cloud_hsm_cluster_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"custom_key_store_name": {
Type: schema.TypeString,
Required: true,
},
"key_store_password": {
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: validation.ToDiagFunc(validation.StringLenBetween(7, 32)),
},
"trust_anchor_certificate": {
Type: schema.TypeString,
Required: true,
},
},
}
}

const (
ResNameCustomKeyStore = "Custom Key Store"
)

func resourceCustomKeyStoreCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).KMSConn

in := &kms.CreateCustomKeyStoreInput{
CloudHsmClusterId: aws.String(d.Get("cloud_hsm_cluster_id").(string)),
CustomKeyStoreName: aws.String(d.Get("custom_key_store_name").(string)),
KeyStorePassword: aws.String(d.Get("key_store_password").(string)),
TrustAnchorCertificate: aws.String(d.Get("trust_anchor_certificate").(string)),
}

out, err := conn.CreateCustomKeyStoreWithContext(ctx, in)
if err != nil {
return create.DiagError(names.KMS, create.ErrActionCreating, ResNameCustomKeyStore, d.Get("custom_key_store_name").(string), err)
}

if out == nil {
return create.DiagError(names.KMS, create.ErrActionCreating, ResNameCustomKeyStore, d.Get("custom_key_store_name").(string), errors.New("empty output"))
}

d.SetId(aws.StringValue(out.CustomKeyStoreId))

return resourceCustomKeyStoreRead(ctx, d, meta)
}

func resourceCustomKeyStoreRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).KMSConn

out, err := FindCustomKeyStoreByID(ctx, conn, d.Id())

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] KMS CustomKeyStore (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return create.DiagError(names.KMS, create.ErrActionReading, ResNameCustomKeyStore, d.Id(), err)
}

d.Set("cloud_hsm_cluster_id", out.CloudHsmClusterId)
d.Set("custom_key_store_name", out.CustomKeyStoreName)
d.Set("trust_anchor_certificate", out.TrustAnchorCertificate)

return nil
}

func resourceCustomKeyStoreUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).KMSConn

update := false

in := &kms.UpdateCustomKeyStoreInput{
CustomKeyStoreId: aws.String(d.Id()),
CloudHsmClusterId: aws.String(d.Get("cloud_hsm_cluster_id").(string)),
}

if d.HasChange("key_store_password") {
in.KeyStorePassword = aws.String(d.Get("key_store_password").(string))
update = true
}

if d.HasChange("custom_key_store_name") {
in.NewCustomKeyStoreName = aws.String(d.Get("custom_key_store_name").(string))
update = true
}

if !update {
return nil
}

log.Printf("[DEBUG] Updating KMS CustomKeyStore (%s): %#v", d.Id(), in)
_, err := conn.UpdateCustomKeyStoreWithContext(ctx, in)
if err != nil {
return create.DiagError(names.KMS, create.ErrActionUpdating, ResNameCustomKeyStore, d.Id(), err)
}

return resourceCustomKeyStoreRead(ctx, d, meta)
}

func resourceCustomKeyStoreDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).KMSConn

log.Printf("[INFO] Deleting KMS CustomKeyStore %s", d.Id())

_, err := conn.DeleteCustomKeyStoreWithContext(ctx, &kms.DeleteCustomKeyStoreInput{
CustomKeyStoreId: aws.String(d.Id()),
})

if tfawserr.ErrCodeEquals(err, kms.ErrCodeNotFoundException) {
return nil
}

return nil
}
225 changes: 225 additions & 0 deletions internal/service/kms/custom_key_store_test.go
@@ -0,0 +1,225 @@
package kms_test

import (
"context"
"errors"
"fmt"
"os"
"testing"

"github.com/aws/aws-sdk-go/service/kms"
sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/create"
tfkms "github.com/hashicorp/terraform-provider-aws/internal/service/kms"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/names"
)

func testAccCustomKeyStore_basic(t *testing.T) {
if os.Getenv("CLOUD_HSM_CLUSTER_ID") == "" {
t.Skip("CLOUD_HSM_CLUSTER_ID environment variable not set")
}

if os.Getenv("TRUST_ANCHOR_CERTIFICATE") == "" {
t.Skip("TRUST_ANCHOR_CERTIFICATE environment variable not set")
}

if testing.Short() {
t.Skip("skipping long-running test in short mode")
}

var customkeystore kms.CustomKeyStoresListEntry
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_kms_custom_key_store.test"

clusterId := os.Getenv("CLOUD_HSM_CLUSTER_ID")
trustAnchorCertificate := os.Getenv("TRUST_ANCHOR_CERTIFICATE")

resource.Test(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(t)
acctest.PreCheckPartitionHasService(kms.EndpointsID, t)
testAccCustomKeyStoresPreCheck(t)
},
ErrorCheck: acctest.ErrorCheck(t, kms.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckCustomKeyStoreDestroy,
Steps: []resource.TestStep{
{
Config: testAccCustomKeyStoreConfig_basic(rName, clusterId, trustAnchorCertificate),
Check: resource.ComposeTestCheckFunc(
testAccCheckCustomKeyStoreExists(resourceName, &customkeystore),
resource.TestCheckResourceAttr(resourceName, "cloud_hsm_cluster_id", clusterId),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"key_store_password"},
},
},
})
}

func testAccCustomKeyStore_update(t *testing.T) {
if os.Getenv("CLOUD_HSM_CLUSTER_ID") == "" {
t.Skip("CLOUD_HSM_CLUSTER_ID environment variable not set")
}

if os.Getenv("TRUST_ANCHOR_CERTIFICATE") == "" {
t.Skip("TRUST_ANCHOR_CERTIFICATE environment variable not set")
}

if testing.Short() {
t.Skip("skipping long-running test in short mode")
}

var customkeystore kms.CustomKeyStoresListEntry
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_kms_custom_key_store.test"

clusterId := os.Getenv("CLOUD_HSM_CLUSTER_ID")
trustAnchorCertificate := os.Getenv("TRUST_ANCHOR_CERTIFICATE")

resource.Test(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(t)
acctest.PreCheckPartitionHasService(kms.EndpointsID, t)
testAccCustomKeyStoresPreCheck(t)
},
ErrorCheck: acctest.ErrorCheck(t, kms.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckCustomKeyStoreDestroy,
Steps: []resource.TestStep{
{
Config: testAccCustomKeyStoreConfig_basic(fmt.Sprintf("%s-updated", rName), clusterId, trustAnchorCertificate),
Check: resource.ComposeTestCheckFunc(
testAccCheckCustomKeyStoreExists(resourceName, &customkeystore),
resource.TestCheckResourceAttr(resourceName, "cloud_hsm_cluster_id", clusterId),
resource.TestCheckResourceAttr(resourceName, "custom_key_store_name", fmt.Sprintf("%s-updated", rName)),
),
},
},
})
}

func testAccCustomKeyStore_disappears(t *testing.T) {
if os.Getenv("CLOUD_HSM_CLUSTER_ID") == "" {
t.Skip("CLOUD_HSM_CLUSTER_ID environment variable not set")
}

if os.Getenv("TRUST_ANCHOR_CERTIFICATE") == "" {
t.Skip("TRUST_ANCHOR_CERTIFICATE environment variable not set")
}

if testing.Short() {
t.Skip("skipping long-running test in short mode")
}

var customkeystore kms.CustomKeyStoresListEntry
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_kms_custom_key_store.test"

clusterId := os.Getenv("CLOUD_HSM_CLUSTER_ID")
trustAnchorCertificate := os.Getenv("TRUST_ANCHOR_CERTIFICATE")

resource.Test(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(t)
acctest.PreCheckPartitionHasService(kms.EndpointsID, t)
testAccCustomKeyStoresPreCheck(t)
},
ErrorCheck: acctest.ErrorCheck(t, kms.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckCustomKeyStoreDestroy,
Steps: []resource.TestStep{
{
Config: testAccCustomKeyStoreConfig_basic(rName, clusterId, trustAnchorCertificate),
Check: resource.ComposeTestCheckFunc(
testAccCheckCustomKeyStoreExists(resourceName, &customkeystore),
acctest.CheckResourceDisappears(acctest.Provider, tfkms.ResourceCustomKeyStore(), resourceName),
),
ExpectNonEmptyPlan: true,
},
},
})
}

func testAccCheckCustomKeyStoreDestroy(s *terraform.State) error {
conn := acctest.Provider.Meta().(*conns.AWSClient).KMSConn
ctx := context.Background()

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_kms_custom_key_store" {
continue
}

_, err := tfkms.FindCustomKeyStoreByID(ctx, conn, rs.Primary.ID)

if tfresource.NotFound(err) {
continue
}

return create.Error(names.KMS, create.ErrActionCheckingDestroyed, tfkms.ResNameCustomKeyStore, rs.Primary.ID, errors.New("not destroyed"))
}

return nil
}

func testAccCheckCustomKeyStoreExists(name string, customkeystore *kms.CustomKeyStoresListEntry) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
if !ok {
return create.Error(names.KMS, create.ErrActionCheckingExistence, tfkms.ResNameCustomKeyStore, name, errors.New("not found"))
}

if rs.Primary.ID == "" {
return create.Error(names.KMS, create.ErrActionCheckingExistence, tfkms.ResNameCustomKeyStore, name, errors.New("not set"))
}

conn := acctest.Provider.Meta().(*conns.AWSClient).KMSConn
ctx := context.Background()
resp, err := tfkms.FindCustomKeyStoreByID(ctx, conn, rs.Primary.ID)

if err != nil {
return create.Error(names.KMS, create.ErrActionCheckingExistence, tfkms.ResNameCustomKeyStore, rs.Primary.ID, err)
}

*customkeystore = *resp

return nil
}
}

func testAccCustomKeyStoresPreCheck(t *testing.T) {
conn := acctest.Provider.Meta().(*conns.AWSClient).KMSConn
ctx := context.Background()

input := &kms.DescribeCustomKeyStoresInput{}
_, err := conn.DescribeCustomKeyStoresWithContext(ctx, input)

if acctest.PreCheckSkipError(err) {
t.Skipf("skipping acceptance testing: %s", err)
}

if err != nil {
t.Fatalf("unexpected PreCheck error: %s", err)
}
}

func testAccCustomKeyStoreConfig_basic(rName, clusterId, anchorCertificate string) string {
return fmt.Sprintf(`
resource "aws_kms_custom_key_store" "test" {
cloud_hsm_cluster_id = %[2]q
custom_key_store_name = %[1]q
key_store_password = "noplaintextpasswords1"

trust_anchor_certificate = file(%[3]q)
}
`, rName, clusterId, anchorCertificate)
}