Feature: Allow params to support tfe team multitoken (#2498)

* allow params for tfe team multitoken

* enable all tests, changelog for updates

* re-add tests

* add docs and changelog

* skip if vault below v120

* fix comment

* rm duplicate credential_type
This commit is contained in:
drewmullen 2025-09-10 15:48:23 -05:00 committed by GitHub
parent 68847494a4
commit 84784f352f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 138 additions and 1 deletions

1
.gitignore vendored
View file

@ -40,3 +40,4 @@ scratch
# others
.swp
.vscode

View file

@ -1,5 +1,7 @@
## Unreleased
* New parameters for `vault_terraform_cloud_secret_role` to support multi-team tokens, by @drewmullen ([#2498](https://github.com/hashicorp/terraform-provider-vault/pull/2498))
## 5.3.0 (Sep 4, 2025)
FEATURES:

View file

@ -10,6 +10,7 @@ import (
"strings"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-vault/internal/provider"
)
@ -43,6 +44,18 @@ func terraformCloudSecretRoleResource() *schema.Resource {
ForceNew: true,
Description: "The path of the Terraform Cloud Secret Backend the role belongs to.",
},
"credential_type": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Description: "The type of credential to generate. Valid values are 'team', 'team_legacy', 'user', or 'organization'.",
ValidateFunc: validation.StringInSlice([]string{"team", "team_legacy", "user", "organization"}, false),
},
"description": {
Type: schema.TypeString,
Optional: true,
Description: "Description of the role. This is used as a prefix to help identify the token in the HCP Terraform UI. Only valid with 'team' or 'user' credential types.",
},
"organization": {
Type: schema.TypeString,
Optional: true,
@ -114,6 +127,16 @@ func terraformCloudSecretRoleWrite(d *schema.ResourceData, meta interface{}) err
if v, ok := d.GetOkExists("user_id"); ok {
payload["user_id"] = v
}
if v, ok := d.GetOk("description"); ok {
payload["description"] = v
}
if provider.IsAPISupported(meta, provider.VaultVersion120) {
// parse credential_type field if 1.20 server or higher
if v, ok := d.GetOk("credential_type"); ok {
payload["credential_type"] = v
}
}
log.Printf("[DEBUG] Configuring Terraform Cloud secrets backend role at %q", path)
@ -167,6 +190,12 @@ func terraformCloudSecretRoleRead(d *schema.ResourceData, meta interface{}) erro
d.Set("user_id", data["user_id"])
d.Set("max_ttl", data["max_ttl"])
d.Set("ttl", data["ttl"])
if data["description"] != nil {
d.Set("description", data["description"])
}
if data["credential_type"] != nil {
d.Set("credential_type", data["credential_type"])
}
return nil
}

View file

@ -16,7 +16,7 @@ import (
"github.com/hashicorp/terraform-provider-vault/testutil"
)
func TestTerraformCloudSecretRole(t *testing.T) {
func TestTerraformCloudSecretRole_basic(t *testing.T) {
backend := acctest.RandomWithPrefix("tf-test-backend")
name := acctest.RandomWithPrefix("tf-test-name")
organization := "hashicorp-vault-testing"
@ -73,6 +73,53 @@ func TestTerraformCloudSecretRole(t *testing.T) {
})
}
func TestTerraformCloudSecretRole_options(t *testing.T) {
backend := acctest.RandomWithPrefix("tf-test-backend")
name := acctest.RandomWithPrefix("tf-test-name")
vals := testutil.SkipTestEnvUnset(t, "TEST_TF_TOKEN", "TEST_TF_TEAM_ID")
token, teamID := vals[0], vals[1]
resource.Test(t, resource.TestCase{
ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(context.Background(), t),
PreCheck: func() {
testutil.TestAccPreCheck(t)
SkipIfAPIVersionLT(t, testProvider.Meta(), provider.VaultVersion120)
},
CheckDestroy: testAccTerraformCloudSecretRoleCheckDestroy,
Steps: []resource.TestStep{
{
Config: testTerraformCloudSecretRole_optionsInitialConfig(backend, token, name, teamID),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team", "name", name+"_team_id"),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team", "description", "team role"),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team", "credential_type", "team"),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team", "team_id", teamID),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team", "ttl", "100"),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team", "max_ttl", "200"),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team_legacy", "name", name+"_team_legacy_id"),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team_legacy", "credential_type", "team_legacy"),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team_legacy", "team_id", teamID),
),
},
{
Config: testTerraformCloudSecretRole_optionsUpdatedConfig(backend, token, name, teamID),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team", "name", name+"_team_id"),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team", "description", "team role2"),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team", "credential_type", "team"),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team", "team_id", teamID),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team", "ttl", "200"),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team", "max_ttl", "300"),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team_legacy", "name", name+"_team_legacy_id"),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team_legacy", "credential_type", "team_legacy"),
resource.TestCheckResourceAttr("vault_terraform_cloud_secret_role.test_team_legacy", "team_id", teamID),
),
},
},
})
}
func testAccTerraformCloudSecretRoleCheckDestroy(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
if rs.Type != "vault_terraform_cloud_secret_role" {
@ -163,6 +210,60 @@ resource "vault_terraform_cloud_secret_role" "test_user" {
`, backend, token, name, organization, teamId, userId)
}
func testTerraformCloudSecretRole_optionsInitialConfig(backend, token, name, teamId string) string {
return fmt.Sprintf(`
resource "vault_terraform_cloud_secret_backend" "test" {
backend = "%s"
description = "test description"
token = "%s"
}
resource "vault_terraform_cloud_secret_role" "test_team" {
backend = vault_terraform_cloud_secret_backend.test.backend
name = "%[3]s_team_id"
team_id = "%[4]s"
credential_type = "team"
description = "team role"
ttl = 100
max_ttl = 200
}
resource "vault_terraform_cloud_secret_role" "test_team_legacy" {
backend = vault_terraform_cloud_secret_backend.test.backend
name = "%[3]s_team_legacy_id"
team_id = "%[4]s"
credential_type = "team_legacy"
}
`, backend, token, name, teamId)
}
func testTerraformCloudSecretRole_optionsUpdatedConfig(backend, token, name, teamId string) string {
return fmt.Sprintf(`
resource "vault_terraform_cloud_secret_backend" "test" {
backend = "%s"
description = "test description"
token = "%s"
}
resource "vault_terraform_cloud_secret_role" "test_team" {
backend = vault_terraform_cloud_secret_backend.test.backend
name = "%[3]s_team_id"
team_id = "%[4]s"
credential_type = "team"
description = "team role2"
ttl = 200
max_ttl = 300
}
resource "vault_terraform_cloud_secret_role" "test_team_legacy" {
backend = vault_terraform_cloud_secret_backend.test.backend
name = "%[3]s_team_legacy_id"
team_id = "%[4]s"
credential_type = "team_legacy"
}
`, backend, token, name, teamId)
}
func TestTerraformCloudSecretBackendRoleNameFromPath(t *testing.T) {
{
name, err := terraformCloudSecretRoleNameFromPath("foo/role/bar")

View file

@ -51,6 +51,10 @@ The following arguments are supported:
* `ttl` - (Optional) Specifies the TTL for this role, in seconds.
* `credential_type` - (Optional) The type of credential to generate. Valid values are 'team', 'team_legacy', 'user', or 'organization'. Can only create multiple-team tokens with `team`.
* `description` - (Optional) Description of the role. This is used as a prefix to help identify the token in the HCP Terraform UI. Only valid with `team` or `user` credential types.
## Attributes Reference
No additional attributes are exported by this resource.