Skip to content

Commit

Permalink
Vault 32530 add external id to aws auth backend sts role (#2370)
Browse files Browse the repository at this point in the history
* 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: hashicorp/vault#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 <[email protected]>

---------

Co-authored-by: vinay-gopalan <[email protected]>
  • Loading branch information
helenfufu and vinay-gopalan authored Nov 22, 2024
1 parent 4473d75 commit 0cbe249
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 23 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)

Expand Down
42 changes: 36 additions & 6 deletions vault/resource_aws_auth_backend_sts_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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.",
},
},
}
}
Expand All @@ -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)

Expand Down Expand Up @@ -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
}

Expand All @@ -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)
}
Expand Down
73 changes: 57 additions & 16 deletions vault/resource_aws_auth_backend_sts_role_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand All @@ -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,
},
},
})
}
Expand Down Expand Up @@ -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")
}
2 changes: 2 additions & 0 deletions website/docs/r/aws_auth_backend_sts_role.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 0cbe249

Please sign in to comment.