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

ssm/parameter: Add insecure_value argument #25721

Merged
merged 2 commits into from
Jul 7, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/25721.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_ssm_parameter: Add `insecure_value` argument to enable dynamic use of SSM parameter values
```
111 changes: 73 additions & 38 deletions internal/service/ssm/parameter.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,53 @@ func ResourceParameter() *schema.Resource {
},

Schema: map[string]*schema.Schema{
"name": {
"allowed_pattern": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringLenBetween(1, 2048),
Optional: true,
ValidateFunc: validation.StringLenBetween(0, 1024),
},
"arn": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"data_type": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringInSlice([]string{
"aws:ec2:image",
"text",
}, false),
},
"description": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringLenBetween(0, 1024),
},
"insecure_value": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ExactlyOneOf: []string{"insecure_value", "value"},
},
"key_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringLenBetween(1, 2048),
},
"overwrite": {
Type: schema.TypeBool,
Optional: true,
},
"tags": tftags.TagsSchema(),
"tags_all": tftags.TagsSchemaComputed(),
"tier": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -64,44 +100,16 @@ func ResourceParameter() *schema.Resource {
ValidateFunc: validation.StringInSlice(ssm.ParameterType_Values(), false),
},
"value": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
},
"arn": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"key_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"data_type": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringInSlice([]string{
"aws:ec2:image",
"text",
}, false),
},
"overwrite": {
Type: schema.TypeBool,
Optional: true,
},
"allowed_pattern": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringLenBetween(0, 1024),
Sensitive: true,
Computed: true,
ExactlyOneOf: []string{"insecure_value", "value"},
},
"version": {
Type: schema.TypeInt,
Computed: true,
},
"tags": tftags.TagsSchema(),
"tags_all": tftags.TagsSchemaComputed(),
},

CustomizeDiff: customdiff.Sequence(
Expand All @@ -113,6 +121,13 @@ func ResourceParameter() *schema.Resource {
customdiff.ComputedIf("version", func(_ context.Context, diff *schema.ResourceDiff, meta interface{}) bool {
return diff.HasChange("value")
}),
customdiff.ComputedIf("value", func(_ context.Context, diff *schema.ResourceDiff, meta interface{}) bool {
return diff.HasChange("insecure_value")
}),
customdiff.ComputedIf("insecure_value", func(_ context.Context, diff *schema.ResourceDiff, meta interface{}) bool {
return diff.HasChange("value")
}),

verify.SetTagsDiff,
),
}
Expand All @@ -125,10 +140,16 @@ func resourceParameterCreate(d *schema.ResourceData, meta interface{}) error {

name := d.Get("name").(string)

value := d.Get("value").(string)

if v, ok := d.Get("insecure_value").(string); ok && v != "" {
value = v
}

paramInput := &ssm.PutParameterInput{
Name: aws.String(name),
Type: aws.String(d.Get("type").(string)),
Value: aws.String(d.Get("value").(string)),
Value: aws.String(value),
AllowedPattern: aws.String(d.Get("allowed_pattern").(string)),
}

Expand Down Expand Up @@ -213,9 +234,18 @@ func resourceParameterRead(d *schema.ResourceData, meta interface{}) error {
name := aws.StringValue(param.Name)
d.Set("name", name)
d.Set("type", param.Type)
d.Set("value", param.Value)
d.Set("version", param.Version)

if _, ok := d.GetOk("insecure_value"); ok && aws.StringValue(param.Type) != ssm.ParameterTypeSecureString {
d.Set("insecure_value", param.Value)
} else {
d.Set("value", param.Value)
}

if aws.StringValue(param.Type) == ssm.ParameterTypeSecureString && d.Get("insecure_value").(string) != "" {
return fmt.Errorf("invalid configuration, cannot set type = %s and insecure_value", aws.StringValue(param.Type))
}

describeParamsInput := &ssm.DescribeParametersInput{
ParameterFilters: []*ssm.ParameterStringFilter{
{
Expand Down Expand Up @@ -269,11 +299,16 @@ func resourceParameterUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).SSMConn

if d.HasChangesExcept("tags", "tags_all") {
value := d.Get("value").(string)

if v, ok := d.Get("insecure_value").(string); ok && v != "" {
value = v
}
paramInput := &ssm.PutParameterInput{
Name: aws.String(d.Get("name").(string)),
Type: aws.String(d.Get("type").(string)),
Tier: aws.String(d.Get("tier").(string)),
Value: aws.String(d.Get("value").(string)),
Value: aws.String(value),
Overwrite: aws.Bool(ShouldUpdateParameter(d)),
AllowedPattern: aws.String(d.Get("allowed_pattern").(string)),
}
Expand Down
114 changes: 102 additions & 12 deletions internal/service/ssm/parameter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ssm_test

import (
"fmt"
"regexp"
"testing"

"github.com/aws/aws-sdk-go/aws"
Expand Down Expand Up @@ -273,7 +274,7 @@ func TestAccSSMParameter_disappears(t *testing.T) {
})
}

func TestAccSSMParameter_overwrite(t *testing.T) {
func TestAccSSMParameter_Overwrite_basic(t *testing.T) {
var param ssm.Parameter
name := fmt.Sprintf("%s_%s", t.Name(), sdkacctest.RandString(10))
resourceName := "aws_ssm_parameter.test"
Expand Down Expand Up @@ -310,7 +311,7 @@ func TestAccSSMParameter_overwrite(t *testing.T) {
}

// Reference: https://github.com/hashicorp/terraform-provider-aws/issues/12213
func TestAccSSMParameter_overwriteCascade(t *testing.T) {
func TestAccSSMParameter_Overwrite_cascade(t *testing.T) {
name := fmt.Sprintf("%s_%s", t.Name(), sdkacctest.RandString(10))

resource.ParallelTest(t, resource.TestCase{
Expand All @@ -335,7 +336,7 @@ func TestAccSSMParameter_overwriteCascade(t *testing.T) {
}

// Reference: https://github.com/hashicorp/terraform-provider-aws/issues/18550
func TestAccSSMParameter_overwriteWithTags(t *testing.T) {
func TestAccSSMParameter_Overwrite_tags(t *testing.T) {
var param ssm.Parameter
rName := fmt.Sprintf("%s_%s", t.Name(), sdkacctest.RandString(10))
resourceName := "aws_ssm_parameter.test"
Expand Down Expand Up @@ -365,7 +366,7 @@ func TestAccSSMParameter_overwriteWithTags(t *testing.T) {
}

// Reference: https://github.com/hashicorp/terraform-provider-aws/issues/18550
func TestAccSSMParameter_noOverwriteWithTags(t *testing.T) {
func TestAccSSMParameter_Overwrite_noOverwriteTags(t *testing.T) {
var param ssm.Parameter
rName := fmt.Sprintf("%s_%s", t.Name(), sdkacctest.RandString(10))
resourceName := "aws_ssm_parameter.test"
Expand Down Expand Up @@ -395,7 +396,7 @@ func TestAccSSMParameter_noOverwriteWithTags(t *testing.T) {
}

// Reference: https://github.com/hashicorp/terraform-provider-aws/issues/18550
func TestAccSSMParameter_updateToOverwriteWithTags(t *testing.T) {
func TestAccSSMParameter_Overwrite_updateToTags(t *testing.T) {
var param ssm.Parameter
rName := fmt.Sprintf("%s_%s", t.Name(), sdkacctest.RandString(10))
resourceName := "aws_ssm_parameter.test"
Expand Down Expand Up @@ -508,7 +509,7 @@ func TestAccSSMParameter_updateType(t *testing.T) {
})
}

func TestAccSSMParameter_updateDescription(t *testing.T) {
func TestAccSSMParameter_Overwrite_updateDescription(t *testing.T) {
var param ssm.Parameter
name := fmt.Sprintf("%s_%s", t.Name(), sdkacctest.RandString(10))
resourceName := "aws_ssm_parameter.test"
Expand Down Expand Up @@ -604,7 +605,7 @@ func TestAccSSMParameter_fullPath(t *testing.T) {
})
}

func TestAccSSMParameter_secure(t *testing.T) {
func TestAccSSMParameter_Secure_basic(t *testing.T) {
var param ssm.Parameter
name := fmt.Sprintf("%s_%s", t.Name(), sdkacctest.RandString(10))
resourceName := "aws_ssm_parameter.test"
Expand Down Expand Up @@ -634,6 +635,85 @@ func TestAccSSMParameter_secure(t *testing.T) {
})
}

func TestAccSSMParameter_Secure_insecure(t *testing.T) {
var param ssm.Parameter
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_ssm_parameter.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, ssm.EndpointsID),
ProviderFactories: acctest.ProviderFactories,
CheckDestroy: testAccCheckParameterDestroy,
Steps: []resource.TestStep{
{
Config: testAccParameterConfig_insecure(rName, "String", "notsecret"),
Check: resource.ComposeTestCheckFunc(
testAccCheckParameterExists(resourceName, &param),
resource.TestCheckResourceAttr(resourceName, "insecure_value", "notsecret"),
resource.TestCheckResourceAttr(resourceName, "type", "String"),
),
},
{
Config: testAccParameterConfig_insecure(rName, "String", "newvalue"),
Check: resource.ComposeTestCheckFunc(
testAccCheckParameterExists(resourceName, &param),
resource.TestCheckResourceAttr(resourceName, "insecure_value", "newvalue"),
resource.TestCheckResourceAttr(resourceName, "type", "String"),
),
},
{
Config: testAccParameterConfig_insecure(rName, "String", "diff"),
PlanOnly: true,
ExpectNonEmptyPlan: true,
},
{
Config: testAccParameterConfig_insecure(rName, "SecureString", "notsecret"),
ExpectError: regexp.MustCompile("invalid configuration"),
},
},
})
}

func TestAccSSMParameter_Secure_insecureChangeSecure(t *testing.T) {
var param ssm.Parameter
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_ssm_parameter.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, ssm.EndpointsID),
ProviderFactories: acctest.ProviderFactories,
CheckDestroy: testAccCheckParameterDestroy,
Steps: []resource.TestStep{
{
Config: testAccParameterConfig_insecure(rName, "String", "notsecret"),
Check: resource.ComposeTestCheckFunc(
testAccCheckParameterExists(resourceName, &param),
resource.TestCheckResourceAttr(resourceName, "insecure_value", "notsecret"),
resource.TestCheckResourceAttr(resourceName, "type", "String"),
),
},
{
Config: testAccParameterConfig_secure(rName, "newvalue"),
Check: resource.ComposeTestCheckFunc(
testAccCheckParameterExists(resourceName, &param),
resource.TestCheckResourceAttr(resourceName, "value", "newvalue"),
resource.TestCheckResourceAttr(resourceName, "type", "SecureString"),
),
},
{
Config: testAccParameterConfig_insecure(rName, "String", "atlantis"),
Check: resource.ComposeTestCheckFunc(
testAccCheckParameterExists(resourceName, &param),
resource.TestCheckResourceAttr(resourceName, "insecure_value", "atlantis"),
resource.TestCheckResourceAttr(resourceName, "type", "String"),
),
},
},
})
}

func TestAccSSMParameter_DataType_ec2Image(t *testing.T) {
var param ssm.Parameter
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
Expand Down Expand Up @@ -662,11 +742,11 @@ func TestAccSSMParameter_DataType_ec2Image(t *testing.T) {
})
}

func TestAccSSMParameter_secureWithKey(t *testing.T) {
func TestAccSSMParameter_Secure_key(t *testing.T) {
var param ssm.Parameter
randString := sdkacctest.RandString(10)
name := fmt.Sprintf("%s_%s", t.Name(), randString)
resourceName := "aws_ssm_parameter.secret_test"
resourceName := "aws_ssm_parameter.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
Expand Down Expand Up @@ -697,7 +777,7 @@ func TestAccSSMParameter_Secure_keyUpdate(t *testing.T) {
var param ssm.Parameter
randString := sdkacctest.RandString(10)
name := fmt.Sprintf("%s_%s", t.Name(), randString)
resourceName := "aws_ssm_parameter.secret_test"
resourceName := "aws_ssm_parameter.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
Expand Down Expand Up @@ -822,6 +902,16 @@ resource "aws_ssm_parameter" "test" {
`, rName, pType, value)
}

func testAccParameterConfig_insecure(rName, pType, value string) string {
return fmt.Sprintf(`
resource "aws_ssm_parameter" "test" {
name = %[1]q
type = %[2]q
insecure_value = %[3]q
}
`, rName, pType, value)
}

func testAccParameterConfig_tier(rName, tier string) string {
return fmt.Sprintf(`
resource "aws_ssm_parameter" "test" {
Expand Down Expand Up @@ -943,7 +1033,7 @@ resource "aws_ssm_parameter" "test_downstream" {

func testAccParameterConfig_secure(rName string, value string) string {
return fmt.Sprintf(`
resource "aws_ssm_parameter" "secret_test" {
resource "aws_ssm_parameter" "test" {
name = "test_secure_parameter-%[1]s"
description = "description for parameter %[1]s"
type = "SecureString"
Expand All @@ -954,7 +1044,7 @@ resource "aws_ssm_parameter" "secret_test" {

func testAccParameterConfig_secureKey(rName string, value string, keyAlias string) string {
return fmt.Sprintf(`
resource "aws_ssm_parameter" "secret_test" {
resource "aws_ssm_parameter" "test" {
name = "test_secure_parameter-%[1]s"
description = "description for parameter %[1]s"
type = "SecureString"
Expand Down
Loading