Skip to content

Commit

Permalink
r/aws_elasticache_cluster: Add support for in-transit encryption (#26987
Browse files Browse the repository at this point in the history
)

* r/aws_elasticache_cluster: Add support for in-transit encryption

Fixes: #26367

* r/aws_elasticache_cluster(test): switch to regexache

* r/aws_elasticache_cluster(docs): tidy transit_encryption_enabled

* r/aws_elasticache_cluster: centralize customize diff func

* r/aws_elasticache_cluster(test): extend test checks

* r/aws_elasticache_cluster: set transit_encryption_enabled on read

* chore: changelog

---------

Co-authored-by: Jared Baker <jared.baker@hashicorp.com>
  • Loading branch information
tmccombs and jar-b committed Sep 7, 2023
1 parent b27f478 commit 1c005e9
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/26987.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_elaticache_cluster: Add `transit_encryption_enabled` argument, enabling in-transit encryption for Memcached clusters inside a VPC
```
12 changes: 12 additions & 0 deletions internal/service/elasticache/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,12 @@ func ResourceCluster() *schema.Resource {
Computed: true,
ForceNew: true,
},
"transit_encryption_enabled": {
Type: schema.TypeBool,
ForceNew: true,
Optional: true,
Default: false,
},
names.AttrTags: tftags.TagsSchema(),
names.AttrTagsAll: tftags.TagsSchemaComputed(),
},
Expand All @@ -337,6 +343,7 @@ func ResourceCluster() *schema.Resource {
CustomizeDiffValidateClusterNumCacheNodes,
CustomizeDiffClusterMemcachedNodeType,
CustomizeDiffValidateClusterMemcachedSnapshotIdentifier,
CustomizeDiffValidateTransitEncryptionEnabled,
verify.SetTagsDiff,
),
}
Expand Down Expand Up @@ -437,6 +444,10 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int
input.SnapshotName = aws.String(v.(string))
}

if v, ok := d.GetOk("transit_encryption_enabled"); ok {
input.TransitEncryptionEnabled = aws.Bool(v.(bool))
}

if v, ok := d.GetOk("az_mode"); ok {
input.AZMode = aws.String(v.(string))
}
Expand Down Expand Up @@ -543,6 +554,7 @@ func resourceClusterRead(ctx context.Context, d *schema.ResourceData, meta inter
d.Set("ip_discovery", c.IpDiscovery)
d.Set("network_type", c.NetworkType)
d.Set("preferred_outpost_arn", c.PreferredOutpostArn)
d.Set("transit_encryption_enabled", c.TransitEncryptionEnabled)

return diags
}
Expand Down
50 changes: 50 additions & 0 deletions internal/service/elasticache/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1228,6 +1228,42 @@ func TestAccElastiCacheCluster_tagWithOtherModification(t *testing.T) {
})
}

func TestAccElastiCacheCluster_TransitEncryption(t *testing.T) {
ctx := acctest.Context(t)
if testing.Short() {
t.Skip("skipping long-running test in short mode")
}
var cluster elasticache.CacheCluster
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_elasticache_cluster.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, elasticache.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckClusterDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccClusterConfig_transitEncryption(rName, "memcached", "1.6.11"),
ExpectError: regexache.MustCompile(`Transit encryption is not supported for memcached version 1.6.11`),
},
{
Config: testAccClusterConfig_transitEncryption(rName, "redis", "6.2"),
ExpectError: regexache.MustCompile(`aws_elasticache_cluster does not support transit encryption using the redis engine, use aws_elasticache_replication_group instead`),
},
{
Config: testAccClusterConfig_transitEncryption(rName, "memcached", "1.6.12"),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckClusterExists(ctx, resourceName, &cluster),
resource.TestCheckResourceAttr(resourceName, "engine", "memcached"),
resource.TestCheckResourceAttr(resourceName, "engine_version", "1.6.12"),
resource.TestCheckResourceAttr(resourceName, "transit_encryption_enabled", "true"),
),
},
},
})
}

func TestAccElastiCacheCluster_outpost_memcached(t *testing.T) {
ctx := acctest.Context(t)
if testing.Short() {
Expand Down Expand Up @@ -2153,3 +2189,17 @@ resource "aws_elasticache_cluster" "test" {
}
`, rName, version, tagKey1, tagValue1)
}

func testAccClusterConfig_transitEncryption(rName, engine, version string) string {
return fmt.Sprintf(`
resource "aws_elasticache_cluster" "test" {
apply_immediately = true
cluster_id = "%[1]s"
engine = "%[2]s"
engine_version = "%[3]s"
node_type = "cache.t3.medium"
num_cache_nodes = 1
transit_encryption_enabled = true
}
`, rName, engine, version)
}
28 changes: 28 additions & 0 deletions internal/service/elasticache/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ package elasticache
import (
"context"
"errors"
"fmt"

"github.com/aws/aws-sdk-go/service/elasticache"
gversion "github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

var minMemcachedTransitEncryptionVersion = gversion.Must(gversion.NewVersion("1.6.12"))

// CustomizeDiffValidateClusterAZMode validates that `num_cache_nodes` is greater than 1 when `az_mode` is "cross-az"
func CustomizeDiffValidateClusterAZMode(_ context.Context, diff *schema.ResourceDiff, v interface{}) error {
if v, ok := diff.GetOk("az_mode"); !ok || v.(string) != elasticache.AZModeCrossAz {
Expand Down Expand Up @@ -69,3 +73,27 @@ func CustomizeDiffValidateReplicationGroupAutomaticFailover(_ context.Context, d
}
return nil
}

// CustomizeDiffValidateTransitEncryptionEnabled validates that an appropriate engine type and version
// are utilized when in-transit encryption is enabled
func CustomizeDiffValidateTransitEncryptionEnabled(_ context.Context, diff *schema.ResourceDiff, _ interface{}) error {
if v, ok := diff.GetOk("transit_encryption_enabled"); ok && v.(bool) {
if engine := diff.Get("engine").(string); engine == engineRedis {
return errors.New("aws_elasticache_cluster does not support transit encryption using the redis engine, use aws_elasticache_replication_group instead")
}

engineVersion, ok := diff.GetOk("engine_version")
if !ok {
return nil
}
version, err := normalizeEngineVersion(engineVersion.(string))
if err != nil {
return err
}
if version.LessThan(minMemcachedTransitEncryptionVersion) {
return fmt.Errorf("Transit encryption is not supported for memcached version %v", version)
}
}

return nil
}
1 change: 1 addition & 0 deletions website/docs/r/elasticache_cluster.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ The minimum maintenance window is a 60 minute period. Example: `sun:05:00-sun:09
* `snapshot_window` - (Optional, Redis only) Daily time range (in UTC) during which ElastiCache will begin taking a daily snapshot of your cache cluster. Example: 05:00-09:00
* `subnet_group_name` – (Optional, VPC only) Name of the subnet group to be used for the cache cluster. Changing this value will re-create the resource.
* `tags` - (Optional) Map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level.
* `transit_encryption_enabled` - (Optional) Enable encryption in-transit. Supported only with Memcached versions `1.6.12` and later, running in a VPC. See the [ElastiCache in-transit encryption](https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/in-transit-encryption-mc.html) documentation for more details.

### Log Delivery Configuration

Expand Down

0 comments on commit 1c005e9

Please sign in to comment.