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

Vault 32530 add external id to aws auth backend sts role #2370

Merged
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ FEATURES:
* Add support for `connection_timeout` field for the `vault_ldap_auth_backend` resource ([#2358](https://github.com/hashicorp/terraform-provider-vault/pull/2358))
* Add support for Rootless Configuration for Static Roles to Postgres DB ([#2341](https://github.com/hashicorp/terraform-provider-vault/pull/2341))
* Add support for `use_annotations_as_alias_metadata` field for the `vault_kubernetes_auth_backend_config` resource ([#2226](https://github.com/hashicorp/terraform-provider-vault/pull/2226))
* 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))

BUGS:

Expand Down
40 changes: 34 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,13 @@ 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 {
d.Set(consts.FieldExternalID, v)
vinay-gopalan marked this conversation as resolved.
Show resolved Hide resolved
}
}

return nil
}

Expand All @@ -127,12 +147,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
88 changes: 76 additions & 12 deletions vault/resource_aws_auth_backend_sts_role_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ 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"
)
Expand All @@ -20,13 +22,41 @@ func TestAccAWSAuthBackendSTSRole_import(t *testing.T) {
backend := acctest.RandomWithPrefix("aws")
accountID := strconv.Itoa(acctest.RandInt())
arn := acctest.RandomWithPrefix("arn:aws:iam::" + accountID + ":role/test-role")

resource.Test(t, resource.TestCase{
PreCheck: func() { testutil.TestAccPreCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: testAccCheckAWSAuthBackendSTSRoleDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, arn),
Config: testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, arn, ""),
Check: testAccAWSAuthBackendSTSRoleCheck_attrs(backend, accountID, arn),
},
{
ResourceName: "vault_aws_auth_backend_sts_role.role",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccAWSAuthBackendSTSRole_importWithExternalID(t *testing.T) {
helenfufu marked this conversation as resolved.
Show resolved Hide resolved
backend := acctest.RandomWithPrefix("aws")
accountID := strconv.Itoa(acctest.RandInt())
arn := acctest.RandomWithPrefix("arn:aws:iam::" + accountID + ":role/test-role")
externalID := "external-id"

resource.Test(t, resource.TestCase{
PreCheck: func() {
testutil.TestAccPreCheck(t)
SkipIfAPIVersionLT(t, testProvider.Meta(), provider.VaultVersion117)
},
ProviderFactories: providerFactories,
CheckDestroy: testAccCheckAWSAuthBackendSTSRoleDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, arn, externalID),
Check: testAccAWSAuthBackendSTSRoleCheck_attrs(backend, accountID, arn),
},
{
Expand All @@ -43,17 +73,35 @@ func TestAccAWSAuthBackendSTSRole_basic(t *testing.T) {
accountID := strconv.Itoa(acctest.RandInt())
arn := acctest.RandomWithPrefix("arn:aws:iam::" + accountID + ":role/test-role")
updatedArn := acctest.RandomWithPrefix("arn:aws:iam::" + accountID + ":role/test-role")
externalID := "external-id"
updatedExternalID := "external-id-updated"
resource.Test(t, resource.TestCase{
PreCheck: func() { testutil.TestAccPreCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: testAccCheckAWSAuthBackendSTSRoleDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, arn),
Config: testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, arn, ""),
Check: testAccAWSAuthBackendSTSRoleCheck_attrs(backend, accountID, arn),
},
{
Config: testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, updatedArn),
// Update ARN.
Config: testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, updatedArn, ""),
Check: testAccAWSAuthBackendSTSRoleCheck_attrs(backend, accountID, updatedArn),
},
{
// Add external ID.
Config: testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, updatedArn, externalID),
Check: testAccAWSAuthBackendSTSRoleCheck_attrs(backend, accountID, updatedArn),
},
{
// Update external ID.
Config: testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, updatedArn, updatedExternalID),
Check: testAccAWSAuthBackendSTSRoleCheck_attrs(backend, accountID, updatedArn),
},
{
// Remove external ID.
Config: testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, updatedArn, ""),
Check: testAccAWSAuthBackendSTSRoleCheck_attrs(backend, accountID, updatedArn),
},
},
Expand Down Expand Up @@ -117,6 +165,11 @@ func testAccAWSAuthBackendSTSRoleCheck_attrs(backend, accountID, stsRole string)
attrs := map[string]string{
"sts_role": "sts_role",
}
// Only check external_id if Vault version is >= 1.17.0
if provider.IsAPISupported(testProvider.Meta(), provider.VaultVersion117) {
attrs[consts.FieldExternalID] = consts.FieldExternalID
}
helenfufu marked this conversation as resolved.
Show resolved Hide resolved

for stateAttr, apiAttr := range attrs {
if resp.Data[apiAttr] == nil && instanceState.Attributes[stateAttr] == "" {
continue
Expand All @@ -129,17 +182,28 @@ func testAccAWSAuthBackendSTSRoleCheck_attrs(backend, accountID, stsRole string)
}
}

func testAccAWSAuthBackendSTSRoleConfig_basic(backend, accountID, stsRole string) string {
return fmt.Sprintf(`
func testAccAWSAuthBackendSTSRoleConfig_basic(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.
helenfufu marked this conversation as resolved.
Show resolved Hide resolved

## Attributes Reference

No additional attributes are exported by this resource.
Expand Down