diff --git a/internal/consts/consts.go b/internal/consts/consts.go index cb271ad56..46836de1e 100644 --- a/internal/consts/consts.go +++ b/internal/consts/consts.go @@ -371,6 +371,7 @@ const ( FieldObjectID = "object_id" FieldApplicationObjectID = "application_object_id" FieldPermanentlyDelete = "permanently_delete" + FieldPersistApp = "persist_app" FieldSignInAudience = "sign_in_audience" FieldTags = "tags" FieldSkipStaticRoleImportRotation = "skip_static_role_import_rotation" diff --git a/vault/resource_azure_secret_backend_role.go b/vault/resource_azure_secret_backend_role.go index 249af97d4..bb24e30ec 100644 --- a/vault/resource_azure_secret_backend_role.go +++ b/vault/resource_azure_secret_backend_role.go @@ -6,10 +6,11 @@ package vault import ( "context" "encoding/json" - "github.com/hashicorp/terraform-provider-vault/util" "log" "strings" + "github.com/hashicorp/terraform-provider-vault/util" + "github.com/hashicorp/terraform-provider-vault/internal/consts" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -110,6 +111,12 @@ func azureSecretBackendRoleResource() *schema.Resource { Computed: true, Description: "Indicates whether the applications and service principals created by Vault will be permanently deleted when the corresponding leases expire.", }, + consts.FieldPersistApp: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Persists the created service principal and application for the lifetime of the role. Useful for when the Service Principal needs to maintain ownership of objects it creates. Defaults to false in Vault 1.16+", + }, consts.FieldTTL: { Type: schema.TypeString, Optional: true, @@ -195,6 +202,7 @@ func azureSecretBackendRoleUpdateFields(_ context.Context, d *schema.ResourceDat data[consts.FieldTags] = strings.Join(tags, ",") } } + data[consts.FieldPersistApp] = d.Get(consts.FieldPersistApp).(bool) } if provider.IsAPISupported(meta, provider.VaultVersion112) { diff --git a/vault/resource_azure_secret_backend_role_test.go b/vault/resource_azure_secret_backend_role_test.go index f8093e972..7cc6ff2e4 100644 --- a/vault/resource_azure_secret_backend_role_test.go +++ b/vault/resource_azure_secret_backend_role_test.go @@ -98,6 +98,23 @@ func TestAzureSecretBackendRole_AzureRoles(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName+".test_azure_roles", "azure_roles.0.role_id"), ), }, + { + // persist application registration when true + SkipFunc: func() (bool, error) { + meta := testProvider.Meta().(*provider.ProviderMeta) + return !meta.IsAPISupported(provider.VaultVersion116), nil + }, + Config: testAzureSecretBackendRolePersistApp_azureRoles(subscriptionID, tenantID, clientID, clientSecret, path, role, resourceGroup), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName+".test_azure_roles", "role", role+"-azure-roles"), + resource.TestCheckResourceAttr(resourceName+".test_azure_roles", "description", "Test for Vault Provider"), + resource.TestCheckResourceAttr(resourceName+".test_azure_roles", "persist_app", "false"), + resource.TestCheckResourceAttr(resourceName+".test_azure_roles", "azure_roles.#", "1"), + resource.TestCheckResourceAttr(resourceName+".test_azure_roles", "azure_roles.0.role_name", "Reader"), + resource.TestCheckResourceAttrSet(resourceName+".test_azure_roles", "azure_roles.0.scope"), + resource.TestCheckResourceAttrSet(resourceName+".test_azure_roles", "azure_roles.0.role_id"), + ), + }, }, }) } @@ -162,6 +179,22 @@ func TestAzureSecretBackendRole_AzureGroups(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName+".test_azure_groups", "azure_groups.0.object_id"), ), }, + { + // persist application registration when true + SkipFunc: func() (bool, error) { + meta := testProvider.Meta().(*provider.ProviderMeta) + return !meta.IsAPISupported(provider.VaultVersion116), nil + }, + Config: testAzureSecretBackendRolePersistApp_azureGroups(subscriptionID, tenantID, clientID, clientSecret, path, role, resourceGroup), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName+".test_azure_groups", "role", role+"-azure-groups"), + resource.TestCheckResourceAttr(resourceName+".test_azure_groups", "description", "Test for Vault Provider"), + resource.TestCheckResourceAttr(resourceName+".test_azure_groups", "persist_app", "true"), + resource.TestCheckResourceAttr(resourceName+".test_azure_groups", "azure_groups.#", "1"), + resource.TestCheckResourceAttr(resourceName+".test_azure_groups", "azure_groups.0.group_name", "foobar"), + resource.TestCheckResourceAttrSet(resourceName+".test_azure_groups", "azure_groups.0.object_id"), + ), + }, }, }) } @@ -344,3 +377,53 @@ resource "vault_azure_secret_backend_role" "test_azure_groups" { } `, subscriptionID, tenantID, clientID, clientSecret, path, role, resourceGroup) } + +func testAzureSecretBackendRolePersistApp_azureRoles(subscriptionID string, tenantID string, clientID string, clientSecret string, path string, role string, resourceGroup string) string { + return fmt.Sprintf(` +resource "vault_azure_secret_backend" "azure" { + subscription_id = "%s" + tenant_id = "%s" + client_id = "%s" + client_secret = "%s" + path = "%s" +} + +resource "vault_azure_secret_backend_role" "test_azure_roles" { + backend = vault_azure_secret_backend.azure.path + role = "%[6]s-azure-roles" + ttl = 300 + max_ttl = 600 + description = "Test for Vault Provider" + + azure_roles { + role_name = "Reader" + scope = "/subscriptions/%[1]s/resourceGroups/%[7]s" + } +} +`, subscriptionID, tenantID, clientID, clientSecret, path, role, resourceGroup) +} + +func testAzureSecretBackendRolePersistApp_azureGroups(subscriptionID string, tenantID string, clientID string, clientSecret string, path string, role string, resourceGroup string) string { + return fmt.Sprintf(` +resource "vault_azure_secret_backend" "azure" { + subscription_id = "%s" + tenant_id = "%s" + client_id = "%s" + client_secret = "%s" + path = "%s" +} + +resource "vault_azure_secret_backend_role" "test_azure_groups" { + backend = vault_azure_secret_backend.azure.path + role = "%[6]s-azure-groups" + ttl = 300 + max_ttl = 600 + description = "Test for Vault Provider" + persist_app = true + + azure_groups { + group_name = "foobar" + } +} +`, subscriptionID, tenantID, clientID, clientSecret, path, role, resourceGroup) +}