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

[#19212] Fix secretsmanager_secret_version update #19943

Merged
61 changes: 60 additions & 1 deletion aws/resource_aws_secretsmanager_secret_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,18 +191,77 @@ func resourceAwsSecretsManagerSecretVersionUpdate(d *schema.ResourceData, meta i
stagesToAdd := ns.Difference(os).List()
stagesToRemove := os.Difference(ns).List()

var describedSecret *secretsmanager.DescribeSecretOutput
awsPreviousVersionID := aws.String(versionID)

for _, stage := range stagesToAdd {
input := &secretsmanager.UpdateSecretVersionStageInput{
MoveToVersionId: aws.String(versionID),
SecretId: aws.String(secretID),
VersionStage: aws.String(stage.(string)),
}

if stage.(string) == "AWSCURRENT" {
log.Printf("[DEBUG] Going to set AWSCURRENT staging label for secret %q version %q", secretID, versionID)

// NOTE: Cache it to prevent calling it more than once
if describedSecret == nil {
describedSecret, err = conn.DescribeSecret(&secretsmanager.DescribeSecretInput{SecretId: aws.String(secretID)})
if err != nil {
return fmt.Errorf("error updating Secrets Manager Secret %q Version Stage %q: %s", secretID, stage.(string), err)
}

var awsCurrentStageVersionID *string

var nextToken *string = nil

loopListVersionIDsPagination:
for {
output, err := conn.ListSecretVersionIds(&secretsmanager.ListSecretVersionIdsInput{
NextToken: nextToken,
SecretId: aws.String(secretID),
})
if err != nil {
return fmt.Errorf("error updating Secrets Manager Secret %q Version Stage %q: %s", secretID, stage.(string), err)
}

for _, version := range output.Versions {
for _, versionStage := range version.VersionStages {
// NOTE: Even though AWS API can return multiple version stages to a single version,
// there's only one `AWSCURRENT`, therefore return early.
if versionStage != nil && *versionStage == "AWSCURRENT" {
awsCurrentStageVersionID = version.VersionId
break loopListVersionIDsPagination
}
}
}

if output.NextToken == nil {
break
}

nextToken = output.NextToken
}

input.RemoveFromVersionId = awsCurrentStageVersionID
log.Printf(
"[DEBUG] Going to move AWSCURRENT staging label for secret %q from version: %q to version %q",
secretID,
*awsCurrentStageVersionID,
versionID,
)
}

}
log.Printf("[DEBUG] Updating Secrets Manager Secret Version Stage: %s", input)
_, err := conn.UpdateSecretVersionStage(input)
if err != nil {
return fmt.Errorf("error updating Secrets Manager Secret %q Version Stage %q: %s", secretID, stage.(string), err)
}

// NOTE: After changing the `AWSCURRENT`, the previous `AWSCURRENT` is now `AWSPREVIOUS`,
// which we'll need to remove previous labels.
awsPreviousVersionID = input.RemoveFromVersionId
}

for _, stage := range stagesToRemove {
Expand All @@ -212,7 +271,7 @@ func resourceAwsSecretsManagerSecretVersionUpdate(d *schema.ResourceData, meta i
continue
}
input := &secretsmanager.UpdateSecretVersionStageInput{
RemoveFromVersionId: aws.String(versionID),
RemoveFromVersionId: awsPreviousVersionID,
SecretId: aws.String(secretID),
VersionStage: aws.String(stage.(string)),
}
Expand Down
56 changes: 56 additions & 0 deletions aws/resource_aws_secretsmanager_secret_version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@ func TestAccAwsSecretsManagerSecretVersion_VersionStages(t *testing.T) {
resource.TestCheckTypeSetElemAttr(resourceName, "version_stages.*", "AWSCURRENT"),
resource.TestCheckTypeSetElemAttr(resourceName, "version_stages.*", "one"),
),
}, {
Config: testAccAwsSecretsManagerSecretVersionConfig_VersionStages_Single(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsSecretsManagerSecretVersionExists(resourceName, &version),
resource.TestCheckResourceAttr(resourceName, "secret_string", "test-string"),
resource.TestCheckResourceAttr(resourceName, "version_stages.#", "2"),
resource.TestCheckTypeSetElemAttr(resourceName, "version_stages.*", "AWSCURRENT"),
resource.TestCheckTypeSetElemAttr(resourceName, "version_stages.*", "one"),
),
},
{
Config: testAccAwsSecretsManagerSecretVersionConfig_VersionStages_SingleUpdated(rName),
Expand Down Expand Up @@ -126,6 +135,53 @@ func TestAccAwsSecretsManagerSecretVersion_VersionStages(t *testing.T) {
})
}

func TestAccAwsSecretsManagerSecretVersion_VersionStages_external_update(t *testing.T) {
var version secretsmanager.GetSecretValueOutput
rName := acctest.RandomWithPrefix("tf-acc-test")
resourceName := "aws_secretsmanager_secret_version.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSSecretsManager(t) },
ErrorCheck: testAccErrorCheck(t, secretsmanager.EndpointsID),
Providers: testAccProviders,
CheckDestroy: testAccCheckAwsSecretsManagerSecretVersionDestroy,
Steps: []resource.TestStep{
{
Config: testAccAwsSecretsManagerSecretVersionConfig_VersionStages_Single(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsSecretsManagerSecretVersionExists(resourceName, &version),
resource.TestCheckResourceAttr(resourceName, "secret_string", "test-string"),
resource.TestCheckResourceAttr(resourceName, "version_stages.#", "2"),
resource.TestCheckTypeSetElemAttr(resourceName, "version_stages.*", "AWSCURRENT"),
resource.TestCheckTypeSetElemAttr(resourceName, "version_stages.*", "one"),
),
Destroy: false,
},
{
PreConfig: func() {
conn := testAccProvider.Meta().(*AWSClient).secretsmanagerconn

input := &secretsmanager.PutSecretValueInput{
SecretId: version.ARN,
SecretString: aws.String("external_update"),
}
_, err := conn.PutSecretValue(input)
if err != nil {
t.Fatalf("error externally updating (outside Terraform) SecretsManager secret version: %s", err)
}
},
Config: testAccAwsSecretsManagerSecretVersionConfig_VersionStages_Single(rName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "secret_string", "test-string"),
resource.TestCheckResourceAttr(resourceName, "version_stages.#", "2"),
resource.TestCheckTypeSetElemAttr(resourceName, "version_stages.*", "AWSCURRENT"),
resource.TestCheckTypeSetElemAttr(resourceName, "version_stages.*", "one"),
),
},
},
})
}

func testAccCheckAwsSecretsManagerSecretVersionDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).secretsmanagerconn

Expand Down