From 0cbe249861bb5779a7dbe892e41c1a3f9a253f03 Mon Sep 17 00:00:00 2001 From: helenfufu <25168806+helenfufu@users.noreply.github.com> Date: Fri, 22 Nov 2024 14:20:54 -0800 Subject: [PATCH] Vault 32530 add external id to aws auth backend sts role (#2370) * add external_id to aws_auth_backend_sts_role resource * update docs for aws_auth_backend_sts_role resource * update acceptance tests * only support external_id on vault versions >= 1.17 external_id support for aws auth sts configuration added in 1.17.0: https://github.com/hashicorp/vault/pull/26628 * separate import test for external_id case * update changelog * fix changelog: move change under unreleased * add import test steps and remove separate import tests, add separate withExternalID test * handle error on d.Set * rename testAccAWSAuthBackendSTSRoleConfig_basic to more general testAccAWSAuthBackendSTSRoleConfig * note 1.17 version requirement in doc Co-authored-by: vinay-gopalan <86625824+vinay-gopalan@users.noreply.github.com> --------- Co-authored-by: vinay-gopalan <86625824+vinay-gopalan@users.noreply.github.com> --- CHANGELOG.md | 3 +- vault/resource_aws_auth_backend_sts_role.go | 42 +++++++++-- ...resource_aws_auth_backend_sts_role_test.go | 73 +++++++++++++++---- .../docs/r/aws_auth_backend_sts_role.html.md | 2 + 4 files changed, 97 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c944ebfd9..f758c0f522 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ ## Unreleased -FEATURES: +FEATURES: * Update `vault_database_secret_backend_connection`to support `password_authentication` for PostgreSQL, allowing to encrypt password before being passed to PostgreSQL ([#2371](https://github.com/hashicorp/terraform-provider-vault/pull/2371)) +* Add support for `external_id` field for the `vault_aws_auth_backend_sts_role` resource ([#2370](https://github.com/hashicorp/terraform-provider-vault/pull/2370)) ## 4.5.0 (Nov 19, 2024) diff --git a/vault/resource_aws_auth_backend_sts_role.go b/vault/resource_aws_auth_backend_sts_role.go index b79bf35f89..96e481eb5e 100644 --- a/vault/resource_aws_auth_backend_sts_role.go +++ b/vault/resource_aws_auth_backend_sts_role.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-vault/internal/consts" "github.com/hashicorp/terraform-provider-vault/internal/provider" ) @@ -52,6 +53,11 @@ func awsAuthBackendSTSRoleResource() *schema.Resource { return strings.Trim(v.(string), "/") }, }, + consts.FieldExternalID: { + Type: schema.TypeString, + Optional: true, + Description: "External ID expected by the STS role.", + }, }, } } @@ -65,13 +71,20 @@ func awsAuthBackendSTSRoleCreate(d *schema.ResourceData, meta interface{}) error backend := d.Get("backend").(string) accountID := d.Get("account_id").(string) stsRole := d.Get("sts_role").(string) + externalID := d.Get(consts.FieldExternalID).(string) path := awsAuthBackendSTSRolePath(backend, accountID) - log.Printf("[DEBUG] Writing STS role %q to AWS auth backend", path) - _, err := client.Logical().Write(path, map[string]interface{}{ + data := map[string]interface{}{ "sts_role": stsRole, - }) + } + + if provider.IsAPISupported(meta, provider.VaultVersion117) { + data[consts.FieldExternalID] = externalID + } + + log.Printf("[DEBUG] Writing STS role %q to AWS auth backend", path) + _, err := client.Logical().Write(path, data) d.SetId(path) @@ -117,6 +130,15 @@ func awsAuthBackendSTSRoleRead(d *schema.ResourceData, meta interface{}) error { d.Set("backend", backend) d.Set("account_id", accountID) d.Set("sts_role", resp.Data["sts_role"]) + + if provider.IsAPISupported(meta, provider.VaultVersion117) { + if v, ok := resp.Data[consts.FieldExternalID]; ok { + if err := d.Set(consts.FieldExternalID, v); err != nil { + return err + } + } + } + return nil } @@ -127,12 +149,20 @@ func awsAuthBackendSTSRoleUpdate(d *schema.ResourceData, meta interface{}) error } stsRole := d.Get("sts_role").(string) + externalID := d.Get(consts.FieldExternalID).(string) + path := d.Id() - log.Printf("[DEBUG] Updating STS role %q in AWS auth backend", path) - _, err := client.Logical().Write(path, map[string]interface{}{ + data := map[string]interface{}{ "sts_role": stsRole, - }) + } + + if provider.IsAPISupported(meta, provider.VaultVersion117) { + data[consts.FieldExternalID] = externalID + } + + log.Printf("[DEBUG] Updating STS role %q in AWS auth backend", path) + _, err := client.Logical().Write(path, data) if err != nil { return fmt.Errorf("error updating STS role %q in AWS auth backend", path) } diff --git a/vault/resource_aws_auth_backend_sts_role_test.go b/vault/resource_aws_auth_backend_sts_role_test.go index b331594b6b..80d241426c 100644 --- a/vault/resource_aws_auth_backend_sts_role_test.go +++ b/vault/resource_aws_auth_backend_sts_role_test.go @@ -6,31 +6,55 @@ package vault import ( "fmt" "strconv" + "strings" "testing" "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-vault/internal/consts" "github.com/hashicorp/terraform-provider-vault/internal/provider" "github.com/hashicorp/terraform-provider-vault/testutil" ) -func TestAccAWSAuthBackendSTSRole_import(t *testing.T) { +func TestAccAWSAuthBackendSTSRole_withExternalID(t *testing.T) { backend := acctest.RandomWithPrefix("aws") accountID := strconv.Itoa(acctest.RandInt()) arn := acctest.RandomWithPrefix("arn:aws:iam::" + accountID + ":role/test-role") + externalID := "external-id" + updatedExternalID := "external-id-updated" + resourceName := "vault_aws_auth_backend_sts_role.role" + resource.Test(t, resource.TestCase{ - PreCheck: func() { testutil.TestAccPreCheck(t) }, + PreCheck: func() { + testutil.TestAccPreCheck(t) + SkipIfAPIVersionLT(t, testProvider.Meta(), provider.VaultVersion117) + }, ProviderFactories: providerFactories, CheckDestroy: testAccCheckAWSAuthBackendSTSRoleDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, arn), - Check: testAccAWSAuthBackendSTSRoleCheck_attrs(backend, accountID, arn), + Config: testAccAWSAuthBackendSTSRoleConfig(backend, accountID, arn, externalID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "backend", backend), + resource.TestCheckResourceAttr(resourceName, "account_id", accountID), + resource.TestCheckResourceAttr(resourceName, "sts_role", arn), + resource.TestCheckResourceAttr(resourceName, consts.FieldExternalID, externalID), + ), }, { - ResourceName: "vault_aws_auth_backend_sts_role.role", + // Update external ID. + Config: testAccAWSAuthBackendSTSRoleConfig(backend, accountID, arn, updatedExternalID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "backend", backend), + resource.TestCheckResourceAttr(resourceName, "account_id", accountID), + resource.TestCheckResourceAttr(resourceName, "sts_role", arn), + resource.TestCheckResourceAttr(resourceName, consts.FieldExternalID, updatedExternalID), + ), + }, + { + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -49,13 +73,19 @@ func TestAccAWSAuthBackendSTSRole_basic(t *testing.T) { CheckDestroy: testAccCheckAWSAuthBackendSTSRoleDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, arn), + Config: testAccAWSAuthBackendSTSRoleConfig(backend, accountID, arn, ""), Check: testAccAWSAuthBackendSTSRoleCheck_attrs(backend, accountID, arn), }, { - Config: testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, updatedArn), + // Update ARN. + Config: testAccAWSAuthBackendSTSRoleConfig(backend, accountID, updatedArn, ""), Check: testAccAWSAuthBackendSTSRoleCheck_attrs(backend, accountID, updatedArn), }, + { + ResourceName: "vault_aws_auth_backend_sts_role.role", + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -129,17 +159,28 @@ func testAccAWSAuthBackendSTSRoleCheck_attrs(backend, accountID, stsRole string) } } -func testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, stsRole string) string { - return fmt.Sprintf(` +func testAccAWSAuthBackendSTSRoleConfig(backend, accountID, stsRole, externalID string) string { + backendResource := fmt.Sprintf(` resource "vault_auth_backend" "aws" { - type = "aws" - path = "%s" -} + type = "aws" + path = "%s" +}`, backend) + + roleResourceOptionalFields := "" + if externalID != "" { + roleResourceOptionalFields += fmt.Sprintf(` + external_id = "%s"`, externalID) + } + roleResource := fmt.Sprintf(` resource "vault_aws_auth_backend_sts_role" "role" { - backend = vault_auth_backend.aws.path - account_id = "%s" - sts_role = "%s" + backend = vault_auth_backend.aws.path + account_id = "%s" + sts_role = "%s"%s } -`, backend, accountID, stsRole) +`, accountID, stsRole, roleResourceOptionalFields) + + resources := []string{backendResource, roleResource} + + return strings.Join(resources, "\n") } diff --git a/website/docs/r/aws_auth_backend_sts_role.html.md b/website/docs/r/aws_auth_backend_sts_role.html.md index 20535a6160..98ac51c09b 100644 --- a/website/docs/r/aws_auth_backend_sts_role.html.md +++ b/website/docs/r/aws_auth_backend_sts_role.html.md @@ -51,6 +51,8 @@ The following arguments are supported: * `backend` - (Optional) The path the AWS auth backend being configured was mounted at. Defaults to `aws`. +* `external_id` - (Optional) External ID expected by the STS role. The associated STS role must be configured to require the external ID. Requires Vault 1.17+. + ## Attributes Reference No additional attributes are exported by this resource.