From e0db82acb547284244bd120519929a56cabdb229 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 13 Dec 2024 12:29:27 +0100 Subject: [PATCH 01/19] kms: add support for external key store --- internal/service/kms/consts.go | 13 ++ internal/service/kms/custom_key_store.go | 145 ++++++++++++++++++++++- 2 files changed, 153 insertions(+), 5 deletions(-) diff --git a/internal/service/kms/consts.go b/internal/service/kms/consts.go index 7ea54315f315..9e31e3aaf7d7 100644 --- a/internal/service/kms/consts.go +++ b/internal/service/kms/consts.go @@ -3,6 +3,11 @@ package kms +import ( + awstypes "github.com/aws/aws-sdk-go-v2/service/kms/types" + "github.com/hashicorp/terraform-provider-aws/internal/enum" +) + const ( aliasNamePrefix = "alias/" cmkAliasPrefix = aliasNamePrefix + "aws/" @@ -11,3 +16,11 @@ const ( const ( policyNameDefault = "default" ) + +func customKeyStoreType_Values() []string { + return enum.Values[awstypes.CustomKeyStoreType]() +} + +func proxyConnectivityType_Values() []string { + return enum.Values[awstypes.XksProxyConnectivityType]() +} diff --git a/internal/service/kms/custom_key_store.go b/internal/service/kms/custom_key_store.go index ea31baac25f1..756b964551c0 100644 --- a/internal/service/kms/custom_key_store.go +++ b/internal/service/kms/custom_key_store.go @@ -50,9 +50,14 @@ func resourceCustomKeyStore() *schema.Resource { Type: schema.TypeString, Required: true, }, + "custom_key_store_type": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice(customKeyStoreType_Values(), false)), + }, "key_store_password": { Type: schema.TypeString, - Required: true, + Optional: true, ValidateDiagFunc: validation.ToDiagFunc(validation.StringLenBetween(7, 32)), }, "trust_anchor_certificate": { @@ -60,6 +65,40 @@ func resourceCustomKeyStore() *schema.Resource { Required: true, ForceNew: true, }, + "xks_proxy_authentication_credential": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_key_id": { + Type: schema.TypeString, + Required: true, + }, + "raw_secret_access_key": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "xks_proxy_connectivity": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice(proxyConnectivityType_Values(), false)), + }, + "xks_proxy_uri_endpoint": { + Type: schema.TypeString, + Optional: true, + }, + "xks_proxy_uri_path": { + Type: schema.TypeString, + Optional: true, + }, + "xks_proxy_vpc_endpoint_service_name": { + Type: schema.TypeString, + Optional: true, + }, }, } } @@ -70,10 +109,43 @@ func resourceCustomKeyStoreCreate(ctx context.Context, d *schema.ResourceData, m name := d.Get("custom_key_store_name").(string) input := &kms.CreateCustomKeyStoreInput{ - CloudHsmClusterId: aws.String(d.Get("cloud_hsm_cluster_id").(string)), - CustomKeyStoreName: aws.String(name), - KeyStorePassword: aws.String(d.Get("key_store_password").(string)), - TrustAnchorCertificate: aws.String(d.Get("trust_anchor_certificate").(string)), + CustomKeyStoreName: aws.String(name), + } + + if v, ok := d.GetOk("custom_key_store_type"); ok { + input.CustomKeyStoreType = awstypes.CustomKeyStoreType(v.(string)) + } + + if v, ok := d.GetOk("cloud_hsm_cluster_id"); ok { + input.CloudHsmClusterId = aws.String(v.(string)) + } + + if v, ok := d.GetOk("key_store_password"); ok { + input.KeyStorePassword = aws.String(v.(string)) + } + + if v, ok := d.GetOk("trust_anchor_certificate"); ok { + input.TrustAnchorCertificate = aws.String(v.(string)) + } + + if v, ok := d.GetOk("xks_proxy_authentication_credential"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.XksProxyAuthenticationCredential = expandXksProxyAuthenticationCredential(v.([]interface{})) + } + + if v, ok := d.GetOk("xks_proxy_connectivity"); ok { + input.XksProxyConnectivity = awstypes.XksProxyConnectivityType(v.(string)) + } + + if v, ok := d.GetOk("xks_proxy_uri_endpoint"); ok { + input.XksProxyUriEndpoint = aws.String(v.(string)) + } + + if v, ok := d.GetOk("xks_proxy_uri_path"); ok { + input.XksProxyUriPath = aws.String(v.(string)) + } + + if v, ok := d.GetOk("xks_proxy_vpc_endpoint_service_name"); ok { + input.XksProxyVpcEndpointServiceName = aws.String(v.(string)) } output, err := conn.CreateCustomKeyStore(ctx, input) @@ -105,9 +177,15 @@ func resourceCustomKeyStoreRead(ctx context.Context, d *schema.ResourceData, met d.Set("cloud_hsm_cluster_id", output.CloudHsmClusterId) d.Set("custom_key_store_name", output.CustomKeyStoreName) + d.Set("custom_key_store_type", output.CustomKeyStoreType) d.Set("key_store_password", d.Get("key_store_password")) d.Set("trust_anchor_certificate", output.TrustAnchorCertificate) + d.Set("xks_proxy_connectivity", output.XksProxyConfiguration.Connectivity) + d.Set("xks_proxy_uri_endpoint", output.XksProxyConfiguration.UriEndpoint) + d.Set("xks_proxy_uri_path", output.XksProxyConfiguration.UriPath) + d.Set("xks_proxy_vpc_endpoint_service_name", output.XksProxyConfiguration.VpcEndpointServiceName) + return diags } @@ -128,6 +206,26 @@ func resourceCustomKeyStoreUpdate(ctx context.Context, d *schema.ResourceData, m input.KeyStorePassword = aws.String(d.Get("key_store_password").(string)) } + if d.HasChange("xks_proxy_authentication_credential") { + input.XksProxyAuthenticationCredential = expandXksProxyAuthenticationCredential(d.Get("xks_proxy_authentication_credential").(*schema.Set).List()) + } + + if d.HasChange("xks_proxy_connectivity") { + input.XksProxyConnectivity = awstypes.XksProxyConnectivityType(d.Get("xks_proxy_connectivity").(string)) + } + + if d.HasChange("xks_proxy_uri_endpoint") { + input.XksProxyUriEndpoint = aws.String(d.Get("xks_proxy_uri_endpoint").(string)) + } + + if d.HasChange("xks_proxy_uri_path") { + input.XksProxyUriPath = aws.String(d.Get("xks_proxy_uri_path").(string)) + } + + if d.HasChange("xks_proxy_vpc_endpoint_service_name") { + input.XksProxyVpcEndpointServiceName = aws.String(d.Get("xks_proxy_vpc_endpoint_service_name").(string)) + } + _, err := conn.UpdateCustomKeyStore(ctx, input) if err != nil { @@ -198,3 +296,40 @@ func findCustomKeyStores(ctx context.Context, conn *kms.Client, input *kms.Descr return output, nil } + +func expandXksProxyAuthenticationCredential(l []interface{}) *awstypes.XksProxyAuthenticationCredentialType { + if len(l) == 0 || l[0] == nil { + return nil + } + + tfMap, ok := l[0].(map[string]interface{}) + + if !ok { + return nil + } + + result := &awstypes.XksProxyAuthenticationCredentialType{} + + if v, ok := tfMap["access_key_id"].(string); ok { + result.AccessKeyId = aws.String(v) + } + + if v, ok := tfMap["raw_secret_access_key"].(string); ok { + result.RawSecretAccessKey = aws.String(v) + } + + return result +} + +func flattenXksProxyAuthenticationCredential(config *awstypes.XksProxyAuthenticationCredentialType) []interface{} { + if config == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "access_key_id": aws.ToString(config.AccessKeyId), + "raw_secret_access_key": aws.ToString(config.RawSecretAccessKey), + } + + return []interface{}{m} +} From 9f8bf0f0e99bc62e8f0d10da00e7579743230510 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 13 Dec 2024 12:36:02 +0100 Subject: [PATCH 02/19] kms: refactor to remove 'cloud_hsm_cluster_id' from required UpdateInput fields --- internal/service/kms/custom_key_store.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/internal/service/kms/custom_key_store.go b/internal/service/kms/custom_key_store.go index 756b964551c0..15ac123b0dc0 100644 --- a/internal/service/kms/custom_key_store.go +++ b/internal/service/kms/custom_key_store.go @@ -175,8 +175,8 @@ func resourceCustomKeyStoreRead(ctx context.Context, d *schema.ResourceData, met return sdkdiag.AppendErrorf(diags, "reading KMS Custom Key Store (%s): %s", d.Id(), err) } - d.Set("cloud_hsm_cluster_id", output.CloudHsmClusterId) d.Set("custom_key_store_name", output.CustomKeyStoreName) + d.Set("cloud_hsm_cluster_id", output.CloudHsmClusterId) d.Set("custom_key_store_type", output.CustomKeyStoreType) d.Set("key_store_password", d.Get("key_store_password")) d.Set("trust_anchor_certificate", output.TrustAnchorCertificate) @@ -194,8 +194,11 @@ func resourceCustomKeyStoreUpdate(ctx context.Context, d *schema.ResourceData, m conn := meta.(*conns.AWSClient).KMSClient(ctx) input := &kms.UpdateCustomKeyStoreInput{ - CloudHsmClusterId: aws.String(d.Get("cloud_hsm_cluster_id").(string)), - CustomKeyStoreId: aws.String(d.Id()), + CustomKeyStoreId: aws.String(d.Id()), + } + + if d.HasChange("cloud_hsm_cluster_id") { + input.CloudHsmClusterId = aws.String(d.Get("cloud_hsm_cluster_id").(string)) } if d.HasChange("custom_key_store_name") { @@ -303,24 +306,22 @@ func expandXksProxyAuthenticationCredential(l []interface{}) *awstypes.XksProxyA } tfMap, ok := l[0].(map[string]interface{}) - if !ok { return nil } result := &awstypes.XksProxyAuthenticationCredentialType{} - if v, ok := tfMap["access_key_id"].(string); ok { - result.AccessKeyId = aws.String(v) + if accessKeyId, ok := tfMap["access_key_id"].(string); ok { + result.AccessKeyId = aws.String(accessKeyId) } - if v, ok := tfMap["raw_secret_access_key"].(string); ok { - result.RawSecretAccessKey = aws.String(v) + if rawSecretAccessKey, ok := tfMap["raw_secret_access_key"].(string); ok { + result.RawSecretAccessKey = aws.String(rawSecretAccessKey) } return result } - func flattenXksProxyAuthenticationCredential(config *awstypes.XksProxyAuthenticationCredentialType) []interface{} { if config == nil { return []interface{}{} From 0a5bcaf3fa2b0890a7a14b398d7363a73777d1f8 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 13 Dec 2024 12:36:02 +0100 Subject: [PATCH 03/19] kms: refactor to remove `cloud_hsm_cluster_id` from required UpdateInput fields --- internal/service/kms/custom_key_store.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/internal/service/kms/custom_key_store.go b/internal/service/kms/custom_key_store.go index 756b964551c0..501b68a6cec2 100644 --- a/internal/service/kms/custom_key_store.go +++ b/internal/service/kms/custom_key_store.go @@ -43,7 +43,7 @@ func resourceCustomKeyStore() *schema.Resource { Schema: map[string]*schema.Schema{ "cloud_hsm_cluster_id": { Type: schema.TypeString, - Required: true, + Optional: true, ForceNew: true, }, "custom_key_store_name": { @@ -53,6 +53,7 @@ func resourceCustomKeyStore() *schema.Resource { "custom_key_store_type": { Type: schema.TypeString, Optional: true, + ForceNew: true, ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice(customKeyStoreType_Values(), false)), }, "key_store_password": { @@ -175,8 +176,8 @@ func resourceCustomKeyStoreRead(ctx context.Context, d *schema.ResourceData, met return sdkdiag.AppendErrorf(diags, "reading KMS Custom Key Store (%s): %s", d.Id(), err) } - d.Set("cloud_hsm_cluster_id", output.CloudHsmClusterId) d.Set("custom_key_store_name", output.CustomKeyStoreName) + d.Set("cloud_hsm_cluster_id", output.CloudHsmClusterId) d.Set("custom_key_store_type", output.CustomKeyStoreType) d.Set("key_store_password", d.Get("key_store_password")) d.Set("trust_anchor_certificate", output.TrustAnchorCertificate) @@ -194,8 +195,11 @@ func resourceCustomKeyStoreUpdate(ctx context.Context, d *schema.ResourceData, m conn := meta.(*conns.AWSClient).KMSClient(ctx) input := &kms.UpdateCustomKeyStoreInput{ - CloudHsmClusterId: aws.String(d.Get("cloud_hsm_cluster_id").(string)), - CustomKeyStoreId: aws.String(d.Id()), + CustomKeyStoreId: aws.String(d.Id()), + } + + if d.HasChange("cloud_hsm_cluster_id") { + input.CloudHsmClusterId = aws.String(d.Get("cloud_hsm_cluster_id").(string)) } if d.HasChange("custom_key_store_name") { @@ -303,24 +307,22 @@ func expandXksProxyAuthenticationCredential(l []interface{}) *awstypes.XksProxyA } tfMap, ok := l[0].(map[string]interface{}) - if !ok { return nil } result := &awstypes.XksProxyAuthenticationCredentialType{} - if v, ok := tfMap["access_key_id"].(string); ok { - result.AccessKeyId = aws.String(v) + if accessKeyId, ok := tfMap["access_key_id"].(string); ok { + result.AccessKeyId = aws.String(accessKeyId) } - if v, ok := tfMap["raw_secret_access_key"].(string); ok { - result.RawSecretAccessKey = aws.String(v) + if rawSecretAccessKey, ok := tfMap["raw_secret_access_key"].(string); ok { + result.RawSecretAccessKey = aws.String(rawSecretAccessKey) } return result } - func flattenXksProxyAuthenticationCredential(config *awstypes.XksProxyAuthenticationCredentialType) []interface{} { if config == nil { return []interface{}{} From 59e8dbf97bbee5e020f279806ef452914ea4650b Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 13 Dec 2024 13:02:40 +0100 Subject: [PATCH 04/19] kms: update custom key store documentation to reflect XKS arguments --- .../docs/r/kms_custom_key_store.html.markdown | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/website/docs/r/kms_custom_key_store.html.markdown b/website/docs/r/kms_custom_key_store.html.markdown index 767508bfa257..76efbda06806 100644 --- a/website/docs/r/kms_custom_key_store.html.markdown +++ b/website/docs/r/kms_custom_key_store.html.markdown @@ -12,7 +12,7 @@ Terraform resource for managing an AWS KMS (Key Management) Custom Key Store. ## Example Usage -### Basic Usage +### CloudHSM ```terraform resource "aws_kms_custom_key_store" "test" { @@ -24,14 +24,58 @@ resource "aws_kms_custom_key_store" "test" { } ``` +### External Key Store (VPC) + +```terraform +resource "aws_kms_custom_key_store" "example" { + custom_key_store_name = "example-vpc-xks" + custom_key_store_type = "EXTERNAL_KEY_STORE" + + xks_proxy_authentication_credential { + access_key_id = var.ephemeral_access_key_id + raw_secret_access_key = var.ephemeral_secret_access_key + } + xks_proxy_connectivity = "VPC_ENDPOINT_SERVICE" + xks_proxy_uri_endpoint = "https://myproxy-private.xks.example.com" + xks_proxy_uri_path = "/kms/xks/v1" + xks_proxy_vpc_endpoint_service_name = "com.amazonaws.vpce.us-east-1.vpce-svc-example" +} +``` + +### External Key Store (Public) + +```terraform +resource "aws_kms_custom_key_store" "example" { + custom_key_store_name = "example-public-xks" + custom_key_store_type = "EXTERNAL_KEY_STORE" + + xks_proxy_authentication_credential { + access_key_id = var.ephemeral_access_key_id + raw_secret_access_key = var.ephemeral_secret_access_key + } + xks_proxy_connectivity = "PUBLIC_ENDPOINT" + xks_proxy_uri_endpoint = "https://myproxy.xks.example.com" + xks_proxy_uri_path = "/kms/xks/v1" +} +``` + ## Argument Reference The following arguments are required: -* `cloud_hsm_cluster_id` - (Required) Cluster ID of CloudHSM. * `custom_key_store_name` - (Required) Unique name for Custom Key Store. -* `key_store_password` - (Required) Password for `kmsuser` on CloudHSM. -* `trust_anchor_certificate` - (Required) Customer certificate used for signing on CloudHSM. + +The following arguments are optional: + +* `custom_key_store_type` - (Optional, ForceNew) Specifies the type of key store to create. The default value is `CLOUDHSM`. +* `cloud_hsm_cluster_id` - (Optional) Cluster ID of CloudHSM. This argument is required for custom key stores with `custom_key_store_type` of `AWS_CLOUDHSM`. +* `key_store_password` - (Optional) Specifies the `kmsuser` password for an AWS CloudHSM key store. This argument is required for custom key stores with a `custom_key_store_type` of `AWS_CLOUDHSM`. +* `trust_anchor_certificate` - (Optional) Specifies the certificate for an AWS CloudHSM key store. This argument is required for custom key stores with a `custom_key_store_type` of `AWS_CLOUDHSM`. +* `xks_proxy_authentication_credential` - (Optional) Specifies an authentication credential for the external key store proxy (XKS proxy). This argument is required for all custom key stores with a `custom_key_store_type` of `EXTERNAL_KEY_STORE`. +* `xks_proxy_connectivity` - (Optional) Indicates how AWS KMS communicates with the external key store proxy. This argument is required for custom key stores with a `custom_key_store_type` of `EXTERNAL_KEY_STORE`. +* `xks_proxy_uri_endpoint` - (Optional) Specifies the endpoint that AWS KMS uses to send requests to the external key store proxy (XKS proxy). This argument is required for custom key stores with a `custom_key_store_type` of `EXTERNAL_KEY_STORE`. +* `xks_proxy_uri_path` - (Optional) Specifies the base path to the proxy APIs for this external key store. To find this value, see the documentation for your external key store proxy. This argument is required for all custom key stores with a `custom_key_store_type` of `EXTERNAL_KEY_STORE`. +* `xks_proxy_vpc_endpoint_service_name` - (Optional) Specifies the name of the Amazon VPC endpoint service for interface endpoints that is used to communicate with your external key store proxy (XKS proxy). This argument is required when the value of `custom_key_store_type` is `EXTERNAL_KEY_STORE` and the value of `xks_proxy_connectivity` is `VPC_ENDPOINT_SERVICE`. ## Attribute Reference From 16f6e04f8d97b25a93105fc9d3880971f12dd1b9 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 13 Dec 2024 13:04:31 +0100 Subject: [PATCH 05/19] kms: add XKS changelog --- .changelog/40557.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/40557.txt diff --git a/.changelog/40557.txt b/.changelog/40557.txt new file mode 100644 index 000000000000..9f2d461a8a69 --- /dev/null +++ b/.changelog/40557.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_kms_custom_key_store: Add External Key Store support +``` From e0a0781650186dd255d39e4b772e62a94dfd6a00 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 13 Dec 2024 13:10:43 +0100 Subject: [PATCH 06/19] kms: remove unnecessary enum wrapper --- internal/service/kms/consts.go | 13 ------------- internal/service/kms/custom_key_store.go | 6 ++++-- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/internal/service/kms/consts.go b/internal/service/kms/consts.go index 9e31e3aaf7d7..7ea54315f315 100644 --- a/internal/service/kms/consts.go +++ b/internal/service/kms/consts.go @@ -3,11 +3,6 @@ package kms -import ( - awstypes "github.com/aws/aws-sdk-go-v2/service/kms/types" - "github.com/hashicorp/terraform-provider-aws/internal/enum" -) - const ( aliasNamePrefix = "alias/" cmkAliasPrefix = aliasNamePrefix + "aws/" @@ -16,11 +11,3 @@ const ( const ( policyNameDefault = "default" ) - -func customKeyStoreType_Values() []string { - return enum.Values[awstypes.CustomKeyStoreType]() -} - -func proxyConnectivityType_Values() []string { - return enum.Values[awstypes.XksProxyConnectivityType]() -} diff --git a/internal/service/kms/custom_key_store.go b/internal/service/kms/custom_key_store.go index 501b68a6cec2..c3f2e791076a 100644 --- a/internal/service/kms/custom_key_store.go +++ b/internal/service/kms/custom_key_store.go @@ -16,6 +16,7 @@ import ( "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/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" @@ -54,7 +55,8 @@ func resourceCustomKeyStore() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice(customKeyStoreType_Values(), false)), + Default: awstypes.CustomKeyStoreTypeAwsCloudhsm, + ValidateDiagFunc: enum.Validate[awstypes.CustomKeyStoreType](), }, "key_store_password": { Type: schema.TypeString, @@ -86,7 +88,7 @@ func resourceCustomKeyStore() *schema.Resource { "xks_proxy_connectivity": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice(proxyConnectivityType_Values(), false)), + ValidateDiagFunc: enum.Validate[awstypes.XksProxyConnectivityType](), }, "xks_proxy_uri_endpoint": { Type: schema.TypeString, From 268f08723598fe9aac57774dbd63983ff7b84b9f Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 13 Dec 2024 13:20:29 +0100 Subject: [PATCH 07/19] kms: terrafmt docs --- website/docs/r/kms_custom_key_store.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/r/kms_custom_key_store.html.markdown b/website/docs/r/kms_custom_key_store.html.markdown index 76efbda06806..6aca1437ba76 100644 --- a/website/docs/r/kms_custom_key_store.html.markdown +++ b/website/docs/r/kms_custom_key_store.html.markdown @@ -53,9 +53,9 @@ resource "aws_kms_custom_key_store" "example" { access_key_id = var.ephemeral_access_key_id raw_secret_access_key = var.ephemeral_secret_access_key } - xks_proxy_connectivity = "PUBLIC_ENDPOINT" - xks_proxy_uri_endpoint = "https://myproxy.xks.example.com" - xks_proxy_uri_path = "/kms/xks/v1" + xks_proxy_connectivity = "PUBLIC_ENDPOINT" + xks_proxy_uri_endpoint = "https://myproxy.xks.example.com" + xks_proxy_uri_path = "/kms/xks/v1" } ``` From f21dbc9f3fb238c7a7d0364159fa7682fc165527 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 13 Dec 2024 15:33:40 +0100 Subject: [PATCH 08/19] kms: refactor flatten to read the `access_key_id` --- internal/service/kms/custom_key_store.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/internal/service/kms/custom_key_store.go b/internal/service/kms/custom_key_store.go index c3f2e791076a..2c20391d6cff 100644 --- a/internal/service/kms/custom_key_store.go +++ b/internal/service/kms/custom_key_store.go @@ -184,6 +184,7 @@ func resourceCustomKeyStoreRead(ctx context.Context, d *schema.ResourceData, met d.Set("key_store_password", d.Get("key_store_password")) d.Set("trust_anchor_certificate", output.TrustAnchorCertificate) + d.Set("xks_proxy_authentication_credential", flattenXksProxyConfiguration(output.XksProxyConfiguration)) d.Set("xks_proxy_connectivity", output.XksProxyConfiguration.Connectivity) d.Set("xks_proxy_uri_endpoint", output.XksProxyConfiguration.UriEndpoint) d.Set("xks_proxy_uri_path", output.XksProxyConfiguration.UriPath) @@ -325,14 +326,15 @@ func expandXksProxyAuthenticationCredential(l []interface{}) *awstypes.XksProxyA return result } -func flattenXksProxyAuthenticationCredential(config *awstypes.XksProxyAuthenticationCredentialType) []interface{} { + +// We flatten against `XksProxyConfigurationType` because that contains the `AccessKeyId` field +func flattenXksProxyConfiguration(config *awstypes.XksProxyConfigurationType) []interface{} { if config == nil { return []interface{}{} } m := map[string]interface{}{ - "access_key_id": aws.ToString(config.AccessKeyId), - "raw_secret_access_key": aws.ToString(config.RawSecretAccessKey), + "access_key_id": aws.ToString(config.AccessKeyId), } return []interface{}{m} From dc45631fd698042b5bf9327c00b1b176a890d462 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 13 Dec 2024 15:36:02 +0100 Subject: [PATCH 09/19] kms: add `xks_proxy_authentication_credential` block in docs --- website/docs/r/kms_custom_key_store.html.markdown | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/website/docs/r/kms_custom_key_store.html.markdown b/website/docs/r/kms_custom_key_store.html.markdown index 6aca1437ba76..8c0d031d9a8b 100644 --- a/website/docs/r/kms_custom_key_store.html.markdown +++ b/website/docs/r/kms_custom_key_store.html.markdown @@ -77,6 +77,11 @@ The following arguments are optional: * `xks_proxy_uri_path` - (Optional) Specifies the base path to the proxy APIs for this external key store. To find this value, see the documentation for your external key store proxy. This argument is required for all custom key stores with a `custom_key_store_type` of `EXTERNAL_KEY_STORE`. * `xks_proxy_vpc_endpoint_service_name` - (Optional) Specifies the name of the Amazon VPC endpoint service for interface endpoints that is used to communicate with your external key store proxy (XKS proxy). This argument is required when the value of `custom_key_store_type` is `EXTERNAL_KEY_STORE` and the value of `xks_proxy_connectivity` is `VPC_ENDPOINT_SERVICE`. +The `xks_proxy_authentication_credential` block supports the following arguments: + +* `access_key_id` - (Required) A unique identifier for the raw secret access key. +* `raw_secret_access_key` - (Required) A secret string of 43-64 characters. + ## Attribute Reference This resource exports the following attributes in addition to the arguments above: From 69302e7095c1f4ad95c02f972eeaed96889cdc64 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 16 Dec 2024 16:18:15 +0100 Subject: [PATCH 10/19] kms: add note to changelog --- .changelog/40557.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/40557.txt b/.changelog/40557.txt index 9f2d461a8a69..acb523de70e3 100644 --- a/.changelog/40557.txt +++ b/.changelog/40557.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/aws_kms_custom_key_store: Add External Key Store support +resource/aws_kms_custom_key_store: Add External Key Store support. NOTE: Because we cannot easily test this functionality, it is best effort and we ask for community help in testing. ``` From 68c1499297a165f0934db4ed8b3be00cdade4a9c Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Fri, 10 Jan 2025 15:40:45 -0500 Subject: [PATCH 11/19] r/aws_kms_custom_key_store: rm default for `custom_key_store_type` Rather than setting a provider default we'll rely on AWS to set the value default to `AWS_CLOUDHSM` and store it as computed. Changing the type will still trigger a forced re-creation. --- internal/service/kms/custom_key_store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/kms/custom_key_store.go b/internal/service/kms/custom_key_store.go index 2c20391d6cff..922e9d6e15d1 100644 --- a/internal/service/kms/custom_key_store.go +++ b/internal/service/kms/custom_key_store.go @@ -54,8 +54,8 @@ func resourceCustomKeyStore() *schema.Resource { "custom_key_store_type": { Type: schema.TypeString, Optional: true, + Computed: true, ForceNew: true, - Default: awstypes.CustomKeyStoreTypeAwsCloudhsm, ValidateDiagFunc: enum.Validate[awstypes.CustomKeyStoreType](), }, "key_store_password": { From 0385103f183ebb5d7aaf387198254d74e33441d5 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Fri, 10 Jan 2025 15:40:54 -0500 Subject: [PATCH 12/19] chore: tidy changelog --- .changelog/40557.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.changelog/40557.txt b/.changelog/40557.txt index acb523de70e3..c11361870271 100644 --- a/.changelog/40557.txt +++ b/.changelog/40557.txt @@ -1,3 +1,6 @@ ```release-note:enhancement -resource/aws_kms_custom_key_store: Add External Key Store support. NOTE: Because we cannot easily test this functionality, it is best effort and we ask for community help in testing. +resource/aws_kms_custom_key_store: Add support for external key stores +``` +```release-note:note +resource/aws_kms_custom_key_store: We cannot acceptance test the support for external key stores added in this release. The impementation is best effort and we ask for community help in testing. ``` From 549ff180fe003b2b4028f6a959588ff617ad364d Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Fri, 10 Jan 2025 15:41:07 -0500 Subject: [PATCH 13/19] docs: document missing acceptance testing env vars --- docs/acc-test-environment-variables.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/acc-test-environment-variables.md b/docs/acc-test-environment-variables.md index 60dd1418e7eb..fbabd324843d 100644 --- a/docs/acc-test-environment-variables.md +++ b/docs/acc-test-environment-variables.md @@ -65,6 +65,7 @@ Environment variables (beyond standard AWS Go SDK ones) used by acceptance testi | `CHATBOT_TEAMS_CHANNEL_ID` | ID of the Microsoft Teams channel. | | `CHATBOT_TEAMS_TEAM_ID` | ID of the Microsoft Teams workspace authorized with AWS Chatbot. | | `CHATBOT_TEAMS_TENANT_ID` | ID of the Microsoft Teams tenant. | +| `CLOUD_HSM_CLUSTER_ID` | Cloud HSM cluster identifier for KMS custom key store acceptance tests. | | `DX_CONNECTION_ID` | Identifier for Direct Connect Connection testing. | | `DX_VIRTUAL_INTERFACE_ID` | Identifier for Direct Connect Virtual Interface testing. | | `EC2_SECURITY_GROUP_RULES_PER_GROUP_LIMIT` | EC2 Quota for Rules per Security Group. Defaults to 50. **DEPRECATED:** Can be augmented or replaced with Service Quotas lookup. | @@ -97,3 +98,4 @@ Environment variables (beyond standard AWS Go SDK ones) used by acceptance testi | `TF_AWS_LICENSE_MANAGER_GRANT_PRINCIPAL` | ARN of a principal to share the License Manager license with. Either a root user, Organization, or Organizational Unit. | | `TF_TEST_CLOUDFRONT_RETAIN` | Flag to disable but dangle CloudFront Distributions during testing to reduce feedback time (must be manually destroyed afterwards) | | `TF_TEST_ELASTICACHE_RESERVED_CACHE_NODE` | Flag to enable resource tests for ElastiCache reserved nodes. Set to `1` to run tests | +| `TRUST_ANCHOR_CERTIFICATE` | Trust anchor certificate for KMS custom key store acceptance tests. | From 6a9b8f0b3776d20a8d8262484023ad86166ee69a Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Fri, 10 Jan 2025 15:56:13 -0500 Subject: [PATCH 14/19] r/aws_kms_custom_key_store: tidy flex functions --- internal/service/kms/custom_key_store.go | 28 ++++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/internal/service/kms/custom_key_store.go b/internal/service/kms/custom_key_store.go index 922e9d6e15d1..b4fccaddbfd9 100644 --- a/internal/service/kms/custom_key_store.go +++ b/internal/service/kms/custom_key_store.go @@ -304,38 +304,38 @@ func findCustomKeyStores(ctx context.Context, conn *kms.Client, input *kms.Descr return output, nil } -func expandXksProxyAuthenticationCredential(l []interface{}) *awstypes.XksProxyAuthenticationCredentialType { - if len(l) == 0 || l[0] == nil { +func expandXksProxyAuthenticationCredential(tfList []interface{}) *awstypes.XksProxyAuthenticationCredentialType { + if len(tfList) == 0 || tfList[0] == nil { return nil } - tfMap, ok := l[0].(map[string]interface{}) + tfMap, ok := tfList[0].(map[string]interface{}) if !ok { return nil } - result := &awstypes.XksProxyAuthenticationCredentialType{} + apiObject := &awstypes.XksProxyAuthenticationCredentialType{} - if accessKeyId, ok := tfMap["access_key_id"].(string); ok { - result.AccessKeyId = aws.String(accessKeyId) + if v, ok := tfMap["access_key_id"].(string); ok { + apiObject.AccessKeyId = aws.String(v) } - if rawSecretAccessKey, ok := tfMap["raw_secret_access_key"].(string); ok { - result.RawSecretAccessKey = aws.String(rawSecretAccessKey) + if v, ok := tfMap["raw_secret_access_key"].(string); ok { + apiObject.RawSecretAccessKey = aws.String(v) } - return result + return apiObject } // We flatten against `XksProxyConfigurationType` because that contains the `AccessKeyId` field -func flattenXksProxyConfiguration(config *awstypes.XksProxyConfigurationType) []interface{} { - if config == nil { +func flattenXksProxyConfiguration(apiObject *awstypes.XksProxyConfigurationType) []interface{} { + if apiObject == nil { return []interface{}{} } - m := map[string]interface{}{ - "access_key_id": aws.ToString(config.AccessKeyId), + tfMap := map[string]interface{}{ + "access_key_id": aws.ToString(apiObject.AccessKeyId), } - return []interface{}{m} + return []interface{}{tfMap} } From e72216858ee85614ebffc8b77a35f831f709e9ef Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Fri, 10 Jan 2025 15:57:03 -0500 Subject: [PATCH 15/19] r/aws_kms_custom_key_store(doc): adjust optional argument format --- .../docs/r/kms_custom_key_store.html.markdown | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/website/docs/r/kms_custom_key_store.html.markdown b/website/docs/r/kms_custom_key_store.html.markdown index 8c0d031d9a8b..2a0741686e77 100644 --- a/website/docs/r/kms_custom_key_store.html.markdown +++ b/website/docs/r/kms_custom_key_store.html.markdown @@ -67,17 +67,23 @@ The following arguments are required: The following arguments are optional: -* `custom_key_store_type` - (Optional, ForceNew) Specifies the type of key store to create. The default value is `CLOUDHSM`. -* `cloud_hsm_cluster_id` - (Optional) Cluster ID of CloudHSM. This argument is required for custom key stores with `custom_key_store_type` of `AWS_CLOUDHSM`. -* `key_store_password` - (Optional) Specifies the `kmsuser` password for an AWS CloudHSM key store. This argument is required for custom key stores with a `custom_key_store_type` of `AWS_CLOUDHSM`. -* `trust_anchor_certificate` - (Optional) Specifies the certificate for an AWS CloudHSM key store. This argument is required for custom key stores with a `custom_key_store_type` of `AWS_CLOUDHSM`. -* `xks_proxy_authentication_credential` - (Optional) Specifies an authentication credential for the external key store proxy (XKS proxy). This argument is required for all custom key stores with a `custom_key_store_type` of `EXTERNAL_KEY_STORE`. -* `xks_proxy_connectivity` - (Optional) Indicates how AWS KMS communicates with the external key store proxy. This argument is required for custom key stores with a `custom_key_store_type` of `EXTERNAL_KEY_STORE`. -* `xks_proxy_uri_endpoint` - (Optional) Specifies the endpoint that AWS KMS uses to send requests to the external key store proxy (XKS proxy). This argument is required for custom key stores with a `custom_key_store_type` of `EXTERNAL_KEY_STORE`. -* `xks_proxy_uri_path` - (Optional) Specifies the base path to the proxy APIs for this external key store. To find this value, see the documentation for your external key store proxy. This argument is required for all custom key stores with a `custom_key_store_type` of `EXTERNAL_KEY_STORE`. -* `xks_proxy_vpc_endpoint_service_name` - (Optional) Specifies the name of the Amazon VPC endpoint service for interface endpoints that is used to communicate with your external key store proxy (XKS proxy). This argument is required when the value of `custom_key_store_type` is `EXTERNAL_KEY_STORE` and the value of `xks_proxy_connectivity` is `VPC_ENDPOINT_SERVICE`. - -The `xks_proxy_authentication_credential` block supports the following arguments: +* `custom_key_store_type` - (Optional, ForceNew) Specifies the type of key store to create. Valid values are `AWS_CLOUDHSM` and `EXTERNAL_KEY_STORE`. If omitted, AWS will default the value to `AWS_CLOUDHSM`. + +If `custom_key_store_type` is `AWS_CLOUDHSM`, the following optional arguments must be set: + +* `cloud_hsm_cluster_id` - (Optional) Cluster ID of CloudHSM. +* `key_store_password` - (Optional) Specifies the `kmsuser` password for an AWS CloudHSM key store. +* `trust_anchor_certificate` - (Optional) Specifies the certificate for an AWS CloudHSM key store. + +If `custom_key_store_type` is `EXTERNAL_KEY_STORE`, the following optional arguments must be set: + +* `xks_proxy_authentication_credential` - (Optional) Specifies an authentication credential for the external key store proxy (XKS proxy). See [`xks_proxy_authentication_credential` attribute reference](#xks_proxy_authentication_credential-argument-reference) below. +* `xks_proxy_connectivity` - (Optional) Indicates how AWS KMS communicates with the external key store proxy. +* `xks_proxy_uri_endpoint` - (Optional) Specifies the endpoint that AWS KMS uses to send requests to the external key store proxy (XKS proxy). +* `xks_proxy_uri_path` - (Optional) Specifies the base path to the proxy APIs for this external key store. To find this value, see the documentation for your external key store proxy. +* `xks_proxy_vpc_endpoint_service_name` - (Optional) Specifies the name of the Amazon VPC endpoint service for interface endpoints that is used to communicate with your external key store proxy (XKS proxy). This argument is required when the value of `xks_proxy_connectivity` is `VPC_ENDPOINT_SERVICE`. + +### `xks_proxy_authentication_credential` Argument Reference * `access_key_id` - (Required) A unique identifier for the raw secret access key. * `raw_secret_access_key` - (Required) A secret string of 43-64 characters. From 069e6ea65e17739e8ab31da0c0c636877e481be7 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Fri, 10 Jan 2025 16:03:26 -0500 Subject: [PATCH 16/19] r/aws_kms_custom_key_store: `trust_anchor_certificate` is now optional This argument is now only required if `custom_key_store_type` is `AWS_CLOUDHSM`. --- internal/service/kms/custom_key_store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/kms/custom_key_store.go b/internal/service/kms/custom_key_store.go index b4fccaddbfd9..eb318f47e015 100644 --- a/internal/service/kms/custom_key_store.go +++ b/internal/service/kms/custom_key_store.go @@ -65,7 +65,7 @@ func resourceCustomKeyStore() *schema.Resource { }, "trust_anchor_certificate": { Type: schema.TypeString, - Required: true, + Optional: true, ForceNew: true, }, "xks_proxy_authentication_credential": { From fa301ab8871ed97a7d8d3739f111e8e8617b24a2 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Mon, 13 Jan 2025 10:05:31 -0500 Subject: [PATCH 17/19] r/aws_kms_custom_key_store: remove `xks_proxy_authentication_credential` flattener Removes the flattener for `xks_proxy_authentication_credential` given only one of the two nested arguments is returned from the AWS API. This was done as a precaution to eliminate potential failure modes in writing the returned value given we cannot acceptance test these changes. If drift detection on the nested `access_key_id` argument is desired by the community, it will be added in a future release. --- internal/service/kms/custom_key_store.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/internal/service/kms/custom_key_store.go b/internal/service/kms/custom_key_store.go index eb318f47e015..d66819625e0a 100644 --- a/internal/service/kms/custom_key_store.go +++ b/internal/service/kms/custom_key_store.go @@ -184,7 +184,6 @@ func resourceCustomKeyStoreRead(ctx context.Context, d *schema.ResourceData, met d.Set("key_store_password", d.Get("key_store_password")) d.Set("trust_anchor_certificate", output.TrustAnchorCertificate) - d.Set("xks_proxy_authentication_credential", flattenXksProxyConfiguration(output.XksProxyConfiguration)) d.Set("xks_proxy_connectivity", output.XksProxyConfiguration.Connectivity) d.Set("xks_proxy_uri_endpoint", output.XksProxyConfiguration.UriEndpoint) d.Set("xks_proxy_uri_path", output.XksProxyConfiguration.UriPath) @@ -326,16 +325,3 @@ func expandXksProxyAuthenticationCredential(tfList []interface{}) *awstypes.XksP return apiObject } - -// We flatten against `XksProxyConfigurationType` because that contains the `AccessKeyId` field -func flattenXksProxyConfiguration(apiObject *awstypes.XksProxyConfigurationType) []interface{} { - if apiObject == nil { - return []interface{}{} - } - - tfMap := map[string]interface{}{ - "access_key_id": aws.ToString(apiObject.AccessKeyId), - } - - return []interface{}{tfMap} -} From a80b55ee421a32eeaf38a1c35cbecd543eb77959 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Mon, 13 Jan 2025 10:20:06 -0500 Subject: [PATCH 18/19] r/aws_kms_custom_key_store(test): tidy serial test structure --- internal/service/kms/kms_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/service/kms/kms_test.go b/internal/service/kms/kms_test.go index 4564f821aea3..4310bc8a3e20 100644 --- a/internal/service/kms/kms_test.go +++ b/internal/service/kms/kms_test.go @@ -17,7 +17,9 @@ func TestAccKMS_serial(t *testing.T) { acctest.CtBasic: testAccCustomKeyStore_basic, "update": testAccCustomKeyStore_update, acctest.CtDisappears: testAccCustomKeyStore_disappears, - "DataSource_basic": testAccCustomKeyStoreDataSource_basic, + }, + "CustomKeyStoreDataSource": { + "basic": testAccCustomKeyStoreDataSource_basic, }, } From 53bce243127f6bfced1d147ff910afd92d4cfa9c Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Mon, 13 Jan 2025 10:49:19 -0500 Subject: [PATCH 19/19] chore: make fix-constants --- internal/service/kms/kms_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/kms/kms_test.go b/internal/service/kms/kms_test.go index 4310bc8a3e20..0e0191bc8367 100644 --- a/internal/service/kms/kms_test.go +++ b/internal/service/kms/kms_test.go @@ -19,7 +19,7 @@ func TestAccKMS_serial(t *testing.T) { acctest.CtDisappears: testAccCustomKeyStore_disappears, }, "CustomKeyStoreDataSource": { - "basic": testAccCustomKeyStoreDataSource_basic, + acctest.CtBasic: testAccCustomKeyStoreDataSource_basic, }, }