From 223a5d83758676fe59d6282f2380d908a25a7934 Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Sun, 22 Apr 2018 23:26:26 -0400 Subject: [PATCH 01/23] Initial support for Azure Key Vault Policy resource --- azurerm/key_vault_policy.go | 84 +++++ azurerm/provider.go | 1 + azurerm/resource_arm_key_vault.go | 113 +----- azurerm/resource_arm_key_vault_policy.go | 234 ++++++++++++ azurerm/resource_arm_key_vault_policy_test.go | 355 ++++++++++++++++++ website/docs/r/key_vault.html.markdown | 4 +- website/docs/r/key_vault_policy.html.markdown | 96 +++++ 7 files changed, 776 insertions(+), 111 deletions(-) create mode 100644 azurerm/key_vault_policy.go create mode 100644 azurerm/resource_arm_key_vault_policy.go create mode 100644 azurerm/resource_arm_key_vault_policy_test.go create mode 100644 website/docs/r/key_vault_policy.html.markdown diff --git a/azurerm/key_vault_policy.go b/azurerm/key_vault_policy.go new file mode 100644 index 000000000000..af1d31b8b27d --- /dev/null +++ b/azurerm/key_vault_policy.go @@ -0,0 +1,84 @@ +package azurerm + +import ( + "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" +) + +func keyPermissionsSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(keyvault.KeyPermissionsBackup), + string(keyvault.KeyPermissionsCreate), + string(keyvault.KeyPermissionsDecrypt), + string(keyvault.KeyPermissionsDelete), + string(keyvault.KeyPermissionsEncrypt), + string(keyvault.KeyPermissionsGet), + string(keyvault.KeyPermissionsImport), + string(keyvault.KeyPermissionsList), + string(keyvault.KeyPermissionsPurge), + string(keyvault.KeyPermissionsRecover), + string(keyvault.KeyPermissionsRestore), + string(keyvault.KeyPermissionsSign), + string(keyvault.KeyPermissionsUnwrapKey), + string(keyvault.KeyPermissionsUpdate), + string(keyvault.KeyPermissionsVerify), + string(keyvault.KeyPermissionsWrapKey), + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + }, + } +} + +func secretPermissionsSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(keyvault.SecretPermissionsBackup), + string(keyvault.SecretPermissionsDelete), + string(keyvault.SecretPermissionsGet), + string(keyvault.SecretPermissionsList), + string(keyvault.SecretPermissionsPurge), + string(keyvault.SecretPermissionsRecover), + string(keyvault.SecretPermissionsRestore), + string(keyvault.SecretPermissionsSet), + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + }, + } +} + +func certificatePermissionsSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(keyvault.Create), + string(keyvault.Delete), + string(keyvault.Deleteissuers), + string(keyvault.Get), + string(keyvault.Getissuers), + string(keyvault.Import), + string(keyvault.List), + string(keyvault.Listissuers), + string(keyvault.Managecontacts), + string(keyvault.Manageissuers), + string(keyvault.Purge), + string(keyvault.Recover), + string(keyvault.Setissuers), + string(keyvault.Update), + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + }, + } +} diff --git a/azurerm/provider.go b/azurerm/provider.go index 13388cb2e9a4..81d719d47dc2 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -151,6 +151,7 @@ func Provider() terraform.ResourceProvider { "azurerm_key_vault_certificate": resourceArmKeyVaultCertificate(), "azurerm_key_vault_key": resourceArmKeyVaultKey(), "azurerm_key_vault_secret": resourceArmKeyVaultSecret(), + "azurerm_key_vault_policy": resourceArmKeyVaultPolicy(), "azurerm_kubernetes_cluster": resourceArmKubernetesCluster(), "azurerm_lb": resourceArmLoadBalancer(), "azurerm_lb_backend_address_pool": resourceArmLoadBalancerBackendAddressPool(), diff --git a/azurerm/resource_arm_key_vault.go b/azurerm/resource_arm_key_vault.go index 978a687575b3..64ba514cc287 100644 --- a/azurerm/resource_arm_key_vault.go +++ b/azurerm/resource_arm_key_vault.go @@ -76,7 +76,7 @@ func resourceArmKeyVault() *schema.Resource { "access_policy": { Type: schema.TypeList, Optional: true, - MinItems: 1, + MinItems: 0, MaxItems: 16, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -95,74 +95,9 @@ func resourceArmKeyVault() *schema.Resource { Optional: true, ValidateFunc: validateUUID, }, - "certificate_permissions": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{ - string(keyvault.Create), - string(keyvault.Delete), - string(keyvault.Deleteissuers), - string(keyvault.Get), - string(keyvault.Getissuers), - string(keyvault.Import), - string(keyvault.List), - string(keyvault.Listissuers), - string(keyvault.Managecontacts), - string(keyvault.Manageissuers), - string(keyvault.Purge), - string(keyvault.Recover), - string(keyvault.Setissuers), - string(keyvault.Update), - }, true), - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, - }, - }, - "key_permissions": { - Type: schema.TypeList, - Required: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{ - string(keyvault.KeyPermissionsBackup), - string(keyvault.KeyPermissionsCreate), - string(keyvault.KeyPermissionsDecrypt), - string(keyvault.KeyPermissionsDelete), - string(keyvault.KeyPermissionsEncrypt), - string(keyvault.KeyPermissionsGet), - string(keyvault.KeyPermissionsImport), - string(keyvault.KeyPermissionsList), - string(keyvault.KeyPermissionsPurge), - string(keyvault.KeyPermissionsRecover), - string(keyvault.KeyPermissionsRestore), - string(keyvault.KeyPermissionsSign), - string(keyvault.KeyPermissionsUnwrapKey), - string(keyvault.KeyPermissionsUpdate), - string(keyvault.KeyPermissionsVerify), - string(keyvault.KeyPermissionsWrapKey), - }, true), - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, - }, - }, - "secret_permissions": { - Type: schema.TypeList, - Required: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{ - string(keyvault.SecretPermissionsBackup), - string(keyvault.SecretPermissionsDelete), - string(keyvault.SecretPermissionsGet), - string(keyvault.SecretPermissionsList), - string(keyvault.SecretPermissionsPurge), - string(keyvault.SecretPermissionsRecover), - string(keyvault.SecretPermissionsRestore), - string(keyvault.SecretPermissionsSet), - }, true), - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, - }, - }, + "certificate_permissions": certificatePermissionsSchema(), + "key_permissions": keyPermissionsSchema(), + "secret_permissions": secretPermissionsSchema(), }, }, }, @@ -273,7 +208,6 @@ func resourceArmKeyVaultRead(d *schema.ResourceData, meta interface{}) error { d.Set("enabled_for_disk_encryption", resp.Properties.EnabledForDiskEncryption) d.Set("enabled_for_template_deployment", resp.Properties.EnabledForTemplateDeployment) d.Set("sku", flattenKeyVaultSku(resp.Properties.Sku)) - d.Set("access_policy", flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) d.Set("vault_uri", resp.Properties.VaultURI) flattenAndSetTags(d, resp.Tags) @@ -364,50 +298,11 @@ func flattenKeyVaultSku(sku *keyvault.Sku) []interface{} { return []interface{}{result} } -func flattenKeyVaultAccessPolicies(policies *[]keyvault.AccessPolicyEntry) []interface{} { - result := make([]interface{}, 0, len(*policies)) - - for _, policy := range *policies { - policyRaw := make(map[string]interface{}) - - keyPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Keys)) - for _, keyPermission := range *policy.Permissions.Keys { - keyPermissionsRaw = append(keyPermissionsRaw, string(keyPermission)) - } - - secretPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Secrets)) - for _, secretPermission := range *policy.Permissions.Secrets { - secretPermissionsRaw = append(secretPermissionsRaw, string(secretPermission)) - } - - policyRaw["tenant_id"] = policy.TenantID.String() - policyRaw["object_id"] = *policy.ObjectID - if policy.ApplicationID != nil { - policyRaw["application_id"] = policy.ApplicationID.String() - } - policyRaw["key_permissions"] = keyPermissionsRaw - policyRaw["secret_permissions"] = secretPermissionsRaw - - if policy.Permissions.Certificates != nil { - certificatePermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Certificates)) - for _, certificatePermission := range *policy.Permissions.Certificates { - certificatePermissionsRaw = append(certificatePermissionsRaw, string(certificatePermission)) - } - policyRaw["certificate_permissions"] = certificatePermissionsRaw - } - - result = append(result, policyRaw) - } - - return result -} - func validateKeyVaultName(v interface{}, k string) (ws []string, errors []error) { value := v.(string) if matched := regexp.MustCompile(`^[a-zA-Z0-9-]{3,24}$`).Match([]byte(value)); !matched { errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters and dashes and must be between 3-24 chars", k)) } - return } diff --git a/azurerm/resource_arm_key_vault_policy.go b/azurerm/resource_arm_key_vault_policy.go new file mode 100644 index 000000000000..eee5d094dbc7 --- /dev/null +++ b/azurerm/resource_arm_key_vault_policy.go @@ -0,0 +1,234 @@ +package azurerm + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + uuid "github.com/satori/go.uuid" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmKeyVaultPolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceArmKeyVaultPolicyCreate, + Read: resourceArmKeyVaultPolicyRead, + Update: resourceArmKeyVaultPolicyUpdate, + Delete: resourceArmKeyVaultPolicyDelete, + + Schema: map[string]*schema.Schema{ + "vault_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "vault_resource_group": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "tenant_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateUUID, + ForceNew: true, + }, + "object_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateUUID, + ForceNew: true, + }, + "application_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateUUID, + ForceNew: true, + }, + "certificate_permissions": certificatePermissionsSchema(), + "key_permissions": keyPermissionsSchema(), + "secret_permissions": secretPermissionsSchema(), + }, + } +} + +func createKeyVaultAccessPolicy(d *schema.ResourceData) *keyvault.AccessPolicyEntry { + + certificatePermissionsRaw := d.Get("certificate_permissions").([]interface{}) + certificatePermissions := []keyvault.CertificatePermissions{} + for _, permission := range certificatePermissionsRaw { + certificatePermissions = append(certificatePermissions, keyvault.CertificatePermissions(permission.(string))) + } + + keyPermissionsRaw := d.Get("key_permissions").([]interface{}) + keyPermissions := []keyvault.KeyPermissions{} + for _, permission := range keyPermissionsRaw { + keyPermissions = append(keyPermissions, keyvault.KeyPermissions(permission.(string))) + } + + secretPermissionsRaw := d.Get("secret_permissions").([]interface{}) + secretPermissions := []keyvault.SecretPermissions{} + for _, permission := range secretPermissionsRaw { + secretPermissions = append(secretPermissions, keyvault.SecretPermissions(permission.(string))) + } + + policy := keyvault.AccessPolicyEntry{ + Permissions: &keyvault.Permissions{ + Certificates: &certificatePermissions, + Keys: &keyPermissions, + Secrets: &secretPermissions, + }, + } + + tenantUUID := uuid.FromStringOrNil(d.Get("tenant_id").(string)) + policy.TenantID = &tenantUUID + objectUUID := d.Get("object_id").(string) + policy.ObjectID = &objectUUID + + if v := d.Get("application_id"); v != "" { + applicationUUID := uuid.FromStringOrNil(v.(string)) + policy.ApplicationID = &applicationUUID + } + + return &policy + +} + +func resourceArmKeyVaultPolicyCreateOrDelete(d *schema.ResourceData, meta interface{}, action keyvault.AccessPolicyUpdateKind) error { + client := meta.(*ArmClient).keyVaultClient + ctx := meta.(*ArmClient).StopContext + log.Printf("[INFO] preparing arguments for Azure ARM Policy: %s.", action) + + name := d.Get("vault_name").(string) + //location := azureRMNormalizeLocation(d.Get("vault_location").(string)) + resGroup := d.Get("vault_resource_group").(string) + + parameters := keyvault.VaultAccessPolicyParameters{ + Name: &name, + Properties: &keyvault.VaultAccessPolicyProperties{ + AccessPolicies: &[]keyvault.AccessPolicyEntry{*createKeyVaultAccessPolicy(d)}, + }, + } + + _, err := client.UpdateAccessPolicy(ctx, resGroup, name, action, parameters) + if err != nil { + return err + } + + read, err := client.Get(ctx, resGroup, name) + if err != nil { + return err + } + if read.ID == nil { + return fmt.Errorf("cannot read KeyVault %s (resource group %s) ID", name, resGroup) + } + + d.SetId(*read.ID) + + if d.IsNewResource() { + if props := read.Properties; props != nil { + if vault := props.VaultURI; vault != nil { + err := resource.Retry(120*time.Second, checkKeyVaultDNSIsAvailable(*vault)) + if err != nil { + return err + } + } + } + } + + return resourceArmKeyVaultRead(d, meta) +} + +func resourceArmKeyVaultPolicyCreate(d *schema.ResourceData, meta interface{}) error { + return resourceArmKeyVaultPolicyCreateOrDelete(d, meta, keyvault.Add) +} + +func resourceArmKeyVaultPolicyDelete(d *schema.ResourceData, meta interface{}) error { + return resourceArmKeyVaultPolicyCreateOrDelete(d, meta, keyvault.Remove) +} + +func resourceArmKeyVaultPolicyUpdate(d *schema.ResourceData, meta interface{}) error { + return resourceArmKeyVaultPolicyCreateOrDelete(d, meta, keyvault.Replace) +} + +func resourceArmKeyVaultPolicyRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).keyVaultClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resGroup := id.ResourceGroup + name := id.Path["vaults"] + + objectUUID := d.Get("object_id").(string) + + resp, err := client.Get(ctx, resGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("Error making Read request on Azure KeyVault %s: %+v", name, err) + } + + policy := findKeyVaultAccessPolicy(objectUUID, resp.Properties.AccessPolicies) + + d.Set("vault_name", resp.Name) + d.Set("vault_resource_group", resGroup) + d.Set("tenant_id", resp.Properties.TenantID.String()) + d.Set("application_id", policy["application_id"]) + d.Set("key_permissions", policy["key_permissions"]) + d.Set("secret_permissions", policy["secret_permissions"]) + d.Set("certificate_permissions", policy["certificate_permissions"]) + + flattenAndSetTags(d, resp.Tags) + + return nil +} + +func findKeyVaultAccessPolicy(objectID string, policies *[]keyvault.AccessPolicyEntry) map[string]interface{} { + + for _, policy := range *policies { + result := make(map[string]interface{}) + + if objectID != *policy.ObjectID { + continue + } + + keyPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Keys)) + for _, keyPermission := range *policy.Permissions.Keys { + keyPermissionsRaw = append(keyPermissionsRaw, string(keyPermission)) + } + + secretPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Secrets)) + for _, secretPermission := range *policy.Permissions.Secrets { + secretPermissionsRaw = append(secretPermissionsRaw, string(secretPermission)) + } + + result["tenant_id"] = policy.TenantID.String() + result["object_id"] = *policy.ObjectID + if policy.ApplicationID != nil { + result["application_id"] = policy.ApplicationID.String() + } + result["key_permissions"] = keyPermissionsRaw + result["secret_permissions"] = secretPermissionsRaw + + if policy.Permissions.Certificates != nil { + certificatePermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Certificates)) + for _, certificatePermission := range *policy.Permissions.Certificates { + certificatePermissionsRaw = append(certificatePermissionsRaw, string(certificatePermission)) + } + result["certificate_permissions"] = certificatePermissionsRaw + } + + return result + } + + return nil +} diff --git a/azurerm/resource_arm_key_vault_policy_test.go b/azurerm/resource_arm_key_vault_policy_test.go new file mode 100644 index 000000000000..f110103eb1c2 --- /dev/null +++ b/azurerm/resource_arm_key_vault_policy_test.go @@ -0,0 +1,355 @@ +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMKeyVaultPolicy_basic(t *testing.T) { + resourceName := "azurerm_key_vault_policy.test" + rs := acctest.RandString(6) + config := testAccAzureRMKeyVaultPolicy_basic(rs, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMKeyVaultDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMKeyVaultPolicyExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "get"), + resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), + resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "set"), + ), + }, + }, + }) +} + +func TestAccAzureRMKeyVaultPolicy_complete(t *testing.T) { + resourceName := "azurerm_key_vault_policy.test" + rs := acctest.RandString(6) + config := testAccAzureRMKeyVaultPolicy_complete(rs, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMKeyVaultDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMKeyVaultPolicyExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "create"), + resource.TestCheckResourceAttr(resourceName, "key_permissions.1", "get"), + resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), + resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "delete"), + resource.TestCheckResourceAttr(resourceName, "certificate_permissions.0", "create"), + resource.TestCheckResourceAttr(resourceName, "certificate_permissions.1", "delete"), + ), + }, + }, + }) +} + +func TestAccAzureRMKeyVaultPolicy_update(t *testing.T) { + rs := acctest.RandString(6) + resourceName := "azurerm_key_vault_policy.test" + preConfig := testAccAzureRMKeyVaultPolicy_basic(rs, testLocation()) + postConfig := testAccAzureRMKeyVaultPolicy_update(rs, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + // Using the KeyVaultDestroy checker since that ensures the policy is gone. + CheckDestroy: testCheckAzureRMKeyVaultDestroy, + Steps: []resource.TestStep{ + { + Config: preConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMKeyVaultPolicyExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "get"), + resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), + resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "set"), + ), + }, + { + Config: postConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMKeyVaultPolicyExists("azurerm_key_vault_policy.test"), + resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "list"), + resource.TestCheckResourceAttr(resourceName, "key_permissions.1", "encrypt"), + ), + }, + }, + }) +} + +func TestAccAzureRMKeyVaultPolicy_policyRemoved(t *testing.T) { + rs := acctest.RandString(6) + resourceName := "azurerm_key_vault_policy.test" + preConfig := testAccAzureRMKeyVaultPolicy_basic(rs, testLocation()) + postConfig := testAccAzureRMKeyVaultPolicy_policyRemoved(rs, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + // Using the KeyVaultDestroy checker since that ensures the policy is gone. + CheckDestroy: testCheckAzureRMKeyVaultDestroy, + Steps: []resource.TestStep{ + { + Config: preConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMKeyVaultPolicyExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "get"), + resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), + resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "set"), + ), + }, + { + Config: postConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMKeyVaultPolicyMissing("azurerm_key_vault.test"), + ), + }, + }, + }) +} + +func testCheckAzureRMKeyVaultPolicyExists(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + name := rs.Primary.Attributes["vault_name"] + resGroup := rs.Primary.Attributes["vault_resource_group"] + + client := testAccProvider.Meta().(*ArmClient).keyVaultClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + resp, err := client.Get(ctx, resGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Key Vault %q (resource group: %q) does not exist", name, resGroup) + } + + return fmt.Errorf("Bad: Get on keyVaultClient: %+v", err) + } + + objectId := rs.Primary.Attributes["object_id"] + policy := findKeyVaultAccessPolicy(objectId, resp.Properties.AccessPolicies) + + if policy == nil { + return fmt.Errorf("Bad: Key Vault Policy %q (resource group: %q, object_id: %s) does not exist", name, resGroup, objectId) + } + + return nil + } +} + +func testCheckAzureRMKeyVaultPolicyMissing(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + name := rs.Primary.Attributes["name"] + resGroup := rs.Primary.Attributes["resource_group_name"] + + client := testAccProvider.Meta().(*ArmClient).keyVaultClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + resp, err := client.Get(ctx, resGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Key Vault %q (resource group: %q) does not exist", name, resGroup) + } + + return fmt.Errorf("Bad: Get on keyVaultClient: %+v", err) + } + + objectId := rs.Primary.Attributes["tags.policy_object_id"] + + policy := findKeyVaultAccessPolicy(objectId, resp.Properties.AccessPolicies) + + if policy != nil { + return fmt.Errorf("Bad: Key Vault Policy %q (resource group: %q, object_id: %s) exists", name, resGroup, objectId) + } + + return nil + } +} + +func testAccAzureRMKeyVaultPolicy_basic(rString string, location string) string { + return fmt.Sprintf(` +data "azurerm_client_config" "current" {} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%s" + location = "%s" +} + +resource "azurerm_key_vault" "test" { + name = "acctestkv-%s" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + + sku { + name = "premium" + } + + tags { + environment = "Production" + } +} + +resource "azurerm_key_vault_policy" "test" { + vault_name = "${azurerm_key_vault.test.name}" + vault_resource_group = "${azurerm_resource_group.test.name}" + + key_permissions = [ + "get" + ] + + secret_permissions = [ + "get", + "set" + ] + + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + object_id = "${data.azurerm_client_config.current.service_principal_object_id}" +} +`, rString, location, rString) +} + +func testAccAzureRMKeyVaultPolicy_complete(rString string, location string) string { + return fmt.Sprintf(` +data "azurerm_client_config" "current" {} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%s" + location = "%s" +} + +resource "azurerm_key_vault" "test" { + name = "acctestkv-%s" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + + + sku { + name = "premium" + } + + tags { + environment = "Production" + } +} + +resource "azurerm_key_vault_policy" "test" { + vault_name = "${azurerm_key_vault.test.name}" + vault_resource_group = "${azurerm_resource_group.test.name}" + + key_permissions = [ + "create", + "get" + ] + + secret_permissions = [ + "get", + "delete" + ] + + certificate_permissions = [ + "create", + "delete" + ] + + application_id = "${data.azurerm_client_config.current.service_principal_application_id}" + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + object_id = "${data.azurerm_client_config.current.service_principal_object_id}" +} +`, rString, location, rString) +} + +func testAccAzureRMKeyVaultPolicy_update(rString string, location string) string { + return fmt.Sprintf(` +data "azurerm_client_config" "current" {} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%s" + location = "%s" +} + +resource "azurerm_key_vault" "test" { + name = "acctestkv-%s" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + + sku { + name = "premium" + } + + tags { + environment = "Production" + } +} + +resource "azurerm_key_vault_policy" "test" { + vault_name = "${azurerm_key_vault.test.name}" + vault_resource_group = "${azurerm_resource_group.test.name}" + + key_permissions = [ + "list", + "encrypt" + ] + + secret_permissions = [ + ] + + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + object_id = "${data.azurerm_client_config.current.service_principal_object_id}" +} +`, rString, location, rString) +} + +func testAccAzureRMKeyVaultPolicy_policyRemoved(rString string, location string) string { + return fmt.Sprintf(` +data "azurerm_client_config" "current" {} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%s" + location = "%s" +} + +resource "azurerm_key_vault" "test" { + name = "acctestkv-%s" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + + sku { + name = "premium" + } + + tags { + environment = "Production" + policy_object_id = "${data.azurerm_client_config.current.service_principal_object_id}" + } +} + +`, rString, location, rString) +} diff --git a/website/docs/r/key_vault.html.markdown b/website/docs/r/key_vault.html.markdown index 1a139de54abb..b6a5c3c0ec82 100644 --- a/website/docs/r/key_vault.html.markdown +++ b/website/docs/r/key_vault.html.markdown @@ -68,8 +68,8 @@ The following arguments are supported: * `tenant_id` - (Required) The Azure Active Directory tenant ID that should be used for authenticating requests to the key vault. -* `access_policy` - (Required) An access policy block as described below. At least - one policy is required up to a maximum of 16. +* `access_policy` - (Required) An access policy block as described below. A maximum of 16 + may be declared. * `enabled_for_deployment` - (Optional) Boolean flag to specify whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key diff --git a/website/docs/r/key_vault_policy.html.markdown b/website/docs/r/key_vault_policy.html.markdown new file mode 100644 index 000000000000..eb1a3ee450b7 --- /dev/null +++ b/website/docs/r/key_vault_policy.html.markdown @@ -0,0 +1,96 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_key_vault_policy" +sidebar_current: "docs-azurerm-resource-key-vault-policy" +description: |- + Create a Key Vault Access Policy. +--- + +# azurerm\_key\_vault\_policy + +Create a Key Vault Access Policy. + +~> **NOTE on Key Vaults and Key Vault Policies:** Terraform currently +provides both a standalone [Key Vault Policy Resource](key_vault_policy.html), and allows for Key Vault Access Polcies to be defined in-line within the [Key Vault Resource](key_vault.html). +At this time you cannot define Key Vault Policy with in-line Key Vault in conjunction with any Key Vault Policy resources. Doing so may cause a conflict of rule settings and will overwrite rules. + + +## Example Usage + +```hcl +resource "azurerm_resource_group" "test" { + name = "resourceGroup1" + location = "West US" +} + +resource "azurerm_key_vault" "test" { + name = "testvault" + location = "West US" + resource_group_name = "${azurerm_resource_group.test.name}" + + sku { + name = "standard" + } + + tenant_id = "d6e396d0-5584-41dc-9fc0-268df99bc610" + + enabled_for_disk_encryption = true + + tags { + environment = "Production" + } +} + +resource "azurerm_key_vault_policy" "test" { + vault_name = "${azurerm_key_vault.test.name}" + vault_resource_group = "${azurerm_key_vault.test.resource_group_name}" + + tenant_id = "d6e396d0-5584-41dc-9fc0-268df99bc610" + object_id = "d746815a-0433-4a21-b95d-fc437d2d475b" + + key_permissions = [ + "get", + ] + + secret_permissions = [ + "get", + ] + +} + +``` + +## Argument Reference + +The following arguments are supported: + +* `vault_name` - (Required) Specifies the name of the Key Vault resource. Changing this + forces a new resource to be created. + +* `vault_resource_group` - (Required) The name of the resource group in which to + create the namespace. Changing this forces a new resource to be created. + +* `tenant_id` - (Required) The Azure Active Directory tenant ID that should be used + for authenticating requests to the key vault. Must match the `tenant_id` used + above. + +* `object_id` - (Required) The object ID of a user, service principal or security + group in the Azure Active Directory tenant for the vault. The object ID must + be unique for the list of access policies. + +* `application_id` - (Optional) The object ID of an Application in Azure Active Directory. + +* `certificate_permissions` - (Optional) List of certificate permissions, must be one or more from + the following: `create`, `delete`, `deleteissuers`, `get`, `getissuers`, `import`, `list`, `listissuers`, `managecontacts`, `manageissuers`, `purge`, `recover`, `setissuers` and `update`. + +* `key_permissions` - (Required) List of key permissions, must be one or more from + the following: `backup`, `create`, `decrypt`, `delete`, `encrypt`, `get`, `import`, `list`, `purge`, `recover`, `restore`, `sign`, `unwrapKey`, `update`, `verify` and `wrapKey`. + +* `secret_permissions` - (Required) List of secret permissions, must be one or more + from the following: `backup`, `delete`, `get`, `list`, `purge`, `recover`, `restore` and `set`. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The Vault ID. From aae88448eb908c96762e0d3d13075fa3c9baeeaa Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Fri, 4 May 2018 14:52:53 -0400 Subject: [PATCH 02/23] Updated to fix the test broken from updating the source code. We don't need to wait for keyvaults creationg as we aren't creating keyvaults --- azurerm/resource_arm_key_vault_policy.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/azurerm/resource_arm_key_vault_policy.go b/azurerm/resource_arm_key_vault_policy.go index eee5d094dbc7..3efdb994a1e2 100644 --- a/azurerm/resource_arm_key_vault_policy.go +++ b/azurerm/resource_arm_key_vault_policy.go @@ -3,10 +3,8 @@ package azurerm import ( "fmt" "log" - "time" "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" - "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" uuid "github.com/satori/go.uuid" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" @@ -129,17 +127,6 @@ func resourceArmKeyVaultPolicyCreateOrDelete(d *schema.ResourceData, meta interf d.SetId(*read.ID) - if d.IsNewResource() { - if props := read.Properties; props != nil { - if vault := props.VaultURI; vault != nil { - err := resource.Retry(120*time.Second, checkKeyVaultDNSIsAvailable(*vault)) - if err != nil { - return err - } - } - } - } - return resourceArmKeyVaultRead(d, meta) } From 24df15d2af9189d0ae11716e43ca3ed4b3ed971d Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Tue, 8 May 2018 00:50:50 -0400 Subject: [PATCH 03/23] Addressed PR comments --- azurerm/resource_arm_key_vault.go | 1 - azurerm/resource_arm_key_vault_policy.go | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/azurerm/resource_arm_key_vault.go b/azurerm/resource_arm_key_vault.go index 4a0a0690bf36..d038089e99f4 100644 --- a/azurerm/resource_arm_key_vault.go +++ b/azurerm/resource_arm_key_vault.go @@ -76,7 +76,6 @@ func resourceArmKeyVault() *schema.Resource { "access_policy": { Type: schema.TypeList, Optional: true, - MinItems: 0, MaxItems: 16, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ diff --git a/azurerm/resource_arm_key_vault_policy.go b/azurerm/resource_arm_key_vault_policy.go index 3efdb994a1e2..8c886f006939 100644 --- a/azurerm/resource_arm_key_vault_policy.go +++ b/azurerm/resource_arm_key_vault_policy.go @@ -102,7 +102,6 @@ func resourceArmKeyVaultPolicyCreateOrDelete(d *schema.ResourceData, meta interf log.Printf("[INFO] preparing arguments for Azure ARM Policy: %s.", action) name := d.Get("vault_name").(string) - //location := azureRMNormalizeLocation(d.Get("vault_location").(string)) resGroup := d.Get("vault_resource_group").(string) parameters := keyvault.VaultAccessPolicyParameters{ @@ -125,7 +124,9 @@ func resourceArmKeyVaultPolicyCreateOrDelete(d *schema.ResourceData, meta interf return fmt.Errorf("cannot read KeyVault %s (resource group %s) ID", name, resGroup) } - d.SetId(*read.ID) + if action != keyvault.Remove { + d.SetId(*read.ID) + } return resourceArmKeyVaultRead(d, meta) } From 000963eb9509aa0a734eca9835cbc7244b605c30 Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Tue, 8 May 2018 21:23:41 -0400 Subject: [PATCH 04/23] Return nil on a delete for the shared delete/update function --- azurerm/resource_arm_key_vault_policy.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/azurerm/resource_arm_key_vault_policy.go b/azurerm/resource_arm_key_vault_policy.go index 8c886f006939..05d2aeb06a97 100644 --- a/azurerm/resource_arm_key_vault_policy.go +++ b/azurerm/resource_arm_key_vault_policy.go @@ -126,9 +126,10 @@ func resourceArmKeyVaultPolicyCreateOrDelete(d *schema.ResourceData, meta interf if action != keyvault.Remove { d.SetId(*read.ID) + return resourceArmKeyVaultRead(d, meta) + } else { + return nil } - - return resourceArmKeyVaultRead(d, meta) } func resourceArmKeyVaultPolicyCreate(d *schema.ResourceData, meta interface{}) error { From 6490dad6426ee125a731820a062db46a7f89c68f Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Mon, 14 May 2018 15:04:06 -0400 Subject: [PATCH 05/23] Removed reference to old code --- azurerm/resource_arm_key_vault.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/azurerm/resource_arm_key_vault.go b/azurerm/resource_arm_key_vault.go index 9d19233397aa..ac6a21d1e2c1 100644 --- a/azurerm/resource_arm_key_vault.go +++ b/azurerm/resource_arm_key_vault.go @@ -221,9 +221,6 @@ func resourceArmKeyVaultRead(d *schema.ResourceData, meta interface{}) error { if err := d.Set("sku", flattenKeyVaultSku(props.Sku)); err != nil { return fmt.Errorf("Error flattening `sku` for KeyVault %q: %+v", resp.Name, err) } - if err := d.Set("access_policy", flattenKeyVaultAccessPolicies(props.AccessPolicies)); err != nil { - return fmt.Errorf("Error flattening `access_policy` for KeyVault %q: %+v", resp.Name, err) - } d.Set("vault_uri", props.VaultURI) } From 56dadaabc5d5ce7450f7896d2b9826a5a153bc7e Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Wed, 23 May 2018 15:21:34 -0400 Subject: [PATCH 06/23] Starting to address PR comments --- ...> resource_arm_key_vault_access_policy.go} | 0 ...ource_arm_key_vault_access_policy_test.go} | 58 +++++++++---------- 2 files changed, 29 insertions(+), 29 deletions(-) rename azurerm/{resource_arm_key_vault_policy.go => resource_arm_key_vault_access_policy.go} (100%) rename azurerm/{resource_arm_key_vault_policy_test.go => resource_arm_key_vault_access_policy_test.go} (81%) diff --git a/azurerm/resource_arm_key_vault_policy.go b/azurerm/resource_arm_key_vault_access_policy.go similarity index 100% rename from azurerm/resource_arm_key_vault_policy.go rename to azurerm/resource_arm_key_vault_access_policy.go diff --git a/azurerm/resource_arm_key_vault_policy_test.go b/azurerm/resource_arm_key_vault_access_policy_test.go similarity index 81% rename from azurerm/resource_arm_key_vault_policy_test.go rename to azurerm/resource_arm_key_vault_access_policy_test.go index f110103eb1c2..147fe6b935d1 100644 --- a/azurerm/resource_arm_key_vault_policy_test.go +++ b/azurerm/resource_arm_key_vault_access_policy_test.go @@ -10,10 +10,10 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -func TestAccAzureRMKeyVaultPolicy_basic(t *testing.T) { - resourceName := "azurerm_key_vault_policy.test" +func TestAccAzureRMKeyVaultAccessPolicy_basic(t *testing.T) { + resourceName := "azurerm_key_vault_access_policy.test" rs := acctest.RandString(6) - config := testAccAzureRMKeyVaultPolicy_basic(rs, testLocation()) + config := testAccAzureRMKeyVaultAccessPolicy_basic(rs, testLocation()) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -23,7 +23,7 @@ func TestAccAzureRMKeyVaultPolicy_basic(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultPolicyExists(resourceName), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "set"), @@ -33,10 +33,10 @@ func TestAccAzureRMKeyVaultPolicy_basic(t *testing.T) { }) } -func TestAccAzureRMKeyVaultPolicy_complete(t *testing.T) { - resourceName := "azurerm_key_vault_policy.test" +func TestAccAzureRMKeyVaultAccessPolicy_complete(t *testing.T) { + resourceName := "azurerm_key_vault_access_policy.test" rs := acctest.RandString(6) - config := testAccAzureRMKeyVaultPolicy_complete(rs, testLocation()) + config := testAccAzureRMKeyVaultAccessPolicy_complete(rs, testLocation()) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -46,7 +46,7 @@ func TestAccAzureRMKeyVaultPolicy_complete(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultPolicyExists(resourceName), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "create"), resource.TestCheckResourceAttr(resourceName, "key_permissions.1", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), @@ -59,11 +59,11 @@ func TestAccAzureRMKeyVaultPolicy_complete(t *testing.T) { }) } -func TestAccAzureRMKeyVaultPolicy_update(t *testing.T) { +func TestAccAzureRMKeyVaultAccessPolicy_update(t *testing.T) { rs := acctest.RandString(6) - resourceName := "azurerm_key_vault_policy.test" - preConfig := testAccAzureRMKeyVaultPolicy_basic(rs, testLocation()) - postConfig := testAccAzureRMKeyVaultPolicy_update(rs, testLocation()) + resourceName := "azurerm_key_vault_access_policy.test" + preConfig := testAccAzureRMKeyVaultAccessPolicy_basic(rs, testLocation()) + postConfig := testAccAzureRMKeyVaultAccessPolicy_update(rs, testLocation()) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -74,7 +74,7 @@ func TestAccAzureRMKeyVaultPolicy_update(t *testing.T) { { Config: preConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultPolicyExists(resourceName), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "set"), @@ -83,7 +83,7 @@ func TestAccAzureRMKeyVaultPolicy_update(t *testing.T) { { Config: postConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultPolicyExists("azurerm_key_vault_policy.test"), + testCheckAzureRMKeyVaultAccessPolicyExists("azurerm_key_vault_access_policy.test"), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "list"), resource.TestCheckResourceAttr(resourceName, "key_permissions.1", "encrypt"), ), @@ -92,11 +92,11 @@ func TestAccAzureRMKeyVaultPolicy_update(t *testing.T) { }) } -func TestAccAzureRMKeyVaultPolicy_policyRemoved(t *testing.T) { +func TestAccAzureRMKeyVaultAccessPolicy_policyRemoved(t *testing.T) { rs := acctest.RandString(6) - resourceName := "azurerm_key_vault_policy.test" - preConfig := testAccAzureRMKeyVaultPolicy_basic(rs, testLocation()) - postConfig := testAccAzureRMKeyVaultPolicy_policyRemoved(rs, testLocation()) + resourceName := "azurerm_key_vault_access_policy.test" + preConfig := testAccAzureRMKeyVaultAccessPolicy_basic(rs, testLocation()) + postConfig := testAccAzureRMKeyVaultAccessPolicy_policyRemoved(rs, testLocation()) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -107,7 +107,7 @@ func TestAccAzureRMKeyVaultPolicy_policyRemoved(t *testing.T) { { Config: preConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultPolicyExists(resourceName), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "set"), @@ -116,14 +116,14 @@ func TestAccAzureRMKeyVaultPolicy_policyRemoved(t *testing.T) { { Config: postConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultPolicyMissing("azurerm_key_vault.test"), + testCheckAzureRMKeyVaultAccessPolicyMissing("azurerm_key_vault_access_policy.test"), ), }, }, }) } -func testCheckAzureRMKeyVaultPolicyExists(name string) resource.TestCheckFunc { +func testCheckAzureRMKeyVaultAccessPolicyExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure we have enough information in state to look up in API rs, ok := s.RootModule().Resources[name] @@ -156,7 +156,7 @@ func testCheckAzureRMKeyVaultPolicyExists(name string) resource.TestCheckFunc { } } -func testCheckAzureRMKeyVaultPolicyMissing(name string) resource.TestCheckFunc { +func testCheckAzureRMKeyVaultAccessPolicyMissing(name string) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure we have enough information in state to look up in API rs, ok := s.RootModule().Resources[name] @@ -190,7 +190,7 @@ func testCheckAzureRMKeyVaultPolicyMissing(name string) resource.TestCheckFunc { } } -func testAccAzureRMKeyVaultPolicy_basic(rString string, location string) string { +func testAccAzureRMKeyVaultAccessPolicy_basic(rString string, location string) string { return fmt.Sprintf(` data "azurerm_client_config" "current" {} @@ -214,7 +214,7 @@ resource "azurerm_key_vault" "test" { } } -resource "azurerm_key_vault_policy" "test" { +resource "azurerm_key_vault_access_policy" "test" { vault_name = "${azurerm_key_vault.test.name}" vault_resource_group = "${azurerm_resource_group.test.name}" @@ -233,7 +233,7 @@ resource "azurerm_key_vault_policy" "test" { `, rString, location, rString) } -func testAccAzureRMKeyVaultPolicy_complete(rString string, location string) string { +func testAccAzureRMKeyVaultAccessPolicy_complete(rString string, location string) string { return fmt.Sprintf(` data "azurerm_client_config" "current" {} @@ -258,7 +258,7 @@ resource "azurerm_key_vault" "test" { } } -resource "azurerm_key_vault_policy" "test" { +resource "azurerm_key_vault_access_policy" "test" { vault_name = "${azurerm_key_vault.test.name}" vault_resource_group = "${azurerm_resource_group.test.name}" @@ -284,7 +284,7 @@ resource "azurerm_key_vault_policy" "test" { `, rString, location, rString) } -func testAccAzureRMKeyVaultPolicy_update(rString string, location string) string { +func testAccAzureRMKeyVaultAccessPolicy_update(rString string, location string) string { return fmt.Sprintf(` data "azurerm_client_config" "current" {} @@ -308,7 +308,7 @@ resource "azurerm_key_vault" "test" { } } -resource "azurerm_key_vault_policy" "test" { +resource "azurerm_key_vault_access_policy" "test" { vault_name = "${azurerm_key_vault.test.name}" vault_resource_group = "${azurerm_resource_group.test.name}" @@ -326,7 +326,7 @@ resource "azurerm_key_vault_policy" "test" { `, rString, location, rString) } -func testAccAzureRMKeyVaultPolicy_policyRemoved(rString string, location string) string { +func testAccAzureRMKeyVaultAccessPolicy_policyRemoved(rString string, location string) string { return fmt.Sprintf(` data "azurerm_client_config" "current" {} From 2422a1f2b3ca8bad7457753aea006c45e66ffd5b Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Wed, 23 May 2018 15:21:52 -0400 Subject: [PATCH 07/23] Starting to address PR comments --- azurerm/provider.go | 2 +- azurerm/resource_arm_key_vault.go | 40 +++++++++++++++++++ .../resource_arm_key_vault_access_policy.go | 26 ++++++------ 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/azurerm/provider.go b/azurerm/provider.go index f7bd4dbba75a..102cff225ccd 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -153,10 +153,10 @@ func Provider() terraform.ResourceProvider { "azurerm_image": resourceArmImage(), "azurerm_iothub": resourceArmIotHub(), "azurerm_key_vault": resourceArmKeyVault(), + "azurerm_key_vault_access_policy": resourceArmKeyVaultAccessPolicy(), "azurerm_key_vault_certificate": resourceArmKeyVaultCertificate(), "azurerm_key_vault_key": resourceArmKeyVaultKey(), "azurerm_key_vault_secret": resourceArmKeyVaultSecret(), - "azurerm_key_vault_policy": resourceArmKeyVaultPolicy(), "azurerm_kubernetes_cluster": resourceArmKubernetesCluster(), "azurerm_lb": resourceArmLoadBalancer(), "azurerm_lb_backend_address_pool": resourceArmLoadBalancerBackendAddressPool(), diff --git a/azurerm/resource_arm_key_vault.go b/azurerm/resource_arm_key_vault.go index ac6a21d1e2c1..679904820dfc 100644 --- a/azurerm/resource_arm_key_vault.go +++ b/azurerm/resource_arm_key_vault.go @@ -76,6 +76,7 @@ func resourceArmKeyVault() *schema.Resource { "access_policy": { Type: schema.TypeList, Optional: true, + Computed: true, MaxItems: 16, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -314,6 +315,45 @@ func flattenKeyVaultSku(sku *keyvault.Sku) []interface{} { return []interface{}{result} } + +func flattenKeyVaultAccessPolicies(policies *[]keyvault.AccessPolicyEntry) []interface{} { + result := make([]interface{}, 0, len(*policies)) + + for _, policy := range *policies { + policyRaw := make(map[string]interface{}) + + keyPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Keys)) + for _, keyPermission := range *policy.Permissions.Keys { + keyPermissionsRaw = append(keyPermissionsRaw, string(keyPermission)) + } + + secretPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Secrets)) + for _, secretPermission := range *policy.Permissions.Secrets { + secretPermissionsRaw = append(secretPermissionsRaw, string(secretPermission)) + } + + policyRaw["tenant_id"] = policy.TenantID.String() + policyRaw["object_id"] = *policy.ObjectID + if policy.ApplicationID != nil { + policyRaw["application_id"] = policy.ApplicationID.String() + } + policyRaw["key_permissions"] = keyPermissionsRaw + policyRaw["secret_permissions"] = secretPermissionsRaw + + if policy.Permissions.Certificates != nil { + certificatePermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Certificates)) + for _, certificatePermission := range *policy.Permissions.Certificates { + certificatePermissionsRaw = append(certificatePermissionsRaw, string(certificatePermission)) + } + policyRaw["certificate_permissions"] = certificatePermissionsRaw + } + + result = append(result, policyRaw) + } + + return result +} + func validateKeyVaultName(v interface{}, k string) (ws []string, errors []error) { value := v.(string) if matched := regexp.MustCompile(`^[a-zA-Z0-9-]{3,24}$`).Match([]byte(value)); !matched { diff --git a/azurerm/resource_arm_key_vault_access_policy.go b/azurerm/resource_arm_key_vault_access_policy.go index 05d2aeb06a97..b68ae86e526f 100644 --- a/azurerm/resource_arm_key_vault_access_policy.go +++ b/azurerm/resource_arm_key_vault_access_policy.go @@ -10,12 +10,12 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -func resourceArmKeyVaultPolicy() *schema.Resource { +func resourceArmKeyVaultAccessPolicy() *schema.Resource { return &schema.Resource{ - Create: resourceArmKeyVaultPolicyCreate, - Read: resourceArmKeyVaultPolicyRead, - Update: resourceArmKeyVaultPolicyUpdate, - Delete: resourceArmKeyVaultPolicyDelete, + Create: resourceArmKeyVaultAccessPolicyCreate, + Read: resourceArmKeyVaultAccessPolicyRead, + Update: resourceArmKeyVaultAccessPolicyUpdate, + Delete: resourceArmKeyVaultAccessPolicyDelete, Schema: map[string]*schema.Schema{ "vault_name": { @@ -96,7 +96,7 @@ func createKeyVaultAccessPolicy(d *schema.ResourceData) *keyvault.AccessPolicyEn } -func resourceArmKeyVaultPolicyCreateOrDelete(d *schema.ResourceData, meta interface{}, action keyvault.AccessPolicyUpdateKind) error { +func resourceArmKeyVaultAccessPolicyCreateOrDelete(d *schema.ResourceData, meta interface{}, action keyvault.AccessPolicyUpdateKind) error { client := meta.(*ArmClient).keyVaultClient ctx := meta.(*ArmClient).StopContext log.Printf("[INFO] preparing arguments for Azure ARM Policy: %s.", action) @@ -132,19 +132,19 @@ func resourceArmKeyVaultPolicyCreateOrDelete(d *schema.ResourceData, meta interf } } -func resourceArmKeyVaultPolicyCreate(d *schema.ResourceData, meta interface{}) error { - return resourceArmKeyVaultPolicyCreateOrDelete(d, meta, keyvault.Add) +func resourceArmKeyVaultAccessPolicyCreate(d *schema.ResourceData, meta interface{}) error { + return resourceArmKeyVaultAccessPolicyCreateOrDelete(d, meta, keyvault.Add) } -func resourceArmKeyVaultPolicyDelete(d *schema.ResourceData, meta interface{}) error { - return resourceArmKeyVaultPolicyCreateOrDelete(d, meta, keyvault.Remove) +func resourceArmKeyVaultAccessPolicyDelete(d *schema.ResourceData, meta interface{}) error { + return resourceArmKeyVaultAccessPolicyCreateOrDelete(d, meta, keyvault.Remove) } -func resourceArmKeyVaultPolicyUpdate(d *schema.ResourceData, meta interface{}) error { - return resourceArmKeyVaultPolicyCreateOrDelete(d, meta, keyvault.Replace) +func resourceArmKeyVaultAccessPolicyUpdate(d *schema.ResourceData, meta interface{}) error { + return resourceArmKeyVaultAccessPolicyCreateOrDelete(d, meta, keyvault.Replace) } -func resourceArmKeyVaultPolicyRead(d *schema.ResourceData, meta interface{}) error { +func resourceArmKeyVaultAccessPolicyRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*ArmClient).keyVaultClient ctx := meta.(*ArmClient).StopContext From 4638772b3c8bd40bddad55c1145fc90696166655 Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Thu, 24 May 2018 22:41:02 -0400 Subject: [PATCH 08/23] Working my way through the PR comments --- ...t_policy.go => key_vault_access_policy.go} | 65 +++++++ azurerm/resource_arm_key_vault.go | 180 ++++++------------ .../resource_arm_key_vault_access_policy.go | 134 +++++-------- ...source_arm_key_vault_access_policy_test.go | 78 ++++---- website/azurerm.erb | 4 + website/docs/r/key_vault.html.markdown | 6 +- ... => key_vault_access_policy.html.markdown} | 31 +-- 7 files changed, 233 insertions(+), 265 deletions(-) rename azurerm/{key_vault_policy.go => key_vault_access_policy.go} (50%) rename website/docs/r/{key_vault_policy.html.markdown => key_vault_access_policy.html.markdown} (73%) diff --git a/azurerm/key_vault_policy.go b/azurerm/key_vault_access_policy.go similarity index 50% rename from azurerm/key_vault_policy.go rename to azurerm/key_vault_access_policy.go index af1d31b8b27d..8d4af37cd911 100644 --- a/azurerm/key_vault_policy.go +++ b/azurerm/key_vault_access_policy.go @@ -82,3 +82,68 @@ func certificatePermissionsSchema() *schema.Schema { }, } } + +func flattenKeyVaultAccessPolicies(policies *[]keyvault.AccessPolicyEntry) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(*policies)) + + for _, policy := range *policies { + policyRaw := make(map[string]interface{}) + + keyPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Keys)) + for _, keyPermission := range *policy.Permissions.Keys { + keyPermissionsRaw = append(keyPermissionsRaw, string(keyPermission)) + } + + secretPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Secrets)) + for _, secretPermission := range *policy.Permissions.Secrets { + secretPermissionsRaw = append(secretPermissionsRaw, string(secretPermission)) + } + + policyRaw["tenant_id"] = policy.TenantID.String() + policyRaw["object_id"] = *policy.ObjectID + if policy.ApplicationID != nil { + policyRaw["application_id"] = policy.ApplicationID.String() + } + policyRaw["key_permissions"] = keyPermissionsRaw + policyRaw["secret_permissions"] = secretPermissionsRaw + + if policy.Permissions.Certificates != nil { + certificatePermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Certificates)) + for _, certificatePermission := range *policy.Permissions.Certificates { + certificatePermissionsRaw = append(certificatePermissionsRaw, string(certificatePermission)) + } + policyRaw["certificate_permissions"] = certificatePermissionsRaw + } + + result = append(result, policyRaw) + } + + return result +} + +func expandKeyVaultAccessPolicyCertificatePermissions(certificatePermissionsRaw []interface{}) *[]keyvault.CertificatePermissions { + certificatePermissions := []keyvault.CertificatePermissions{} + + for _, permission := range certificatePermissionsRaw { + certificatePermissions = append(certificatePermissions, keyvault.CertificatePermissions(permission.(string))) + } + return &certificatePermissions +} + +func expandKeyVaultAccessPolicyKeyPermissions(keyPermissionsRaw []interface{}) *[]keyvault.KeyPermissions { + keyPermissions := []keyvault.KeyPermissions{} + + for _, permission := range keyPermissionsRaw { + keyPermissions = append(keyPermissions, keyvault.KeyPermissions(permission.(string))) + } + return &keyPermissions +} + +func expandKeyVaultAccessPolicySecretPermissions(secretPermissionsRaw []interface{}) *[]keyvault.SecretPermissions { + secretPermissions := []keyvault.SecretPermissions{} + + for _, permission := range secretPermissionsRaw { + secretPermissions = append(secretPermissions, keyvault.SecretPermissions(permission.(string))) + } + return &secretPermissions +} diff --git a/azurerm/resource_arm_key_vault.go b/azurerm/resource_arm_key_vault.go index 679904820dfc..36017651bb34 100644 --- a/azurerm/resource_arm_key_vault.go +++ b/azurerm/resource_arm_key_vault.go @@ -12,7 +12,7 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" - "github.com/satori/go.uuid" + uuid "github.com/satori/go.uuid" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -21,6 +21,8 @@ import ( // https://github.com/Azure/azure-rest-api-specs/blob/master/arm-keyvault/2015-06-01/swagger/keyvault.json#L239 var armKeyVaultSkuFamily = "A" +var keyVaultResourceName = "azurerm_key_vault" + func resourceArmKeyVault() *schema.Resource { return &schema.Resource{ Create: resourceArmKeyVaultCreate, @@ -149,14 +151,17 @@ func resourceArmKeyVaultCreate(d *schema.ResourceData, meta interface{}) error { Tags: expandTags(tags), } + azureRMLockByName(name, keyVaultResourceName) + defer azureRMUnlockByName(name, keyVaultResourceName) + _, err := client.CreateOrUpdate(ctx, resGroup, name, parameters) if err != nil { - return err + return fmt.Errorf("Error updating Key Vault (Key Vault %q / Resource Group %q): %+v", name, resGroup, err) } read, err := client.Get(ctx, resGroup, name) if err != nil { - return err + return fmt.Errorf("Error retrieving Key Vault %q (Resource Group %q): %+v", name, resGroup, err) } if read.ID == nil { return fmt.Errorf("Cannot read KeyVault %s (resource group %s) ID", name, resGroup) @@ -167,19 +172,9 @@ func resourceArmKeyVaultCreate(d *schema.ResourceData, meta interface{}) error { if d.IsNewResource() { if props := read.Properties; props != nil { if vault := props.VaultURI; vault != nil { - log.Printf("[DEBUG] Waiting for Key Vault %q (Resource Group %q) to become available", name, resGroup) - stateConf := &resource.StateChangeConf{ - Pending: []string{"pending"}, - Target: []string{"available"}, - Refresh: keyVaultRefreshFunc(*vault), - Timeout: 30 * time.Minute, - Delay: 30 * time.Second, - PollInterval: 10 * time.Second, - ContinuousTargetOccurence: 10, - } - - if _, err := stateConf.WaitForState(); err != nil { - return fmt.Errorf("Error waiting for Key Vault %q (Resource Group %q) to become available: %s", name, resGroup, err) + err := resource.Retry(120*time.Second, checkKeyVaultDNSIsAvailable(*vault)) + if err != nil { + return err } } } @@ -213,19 +208,16 @@ func resourceArmKeyVaultRead(d *schema.ResourceData, meta interface{}) error { if location := resp.Location; location != nil { d.Set("location", azureRMNormalizeLocation(*location)) } - - if props := resp.Properties; props != nil { - d.Set("tenant_id", props.TenantID.String()) - d.Set("enabled_for_deployment", props.EnabledForDeployment) - d.Set("enabled_for_disk_encryption", props.EnabledForDiskEncryption) - d.Set("enabled_for_template_deployment", props.EnabledForTemplateDeployment) - if err := d.Set("sku", flattenKeyVaultSku(props.Sku)); err != nil { - return fmt.Errorf("Error flattening `sku` for KeyVault %q: %+v", resp.Name, err) - } - d.Set("vault_uri", props.VaultURI) - } + d.Set("tenant_id", resp.Properties.TenantID.String()) + d.Set("enabled_for_deployment", resp.Properties.EnabledForDeployment) + d.Set("enabled_for_disk_encryption", resp.Properties.EnabledForDiskEncryption) + d.Set("enabled_for_template_deployment", resp.Properties.EnabledForTemplateDeployment) + d.Set("sku", flattenKeyVaultSku(resp.Properties.Sku)) + d.Set("access_policy", flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) + d.Set("vault_uri", resp.Properties.VaultURI) flattenAndSetTags(d, resp.Tags) + return nil } @@ -255,6 +247,40 @@ func expandKeyVaultSku(d *schema.ResourceData) *keyvault.Sku { } } +func flattenKeyVaultSku(sku *keyvault.Sku) []interface{} { + result := map[string]interface{}{ + "name": string(sku.Name), + } + + return []interface{}{result} +} + +func validateKeyVaultName(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + if matched := regexp.MustCompile(`^[a-zA-Z0-9-]{3,24}$`).Match([]byte(value)); !matched { + errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters and dashes and must be between 3-24 chars", k)) + } + + return +} + +func checkKeyVaultDNSIsAvailable(vaultUri string) func() *resource.RetryError { + return func() *resource.RetryError { + uri, err := url.Parse(vaultUri) + if err != nil { + return resource.NonRetryableError(err) + } + + conn, err := net.Dial("tcp", fmt.Sprintf("%s:443", uri.Host)) + if err != nil { + return resource.RetryableError(err) + } + + _ = conn.Close() + return nil + } +} + func expandKeyVaultAccessPolicies(d *schema.ResourceData) *[]keyvault.AccessPolicyEntry { policies := d.Get("access_policy").([]interface{}) result := make([]keyvault.AccessPolicyEntry, 0, len(policies)) @@ -263,31 +289,14 @@ func expandKeyVaultAccessPolicies(d *schema.ResourceData) *[]keyvault.AccessPoli policyRaw := policySet.(map[string]interface{}) certificatePermissionsRaw := policyRaw["certificate_permissions"].([]interface{}) - certificatePermissions := make([]keyvault.CertificatePermissions, 0) - for _, v := range certificatePermissionsRaw { - permission := keyvault.CertificatePermissions(v.(string)) - certificatePermissions = append(certificatePermissions, permission) - } - keyPermissionsRaw := policyRaw["key_permissions"].([]interface{}) - keyPermissions := make([]keyvault.KeyPermissions, 0) - for _, v := range keyPermissionsRaw { - permission := keyvault.KeyPermissions(v.(string)) - keyPermissions = append(keyPermissions, permission) - } - secretPermissionsRaw := policyRaw["secret_permissions"].([]interface{}) - secretPermissions := make([]keyvault.SecretPermissions, 0) - for _, v := range secretPermissionsRaw { - permission := keyvault.SecretPermissions(v.(string)) - secretPermissions = append(secretPermissions, permission) - } policy := keyvault.AccessPolicyEntry{ Permissions: &keyvault.Permissions{ - Certificates: &certificatePermissions, - Keys: &keyPermissions, - Secrets: &secretPermissions, + Certificates: expandKeyVaultAccessPolicyCertificatePermissions(certificatePermissionsRaw), + Keys: expandKeyVaultAccessPolicyKeyPermissions(keyPermissionsRaw), + Secrets: expandKeyVaultAccessPolicySecretPermissions(secretPermissionsRaw), }, } @@ -306,80 +315,3 @@ func expandKeyVaultAccessPolicies(d *schema.ResourceData) *[]keyvault.AccessPoli return &result } - -func flattenKeyVaultSku(sku *keyvault.Sku) []interface{} { - result := map[string]interface{}{ - "name": string(sku.Name), - } - - return []interface{}{result} -} - - -func flattenKeyVaultAccessPolicies(policies *[]keyvault.AccessPolicyEntry) []interface{} { - result := make([]interface{}, 0, len(*policies)) - - for _, policy := range *policies { - policyRaw := make(map[string]interface{}) - - keyPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Keys)) - for _, keyPermission := range *policy.Permissions.Keys { - keyPermissionsRaw = append(keyPermissionsRaw, string(keyPermission)) - } - - secretPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Secrets)) - for _, secretPermission := range *policy.Permissions.Secrets { - secretPermissionsRaw = append(secretPermissionsRaw, string(secretPermission)) - } - - policyRaw["tenant_id"] = policy.TenantID.String() - policyRaw["object_id"] = *policy.ObjectID - if policy.ApplicationID != nil { - policyRaw["application_id"] = policy.ApplicationID.String() - } - policyRaw["key_permissions"] = keyPermissionsRaw - policyRaw["secret_permissions"] = secretPermissionsRaw - - if policy.Permissions.Certificates != nil { - certificatePermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Certificates)) - for _, certificatePermission := range *policy.Permissions.Certificates { - certificatePermissionsRaw = append(certificatePermissionsRaw, string(certificatePermission)) - } - policyRaw["certificate_permissions"] = certificatePermissionsRaw - } - - result = append(result, policyRaw) - } - - return result -} - -func validateKeyVaultName(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - if matched := regexp.MustCompile(`^[a-zA-Z0-9-]{3,24}$`).Match([]byte(value)); !matched { - errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters and dashes and must be between 3-24 chars", k)) - } - return -} - -func keyVaultRefreshFunc(vaultUri string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - log.Printf("[DEBUG] Checking to see if KeyVault %q is available..", vaultUri) - uri, err := url.Parse(vaultUri) - if err != nil { - return nil, "error", fmt.Errorf("Error parsing URI %q: %s", vaultUri, err) - } - - hostAndPort := fmt.Sprintf("%s:443", uri.Host) - conn, err := net.Dial("tcp", hostAndPort) - if err != nil { - log.Printf("[DEBUG] Didn't find KeyVault at %q", hostAndPort) - return nil, "pending", fmt.Errorf("Error connecting to %q: %s", hostAndPort, err) - } - - _ = conn.Close() - - log.Printf("[DEBUG] Found KeyVault at %q", hostAndPort) - return "available", "available", nil - } -} diff --git a/azurerm/resource_arm_key_vault_access_policy.go b/azurerm/resource_arm_key_vault_access_policy.go index b68ae86e526f..35ef98fe41af 100644 --- a/azurerm/resource_arm_key_vault_access_policy.go +++ b/azurerm/resource_arm_key_vault_access_policy.go @@ -5,6 +5,7 @@ import ( "log" "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" + "github.com/davecgh/go-spew/spew" "github.com/hashicorp/terraform/helper/schema" uuid "github.com/satori/go.uuid" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" @@ -24,7 +25,7 @@ func resourceArmKeyVaultAccessPolicy() *schema.Resource { ForceNew: true, }, - "vault_resource_group": { + "resource_group_name": { Type: schema.TypeString, Required: true, ForceNew: true, @@ -54,82 +55,50 @@ func resourceArmKeyVaultAccessPolicy() *schema.Resource { } } -func createKeyVaultAccessPolicy(d *schema.ResourceData) *keyvault.AccessPolicyEntry { - - certificatePermissionsRaw := d.Get("certificate_permissions").([]interface{}) - certificatePermissions := []keyvault.CertificatePermissions{} - for _, permission := range certificatePermissionsRaw { - certificatePermissions = append(certificatePermissions, keyvault.CertificatePermissions(permission.(string))) - } - - keyPermissionsRaw := d.Get("key_permissions").([]interface{}) - keyPermissions := []keyvault.KeyPermissions{} - for _, permission := range keyPermissionsRaw { - keyPermissions = append(keyPermissions, keyvault.KeyPermissions(permission.(string))) - } - - secretPermissionsRaw := d.Get("secret_permissions").([]interface{}) - secretPermissions := []keyvault.SecretPermissions{} - for _, permission := range secretPermissionsRaw { - secretPermissions = append(secretPermissions, keyvault.SecretPermissions(permission.(string))) - } - - policy := keyvault.AccessPolicyEntry{ - Permissions: &keyvault.Permissions{ - Certificates: &certificatePermissions, - Keys: &keyPermissions, - Secrets: &secretPermissions, - }, - } - - tenantUUID := uuid.FromStringOrNil(d.Get("tenant_id").(string)) - policy.TenantID = &tenantUUID - objectUUID := d.Get("object_id").(string) - policy.ObjectID = &objectUUID - - if v := d.Get("application_id"); v != "" { - applicationUUID := uuid.FromStringOrNil(v.(string)) - policy.ApplicationID = &applicationUUID - } - - return &policy - -} - func resourceArmKeyVaultAccessPolicyCreateOrDelete(d *schema.ResourceData, meta interface{}, action keyvault.AccessPolicyUpdateKind) error { client := meta.(*ArmClient).keyVaultClient ctx := meta.(*ArmClient).StopContext - log.Printf("[INFO] preparing arguments for Azure ARM Policy: %s.", action) + log.Printf("[INFO]Preparing arguments for Key Vault Access Policy: %s.", action) name := d.Get("vault_name").(string) - resGroup := d.Get("vault_resource_group").(string) + resGroup := d.Get("resource_group_name").(string) + + accessPolicy := expandKeyVaultAccessPolicy(d) + accessPolicies := []keyvault.AccessPolicyEntry{accessPolicy} + + log.Printf("SPEW: %s", spew.Sdump(accessPolicies)) parameters := keyvault.VaultAccessPolicyParameters{ Name: &name, Properties: &keyvault.VaultAccessPolicyProperties{ - AccessPolicies: &[]keyvault.AccessPolicyEntry{*createKeyVaultAccessPolicy(d)}, + AccessPolicies: &accessPolicies, }, } + //return fmt.Errorf("Error updating Key Vault Access Policy: %+v ApplicationID: %s", accessPolicies, d.Get("application_id").(string)) + + azureRMLockByName(name, keyVaultResourceName) + defer azureRMUnlockByName(name, keyVaultResourceName) + _, err := client.UpdateAccessPolicy(ctx, resGroup, name, action, parameters) if err != nil { - return err + return fmt.Errorf("Error updating Key Vault Access Policy (Key Vault %q / Resource Group %q): %+v", name, resGroup, err) } read, err := client.Get(ctx, resGroup, name) if err != nil { - return err + return fmt.Errorf("Error retrieving Key Vault %q (Resource Group %q): %+v", name, resGroup, err) } + if read.ID == nil { return fmt.Errorf("cannot read KeyVault %s (resource group %s) ID", name, resGroup) } - if action != keyvault.Remove { + if d.IsNewResource() { d.SetId(*read.ID) - return resourceArmKeyVaultRead(d, meta) - } else { - return nil } + + return nil } func resourceArmKeyVaultAccessPolicyCreate(d *schema.ResourceData, meta interface{}) error { @@ -166,11 +135,13 @@ func resourceArmKeyVaultAccessPolicyRead(d *schema.ResourceData, meta interface{ return fmt.Errorf("Error making Read request on Azure KeyVault %s: %+v", name, err) } - policy := findKeyVaultAccessPolicy(objectUUID, resp.Properties.AccessPolicies) + flattenedPolicy := flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies) + policy := findKeyVaultAccessPolicy(objectUUID, flattenedPolicy) d.Set("vault_name", resp.Name) - d.Set("vault_resource_group", resGroup) + d.Set("resource_group_name", resGroup) d.Set("tenant_id", resp.Properties.TenantID.String()) + d.Set("application_id", policy["application_id"]) d.Set("key_permissions", policy["key_permissions"]) d.Set("secret_permissions", policy["secret_permissions"]) @@ -181,43 +152,34 @@ func resourceArmKeyVaultAccessPolicyRead(d *schema.ResourceData, meta interface{ return nil } -func findKeyVaultAccessPolicy(objectID string, policies *[]keyvault.AccessPolicyEntry) map[string]interface{} { - - for _, policy := range *policies { - result := make(map[string]interface{}) - - if objectID != *policy.ObjectID { - continue +func findKeyVaultAccessPolicy(objectID string, policies []map[string]interface{}) map[string]interface{} { + for _, policy := range policies { + if policy["object_id"] != nil || policy["object_id"] == objectID { + return policy } + } + return nil +} - keyPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Keys)) - for _, keyPermission := range *policy.Permissions.Keys { - keyPermissionsRaw = append(keyPermissionsRaw, string(keyPermission)) - } +func expandKeyVaultAccessPolicy(d *schema.ResourceData) keyvault.AccessPolicyEntry { - secretPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Secrets)) - for _, secretPermission := range *policy.Permissions.Secrets { - secretPermissionsRaw = append(secretPermissionsRaw, string(secretPermission)) - } + policy := keyvault.AccessPolicyEntry{ + Permissions: &keyvault.Permissions{ + Certificates: expandKeyVaultAccessPolicyCertificatePermissions(d.Get("certificate_permissions").([]interface{})), + Keys: expandKeyVaultAccessPolicyKeyPermissions(d.Get("certificate_permissions").([]interface{})), + Secrets: expandKeyVaultAccessPolicySecretPermissions(d.Get("certificate_permissions").([]interface{})), + }, + } - result["tenant_id"] = policy.TenantID.String() - result["object_id"] = *policy.ObjectID - if policy.ApplicationID != nil { - result["application_id"] = policy.ApplicationID.String() - } - result["key_permissions"] = keyPermissionsRaw - result["secret_permissions"] = secretPermissionsRaw - - if policy.Permissions.Certificates != nil { - certificatePermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Certificates)) - for _, certificatePermission := range *policy.Permissions.Certificates { - certificatePermissionsRaw = append(certificatePermissionsRaw, string(certificatePermission)) - } - result["certificate_permissions"] = certificatePermissionsRaw - } + tenantUUID := uuid.FromStringOrNil(d.Get("tenant_id").(string)) + policy.TenantID = &tenantUUID + objectUUID := d.Get("object_id").(string) + policy.ObjectID = &objectUUID - return result + if v := d.Get("application_id"); v != "" { + applicationUUID := uuid.FromStringOrNil(v.(string)) + policy.ApplicationID = &applicationUUID } - return nil + return policy } diff --git a/azurerm/resource_arm_key_vault_access_policy_test.go b/azurerm/resource_arm_key_vault_access_policy_test.go index 147fe6b935d1..e21387de74d4 100644 --- a/azurerm/resource_arm_key_vault_access_policy_test.go +++ b/azurerm/resource_arm_key_vault_access_policy_test.go @@ -23,7 +23,7 @@ func TestAccAzureRMKeyVaultAccessPolicy_basic(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(resourceName), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id"), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "set"), @@ -46,7 +46,7 @@ func TestAccAzureRMKeyVaultAccessPolicy_complete(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(resourceName), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id"), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "create"), resource.TestCheckResourceAttr(resourceName, "key_permissions.1", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), @@ -74,7 +74,7 @@ func TestAccAzureRMKeyVaultAccessPolicy_update(t *testing.T) { { Config: preConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(resourceName), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id"), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "set"), @@ -83,7 +83,7 @@ func TestAccAzureRMKeyVaultAccessPolicy_update(t *testing.T) { { Config: postConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists("azurerm_key_vault_access_policy.test"), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id"), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "list"), resource.TestCheckResourceAttr(resourceName, "key_permissions.1", "encrypt"), ), @@ -107,7 +107,7 @@ func TestAccAzureRMKeyVaultAccessPolicy_policyRemoved(t *testing.T) { { Config: preConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(resourceName), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id"), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "set"), @@ -116,14 +116,14 @@ func TestAccAzureRMKeyVaultAccessPolicy_policyRemoved(t *testing.T) { { Config: postConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyMissing("azurerm_key_vault_access_policy.test"), + testCheckAzureRMKeyVaultAccessPolicyMissing(resourceName, "tags.policy_object_id"), ), }, }, }) } -func testCheckAzureRMKeyVaultAccessPolicyExists(name string) resource.TestCheckFunc { +func testCheckAzureRMKeyVaultAccessPolicyExists(name string, policyObjectTag string) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure we have enough information in state to look up in API rs, ok := s.RootModule().Resources[name] @@ -131,7 +131,7 @@ func testCheckAzureRMKeyVaultAccessPolicyExists(name string) resource.TestCheckF return fmt.Errorf("Not found: %s", name) } name := rs.Primary.Attributes["vault_name"] - resGroup := rs.Primary.Attributes["vault_resource_group"] + resGroup := rs.Primary.Attributes["resource_group_name"] client := testAccProvider.Meta().(*ArmClient).keyVaultClient ctx := testAccProvider.Meta().(*ArmClient).StopContext @@ -145,8 +145,8 @@ func testCheckAzureRMKeyVaultAccessPolicyExists(name string) resource.TestCheckF return fmt.Errorf("Bad: Get on keyVaultClient: %+v", err) } - objectId := rs.Primary.Attributes["object_id"] - policy := findKeyVaultAccessPolicy(objectId, resp.Properties.AccessPolicies) + objectId := rs.Primary.Attributes[policyObjectTag] + policy := findKeyVaultAccessPolicy(objectId, flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) if policy == nil { return fmt.Errorf("Bad: Key Vault Policy %q (resource group: %q, object_id: %s) does not exist", name, resGroup, objectId) @@ -156,7 +156,7 @@ func testCheckAzureRMKeyVaultAccessPolicyExists(name string) resource.TestCheckF } } -func testCheckAzureRMKeyVaultAccessPolicyMissing(name string) resource.TestCheckFunc { +func testCheckAzureRMKeyVaultAccessPolicyMissing(name string, policyObjectTag string) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure we have enough information in state to look up in API rs, ok := s.RootModule().Resources[name] @@ -178,9 +178,9 @@ func testCheckAzureRMKeyVaultAccessPolicyMissing(name string) resource.TestCheck return fmt.Errorf("Bad: Get on keyVaultClient: %+v", err) } - objectId := rs.Primary.Attributes["tags.policy_object_id"] + objectId := rs.Primary.Attributes[policyObjectTag] - policy := findKeyVaultAccessPolicy(objectId, resp.Properties.AccessPolicies) + policy := findKeyVaultAccessPolicy(objectId, flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) if policy != nil { return fmt.Errorf("Bad: Key Vault Policy %q (resource group: %q, object_id: %s) exists", name, resGroup, objectId) @@ -216,7 +216,7 @@ resource "azurerm_key_vault" "test" { resource "azurerm_key_vault_access_policy" "test" { vault_name = "${azurerm_key_vault.test.name}" - vault_resource_group = "${azurerm_resource_group.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" key_permissions = [ "get" @@ -243,40 +243,40 @@ resource "azurerm_resource_group" "test" { } resource "azurerm_key_vault" "test" { - name = "acctestkv-%s" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - tenant_id = "${data.azurerm_client_config.current.tenant_id}" - - - sku { - name = "premium" - } - - tags { - environment = "Production" - } + name = "acctestkv-%s" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + + + sku { + name = "premium" + } + + tags { + environment = "Production" + } } resource "azurerm_key_vault_access_policy" "test" { vault_name = "${azurerm_key_vault.test.name}" - vault_resource_group = "${azurerm_resource_group.test.name}" - + resource_group_name = "${azurerm_resource_group.test.name}" + key_permissions = [ "create", - "get" + "get" ] - - secret_permissions = [ - "get", - "delete" - ] - + + secret_permissions = [ + "get", + "delete" + ] + certificate_permissions = [ "create", "delete" ] - + application_id = "${data.azurerm_client_config.current.service_principal_application_id}" tenant_id = "${data.azurerm_client_config.current.tenant_id}" object_id = "${data.azurerm_client_config.current.service_principal_object_id}" @@ -309,8 +309,8 @@ resource "azurerm_key_vault" "test" { } resource "azurerm_key_vault_access_policy" "test" { - vault_name = "${azurerm_key_vault.test.name}" - vault_resource_group = "${azurerm_resource_group.test.name}" + vault_name = "${azurerm_key_vault.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" key_permissions = [ "list", diff --git a/website/azurerm.erb b/website/azurerm.erb index 8a205cdae715..0180589012bd 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -444,6 +444,10 @@ azurerm_key_vault + > + azurerm_key_vault_access_policy + + > azurerm_key_vault_certificate diff --git a/website/docs/r/key_vault.html.markdown b/website/docs/r/key_vault.html.markdown index d6c98229c8b6..b5170427096f 100644 --- a/website/docs/r/key_vault.html.markdown +++ b/website/docs/r/key_vault.html.markdown @@ -68,8 +68,12 @@ The following arguments are supported: * `tenant_id` - (Required) The Azure Active Directory tenant ID that should be used for authenticating requests to the key vault. -* `access_policy` - (Required) An access policy block as described below. A maximum of 16 +* `access_policy` - (Optional) An access policy block as described below. A maximum of 16 may be declared. + +~> **Please Note:** Access Policies can also be defined using the [Key Vault Access Policy Resource](key_vault_access_policy.html) +resource (however you cannot use the independent resource and the built-in access_policy +field together, since they'll conflict). * `enabled_for_deployment` - (Optional) Boolean flag to specify whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key diff --git a/website/docs/r/key_vault_policy.html.markdown b/website/docs/r/key_vault_access_policy.html.markdown similarity index 73% rename from website/docs/r/key_vault_policy.html.markdown rename to website/docs/r/key_vault_access_policy.html.markdown index eb1a3ee450b7..2eebb91fc224 100644 --- a/website/docs/r/key_vault_policy.html.markdown +++ b/website/docs/r/key_vault_access_policy.html.markdown @@ -1,18 +1,18 @@ --- layout: "azurerm" -page_title: "Azure Resource Manager: azurerm_key_vault_policy" -sidebar_current: "docs-azurerm-resource-key-vault-policy" +page_title: "Azure Resource Manager: azurerm_key_vault_access_policy" +sidebar_current: "docs-azurerm-resource-key-vault-access-policy" description: |- - Create a Key Vault Access Policy. + Manages a Key Vault Access Policy. --- -# azurerm\_key\_vault\_policy +# azurerm_key_vault_access_policy -Create a Key Vault Access Policy. +Manages a Key Vault Access Policy. ~> **NOTE on Key Vaults and Key Vault Policies:** Terraform currently provides both a standalone [Key Vault Policy Resource](key_vault_policy.html), and allows for Key Vault Access Polcies to be defined in-line within the [Key Vault Resource](key_vault.html). -At this time you cannot define Key Vault Policy with in-line Key Vault in conjunction with any Key Vault Policy resources. Doing so may cause a conflict of rule settings and will overwrite rules. +At this time you cannot define Key Vault Policy with in-line Key Vault in conjunction with any Key Vault Policy resources. Doing so may cause a conflict of Access Policies and will overwrite Access Policies. ## Example Usage @@ -20,12 +20,12 @@ At this time you cannot define Key Vault Policy with in-line Key Vault in conjun ```hcl resource "azurerm_resource_group" "test" { name = "resourceGroup1" - location = "West US" + location = "${azurerm_resource_group.test.location}" } resource "azurerm_key_vault" "test" { name = "testvault" - location = "West US" + location = "${azurerm_resource_group.test.location}" resource_group_name = "${azurerm_resource_group.test.name}" sku { @@ -42,8 +42,8 @@ resource "azurerm_key_vault" "test" { } resource "azurerm_key_vault_policy" "test" { - vault_name = "${azurerm_key_vault.test.name}" - vault_resource_group = "${azurerm_key_vault.test.resource_group_name}" + vault_name = "${azurerm_key_vault.test.name}" + resource_group_name = "${azurerm_key_vault.test.resource_group_name}" tenant_id = "d6e396d0-5584-41dc-9fc0-268df99bc610" object_id = "d746815a-0433-4a21-b95d-fc437d2d475b" @@ -67,16 +67,17 @@ The following arguments are supported: * `vault_name` - (Required) Specifies the name of the Key Vault resource. Changing this forces a new resource to be created. -* `vault_resource_group` - (Required) The name of the resource group in which to +* `resource_group_name` - (Required) The name of the resource group in which to create the namespace. Changing this forces a new resource to be created. * `tenant_id` - (Required) The Azure Active Directory tenant ID that should be used - for authenticating requests to the key vault. Must match the `tenant_id` used - above. + for authenticating requests to the key vault. Changing this forces a new resource + to be created. * `object_id` - (Required) The object ID of a user, service principal or security group in the Azure Active Directory tenant for the vault. The object ID must - be unique for the list of access policies. + be unique for the list of access policies. Changing this forces a new resource + to be created. * `application_id` - (Optional) The object ID of an Application in Azure Active Directory. @@ -93,4 +94,4 @@ The following arguments are supported: The following attributes are exported: -* `id` - The Vault ID. +* `id` - Key Vault Access Policy ID. From 2c81721c1cfedccf9271ceb2b60d58fc5a330932 Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Tue, 29 May 2018 13:58:14 -0400 Subject: [PATCH 09/23] Fixed some of the tests --- azurerm/resource_arm_key_vault.go | 11 ++++- .../resource_arm_key_vault_access_policy.go | 19 ++++--- ...source_arm_key_vault_access_policy_test.go | 17 ++++--- azurerm/resource_arm_route_test.go | 49 +++++++++++++++++++ 4 files changed, 81 insertions(+), 15 deletions(-) diff --git a/azurerm/resource_arm_key_vault.go b/azurerm/resource_arm_key_vault.go index 36017651bb34..6a2f5a916bb0 100644 --- a/azurerm/resource_arm_key_vault.go +++ b/azurerm/resource_arm_key_vault.go @@ -8,6 +8,7 @@ import ( "time" "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" + //"github.com/davecgh/go-spew/spew" "github.com/hashicorp/go-getter/helper/url" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" @@ -21,7 +22,7 @@ import ( // https://github.com/Azure/azure-rest-api-specs/blob/master/arm-keyvault/2015-06-01/swagger/keyvault.json#L239 var armKeyVaultSkuFamily = "A" -var keyVaultResourceName = "azurerm_key_vault" +var keyVaultAccessPolicyResourceName = "azurerm_key_vault_access_policy" func resourceArmKeyVault() *schema.Resource { return &schema.Resource{ @@ -151,6 +152,8 @@ func resourceArmKeyVaultCreate(d *schema.ResourceData, meta interface{}) error { Tags: expandTags(tags), } + //return fmt.Errorf("%s", spew.Sdump(parameters)) + azureRMLockByName(name, keyVaultResourceName) defer azureRMUnlockByName(name, keyVaultResourceName) @@ -194,6 +197,9 @@ func resourceArmKeyVaultRead(d *schema.ResourceData, meta interface{}) error { resGroup := id.ResourceGroup name := id.Path["vaults"] + azureRMLockByName(d.Get("name").(string), keyVaultAccessPolicyResourceName) + defer azureRMUnlockByName(d.Get("name").(string), keyVaultAccessPolicyResourceName) + resp, err := client.Get(ctx, resGroup, name) if err != nil { if utils.ResponseWasNotFound(resp.Response) { @@ -232,6 +238,9 @@ func resourceArmKeyVaultDelete(d *schema.ResourceData, meta interface{}) error { resGroup := id.ResourceGroup name := id.Path["vaults"] + azureRMLockByName(name, keyVaultResourceName) + defer azureRMUnlockByName(name, keyVaultResourceName) + _, err = client.Delete(ctx, resGroup, name) return err diff --git a/azurerm/resource_arm_key_vault_access_policy.go b/azurerm/resource_arm_key_vault_access_policy.go index 35ef98fe41af..0587b5bdd4ce 100644 --- a/azurerm/resource_arm_key_vault_access_policy.go +++ b/azurerm/resource_arm_key_vault_access_policy.go @@ -11,12 +11,17 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) +var keyVaultResourceName = "azurerm_key_vault" + func resourceArmKeyVaultAccessPolicy() *schema.Resource { return &schema.Resource{ Create: resourceArmKeyVaultAccessPolicyCreate, Read: resourceArmKeyVaultAccessPolicyRead, Update: resourceArmKeyVaultAccessPolicyUpdate, Delete: resourceArmKeyVaultAccessPolicyDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "vault_name": { @@ -75,11 +80,6 @@ func resourceArmKeyVaultAccessPolicyCreateOrDelete(d *schema.ResourceData, meta }, } - //return fmt.Errorf("Error updating Key Vault Access Policy: %+v ApplicationID: %s", accessPolicies, d.Get("application_id").(string)) - - azureRMLockByName(name, keyVaultResourceName) - defer azureRMUnlockByName(name, keyVaultResourceName) - _, err := client.UpdateAccessPolicy(ctx, resGroup, name, action, parameters) if err != nil { return fmt.Errorf("Error updating Key Vault Access Policy (Key Vault %q / Resource Group %q): %+v", name, resGroup, err) @@ -106,6 +106,9 @@ func resourceArmKeyVaultAccessPolicyCreate(d *schema.ResourceData, meta interfac } func resourceArmKeyVaultAccessPolicyDelete(d *schema.ResourceData, meta interface{}) error { + azureRMLockByName(d.Get("vault_name").(string), keyVaultAccessPolicyResourceName) + defer azureRMUnlockByName(d.Get("vault_name").(string), keyVaultAccessPolicyResourceName) + return resourceArmKeyVaultAccessPolicyCreateOrDelete(d, meta, keyvault.Remove) } @@ -154,7 +157,7 @@ func resourceArmKeyVaultAccessPolicyRead(d *schema.ResourceData, meta interface{ func findKeyVaultAccessPolicy(objectID string, policies []map[string]interface{}) map[string]interface{} { for _, policy := range policies { - if policy["object_id"] != nil || policy["object_id"] == objectID { + if policy["object_id"] != nil && policy["object_id"] == objectID { return policy } } @@ -166,8 +169,8 @@ func expandKeyVaultAccessPolicy(d *schema.ResourceData) keyvault.AccessPolicyEnt policy := keyvault.AccessPolicyEntry{ Permissions: &keyvault.Permissions{ Certificates: expandKeyVaultAccessPolicyCertificatePermissions(d.Get("certificate_permissions").([]interface{})), - Keys: expandKeyVaultAccessPolicyKeyPermissions(d.Get("certificate_permissions").([]interface{})), - Secrets: expandKeyVaultAccessPolicySecretPermissions(d.Get("certificate_permissions").([]interface{})), + Keys: expandKeyVaultAccessPolicyKeyPermissions(d.Get("key_permissions").([]interface{})), + Secrets: expandKeyVaultAccessPolicySecretPermissions(d.Get("secret_permissions").([]interface{})), }, } diff --git a/azurerm/resource_arm_key_vault_access_policy_test.go b/azurerm/resource_arm_key_vault_access_policy_test.go index e21387de74d4..345c179178aa 100644 --- a/azurerm/resource_arm_key_vault_access_policy_test.go +++ b/azurerm/resource_arm_key_vault_access_policy_test.go @@ -8,6 +8,8 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" + "log" + "github.com/davecgh/go-spew/spew" ) func TestAccAzureRMKeyVaultAccessPolicy_basic(t *testing.T) { @@ -94,7 +96,8 @@ func TestAccAzureRMKeyVaultAccessPolicy_update(t *testing.T) { func TestAccAzureRMKeyVaultAccessPolicy_policyRemoved(t *testing.T) { rs := acctest.RandString(6) - resourceName := "azurerm_key_vault_access_policy.test" + policyResourceName := "azurerm_key_vault_access_policy.test" + vaultResourceName := "azurerm_key_vault.test" preConfig := testAccAzureRMKeyVaultAccessPolicy_basic(rs, testLocation()) postConfig := testAccAzureRMKeyVaultAccessPolicy_policyRemoved(rs, testLocation()) @@ -107,16 +110,16 @@ func TestAccAzureRMKeyVaultAccessPolicy_policyRemoved(t *testing.T) { { Config: preConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id"), - resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "get"), - resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), - resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "set"), + testCheckAzureRMKeyVaultAccessPolicyExists(policyResourceName, "object_id"), + resource.TestCheckResourceAttr(policyResourceName, "key_permissions.0", "get"), + resource.TestCheckResourceAttr(policyResourceName, "secret_permissions.0", "get"), + resource.TestCheckResourceAttr(policyResourceName, "secret_permissions.1", "set"), ), }, { Config: postConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyMissing(resourceName, "tags.policy_object_id"), + testCheckAzureRMKeyVaultAccessPolicyMissing(vaultResourceName, "tags.policy_object_id"), ), }, }, @@ -163,6 +166,7 @@ func testCheckAzureRMKeyVaultAccessPolicyMissing(name string, policyObjectTag st if !ok { return fmt.Errorf("Not found: %s", name) } + log.Printf("%s", spew.Sdump(rs)) name := rs.Primary.Attributes["name"] resGroup := rs.Primary.Attributes["resource_group_name"] @@ -211,6 +215,7 @@ resource "azurerm_key_vault" "test" { tags { environment = "Production" + policy_object_id = "${data.azurerm_client_config.current.service_principal_object_id}" } } diff --git a/azurerm/resource_arm_route_test.go b/azurerm/resource_arm_route_test.go index d5639878ded9..81ab3f33e123 100644 --- a/azurerm/resource_arm_route_test.go +++ b/azurerm/resource_arm_route_test.go @@ -79,6 +79,34 @@ func TestAccAzureRMRoute_multipleRoutes(t *testing.T) { }) } +func TestAccAzureRMRoute_removed(t *testing.T) { + ri := acctest.RandInt() + location := testLocation() + preConfig := testAccAzureRMRoute_basic(ri, location) + postConfig := testAccAzureRMRoute_basicUpdate(ri, location) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMRouteDestroy, + Steps: []resource.TestStep{ + { + Config: preConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMRouteExists("azurerm_route.test"), + ), + }, + + { + Config: postConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMRouteExists("azurerm_route.test1"), + ), + }, + }, + }) +} + func testCheckAzureRMRouteExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -215,3 +243,24 @@ resource "azurerm_route" "test1" { } `, rInt, location, rInt, rInt) } + +func testAccAzureRMRoute_basicUpdate(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_route_table" "test" { + name = "acctestrt%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + tags { + environment = "Production" + } +} + + +`, rInt, location, rInt) +} From 2813a054396125dae72d50a73f7e67c5dfe3ea93 Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Tue, 29 May 2018 13:58:45 -0400 Subject: [PATCH 10/23] Ran make fmt --- azurerm/resource_arm_key_vault_access_policy_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/resource_arm_key_vault_access_policy_test.go b/azurerm/resource_arm_key_vault_access_policy_test.go index 345c179178aa..f433577960ae 100644 --- a/azurerm/resource_arm_key_vault_access_policy_test.go +++ b/azurerm/resource_arm_key_vault_access_policy_test.go @@ -4,12 +4,12 @@ import ( "fmt" "testing" + "github.com/davecgh/go-spew/spew" "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" "log" - "github.com/davecgh/go-spew/spew" ) func TestAccAzureRMKeyVaultAccessPolicy_basic(t *testing.T) { From e9d198935c4179b530e098417dac9d1ce9a6e6d7 Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Tue, 29 May 2018 14:05:18 -0400 Subject: [PATCH 11/23] Fixed website links --- website/docs/r/key_vault_access_policy.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/key_vault_access_policy.html.markdown b/website/docs/r/key_vault_access_policy.html.markdown index 2eebb91fc224..75f97292f204 100644 --- a/website/docs/r/key_vault_access_policy.html.markdown +++ b/website/docs/r/key_vault_access_policy.html.markdown @@ -11,7 +11,7 @@ description: |- Manages a Key Vault Access Policy. ~> **NOTE on Key Vaults and Key Vault Policies:** Terraform currently -provides both a standalone [Key Vault Policy Resource](key_vault_policy.html), and allows for Key Vault Access Polcies to be defined in-line within the [Key Vault Resource](key_vault.html). +provides both a standalone [Key Vault Policy Resource](key_vault_access_policy.html), and allows for Key Vault Access Polcies to be defined in-line within the [Key Vault Resource](key_vault.html). At this time you cannot define Key Vault Policy with in-line Key Vault in conjunction with any Key Vault Policy resources. Doing so may cause a conflict of Access Policies and will overwrite Access Policies. @@ -41,7 +41,7 @@ resource "azurerm_key_vault" "test" { } } -resource "azurerm_key_vault_policy" "test" { +resource "azurerm_key_vault_access_policy" "test" { vault_name = "${azurerm_key_vault.test.name}" resource_group_name = "${azurerm_key_vault.test.resource_group_name}" From 2e8329328d2c1a81aa556d8452df192e91c08392 Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Tue, 5 Jun 2018 13:31:19 -0400 Subject: [PATCH 12/23] Updated route test to fail --- azurerm/resource_arm_route_test.go | 35 +++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/azurerm/resource_arm_route_test.go b/azurerm/resource_arm_route_test.go index 81ab3f33e123..b9c4b9f59443 100644 --- a/azurerm/resource_arm_route_test.go +++ b/azurerm/resource_arm_route_test.go @@ -100,13 +100,46 @@ func TestAccAzureRMRoute_removed(t *testing.T) { { Config: postConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMRouteExists("azurerm_route.test1"), + testCheckAzureRMRouteIsEmpty("azurerm_route_table.test"), ), }, }, }) } +func testCheckAzureRMRouteIsEmpty(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %q", name) + } + + name := rs.Primary.Attributes["name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for route: %q", name) + } + + client := testAccProvider.Meta().(*ArmClient).routeTablesClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + resp, err := client.Get(ctx, resourceGroup, name, "") + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Route %q (resource group: %q) does not exist", name, resourceGroup) + } + return fmt.Errorf("Bad: Get on routesClient: %+v", err) + } + + if len(*resp.Routes) != 0 { + return fmt.Errorf("Bad: Expected No Routes found: %d", len(*resp.Routes)) + } + + return nil + } +} + func testCheckAzureRMRouteExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { From 0484bcfa6038c142063c9a2b531bd9de0d5873cd Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Thu, 7 Jun 2018 17:27:57 -0400 Subject: [PATCH 13/23] Updated to support importing an access policy --- .../resource_arm_key_vault_access_policy.go | 45 +++++++++--- ...source_arm_key_vault_access_policy_test.go | 69 +++++++++++++++---- 2 files changed, 88 insertions(+), 26 deletions(-) diff --git a/azurerm/resource_arm_key_vault_access_policy.go b/azurerm/resource_arm_key_vault_access_policy.go index 0587b5bdd4ce..7eda3857ab1c 100644 --- a/azurerm/resource_arm_key_vault_access_policy.go +++ b/azurerm/resource_arm_key_vault_access_policy.go @@ -5,7 +5,6 @@ import ( "log" "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" - "github.com/davecgh/go-spew/spew" "github.com/hashicorp/terraform/helper/schema" uuid "github.com/satori/go.uuid" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" @@ -63,7 +62,7 @@ func resourceArmKeyVaultAccessPolicy() *schema.Resource { func resourceArmKeyVaultAccessPolicyCreateOrDelete(d *schema.ResourceData, meta interface{}, action keyvault.AccessPolicyUpdateKind) error { client := meta.(*ArmClient).keyVaultClient ctx := meta.(*ArmClient).StopContext - log.Printf("[INFO]Preparing arguments for Key Vault Access Policy: %s.", action) + log.Printf("[INFO] Preparing arguments for Key Vault Access Policy: %s.", action) name := d.Get("vault_name").(string) resGroup := d.Get("resource_group_name").(string) @@ -71,8 +70,6 @@ func resourceArmKeyVaultAccessPolicyCreateOrDelete(d *schema.ResourceData, meta accessPolicy := expandKeyVaultAccessPolicy(d) accessPolicies := []keyvault.AccessPolicyEntry{accessPolicy} - log.Printf("SPEW: %s", spew.Sdump(accessPolicies)) - parameters := keyvault.VaultAccessPolicyParameters{ Name: &name, Properties: &keyvault.VaultAccessPolicyProperties{ @@ -95,7 +92,14 @@ func resourceArmKeyVaultAccessPolicyCreateOrDelete(d *schema.ResourceData, meta } if d.IsNewResource() { - d.SetId(*read.ID) + resourceId := fmt.Sprintf("%s/objectId/%s", *read.ID, d.Get("object_id")) + if applicationId, ok := d.GetOk("application_id"); ok { + resourceId = fmt.Sprintf( + "%s/applicationId/%s", + resourceId, + applicationId) + } + d.SetId(resourceId) } return nil @@ -121,14 +125,13 @@ func resourceArmKeyVaultAccessPolicyRead(d *schema.ResourceData, meta interface{ ctx := meta.(*ArmClient).StopContext id, err := parseAzureResourceID(d.Id()) + if err != nil { return err } resGroup := id.ResourceGroup name := id.Path["vaults"] - objectUUID := d.Get("object_id").(string) - resp, err := client.Get(ctx, resGroup, name) if err != nil { if utils.ResponseWasNotFound(resp.Response) { @@ -139,12 +142,23 @@ func resourceArmKeyVaultAccessPolicyRead(d *schema.ResourceData, meta interface{ } flattenedPolicy := flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies) - policy := findKeyVaultAccessPolicy(objectUUID, flattenedPolicy) + + var policy map[string]interface{} + if applicationId, ok := id.Path["applicationId"]; ok { + policy = findKeyVaultAccessPolicyWithApplicationId(id.Path["objectId"], applicationId, flattenedPolicy) + } else { + policy = findKeyVaultAccessPolicy(id.Path["objectId"], flattenedPolicy) + } + + if policy == nil { + d.SetId("") + return fmt.Errorf("Policy for was not found for vault: %s", name) + } d.Set("vault_name", resp.Name) d.Set("resource_group_name", resGroup) + d.Set("object_id", id.Path["objectId"]) d.Set("tenant_id", resp.Properties.TenantID.String()) - d.Set("application_id", policy["application_id"]) d.Set("key_permissions", policy["key_permissions"]) d.Set("secret_permissions", policy["secret_permissions"]) @@ -155,9 +169,18 @@ func resourceArmKeyVaultAccessPolicyRead(d *schema.ResourceData, meta interface{ return nil } -func findKeyVaultAccessPolicy(objectID string, policies []map[string]interface{}) map[string]interface{} { +func findKeyVaultAccessPolicy(objectId string, policies []map[string]interface{}) map[string]interface{} { + for _, policy := range policies { + if policy["object_id"] != nil && policy["object_id"] == objectId { + return policy + } + } + return nil +} + +func findKeyVaultAccessPolicyWithApplicationId(objectId string, applicationId string, policies []map[string]interface{}) map[string]interface{} { for _, policy := range policies { - if policy["object_id"] != nil && policy["object_id"] == objectID { + if policy["object_id"] != nil && policy["application_id"] != nil && policy["object_id"] == objectId && policy["application_id"] == applicationId { return policy } } diff --git a/azurerm/resource_arm_key_vault_access_policy_test.go b/azurerm/resource_arm_key_vault_access_policy_test.go index f433577960ae..c0e9ef71f99e 100644 --- a/azurerm/resource_arm_key_vault_access_policy_test.go +++ b/azurerm/resource_arm_key_vault_access_policy_test.go @@ -25,7 +25,7 @@ func TestAccAzureRMKeyVaultAccessPolicy_basic(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id"), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id", "application_id"), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "set"), @@ -36,7 +36,8 @@ func TestAccAzureRMKeyVaultAccessPolicy_basic(t *testing.T) { } func TestAccAzureRMKeyVaultAccessPolicy_complete(t *testing.T) { - resourceName := "azurerm_key_vault_access_policy.test" + resourceName1 := "azurerm_key_vault_access_policy.test_with_application_id" + resourceName2 := "azurerm_key_vault_access_policy.test_no_application_id" rs := acctest.RandString(6) config := testAccAzureRMKeyVaultAccessPolicy_complete(rs, testLocation()) @@ -48,13 +49,21 @@ func TestAccAzureRMKeyVaultAccessPolicy_complete(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id"), - resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "create"), - resource.TestCheckResourceAttr(resourceName, "key_permissions.1", "get"), - resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), - resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "delete"), - resource.TestCheckResourceAttr(resourceName, "certificate_permissions.0", "create"), - resource.TestCheckResourceAttr(resourceName, "certificate_permissions.1", "delete"), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName1, "object_id", "application_id"), + resource.TestCheckResourceAttr(resourceName1, "key_permissions.0", "create"), + resource.TestCheckResourceAttr(resourceName1, "key_permissions.1", "get"), + resource.TestCheckResourceAttr(resourceName1, "secret_permissions.0", "get"), + resource.TestCheckResourceAttr(resourceName1, "secret_permissions.1", "delete"), + resource.TestCheckResourceAttr(resourceName1, "certificate_permissions.0", "create"), + resource.TestCheckResourceAttr(resourceName1, "certificate_permissions.1", "delete"), + + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName2, "object_id", "application_id"), + resource.TestCheckResourceAttr(resourceName2, "key_permissions.0", "list"), + resource.TestCheckResourceAttr(resourceName2, "key_permissions.1", "encrypt"), + resource.TestCheckResourceAttr(resourceName2, "secret_permissions.0", "list"), + resource.TestCheckResourceAttr(resourceName2, "secret_permissions.1", "delete"), + resource.TestCheckResourceAttr(resourceName2, "certificate_permissions.0", "list"), + resource.TestCheckResourceAttr(resourceName2, "certificate_permissions.1", "delete"), ), }, }, @@ -76,7 +85,7 @@ func TestAccAzureRMKeyVaultAccessPolicy_update(t *testing.T) { { Config: preConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id"), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id", "application_id"), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "set"), @@ -85,7 +94,7 @@ func TestAccAzureRMKeyVaultAccessPolicy_update(t *testing.T) { { Config: postConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id"), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id", "application_id"), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "list"), resource.TestCheckResourceAttr(resourceName, "key_permissions.1", "encrypt"), ), @@ -110,7 +119,7 @@ func TestAccAzureRMKeyVaultAccessPolicy_policyRemoved(t *testing.T) { { Config: preConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(policyResourceName, "object_id"), + testCheckAzureRMKeyVaultAccessPolicyExists(policyResourceName, "object_id", "application_id"), resource.TestCheckResourceAttr(policyResourceName, "key_permissions.0", "get"), resource.TestCheckResourceAttr(policyResourceName, "secret_permissions.0", "get"), resource.TestCheckResourceAttr(policyResourceName, "secret_permissions.1", "set"), @@ -126,7 +135,7 @@ func TestAccAzureRMKeyVaultAccessPolicy_policyRemoved(t *testing.T) { }) } -func testCheckAzureRMKeyVaultAccessPolicyExists(name string, policyObjectTag string) resource.TestCheckFunc { +func testCheckAzureRMKeyVaultAccessPolicyExists(name string, policyObjectTag string, policyApplicationTag string) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure we have enough information in state to look up in API rs, ok := s.RootModule().Resources[name] @@ -149,7 +158,14 @@ func testCheckAzureRMKeyVaultAccessPolicyExists(name string, policyObjectTag str } objectId := rs.Primary.Attributes[policyObjectTag] - policy := findKeyVaultAccessPolicy(objectId, flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) + + var policy map[string]interface{} + + if applicationId, ok := rs.Primary.Attributes[policyApplicationTag]; ok { + policy = findKeyVaultAccessPolicyWithApplicationId(objectId, applicationId, flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) + } else { + policy = findKeyVaultAccessPolicy(objectId, flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) + } if policy == nil { return fmt.Errorf("Bad: Key Vault Policy %q (resource group: %q, object_id: %s) does not exist", name, resGroup, objectId) @@ -263,7 +279,7 @@ resource "azurerm_key_vault" "test" { } } -resource "azurerm_key_vault_access_policy" "test" { +resource "azurerm_key_vault_access_policy" "test_with_application_id" { vault_name = "${azurerm_key_vault.test.name}" resource_group_name = "${azurerm_resource_group.test.name}" @@ -286,6 +302,29 @@ resource "azurerm_key_vault_access_policy" "test" { tenant_id = "${data.azurerm_client_config.current.tenant_id}" object_id = "${data.azurerm_client_config.current.service_principal_object_id}" } + +resource "azurerm_key_vault_access_policy" "test_no_application_id" { + vault_name = "${azurerm_key_vault.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" + + key_permissions = [ + "list", + "encrypt" + ] + + secret_permissions = [ + "list", + "delete" + ] + + certificate_permissions = [ + "list", + "delete" + ] + + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + object_id = "${data.azurerm_client_config.current.service_principal_object_id}" +} `, rString, location, rString) } From bc13b6d9ba02fb502570f1284dacfe402ab1a84b Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Fri, 8 Jun 2018 13:44:27 -0400 Subject: [PATCH 14/23] Updated to support importing of the resource and some enhanced tests --- .../resource_arm_key_vault_access_policy.go | 45 ++++++++++++------- ...source_arm_key_vault_access_policy_test.go | 10 ++--- .../r/key_vault_access_policy.html.markdown | 13 ++++++ 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/azurerm/resource_arm_key_vault_access_policy.go b/azurerm/resource_arm_key_vault_access_policy.go index 7eda3857ab1c..31c5a0a29fc7 100644 --- a/azurerm/resource_arm_key_vault_access_policy.go +++ b/azurerm/resource_arm_key_vault_access_policy.go @@ -92,6 +92,9 @@ func resourceArmKeyVaultAccessPolicyCreateOrDelete(d *schema.ResourceData, meta } if d.IsNewResource() { + // This is because azure doesn't have an 'id' for a keyvault access policy + // In order to compensate for this and allow importing of this resource we are artificially + // creating an identity for a key vault policy object resourceId := fmt.Sprintf("%s/objectId/%s", *read.ID, d.Get("object_id")) if applicationId, ok := d.GetOk("application_id"); ok { resourceId = fmt.Sprintf( @@ -143,12 +146,11 @@ func resourceArmKeyVaultAccessPolicyRead(d *schema.ResourceData, meta interface{ flattenedPolicy := flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies) - var policy map[string]interface{} - if applicationId, ok := id.Path["applicationId"]; ok { - policy = findKeyVaultAccessPolicyWithApplicationId(id.Path["objectId"], applicationId, flattenedPolicy) - } else { - policy = findKeyVaultAccessPolicy(id.Path["objectId"], flattenedPolicy) - } + policyObjectId := id.Path["objectId"] + policyApplicationId := id.Path["applicationId"] + policyId := getPolicyIdentity(&policyObjectId, &policyApplicationId) + + policy := findKeyVaultAccessPolicy(policyId, flattenedPolicy) if policy == nil { d.SetId("") @@ -157,9 +159,9 @@ func resourceArmKeyVaultAccessPolicyRead(d *schema.ResourceData, meta interface{ d.Set("vault_name", resp.Name) d.Set("resource_group_name", resGroup) - d.Set("object_id", id.Path["objectId"]) + d.Set("object_id", policyObjectId) d.Set("tenant_id", resp.Properties.TenantID.String()) - d.Set("application_id", policy["application_id"]) + d.Set("application_id", policyApplicationId) d.Set("key_permissions", policy["key_permissions"]) d.Set("secret_permissions", policy["secret_permissions"]) d.Set("certificate_permissions", policy["certificate_permissions"]) @@ -169,18 +171,29 @@ func resourceArmKeyVaultAccessPolicyRead(d *schema.ResourceData, meta interface{ return nil } -func findKeyVaultAccessPolicy(objectId string, policies []map[string]interface{}) map[string]interface{} { - for _, policy := range policies { - if policy["object_id"] != nil && policy["object_id"] == objectId { - return policy - } +func getPolicyIdentity(objectId *string, applicationId *string) string { + + if applicationId != nil && *applicationId != "" { + return fmt.Sprintf("%s/%s", *objectId, *applicationId) + } else { + return fmt.Sprintf("%s", *objectId) + } +} + +func matchAccessPolicy(policyString string, policy map[string]interface{}) bool { + + policyObjectId := policy["object_id"].(string) + + if policyApplicationId, ok := policy["application_id"]; ok { + return policyString == fmt.Sprintf("%s/%s", policyObjectId, policyApplicationId) + } else { + return policyString == policyObjectId } - return nil } -func findKeyVaultAccessPolicyWithApplicationId(objectId string, applicationId string, policies []map[string]interface{}) map[string]interface{} { +func findKeyVaultAccessPolicy(policyString string, policies []map[string]interface{}) map[string]interface{} { for _, policy := range policies { - if policy["object_id"] != nil && policy["application_id"] != nil && policy["object_id"] == objectId && policy["application_id"] == applicationId { + if matchAccessPolicy(policyString, policy) { return policy } } diff --git a/azurerm/resource_arm_key_vault_access_policy_test.go b/azurerm/resource_arm_key_vault_access_policy_test.go index c0e9ef71f99e..a670aeb40f2f 100644 --- a/azurerm/resource_arm_key_vault_access_policy_test.go +++ b/azurerm/resource_arm_key_vault_access_policy_test.go @@ -158,14 +158,11 @@ func testCheckAzureRMKeyVaultAccessPolicyExists(name string, policyObjectTag str } objectId := rs.Primary.Attributes[policyObjectTag] + applicationId := rs.Primary.Attributes[policyApplicationTag] - var policy map[string]interface{} + policyIdentity := getPolicyIdentity(&objectId, &applicationId) - if applicationId, ok := rs.Primary.Attributes[policyApplicationTag]; ok { - policy = findKeyVaultAccessPolicyWithApplicationId(objectId, applicationId, flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) - } else { - policy = findKeyVaultAccessPolicy(objectId, flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) - } + policy := findKeyVaultAccessPolicy(policyIdentity, flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) if policy == nil { return fmt.Errorf("Bad: Key Vault Policy %q (resource group: %q, object_id: %s) does not exist", name, resGroup, objectId) @@ -349,6 +346,7 @@ resource "azurerm_key_vault" "test" { tags { environment = "Production" + policy_object_id = "${data.azurerm_client_config.current.service_principal_object_id}" } } diff --git a/website/docs/r/key_vault_access_policy.html.markdown b/website/docs/r/key_vault_access_policy.html.markdown index 75f97292f204..3658ba27dc70 100644 --- a/website/docs/r/key_vault_access_policy.html.markdown +++ b/website/docs/r/key_vault_access_policy.html.markdown @@ -95,3 +95,16 @@ The following arguments are supported: The following attributes are exported: * `id` - Key Vault Access Policy ID. + +## Import + +Routes can be imported using the `resource id` of the keyvault with additional metadata containing +the service principal objectId and the applicationId if applicable, e.g. + +```shell +terraform import azurerm_key_vault_access_policy.testPolicy /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.KeyVault/vaults/test-vault/objectId/00000000-0000-0000-0000-000000000000 +``` + +```shell +terraform import azurerm_key_vault_access_policy.testPolicy /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.KeyVault/vaults/test-vault/objectId/00000000-0000-0000-0000-000000000000/applicationId/00000000-0000-0000-0000-000000000000 +``` \ No newline at end of file From cea6c60c1ebd7594279d168c4b0a573ffa3b331e Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Fri, 8 Jun 2018 13:47:31 -0400 Subject: [PATCH 15/23] Reverted route_test to not fail for this pr --- azurerm/resource_arm_route_test.go | 82 ------------------------------ 1 file changed, 82 deletions(-) diff --git a/azurerm/resource_arm_route_test.go b/azurerm/resource_arm_route_test.go index b9c4b9f59443..d5639878ded9 100644 --- a/azurerm/resource_arm_route_test.go +++ b/azurerm/resource_arm_route_test.go @@ -79,67 +79,6 @@ func TestAccAzureRMRoute_multipleRoutes(t *testing.T) { }) } -func TestAccAzureRMRoute_removed(t *testing.T) { - ri := acctest.RandInt() - location := testLocation() - preConfig := testAccAzureRMRoute_basic(ri, location) - postConfig := testAccAzureRMRoute_basicUpdate(ri, location) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testCheckAzureRMRouteDestroy, - Steps: []resource.TestStep{ - { - Config: preConfig, - Check: resource.ComposeTestCheckFunc( - testCheckAzureRMRouteExists("azurerm_route.test"), - ), - }, - - { - Config: postConfig, - Check: resource.ComposeTestCheckFunc( - testCheckAzureRMRouteIsEmpty("azurerm_route_table.test"), - ), - }, - }, - }) -} - -func testCheckAzureRMRouteIsEmpty(name string) resource.TestCheckFunc { - return func(s *terraform.State) error { - - rs, ok := s.RootModule().Resources[name] - if !ok { - return fmt.Errorf("Not found: %q", name) - } - - name := rs.Primary.Attributes["name"] - resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] - if !hasResourceGroup { - return fmt.Errorf("Bad: no resource group found in state for route: %q", name) - } - - client := testAccProvider.Meta().(*ArmClient).routeTablesClient - ctx := testAccProvider.Meta().(*ArmClient).StopContext - - resp, err := client.Get(ctx, resourceGroup, name, "") - if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Bad: Route %q (resource group: %q) does not exist", name, resourceGroup) - } - return fmt.Errorf("Bad: Get on routesClient: %+v", err) - } - - if len(*resp.Routes) != 0 { - return fmt.Errorf("Bad: Expected No Routes found: %d", len(*resp.Routes)) - } - - return nil - } -} - func testCheckAzureRMRouteExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -276,24 +215,3 @@ resource "azurerm_route" "test1" { } `, rInt, location, rInt, rInt) } - -func testAccAzureRMRoute_basicUpdate(rInt int, location string) string { - return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_route_table" "test" { - name = "acctestrt%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - - tags { - environment = "Production" - } -} - - -`, rInt, location, rInt) -} From ee1dcac0eaba8ce9866ce304c84a18ae8eee2f0f Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Fri, 8 Jun 2018 20:51:21 -0400 Subject: [PATCH 16/23] Working through pr comments --- .../{ => helpers/keyvault}/key_vault_access_policy.go | 9 ++++++++- azurerm/resource_arm_key_vault.go | 6 +++--- 2 files changed, 11 insertions(+), 4 deletions(-) rename azurerm/{ => helpers/keyvault}/key_vault_access_policy.go (94%) diff --git a/azurerm/key_vault_access_policy.go b/azurerm/helpers/keyvault/key_vault_access_policy.go similarity index 94% rename from azurerm/key_vault_access_policy.go rename to azurerm/helpers/keyvault/key_vault_access_policy.go index 8d4af37cd911..fa0b93cfc726 100644 --- a/azurerm/key_vault_access_policy.go +++ b/azurerm/helpers/keyvault/key_vault_access_policy.go @@ -1,9 +1,10 @@ -package azurerm +package keyvault import ( "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" + "strings" ) func keyPermissionsSchema() *schema.Schema { @@ -147,3 +148,9 @@ func expandKeyVaultAccessPolicySecretPermissions(secretPermissionsRaw []interfac } return &secretPermissions } + +// ignoreCaseDiffSuppressFunc is a DiffSuppressFunc from helper/schema that is +// used to ignore any case-changes in a return value. +func ignoreCaseDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + return strings.ToLower(old) == strings.ToLower(new) +} diff --git a/azurerm/resource_arm_key_vault.go b/azurerm/resource_arm_key_vault.go index 6a2f5a916bb0..69b1ff899e1f 100644 --- a/azurerm/resource_arm_key_vault.go +++ b/azurerm/resource_arm_key_vault.go @@ -8,7 +8,6 @@ import ( "time" "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" - //"github.com/davecgh/go-spew/spew" "github.com/hashicorp/go-getter/helper/url" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" @@ -152,8 +151,8 @@ func resourceArmKeyVaultCreate(d *schema.ResourceData, meta interface{}) error { Tags: expandTags(tags), } - //return fmt.Errorf("%s", spew.Sdump(parameters)) - + // Locking this resource so we don't make modifications to it at the same time if there is a + // key vault access policy trying to update it as well azureRMLockByName(name, keyVaultResourceName) defer azureRMUnlockByName(name, keyVaultResourceName) @@ -175,6 +174,7 @@ func resourceArmKeyVaultCreate(d *schema.ResourceData, meta interface{}) error { if d.IsNewResource() { if props := read.Properties; props != nil { if vault := props.VaultURI; vault != nil { + log.Printf("[DEBUG] Waiting for Key Vault %q (Resource Group %q) to become available", name, resGroup) err := resource.Retry(120*time.Second, checkKeyVaultDNSIsAvailable(*vault)) if err != nil { return err From 4c618a2070a76a830af247dcd1ab5f924bbfded7 Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Fri, 22 Jun 2018 13:24:02 -0400 Subject: [PATCH 17/23] Updated for PR comments as well as added several unittests for the key_vault_access_policy shared helper library --- .../keyvault/key_vault_access_policy.go | 16 +- .../keyvault/key_vault_access_policy_test.go | 301 ++++++++++++++++++ azurerm/resource_arm_key_vault.go | 123 ++++--- .../resource_arm_key_vault_access_policy.go | 23 +- ...source_arm_key_vault_access_policy_test.go | 8 +- .../r/key_vault_access_policy.html.markdown | 16 +- 6 files changed, 406 insertions(+), 81 deletions(-) create mode 100644 azurerm/helpers/keyvault/key_vault_access_policy_test.go diff --git a/azurerm/helpers/keyvault/key_vault_access_policy.go b/azurerm/helpers/keyvault/key_vault_access_policy.go index fa0b93cfc726..eb8f7e1a4469 100644 --- a/azurerm/helpers/keyvault/key_vault_access_policy.go +++ b/azurerm/helpers/keyvault/key_vault_access_policy.go @@ -7,7 +7,7 @@ import ( "strings" ) -func keyPermissionsSchema() *schema.Schema { +func KeyPermissionsSchema() *schema.Schema { return &schema.Schema{ Type: schema.TypeList, Required: true, @@ -36,7 +36,7 @@ func keyPermissionsSchema() *schema.Schema { } } -func secretPermissionsSchema() *schema.Schema { +func SecretPermissionsSchema() *schema.Schema { return &schema.Schema{ Type: schema.TypeList, Required: true, @@ -57,7 +57,7 @@ func secretPermissionsSchema() *schema.Schema { } } -func certificatePermissionsSchema() *schema.Schema { +func CertificatePermissionsSchema() *schema.Schema { return &schema.Schema{ Type: schema.TypeList, Optional: true, @@ -84,7 +84,7 @@ func certificatePermissionsSchema() *schema.Schema { } } -func flattenKeyVaultAccessPolicies(policies *[]keyvault.AccessPolicyEntry) []map[string]interface{} { +func FlattenKeyVaultAccessPolicies(policies *[]keyvault.AccessPolicyEntry) []map[string]interface{} { result := make([]map[string]interface{}, 0, len(*policies)) for _, policy := range *policies { @@ -122,7 +122,7 @@ func flattenKeyVaultAccessPolicies(policies *[]keyvault.AccessPolicyEntry) []map return result } -func expandKeyVaultAccessPolicyCertificatePermissions(certificatePermissionsRaw []interface{}) *[]keyvault.CertificatePermissions { +func ExpandKeyVaultAccessPolicyCertificatePermissions(certificatePermissionsRaw []interface{}) *[]keyvault.CertificatePermissions { certificatePermissions := []keyvault.CertificatePermissions{} for _, permission := range certificatePermissionsRaw { @@ -131,7 +131,7 @@ func expandKeyVaultAccessPolicyCertificatePermissions(certificatePermissionsRaw return &certificatePermissions } -func expandKeyVaultAccessPolicyKeyPermissions(keyPermissionsRaw []interface{}) *[]keyvault.KeyPermissions { +func ExpandKeyVaultAccessPolicyKeyPermissions(keyPermissionsRaw []interface{}) *[]keyvault.KeyPermissions { keyPermissions := []keyvault.KeyPermissions{} for _, permission := range keyPermissionsRaw { @@ -140,7 +140,7 @@ func expandKeyVaultAccessPolicyKeyPermissions(keyPermissionsRaw []interface{}) * return &keyPermissions } -func expandKeyVaultAccessPolicySecretPermissions(secretPermissionsRaw []interface{}) *[]keyvault.SecretPermissions { +func ExpandKeyVaultAccessPolicySecretPermissions(secretPermissionsRaw []interface{}) *[]keyvault.SecretPermissions { secretPermissions := []keyvault.SecretPermissions{} for _, permission := range secretPermissionsRaw { @@ -149,8 +149,6 @@ func expandKeyVaultAccessPolicySecretPermissions(secretPermissionsRaw []interfac return &secretPermissions } -// ignoreCaseDiffSuppressFunc is a DiffSuppressFunc from helper/schema that is -// used to ignore any case-changes in a return value. func ignoreCaseDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { return strings.ToLower(old) == strings.ToLower(new) } diff --git a/azurerm/helpers/keyvault/key_vault_access_policy_test.go b/azurerm/helpers/keyvault/key_vault_access_policy_test.go new file mode 100644 index 000000000000..de67edf4039d --- /dev/null +++ b/azurerm/helpers/keyvault/key_vault_access_policy_test.go @@ -0,0 +1,301 @@ +package keyvault + +import ( + "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" + "github.com/davecgh/go-spew/spew" + uuid "github.com/satori/go.uuid" + "reflect" + "testing" +) + +func TestFlattenKeyVaultAccessPolicies_noPolicies(t *testing.T) { + policies := make([]keyvault.AccessPolicyEntry, 0, 0) + flattenedPolicies := FlattenKeyVaultAccessPolicies(&policies) + if len(flattenedPolicies) != 0 { + t.Fatalf("Expected empty policy list, received non-empty policy list back") + } +} + +func TestFlattenKeyVaultAccessPolicies_oneEmptyPolicy(t *testing.T) { + tenantId := uuid.NewV4() + objectId := uuid.NewV4().String() + applicationId := uuid.NewV4() + + policies := createPolicies(&tenantId, &objectId, &applicationId, nil) + + expectedPolicy := make(map[string]interface{}) + + expectedPolicy["tenant_id"] = tenantId.String() + expectedPolicy["object_id"] = objectId + expectedPolicy["application_id"] = applicationId.String() + expectedPolicy["key_permissions"] = make([]interface{}, 0, 0) + expectedPolicy["secret_permissions"] = make([]interface{}, 0, 0) + expectedPolicy["certificate_permissions"] = make([]interface{}, 0, 0) + + flattenedPolicies := FlattenKeyVaultAccessPolicies(policies) + + if !reflect.DeepEqual(flattenedPolicies[0], expectedPolicy) { + t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(flattenedPolicies), spew.Sdump(expectedPolicy)) + } +} + +func TestFlattenKeyVaultAccessPolicies_oneFullPolicy(t *testing.T) { + tenantId := uuid.NewV4() + objectId := uuid.NewV4().String() + applicationId := uuid.NewV4() + + certPerms := possibleCertificatePermissionsValues() + keyPerms := possibleKeyPermissionsValues() + secretPerms := possibleSecretPermissionsValues() + + permissions := &keyvault.Permissions{ + Certificates: &certPerms, + Keys: &keyPerms, + Secrets: &secretPerms, + } + + policies := createPolicies(&tenantId, &objectId, &applicationId, permissions) + + expectedPolicy := make(map[string]interface{}) + + expectedPolicy["tenant_id"] = tenantId.String() + expectedPolicy["object_id"] = objectId + expectedPolicy["application_id"] = applicationId.String() + expectedPolicy["key_permissions"] = possibleKeyPermissionsStrings() + expectedPolicy["secret_permissions"] = possibleSecretPermissionsStrings() + expectedPolicy["certificate_permissions"] = possibleCertificatePermissionsStrings() + flattenedPolicies := FlattenKeyVaultAccessPolicies(policies) + + if !reflect.DeepEqual(flattenedPolicies[0], expectedPolicy) { + t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(flattenedPolicies), spew.Sdump(expectedPolicy)) + } +} + +func TestExpandKeyVaultAccessPolicyCertificatePermissions_empty(t *testing.T) { + permissions := make([]interface{}, 0, 0) + certPerms := ExpandKeyVaultAccessPolicyCertificatePermissions(permissions) + + certPermsKeyVault := make([]keyvault.CertificatePermissions, 0, 0) + + if !reflect.DeepEqual(*certPerms, certPermsKeyVault) { + t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(certPerms), spew.Sdump(certPermsKeyVault)) + } +} + +func TestExpandKeyVaultAccessPolicyCertificatePermissions_full(t *testing.T) { + permissions := possibleCertificatePermissionsStrings() + + certPerms := ExpandKeyVaultAccessPolicyCertificatePermissions(permissions) + + certPermsKeyVault := possibleCertificatePermissionsValues() + + if !reflect.DeepEqual(*certPerms, certPermsKeyVault) { + t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(certPerms), spew.Sdump(certPermsKeyVault)) + } +} + +func TestExpandKeyVaultAccessPolicyKeyPermissions_empty(t *testing.T) { + permissions := make([]interface{}, 0, 0) + + keyPerms := ExpandKeyVaultAccessPolicyKeyPermissions(permissions) + + keyPermsKeyVault := make([]keyvault.KeyPermissions, 0, 0) + + if !reflect.DeepEqual(*keyPerms, keyPermsKeyVault) { + t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(keyPerms), spew.Sdump(keyPermsKeyVault)) + } +} + +func TestExpandKeyVaultAccessPolicyKeyPermissions_full(t *testing.T) { + permissions := possibleKeyPermissionsStrings() + + keyPerms := ExpandKeyVaultAccessPolicyKeyPermissions(permissions) + + keyPermsKeyVault := possibleKeyPermissionsValues() + + if !reflect.DeepEqual(*keyPerms, keyPermsKeyVault) { + t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(keyPerms), spew.Sdump(keyPermsKeyVault)) + } +} + +func TestExpandKeyVaultAccessPolicySecretPermissions_empty(t *testing.T) { + permissions := make([]interface{}, 0, 0) + + secretPerms := ExpandKeyVaultAccessPolicySecretPermissions(permissions) + + secretPermsKeyVault := make([]keyvault.SecretPermissions, 0, 0) + + if !reflect.DeepEqual(*secretPerms, secretPermsKeyVault) { + t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(secretPerms), spew.Sdump(secretPermsKeyVault)) + } +} + +func TestExpandKeyVaultAccessPolicySecretPermissions_full(t *testing.T) { + permissions := possibleSecretPermissionsStrings() + + secretPerms := ExpandKeyVaultAccessPolicySecretPermissions(permissions) + + secretPermsKeyVault := possibleSecretPermissionsValues() + + if !reflect.DeepEqual(*secretPerms, secretPermsKeyVault) { + t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(secretPerms), spew.Sdump(secretPermsKeyVault)) + } +} + +func createPolicies(tenantId *uuid.UUID, objectId *string, applicationId *uuid.UUID, permissions *keyvault.Permissions) *[]keyvault.AccessPolicyEntry { + + policies := make([]keyvault.AccessPolicyEntry, 0, 0) + + if permissions == nil { + certPerms := make([]keyvault.CertificatePermissions, 0, 0) + keyPerms := make([]keyvault.KeyPermissions, 0, 0) + secretPerms := make([]keyvault.SecretPermissions, 0, 0) + + permissions = &keyvault.Permissions{ + Certificates: &certPerms, + Keys: &keyPerms, + Secrets: &secretPerms, + } + } + + if applicationId == nil { + policy := keyvault.AccessPolicyEntry{ + TenantID: tenantId, + ObjectID: objectId, + Permissions: permissions, + } + policies = append(policies, policy) + } else { + policy := keyvault.AccessPolicyEntry{ + TenantID: tenantId, + ObjectID: objectId, + ApplicationID: applicationId, + Permissions: permissions, + } + policies = append(policies, policy) + } + + return &policies +} + +func possibleCertificatePermissionsStrings() []interface{} { + + var ret []interface{} + + ret = append( + ret, + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "setissuers", + "update", + ) + + return ret +} + +func possibleCertificatePermissionsValues() []keyvault.CertificatePermissions { + return []keyvault.CertificatePermissions{ + keyvault.Create, + keyvault.Delete, + keyvault.Deleteissuers, + keyvault.Get, + keyvault.Getissuers, + keyvault.Import, + keyvault.List, + keyvault.Listissuers, + keyvault.Managecontacts, + keyvault.Manageissuers, + keyvault.Purge, + keyvault.Recover, + keyvault.Setissuers, + keyvault.Update, + } +} + +func possibleKeyPermissionsStrings() []interface{} { + var ret []interface{} + + ret = append( + ret, + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "import", + "list", + "purge", + "recover", + "restore", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey", + ) + + return ret +} + +func possibleKeyPermissionsValues() []keyvault.KeyPermissions { + return []keyvault.KeyPermissions{ + keyvault.KeyPermissionsBackup, + keyvault.KeyPermissionsCreate, + keyvault.KeyPermissionsDecrypt, + keyvault.KeyPermissionsDelete, + keyvault.KeyPermissionsEncrypt, + keyvault.KeyPermissionsGet, + keyvault.KeyPermissionsImport, + keyvault.KeyPermissionsList, + keyvault.KeyPermissionsPurge, + keyvault.KeyPermissionsRecover, + keyvault.KeyPermissionsRestore, + keyvault.KeyPermissionsSign, + keyvault.KeyPermissionsUnwrapKey, + keyvault.KeyPermissionsUpdate, + keyvault.KeyPermissionsVerify, + keyvault.KeyPermissionsWrapKey, + } +} + +func possibleSecretPermissionsStrings() []interface{} { + var ret []interface{} + + ret = append( + ret, + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set", + ) + + return ret +} + +func possibleSecretPermissionsValues() []keyvault.SecretPermissions { + return []keyvault.SecretPermissions{ + keyvault.SecretPermissionsBackup, + keyvault.SecretPermissionsDelete, + keyvault.SecretPermissionsGet, + keyvault.SecretPermissionsList, + keyvault.SecretPermissionsPurge, + keyvault.SecretPermissionsRecover, + keyvault.SecretPermissionsRestore, + keyvault.SecretPermissionsSet, + } +} diff --git a/azurerm/resource_arm_key_vault.go b/azurerm/resource_arm_key_vault.go index 69b1ff899e1f..697a672637e6 100644 --- a/azurerm/resource_arm_key_vault.go +++ b/azurerm/resource_arm_key_vault.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" uuid "github.com/satori/go.uuid" + keyVaultHelper "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/keyvault" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -97,9 +98,9 @@ func resourceArmKeyVault() *schema.Resource { Optional: true, ValidateFunc: validateUUID, }, - "certificate_permissions": certificatePermissionsSchema(), - "key_permissions": keyPermissionsSchema(), - "secret_permissions": secretPermissionsSchema(), + "certificate_permissions": keyVaultHelper.CertificatePermissionsSchema(), + "key_permissions": keyVaultHelper.KeyPermissionsSchema(), + "secret_permissions": keyVaultHelper.SecretPermissionsSchema(), }, }, }, @@ -175,9 +176,18 @@ func resourceArmKeyVaultCreate(d *schema.ResourceData, meta interface{}) error { if props := read.Properties; props != nil { if vault := props.VaultURI; vault != nil { log.Printf("[DEBUG] Waiting for Key Vault %q (Resource Group %q) to become available", name, resGroup) - err := resource.Retry(120*time.Second, checkKeyVaultDNSIsAvailable(*vault)) - if err != nil { - return err + stateConf := &resource.StateChangeConf{ + Pending: []string{"pending"}, + Target: []string{"available"}, + Refresh: keyVaultRefreshFunc(*vault), + Timeout: 30 * time.Minute, + Delay: 30 * time.Second, + PollInterval: 10 * time.Second, + ContinuousTargetOccurence: 10, + } + + if _, err := stateConf.WaitForState(); err != nil { + return fmt.Errorf("Error waiting for Key Vault %q (Resource Group %q) to become available: %s", name, resGroup, err) } } } @@ -214,16 +224,22 @@ func resourceArmKeyVaultRead(d *schema.ResourceData, meta interface{}) error { if location := resp.Location; location != nil { d.Set("location", azureRMNormalizeLocation(*location)) } - d.Set("tenant_id", resp.Properties.TenantID.String()) - d.Set("enabled_for_deployment", resp.Properties.EnabledForDeployment) - d.Set("enabled_for_disk_encryption", resp.Properties.EnabledForDiskEncryption) - d.Set("enabled_for_template_deployment", resp.Properties.EnabledForTemplateDeployment) - d.Set("sku", flattenKeyVaultSku(resp.Properties.Sku)) - d.Set("access_policy", flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) - d.Set("vault_uri", resp.Properties.VaultURI) - flattenAndSetTags(d, resp.Tags) + if props := resp.Properties; props != nil { + d.Set("tenant_id", props.TenantID.String()) + d.Set("enabled_for_deployment", props.EnabledForDeployment) + d.Set("enabled_for_disk_encryption", props.EnabledForDiskEncryption) + d.Set("enabled_for_template_deployment", props.EnabledForTemplateDeployment) + if err := d.Set("sku", flattenKeyVaultSku(props.Sku)); err != nil { + return fmt.Errorf("Error flattening `sku` for KeyVault %q: %+v", resp.Name, err) + } + if err := d.Set("access_policy", keyVaultHelper.FlattenKeyVaultAccessPolicies(props.AccessPolicies)); err != nil { + return fmt.Errorf("Error flattening `access_policy` for KeyVault %q: %+v", resp.Name, err) + } + d.Set("vault_uri", props.VaultURI) + } + flattenAndSetTags(d, resp.Tags) return nil } @@ -256,40 +272,6 @@ func expandKeyVaultSku(d *schema.ResourceData) *keyvault.Sku { } } -func flattenKeyVaultSku(sku *keyvault.Sku) []interface{} { - result := map[string]interface{}{ - "name": string(sku.Name), - } - - return []interface{}{result} -} - -func validateKeyVaultName(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - if matched := regexp.MustCompile(`^[a-zA-Z0-9-]{3,24}$`).Match([]byte(value)); !matched { - errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters and dashes and must be between 3-24 chars", k)) - } - - return -} - -func checkKeyVaultDNSIsAvailable(vaultUri string) func() *resource.RetryError { - return func() *resource.RetryError { - uri, err := url.Parse(vaultUri) - if err != nil { - return resource.NonRetryableError(err) - } - - conn, err := net.Dial("tcp", fmt.Sprintf("%s:443", uri.Host)) - if err != nil { - return resource.RetryableError(err) - } - - _ = conn.Close() - return nil - } -} - func expandKeyVaultAccessPolicies(d *schema.ResourceData) *[]keyvault.AccessPolicyEntry { policies := d.Get("access_policy").([]interface{}) result := make([]keyvault.AccessPolicyEntry, 0, len(policies)) @@ -303,9 +285,9 @@ func expandKeyVaultAccessPolicies(d *schema.ResourceData) *[]keyvault.AccessPoli policy := keyvault.AccessPolicyEntry{ Permissions: &keyvault.Permissions{ - Certificates: expandKeyVaultAccessPolicyCertificatePermissions(certificatePermissionsRaw), - Keys: expandKeyVaultAccessPolicyKeyPermissions(keyPermissionsRaw), - Secrets: expandKeyVaultAccessPolicySecretPermissions(secretPermissionsRaw), + Certificates: keyVaultHelper.ExpandKeyVaultAccessPolicyCertificatePermissions(certificatePermissionsRaw), + Keys: keyVaultHelper.ExpandKeyVaultAccessPolicyKeyPermissions(keyPermissionsRaw), + Secrets: keyVaultHelper.ExpandKeyVaultAccessPolicySecretPermissions(secretPermissionsRaw), }, } @@ -324,3 +306,42 @@ func expandKeyVaultAccessPolicies(d *schema.ResourceData) *[]keyvault.AccessPoli return &result } + +func flattenKeyVaultSku(sku *keyvault.Sku) []interface{} { + result := map[string]interface{}{ + "name": string(sku.Name), + } + + return []interface{}{result} +} + +func validateKeyVaultName(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + if matched := regexp.MustCompile(`^[a-zA-Z0-9-]{3,24}$`).Match([]byte(value)); !matched { + errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters and dashes and must be between 3-24 chars", k)) + } + + return +} + +func keyVaultRefreshFunc(vaultUri string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + log.Printf("[DEBUG] Checking to see if KeyVault %q is available..", vaultUri) + uri, err := url.Parse(vaultUri) + if err != nil { + return nil, "error", fmt.Errorf("Error parsing URI %q: %s", vaultUri, err) + } + + hostAndPort := fmt.Sprintf("%s:443", uri.Host) + conn, err := net.Dial("tcp", hostAndPort) + if err != nil { + log.Printf("[DEBUG] Didn't find KeyVault at %q", hostAndPort) + return nil, "pending", fmt.Errorf("Error connecting to %q: %s", hostAndPort, err) + } + + _ = conn.Close() + + log.Printf("[DEBUG] Found KeyVault at %q", hostAndPort) + return "available", "available", nil + } +} diff --git a/azurerm/resource_arm_key_vault_access_policy.go b/azurerm/resource_arm_key_vault_access_policy.go index 31c5a0a29fc7..91448deefb4b 100644 --- a/azurerm/resource_arm_key_vault_access_policy.go +++ b/azurerm/resource_arm_key_vault_access_policy.go @@ -7,6 +7,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" "github.com/hashicorp/terraform/helper/schema" uuid "github.com/satori/go.uuid" + keyVaultHelper "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/keyvault" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -52,9 +53,9 @@ func resourceArmKeyVaultAccessPolicy() *schema.Resource { ValidateFunc: validateUUID, ForceNew: true, }, - "certificate_permissions": certificatePermissionsSchema(), - "key_permissions": keyPermissionsSchema(), - "secret_permissions": secretPermissionsSchema(), + "certificate_permissions": keyVaultHelper.CertificatePermissionsSchema(), + "key_permissions": keyVaultHelper.KeyPermissionsSchema(), + "secret_permissions": keyVaultHelper.SecretPermissionsSchema(), }, } } @@ -67,8 +68,7 @@ func resourceArmKeyVaultAccessPolicyCreateOrDelete(d *schema.ResourceData, meta name := d.Get("vault_name").(string) resGroup := d.Get("resource_group_name").(string) - accessPolicy := expandKeyVaultAccessPolicy(d) - accessPolicies := []keyvault.AccessPolicyEntry{accessPolicy} + accessPolicies := []keyvault.AccessPolicyEntry{expandKeyVaultAccessPolicy(d)} parameters := keyvault.VaultAccessPolicyParameters{ Name: &name, @@ -113,6 +113,7 @@ func resourceArmKeyVaultAccessPolicyCreate(d *schema.ResourceData, meta interfac } func resourceArmKeyVaultAccessPolicyDelete(d *schema.ResourceData, meta interface{}) error { + // Lets lock the keyvault during a deletion to prevent a run updating the policies during a deletion azureRMLockByName(d.Get("vault_name").(string), keyVaultAccessPolicyResourceName) defer azureRMUnlockByName(d.Get("vault_name").(string), keyVaultAccessPolicyResourceName) @@ -144,7 +145,11 @@ func resourceArmKeyVaultAccessPolicyRead(d *schema.ResourceData, meta interface{ return fmt.Errorf("Error making Read request on Azure KeyVault %s: %+v", name, err) } - flattenedPolicy := flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies) + if resp.Properties == nil { + return fmt.Errorf("Properties not returned by api for Azurue KeyVault %s", name) + } + + flattenedPolicy := keyVaultHelper.FlattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies) policyObjectId := id.Path["objectId"] policyApplicationId := id.Path["applicationId"] @@ -204,9 +209,9 @@ func expandKeyVaultAccessPolicy(d *schema.ResourceData) keyvault.AccessPolicyEnt policy := keyvault.AccessPolicyEntry{ Permissions: &keyvault.Permissions{ - Certificates: expandKeyVaultAccessPolicyCertificatePermissions(d.Get("certificate_permissions").([]interface{})), - Keys: expandKeyVaultAccessPolicyKeyPermissions(d.Get("key_permissions").([]interface{})), - Secrets: expandKeyVaultAccessPolicySecretPermissions(d.Get("secret_permissions").([]interface{})), + Certificates: keyVaultHelper.ExpandKeyVaultAccessPolicyCertificatePermissions(d.Get("certificate_permissions").([]interface{})), + Keys: keyVaultHelper.ExpandKeyVaultAccessPolicyKeyPermissions(d.Get("key_permissions").([]interface{})), + Secrets: keyVaultHelper.ExpandKeyVaultAccessPolicySecretPermissions(d.Get("secret_permissions").([]interface{})), }, } diff --git a/azurerm/resource_arm_key_vault_access_policy_test.go b/azurerm/resource_arm_key_vault_access_policy_test.go index a670aeb40f2f..8ab2185cf8ce 100644 --- a/azurerm/resource_arm_key_vault_access_policy_test.go +++ b/azurerm/resource_arm_key_vault_access_policy_test.go @@ -4,12 +4,11 @@ import ( "fmt" "testing" - "github.com/davecgh/go-spew/spew" "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" + keyVaultHelper "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/keyvault" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" - "log" ) func TestAccAzureRMKeyVaultAccessPolicy_basic(t *testing.T) { @@ -162,7 +161,7 @@ func testCheckAzureRMKeyVaultAccessPolicyExists(name string, policyObjectTag str policyIdentity := getPolicyIdentity(&objectId, &applicationId) - policy := findKeyVaultAccessPolicy(policyIdentity, flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) + policy := findKeyVaultAccessPolicy(policyIdentity, keyVaultHelper.FlattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) if policy == nil { return fmt.Errorf("Bad: Key Vault Policy %q (resource group: %q, object_id: %s) does not exist", name, resGroup, objectId) @@ -179,7 +178,6 @@ func testCheckAzureRMKeyVaultAccessPolicyMissing(name string, policyObjectTag st if !ok { return fmt.Errorf("Not found: %s", name) } - log.Printf("%s", spew.Sdump(rs)) name := rs.Primary.Attributes["name"] resGroup := rs.Primary.Attributes["resource_group_name"] @@ -197,7 +195,7 @@ func testCheckAzureRMKeyVaultAccessPolicyMissing(name string, policyObjectTag st objectId := rs.Primary.Attributes[policyObjectTag] - policy := findKeyVaultAccessPolicy(objectId, flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) + policy := findKeyVaultAccessPolicy(objectId, keyVaultHelper.FlattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) if policy != nil { return fmt.Errorf("Bad: Key Vault Policy %q (resource group: %q, object_id: %s) exists", name, resGroup, objectId) diff --git a/website/docs/r/key_vault_access_policy.html.markdown b/website/docs/r/key_vault_access_policy.html.markdown index 3658ba27dc70..620b3178a08b 100644 --- a/website/docs/r/key_vault_access_policy.html.markdown +++ b/website/docs/r/key_vault_access_policy.html.markdown @@ -32,7 +32,7 @@ resource "azurerm_key_vault" "test" { name = "standard" } - tenant_id = "d6e396d0-5584-41dc-9fc0-268df99bc610" + tenant_id = "22222222-2222-2222-2222-222222222222" enabled_for_disk_encryption = true @@ -45,8 +45,8 @@ resource "azurerm_key_vault_access_policy" "test" { vault_name = "${azurerm_key_vault.test.name}" resource_group_name = "${azurerm_key_vault.test.resource_group_name}" - tenant_id = "d6e396d0-5584-41dc-9fc0-268df99bc610" - object_id = "d746815a-0433-4a21-b95d-fc437d2d475b" + tenant_id = "00000000-0000-0000-0000-000000000000" + object_id = "11111111-1111-1111-1111-111111111111" key_permissions = [ "get", @@ -82,10 +82,12 @@ The following arguments are supported: * `application_id` - (Optional) The object ID of an Application in Azure Active Directory. * `certificate_permissions` - (Optional) List of certificate permissions, must be one or more from - the following: `create`, `delete`, `deleteissuers`, `get`, `getissuers`, `import`, `list`, `listissuers`, `managecontacts`, `manageissuers`, `purge`, `recover`, `setissuers` and `update`. + the following: `create`, `delete`, `deleteissuers`, `get`, `getissuers`, `import`, `list`, `listissuers`, + `managecontacts`, `manageissuers`, `purge`, `recover`, `setissuers` and `update`. * `key_permissions` - (Required) List of key permissions, must be one or more from - the following: `backup`, `create`, `decrypt`, `delete`, `encrypt`, `get`, `import`, `list`, `purge`, `recover`, `restore`, `sign`, `unwrapKey`, `update`, `verify` and `wrapKey`. + the following: `backup`, `create`, `decrypt`, `delete`, `encrypt`, `get`, `import`, `list`, `purge`, + `recover`, `restore`, `sign`, `unwrapKey`, `update`, `verify` and `wrapKey`. * `secret_permissions` - (Required) List of secret permissions, must be one or more from the following: `backup`, `delete`, `get`, `list`, `purge`, `recover`, `restore` and `set`. @@ -102,9 +104,9 @@ Routes can be imported using the `resource id` of the keyvault with additional m the service principal objectId and the applicationId if applicable, e.g. ```shell -terraform import azurerm_key_vault_access_policy.testPolicy /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.KeyVault/vaults/test-vault/objectId/00000000-0000-0000-0000-000000000000 +terraform import azurerm_key_vault_access_policy.testPolicy /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.KeyVault/vaults/test-vault/objectId/11111111-1111-1111-1111-111111111111 ``` ```shell -terraform import azurerm_key_vault_access_policy.testPolicy /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.KeyVault/vaults/test-vault/objectId/00000000-0000-0000-0000-000000000000/applicationId/00000000-0000-0000-0000-000000000000 +terraform import azurerm_key_vault_access_policy.testPolicy /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.KeyVault/vaults/test-vault/objectId/11111111-1111-1111-1111-111111111111/applicationId/22222222-2222-2222-2222-222222222222 ``` \ No newline at end of file From 17f46df189567124cb94c7076c0be6c2e81d9e60 Mon Sep 17 00:00:00 2001 From: Jeff Albert Date: Fri, 29 Jun 2018 09:31:44 -0400 Subject: [PATCH 18/23] Ran make fmt --- azurerm/provider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/provider.go b/azurerm/provider.go index eadbebc6f365..10a26c8212bf 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -158,7 +158,7 @@ func Provider() terraform.ResourceProvider { "azurerm_image": resourceArmImage(), "azurerm_iothub": resourceArmIotHub(), "azurerm_key_vault": resourceArmKeyVault(), - "azurerm_key_vault_access_policy": resourceArmKeyVaultAccessPolicy(), + "azurerm_key_vault_access_policy": resourceArmKeyVaultAccessPolicy(), "azurerm_key_vault_certificate": resourceArmKeyVaultCertificate(), "azurerm_key_vault_key": resourceArmKeyVaultKey(), "azurerm_key_vault_secret": resourceArmKeyVaultSecret(), From 44b64a0fc474e3ed2c0c76087a881efba180906b Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 6 Jul 2018 17:41:42 +0200 Subject: [PATCH 19/23] Refactoring the helpers into the `helpers/schema` folder Ensuring we only lock on the Key Vault name, since the access policy doesn't matter for locking purposes if we lock on the entire KeyVault ``` $ acctests azurerm TestAccAzureRMKeyVaultAccessPolicy_ === RUN TestAccAzureRMKeyVaultAccessPolicy_basic --- PASS: TestAccAzureRMKeyVaultAccessPolicy_basic (222.29s) === RUN TestAccAzureRMKeyVaultAccessPolicy_multiple --- PASS: TestAccAzureRMKeyVaultAccessPolicy_multiple (228.28s) === RUN TestAccAzureRMKeyVaultAccessPolicy_update --- PASS: TestAccAzureRMKeyVaultAccessPolicy_update (238.59s) PASS ok github.com/terraform-providers/terraform-provider-azurerm/azurerm 689.209s ``` --- azurerm/data_source_key_vault.go | 55 +--- .../keyvault/key_vault_access_policy.go | 154 --------- .../keyvault/key_vault_access_policy_test.go | 301 ------------------ .../helpers/schema/key_vault_access_policy.go | 224 +++++++++++++ azurerm/resource_arm_key_vault.go | 68 ++-- .../resource_arm_key_vault_access_policy.go | 210 ++++++------ ...source_arm_key_vault_access_policy_test.go | 109 ++----- 7 files changed, 383 insertions(+), 738 deletions(-) delete mode 100644 azurerm/helpers/keyvault/key_vault_access_policy.go delete mode 100644 azurerm/helpers/keyvault/key_vault_access_policy_test.go create mode 100644 azurerm/helpers/schema/key_vault_access_policy.go diff --git a/azurerm/data_source_key_vault.go b/azurerm/data_source_key_vault.go index 3107545aba0e..b066ca762b4e 100644 --- a/azurerm/data_source_key_vault.go +++ b/azurerm/data_source_key_vault.go @@ -5,6 +5,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" "github.com/hashicorp/terraform/helper/schema" + kvschema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -140,7 +141,9 @@ func dataSourceArmKeyVaultRead(d *schema.ResourceData, meta interface{}) error { if err := d.Set("sku", flattenKeyVaultDataSourceSku(props.Sku)); err != nil { return fmt.Errorf("Error flattening `sku` for KeyVault %q: %+v", resp.Name, err) } - if err := d.Set("access_policy", flattenKeyVaultDataSourceAccessPolicies(props.AccessPolicies)); err != nil { + + flattenedPolicies := kvschema.FlattenKeyVaultAccessPolicies(props.AccessPolicies) + if err := d.Set("access_policy", flattenedPolicies); err != nil { return fmt.Errorf("Error flattening `access_policy` for KeyVault %q: %+v", resp.Name, err) } d.Set("vault_uri", props.VaultURI) @@ -158,53 +161,3 @@ func flattenKeyVaultDataSourceSku(sku *keyvault.Sku) []interface{} { return []interface{}{result} } - -func flattenKeyVaultDataSourceAccessPolicies(policies *[]keyvault.AccessPolicyEntry) []interface{} { - result := make([]interface{}, 0, len(*policies)) - - if policies == nil { - return result - } - - for _, policy := range *policies { - policyRaw := make(map[string]interface{}) - - keyPermissionsRaw := make([]interface{}, 0) - secretPermissionsRaw := make([]interface{}, 0) - certificatePermissionsRaw := make([]interface{}, 0) - - if permissions := policy.Permissions; permissions != nil { - if keys := permissions.Keys; keys != nil { - for _, keyPermission := range *keys { - keyPermissionsRaw = append(keyPermissionsRaw, string(keyPermission)) - } - } - if secrets := permissions.Secrets; secrets != nil { - for _, secretPermission := range *secrets { - secretPermissionsRaw = append(secretPermissionsRaw, string(secretPermission)) - } - } - - if certificates := permissions.Certificates; certificates != nil { - for _, certificatePermission := range *certificates { - certificatePermissionsRaw = append(certificatePermissionsRaw, string(certificatePermission)) - } - } - } - - policyRaw["tenant_id"] = policy.TenantID.String() - if policy.ObjectID != nil { - policyRaw["object_id"] = *policy.ObjectID - } - if policy.ApplicationID != nil { - policyRaw["application_id"] = policy.ApplicationID.String() - } - policyRaw["key_permissions"] = keyPermissionsRaw - policyRaw["secret_permissions"] = secretPermissionsRaw - policyRaw["certificate_permissions"] = certificatePermissionsRaw - - result = append(result, policyRaw) - } - - return result -} diff --git a/azurerm/helpers/keyvault/key_vault_access_policy.go b/azurerm/helpers/keyvault/key_vault_access_policy.go deleted file mode 100644 index eb8f7e1a4469..000000000000 --- a/azurerm/helpers/keyvault/key_vault_access_policy.go +++ /dev/null @@ -1,154 +0,0 @@ -package keyvault - -import ( - "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" - "github.com/hashicorp/terraform/helper/schema" - "github.com/hashicorp/terraform/helper/validation" - "strings" -) - -func KeyPermissionsSchema() *schema.Schema { - return &schema.Schema{ - Type: schema.TypeList, - Required: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{ - string(keyvault.KeyPermissionsBackup), - string(keyvault.KeyPermissionsCreate), - string(keyvault.KeyPermissionsDecrypt), - string(keyvault.KeyPermissionsDelete), - string(keyvault.KeyPermissionsEncrypt), - string(keyvault.KeyPermissionsGet), - string(keyvault.KeyPermissionsImport), - string(keyvault.KeyPermissionsList), - string(keyvault.KeyPermissionsPurge), - string(keyvault.KeyPermissionsRecover), - string(keyvault.KeyPermissionsRestore), - string(keyvault.KeyPermissionsSign), - string(keyvault.KeyPermissionsUnwrapKey), - string(keyvault.KeyPermissionsUpdate), - string(keyvault.KeyPermissionsVerify), - string(keyvault.KeyPermissionsWrapKey), - }, true), - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, - }, - } -} - -func SecretPermissionsSchema() *schema.Schema { - return &schema.Schema{ - Type: schema.TypeList, - Required: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{ - string(keyvault.SecretPermissionsBackup), - string(keyvault.SecretPermissionsDelete), - string(keyvault.SecretPermissionsGet), - string(keyvault.SecretPermissionsList), - string(keyvault.SecretPermissionsPurge), - string(keyvault.SecretPermissionsRecover), - string(keyvault.SecretPermissionsRestore), - string(keyvault.SecretPermissionsSet), - }, true), - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, - }, - } -} - -func CertificatePermissionsSchema() *schema.Schema { - return &schema.Schema{ - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{ - string(keyvault.Create), - string(keyvault.Delete), - string(keyvault.Deleteissuers), - string(keyvault.Get), - string(keyvault.Getissuers), - string(keyvault.Import), - string(keyvault.List), - string(keyvault.Listissuers), - string(keyvault.Managecontacts), - string(keyvault.Manageissuers), - string(keyvault.Purge), - string(keyvault.Recover), - string(keyvault.Setissuers), - string(keyvault.Update), - }, true), - DiffSuppressFunc: ignoreCaseDiffSuppressFunc, - }, - } -} - -func FlattenKeyVaultAccessPolicies(policies *[]keyvault.AccessPolicyEntry) []map[string]interface{} { - result := make([]map[string]interface{}, 0, len(*policies)) - - for _, policy := range *policies { - policyRaw := make(map[string]interface{}) - - keyPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Keys)) - for _, keyPermission := range *policy.Permissions.Keys { - keyPermissionsRaw = append(keyPermissionsRaw, string(keyPermission)) - } - - secretPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Secrets)) - for _, secretPermission := range *policy.Permissions.Secrets { - secretPermissionsRaw = append(secretPermissionsRaw, string(secretPermission)) - } - - policyRaw["tenant_id"] = policy.TenantID.String() - policyRaw["object_id"] = *policy.ObjectID - if policy.ApplicationID != nil { - policyRaw["application_id"] = policy.ApplicationID.String() - } - policyRaw["key_permissions"] = keyPermissionsRaw - policyRaw["secret_permissions"] = secretPermissionsRaw - - if policy.Permissions.Certificates != nil { - certificatePermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Certificates)) - for _, certificatePermission := range *policy.Permissions.Certificates { - certificatePermissionsRaw = append(certificatePermissionsRaw, string(certificatePermission)) - } - policyRaw["certificate_permissions"] = certificatePermissionsRaw - } - - result = append(result, policyRaw) - } - - return result -} - -func ExpandKeyVaultAccessPolicyCertificatePermissions(certificatePermissionsRaw []interface{}) *[]keyvault.CertificatePermissions { - certificatePermissions := []keyvault.CertificatePermissions{} - - for _, permission := range certificatePermissionsRaw { - certificatePermissions = append(certificatePermissions, keyvault.CertificatePermissions(permission.(string))) - } - return &certificatePermissions -} - -func ExpandKeyVaultAccessPolicyKeyPermissions(keyPermissionsRaw []interface{}) *[]keyvault.KeyPermissions { - keyPermissions := []keyvault.KeyPermissions{} - - for _, permission := range keyPermissionsRaw { - keyPermissions = append(keyPermissions, keyvault.KeyPermissions(permission.(string))) - } - return &keyPermissions -} - -func ExpandKeyVaultAccessPolicySecretPermissions(secretPermissionsRaw []interface{}) *[]keyvault.SecretPermissions { - secretPermissions := []keyvault.SecretPermissions{} - - for _, permission := range secretPermissionsRaw { - secretPermissions = append(secretPermissions, keyvault.SecretPermissions(permission.(string))) - } - return &secretPermissions -} - -func ignoreCaseDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { - return strings.ToLower(old) == strings.ToLower(new) -} diff --git a/azurerm/helpers/keyvault/key_vault_access_policy_test.go b/azurerm/helpers/keyvault/key_vault_access_policy_test.go deleted file mode 100644 index de67edf4039d..000000000000 --- a/azurerm/helpers/keyvault/key_vault_access_policy_test.go +++ /dev/null @@ -1,301 +0,0 @@ -package keyvault - -import ( - "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" - "github.com/davecgh/go-spew/spew" - uuid "github.com/satori/go.uuid" - "reflect" - "testing" -) - -func TestFlattenKeyVaultAccessPolicies_noPolicies(t *testing.T) { - policies := make([]keyvault.AccessPolicyEntry, 0, 0) - flattenedPolicies := FlattenKeyVaultAccessPolicies(&policies) - if len(flattenedPolicies) != 0 { - t.Fatalf("Expected empty policy list, received non-empty policy list back") - } -} - -func TestFlattenKeyVaultAccessPolicies_oneEmptyPolicy(t *testing.T) { - tenantId := uuid.NewV4() - objectId := uuid.NewV4().String() - applicationId := uuid.NewV4() - - policies := createPolicies(&tenantId, &objectId, &applicationId, nil) - - expectedPolicy := make(map[string]interface{}) - - expectedPolicy["tenant_id"] = tenantId.String() - expectedPolicy["object_id"] = objectId - expectedPolicy["application_id"] = applicationId.String() - expectedPolicy["key_permissions"] = make([]interface{}, 0, 0) - expectedPolicy["secret_permissions"] = make([]interface{}, 0, 0) - expectedPolicy["certificate_permissions"] = make([]interface{}, 0, 0) - - flattenedPolicies := FlattenKeyVaultAccessPolicies(policies) - - if !reflect.DeepEqual(flattenedPolicies[0], expectedPolicy) { - t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(flattenedPolicies), spew.Sdump(expectedPolicy)) - } -} - -func TestFlattenKeyVaultAccessPolicies_oneFullPolicy(t *testing.T) { - tenantId := uuid.NewV4() - objectId := uuid.NewV4().String() - applicationId := uuid.NewV4() - - certPerms := possibleCertificatePermissionsValues() - keyPerms := possibleKeyPermissionsValues() - secretPerms := possibleSecretPermissionsValues() - - permissions := &keyvault.Permissions{ - Certificates: &certPerms, - Keys: &keyPerms, - Secrets: &secretPerms, - } - - policies := createPolicies(&tenantId, &objectId, &applicationId, permissions) - - expectedPolicy := make(map[string]interface{}) - - expectedPolicy["tenant_id"] = tenantId.String() - expectedPolicy["object_id"] = objectId - expectedPolicy["application_id"] = applicationId.String() - expectedPolicy["key_permissions"] = possibleKeyPermissionsStrings() - expectedPolicy["secret_permissions"] = possibleSecretPermissionsStrings() - expectedPolicy["certificate_permissions"] = possibleCertificatePermissionsStrings() - flattenedPolicies := FlattenKeyVaultAccessPolicies(policies) - - if !reflect.DeepEqual(flattenedPolicies[0], expectedPolicy) { - t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(flattenedPolicies), spew.Sdump(expectedPolicy)) - } -} - -func TestExpandKeyVaultAccessPolicyCertificatePermissions_empty(t *testing.T) { - permissions := make([]interface{}, 0, 0) - certPerms := ExpandKeyVaultAccessPolicyCertificatePermissions(permissions) - - certPermsKeyVault := make([]keyvault.CertificatePermissions, 0, 0) - - if !reflect.DeepEqual(*certPerms, certPermsKeyVault) { - t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(certPerms), spew.Sdump(certPermsKeyVault)) - } -} - -func TestExpandKeyVaultAccessPolicyCertificatePermissions_full(t *testing.T) { - permissions := possibleCertificatePermissionsStrings() - - certPerms := ExpandKeyVaultAccessPolicyCertificatePermissions(permissions) - - certPermsKeyVault := possibleCertificatePermissionsValues() - - if !reflect.DeepEqual(*certPerms, certPermsKeyVault) { - t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(certPerms), spew.Sdump(certPermsKeyVault)) - } -} - -func TestExpandKeyVaultAccessPolicyKeyPermissions_empty(t *testing.T) { - permissions := make([]interface{}, 0, 0) - - keyPerms := ExpandKeyVaultAccessPolicyKeyPermissions(permissions) - - keyPermsKeyVault := make([]keyvault.KeyPermissions, 0, 0) - - if !reflect.DeepEqual(*keyPerms, keyPermsKeyVault) { - t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(keyPerms), spew.Sdump(keyPermsKeyVault)) - } -} - -func TestExpandKeyVaultAccessPolicyKeyPermissions_full(t *testing.T) { - permissions := possibleKeyPermissionsStrings() - - keyPerms := ExpandKeyVaultAccessPolicyKeyPermissions(permissions) - - keyPermsKeyVault := possibleKeyPermissionsValues() - - if !reflect.DeepEqual(*keyPerms, keyPermsKeyVault) { - t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(keyPerms), spew.Sdump(keyPermsKeyVault)) - } -} - -func TestExpandKeyVaultAccessPolicySecretPermissions_empty(t *testing.T) { - permissions := make([]interface{}, 0, 0) - - secretPerms := ExpandKeyVaultAccessPolicySecretPermissions(permissions) - - secretPermsKeyVault := make([]keyvault.SecretPermissions, 0, 0) - - if !reflect.DeepEqual(*secretPerms, secretPermsKeyVault) { - t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(secretPerms), spew.Sdump(secretPermsKeyVault)) - } -} - -func TestExpandKeyVaultAccessPolicySecretPermissions_full(t *testing.T) { - permissions := possibleSecretPermissionsStrings() - - secretPerms := ExpandKeyVaultAccessPolicySecretPermissions(permissions) - - secretPermsKeyVault := possibleSecretPermissionsValues() - - if !reflect.DeepEqual(*secretPerms, secretPermsKeyVault) { - t.Fatalf("Objects are not equal: %+v != %+v", spew.Sdump(secretPerms), spew.Sdump(secretPermsKeyVault)) - } -} - -func createPolicies(tenantId *uuid.UUID, objectId *string, applicationId *uuid.UUID, permissions *keyvault.Permissions) *[]keyvault.AccessPolicyEntry { - - policies := make([]keyvault.AccessPolicyEntry, 0, 0) - - if permissions == nil { - certPerms := make([]keyvault.CertificatePermissions, 0, 0) - keyPerms := make([]keyvault.KeyPermissions, 0, 0) - secretPerms := make([]keyvault.SecretPermissions, 0, 0) - - permissions = &keyvault.Permissions{ - Certificates: &certPerms, - Keys: &keyPerms, - Secrets: &secretPerms, - } - } - - if applicationId == nil { - policy := keyvault.AccessPolicyEntry{ - TenantID: tenantId, - ObjectID: objectId, - Permissions: permissions, - } - policies = append(policies, policy) - } else { - policy := keyvault.AccessPolicyEntry{ - TenantID: tenantId, - ObjectID: objectId, - ApplicationID: applicationId, - Permissions: permissions, - } - policies = append(policies, policy) - } - - return &policies -} - -func possibleCertificatePermissionsStrings() []interface{} { - - var ret []interface{} - - ret = append( - ret, - "create", - "delete", - "deleteissuers", - "get", - "getissuers", - "import", - "list", - "listissuers", - "managecontacts", - "manageissuers", - "purge", - "recover", - "setissuers", - "update", - ) - - return ret -} - -func possibleCertificatePermissionsValues() []keyvault.CertificatePermissions { - return []keyvault.CertificatePermissions{ - keyvault.Create, - keyvault.Delete, - keyvault.Deleteissuers, - keyvault.Get, - keyvault.Getissuers, - keyvault.Import, - keyvault.List, - keyvault.Listissuers, - keyvault.Managecontacts, - keyvault.Manageissuers, - keyvault.Purge, - keyvault.Recover, - keyvault.Setissuers, - keyvault.Update, - } -} - -func possibleKeyPermissionsStrings() []interface{} { - var ret []interface{} - - ret = append( - ret, - "backup", - "create", - "decrypt", - "delete", - "encrypt", - "get", - "import", - "list", - "purge", - "recover", - "restore", - "sign", - "unwrapKey", - "update", - "verify", - "wrapKey", - ) - - return ret -} - -func possibleKeyPermissionsValues() []keyvault.KeyPermissions { - return []keyvault.KeyPermissions{ - keyvault.KeyPermissionsBackup, - keyvault.KeyPermissionsCreate, - keyvault.KeyPermissionsDecrypt, - keyvault.KeyPermissionsDelete, - keyvault.KeyPermissionsEncrypt, - keyvault.KeyPermissionsGet, - keyvault.KeyPermissionsImport, - keyvault.KeyPermissionsList, - keyvault.KeyPermissionsPurge, - keyvault.KeyPermissionsRecover, - keyvault.KeyPermissionsRestore, - keyvault.KeyPermissionsSign, - keyvault.KeyPermissionsUnwrapKey, - keyvault.KeyPermissionsUpdate, - keyvault.KeyPermissionsVerify, - keyvault.KeyPermissionsWrapKey, - } -} - -func possibleSecretPermissionsStrings() []interface{} { - var ret []interface{} - - ret = append( - ret, - "backup", - "delete", - "get", - "list", - "purge", - "recover", - "restore", - "set", - ) - - return ret -} - -func possibleSecretPermissionsValues() []keyvault.SecretPermissions { - return []keyvault.SecretPermissions{ - keyvault.SecretPermissionsBackup, - keyvault.SecretPermissionsDelete, - keyvault.SecretPermissionsGet, - keyvault.SecretPermissionsList, - keyvault.SecretPermissionsPurge, - keyvault.SecretPermissionsRecover, - keyvault.SecretPermissionsRestore, - keyvault.SecretPermissionsSet, - } -} diff --git a/azurerm/helpers/schema/key_vault_access_policy.go b/azurerm/helpers/schema/key_vault_access_policy.go new file mode 100644 index 000000000000..b73612f788ab --- /dev/null +++ b/azurerm/helpers/schema/key_vault_access_policy.go @@ -0,0 +1,224 @@ +package schema + +import ( + "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + "github.com/satori/go.uuid" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/suppress" +) + +func KeyVaultCertificatePermissionsSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(keyvault.Create), + string(keyvault.Delete), + string(keyvault.Deleteissuers), + string(keyvault.Get), + string(keyvault.Getissuers), + string(keyvault.Import), + string(keyvault.List), + string(keyvault.Listissuers), + string(keyvault.Managecontacts), + string(keyvault.Manageissuers), + string(keyvault.Purge), + string(keyvault.Recover), + string(keyvault.Setissuers), + string(keyvault.Update), + }, true), + DiffSuppressFunc: suppress.CaseDifference, + }, + } +} + +func KeyVaultKeyPermissionsSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(keyvault.KeyPermissionsBackup), + string(keyvault.KeyPermissionsCreate), + string(keyvault.KeyPermissionsDecrypt), + string(keyvault.KeyPermissionsDelete), + string(keyvault.KeyPermissionsEncrypt), + string(keyvault.KeyPermissionsGet), + string(keyvault.KeyPermissionsImport), + string(keyvault.KeyPermissionsList), + string(keyvault.KeyPermissionsPurge), + string(keyvault.KeyPermissionsRecover), + string(keyvault.KeyPermissionsRestore), + string(keyvault.KeyPermissionsSign), + string(keyvault.KeyPermissionsUnwrapKey), + string(keyvault.KeyPermissionsUpdate), + string(keyvault.KeyPermissionsVerify), + string(keyvault.KeyPermissionsWrapKey), + }, true), + DiffSuppressFunc: suppress.CaseDifference, + }, + } +} + +func KeyVaultSecretPermissionsSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(keyvault.SecretPermissionsBackup), + string(keyvault.SecretPermissionsDelete), + string(keyvault.SecretPermissionsGet), + string(keyvault.SecretPermissionsList), + string(keyvault.SecretPermissionsPurge), + string(keyvault.SecretPermissionsRecover), + string(keyvault.SecretPermissionsRestore), + string(keyvault.SecretPermissionsSet), + }, true), + DiffSuppressFunc: suppress.CaseDifference, + }, + } +} + +func ExpandKeyVaultAccessPolicies(input []interface{}) (*[]keyvault.AccessPolicyEntry, error) { + output := make([]keyvault.AccessPolicyEntry, 0) + + for _, policySet := range input { + policyRaw := policySet.(map[string]interface{}) + + certificatePermissionsRaw := policyRaw["certificate_permissions"].([]interface{}) + keyPermissionsRaw := policyRaw["key_permissions"].([]interface{}) + secretPermissionsRaw := policyRaw["secret_permissions"].([]interface{}) + + policy := keyvault.AccessPolicyEntry{ + Permissions: &keyvault.Permissions{ + Certificates: ExpandCertificatePermissions(certificatePermissionsRaw), + Keys: ExpandKeyPermissions(keyPermissionsRaw), + Secrets: ExpandSecretPermissions(secretPermissionsRaw), + }, + } + + tenantUUID := uuid.FromStringOrNil(policyRaw["tenant_id"].(string)) + policy.TenantID = &tenantUUID + objectUUID := policyRaw["object_id"].(string) + policy.ObjectID = &objectUUID + + if v := policyRaw["application_id"]; v != "" { + applicationUUID := uuid.FromStringOrNil(v.(string)) + policy.ApplicationID = &applicationUUID + } + + output = append(output, policy) + } + + return &output, nil +} + +func FlattenKeyVaultAccessPolicies(policies *[]keyvault.AccessPolicyEntry) []map[string]interface{} { + result := make([]map[string]interface{}, 0) + + if policies == nil { + return result + } + + for _, policy := range *policies { + policyRaw := make(map[string]interface{}) + + if tenantId := policy.TenantID; tenantId != nil { + policyRaw["tenant_id"] = tenantId.String() + } + + if objectId := policy.ObjectID; objectId != nil { + policyRaw["object_id"] = *objectId + } + + if appId := policy.ApplicationID; appId != nil { + policyRaw["application_id"] = appId.String() + } + + if permissions := policy.Permissions; permissions != nil { + certs := FlattenCertificatePermissions(permissions.Certificates) + policyRaw["certificate_permissions"] = certs + + keys := FlattenKeyPermissions(permissions.Keys) + policyRaw["key_permissions"] = keys + + secrets := FlattenSecretPermissions(permissions.Secrets) + policyRaw["secret_permissions"] = secrets + } + + result = append(result, policyRaw) + } + + return result +} + +func ExpandCertificatePermissions(input []interface{}) *[]keyvault.CertificatePermissions { + output := make([]keyvault.CertificatePermissions, 0) + + for _, permission := range input { + output = append(output, keyvault.CertificatePermissions(permission.(string))) + } + + return &output +} + +func FlattenCertificatePermissions(input *[]keyvault.CertificatePermissions) []interface{} { + output := make([]interface{}, 0) + + if input != nil { + for _, certificatePermission := range *input { + output = append(output, string(certificatePermission)) + } + } + + return output +} + +func ExpandKeyPermissions(keyPermissionsRaw []interface{}) *[]keyvault.KeyPermissions { + output := make([]keyvault.KeyPermissions, 0) + + for _, permission := range keyPermissionsRaw { + output = append(output, keyvault.KeyPermissions(permission.(string))) + } + return &output +} + +func FlattenKeyPermissions(input *[]keyvault.KeyPermissions) []interface{} { + output := make([]interface{}, 0) + + if input != nil { + for _, keyPermission := range *input { + output = append(output, string(keyPermission)) + } + } + + return output +} + +func ExpandSecretPermissions(input []interface{}) *[]keyvault.SecretPermissions { + output := make([]keyvault.SecretPermissions, 0) + + for _, permission := range input { + output = append(output, keyvault.SecretPermissions(permission.(string))) + } + + return &output +} + +func FlattenSecretPermissions(input *[]keyvault.SecretPermissions) []interface{} { + output := make([]interface{}, 0) + + if input != nil { + for _, secretPermission := range *input { + output = append(output, string(secretPermission)) + } + } + + return output +} diff --git a/azurerm/resource_arm_key_vault.go b/azurerm/resource_arm_key_vault.go index 20a4bbc029f5..6388086e621e 100644 --- a/azurerm/resource_arm_key_vault.go +++ b/azurerm/resource_arm_key_vault.go @@ -12,7 +12,7 @@ import ( "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" uuid "github.com/satori/go.uuid" - keyVaultHelper "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/keyvault" + azschema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -21,13 +21,13 @@ import ( // https://github.com/Azure/azure-rest-api-specs/blob/master/arm-keyvault/2015-06-01/swagger/keyvault.json#L239 var armKeyVaultSkuFamily = "A" -var keyVaultAccessPolicyResourceName = "azurerm_key_vault_access_policy" +var keyVaultResourceName = "azurerm_key_vault" func resourceArmKeyVault() *schema.Resource { return &schema.Resource{ - Create: resourceArmKeyVaultCreate, + Create: resourceArmKeyVaultCreateUpdate, Read: resourceArmKeyVaultRead, - Update: resourceArmKeyVaultCreate, + Update: resourceArmKeyVaultCreateUpdate, Delete: resourceArmKeyVaultDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, @@ -97,9 +97,9 @@ func resourceArmKeyVault() *schema.Resource { Optional: true, ValidateFunc: validateUUID, }, - "certificate_permissions": keyVaultHelper.CertificatePermissionsSchema(), - "key_permissions": keyVaultHelper.KeyPermissionsSchema(), - "secret_permissions": keyVaultHelper.SecretPermissionsSchema(), + "certificate_permissions": azschema.KeyVaultCertificatePermissionsSchema(), + "key_permissions": azschema.KeyVaultKeyPermissionsSchema(), + "secret_permissions": azschema.KeyVaultSecretPermissionsSchema(), }, }, }, @@ -124,7 +124,7 @@ func resourceArmKeyVault() *schema.Resource { } } -func resourceArmKeyVaultCreate(d *schema.ResourceData, meta interface{}) error { +func resourceArmKeyVaultCreateUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*ArmClient).keyVaultClient ctx := meta.(*ArmClient).StopContext log.Printf("[INFO] preparing arguments for Azure ARM KeyVault creation.") @@ -138,12 +138,18 @@ func resourceArmKeyVaultCreate(d *schema.ResourceData, meta interface{}) error { enabledForTemplateDeployment := d.Get("enabled_for_template_deployment").(bool) tags := d.Get("tags").(map[string]interface{}) + policies := d.Get("access_policy").([]interface{}) + accessPolicies, err := azschema.ExpandKeyVaultAccessPolicies(policies) + if err != nil { + return fmt.Errorf("Error expanding `access_policy`: %+v", policies) + } + parameters := keyvault.VaultCreateOrUpdateParameters{ Location: &location, Properties: &keyvault.VaultProperties{ TenantID: &tenantUUID, Sku: expandKeyVaultSku(d), - AccessPolicies: expandKeyVaultAccessPolicies(d), + AccessPolicies: accessPolicies, EnabledForDeployment: &enabledForDeployment, EnabledForDiskEncryption: &enabledForDiskEncryption, EnabledForTemplateDeployment: &enabledForTemplateDeployment, @@ -156,7 +162,7 @@ func resourceArmKeyVaultCreate(d *schema.ResourceData, meta interface{}) error { azureRMLockByName(name, keyVaultResourceName) defer azureRMUnlockByName(name, keyVaultResourceName) - _, err := client.CreateOrUpdate(ctx, resGroup, name, parameters) + _, err = client.CreateOrUpdate(ctx, resGroup, name, parameters) if err != nil { return fmt.Errorf("Error updating Key Vault (Key Vault %q / Resource Group %q): %+v", name, resGroup, err) } @@ -206,9 +212,6 @@ func resourceArmKeyVaultRead(d *schema.ResourceData, meta interface{}) error { resGroup := id.ResourceGroup name := id.Path["vaults"] - azureRMLockByName(d.Get("name").(string), keyVaultAccessPolicyResourceName) - defer azureRMUnlockByName(d.Get("name").(string), keyVaultAccessPolicyResourceName) - resp, err := client.Get(ctx, resGroup, name) if err != nil { if utils.ResponseWasNotFound(resp.Response) { @@ -232,7 +235,9 @@ func resourceArmKeyVaultRead(d *schema.ResourceData, meta interface{}) error { if err := d.Set("sku", flattenKeyVaultSku(props.Sku)); err != nil { return fmt.Errorf("Error flattening `sku` for KeyVault %q: %+v", resp.Name, err) } - if err := d.Set("access_policy", keyVaultHelper.FlattenKeyVaultAccessPolicies(props.AccessPolicies)); err != nil { + + flattenedPolicies := azschema.FlattenKeyVaultAccessPolicies(props.AccessPolicies) + if err := d.Set("access_policy", flattenedPolicies); err != nil { return fmt.Errorf("Error flattening `access_policy` for KeyVault %q: %+v", resp.Name, err) } d.Set("vault_uri", props.VaultURI) @@ -271,41 +276,6 @@ func expandKeyVaultSku(d *schema.ResourceData) *keyvault.Sku { } } -func expandKeyVaultAccessPolicies(d *schema.ResourceData) *[]keyvault.AccessPolicyEntry { - policies := d.Get("access_policy").([]interface{}) - result := make([]keyvault.AccessPolicyEntry, 0, len(policies)) - - for _, policySet := range policies { - policyRaw := policySet.(map[string]interface{}) - - certificatePermissionsRaw := policyRaw["certificate_permissions"].([]interface{}) - keyPermissionsRaw := policyRaw["key_permissions"].([]interface{}) - secretPermissionsRaw := policyRaw["secret_permissions"].([]interface{}) - - policy := keyvault.AccessPolicyEntry{ - Permissions: &keyvault.Permissions{ - Certificates: keyVaultHelper.ExpandKeyVaultAccessPolicyCertificatePermissions(certificatePermissionsRaw), - Keys: keyVaultHelper.ExpandKeyVaultAccessPolicyKeyPermissions(keyPermissionsRaw), - Secrets: keyVaultHelper.ExpandKeyVaultAccessPolicySecretPermissions(secretPermissionsRaw), - }, - } - - tenantUUID := uuid.FromStringOrNil(policyRaw["tenant_id"].(string)) - policy.TenantID = &tenantUUID - objectUUID := policyRaw["object_id"].(string) - policy.ObjectID = &objectUUID - - if v := policyRaw["application_id"]; v != "" { - applicationUUID := uuid.FromStringOrNil(v.(string)) - policy.ApplicationID = &applicationUUID - } - - result = append(result, policy) - } - - return &result -} - func flattenKeyVaultSku(sku *keyvault.Sku) []interface{} { result := map[string]interface{}{ "name": string(sku.Name), diff --git a/azurerm/resource_arm_key_vault_access_policy.go b/azurerm/resource_arm_key_vault_access_policy.go index 91448deefb4b..608af361ee41 100644 --- a/azurerm/resource_arm_key_vault_access_policy.go +++ b/azurerm/resource_arm_key_vault_access_policy.go @@ -4,15 +4,15 @@ import ( "fmt" "log" + "strings" + "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2016-10-01/keyvault" "github.com/hashicorp/terraform/helper/schema" uuid "github.com/satori/go.uuid" - keyVaultHelper "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/keyvault" + azschema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -var keyVaultResourceName = "azurerm_key_vault" - func resourceArmKeyVaultAccessPolicy() *schema.Resource { return &schema.Resource{ Create: resourceArmKeyVaultAccessPolicyCreate, @@ -30,32 +30,34 @@ func resourceArmKeyVaultAccessPolicy() *schema.Resource { ForceNew: true, }, - "resource_group_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, + "resource_group_name": resourceGroupNameSchema(), + "tenant_id": { Type: schema.TypeString, Required: true, - ValidateFunc: validateUUID, ForceNew: true, + ValidateFunc: validateUUID, }, + "object_id": { Type: schema.TypeString, Required: true, - ValidateFunc: validateUUID, ForceNew: true, + ValidateFunc: validateUUID, }, + "application_id": { Type: schema.TypeString, Optional: true, - ValidateFunc: validateUUID, ForceNew: true, + ValidateFunc: validateUUID, }, - "certificate_permissions": keyVaultHelper.CertificatePermissionsSchema(), - "key_permissions": keyVaultHelper.KeyPermissionsSchema(), - "secret_permissions": keyVaultHelper.SecretPermissionsSchema(), + + "certificate_permissions": azschema.KeyVaultCertificatePermissionsSchema(), + + "key_permissions": azschema.KeyVaultKeyPermissionsSchema(), + + "secret_permissions": azschema.KeyVaultSecretPermissionsSchema(), }, } } @@ -65,42 +67,80 @@ func resourceArmKeyVaultAccessPolicyCreateOrDelete(d *schema.ResourceData, meta ctx := meta.(*ArmClient).StopContext log.Printf("[INFO] Preparing arguments for Key Vault Access Policy: %s.", action) - name := d.Get("vault_name").(string) + vaultName := d.Get("vault_name").(string) resGroup := d.Get("resource_group_name").(string) - accessPolicies := []keyvault.AccessPolicyEntry{expandKeyVaultAccessPolicy(d)} + tenantIdRaw := d.Get("tenant_id").(string) + tenantId, err := uuid.FromString(tenantIdRaw) + if err != nil { + return fmt.Errorf("Error parsing Tenant ID %q as a UUID: %+v", tenantIdRaw, err) + } + + objectId := d.Get("object_id").(string) + + certPermissionsRaw := d.Get("certificate_permissions").([]interface{}) + certPermissions := azschema.ExpandCertificatePermissions(certPermissionsRaw) + + keyPermissionsRaw := d.Get("key_permissions").([]interface{}) + keyPermissions := azschema.ExpandKeyPermissions(keyPermissionsRaw) + + secretPermissionsRaw := d.Get("secret_permissions").([]interface{}) + secretPermissions := azschema.ExpandSecretPermissions(secretPermissionsRaw) + + accessPolicy := keyvault.AccessPolicyEntry{ + ObjectID: utils.String(objectId), + TenantID: &tenantId, + Permissions: &keyvault.Permissions{ + Certificates: certPermissions, + Keys: keyPermissions, + Secrets: secretPermissions, + }, + } + + applicationIdRaw := d.Get("application_id").(string) + if applicationIdRaw != "" { + applicationId, err := uuid.FromString(applicationIdRaw) + if err != nil { + return fmt.Errorf("Error parsing Appliciation ID %q as a UUID: %+v", applicationIdRaw, err) + } + + accessPolicy.ApplicationID = &applicationId + } + + accessPolicies := []keyvault.AccessPolicyEntry{accessPolicy} parameters := keyvault.VaultAccessPolicyParameters{ - Name: &name, + Name: &vaultName, Properties: &keyvault.VaultAccessPolicyProperties{ AccessPolicies: &accessPolicies, }, } - _, err := client.UpdateAccessPolicy(ctx, resGroup, name, action, parameters) + // Locking to prevent parallel changes causing issues + azureRMLockByName(vaultName, keyVaultResourceName) + defer azureRMUnlockByName(vaultName, keyVaultResourceName) + + _, err = client.UpdateAccessPolicy(ctx, resGroup, vaultName, action, parameters) if err != nil { - return fmt.Errorf("Error updating Key Vault Access Policy (Key Vault %q / Resource Group %q): %+v", name, resGroup, err) + return fmt.Errorf("Error updating Access Policy (Object ID %q / Application ID %q) for Key Vault %q (Resource Group %q): %+v", objectId, applicationIdRaw, vaultName, resGroup, err) } - read, err := client.Get(ctx, resGroup, name) + read, err := client.Get(ctx, resGroup, vaultName) if err != nil { - return fmt.Errorf("Error retrieving Key Vault %q (Resource Group %q): %+v", name, resGroup, err) + return fmt.Errorf("Error retrieving Key Vault %q (Resource Group %q): %+v", vaultName, resGroup, err) } if read.ID == nil { - return fmt.Errorf("cannot read KeyVault %s (resource group %s) ID", name, resGroup) + return fmt.Errorf("Cannot read KeyVault %q (Resource Group %q) ID", vaultName, resGroup) } if d.IsNewResource() { // This is because azure doesn't have an 'id' for a keyvault access policy // In order to compensate for this and allow importing of this resource we are artificially // creating an identity for a key vault policy object - resourceId := fmt.Sprintf("%s/objectId/%s", *read.ID, d.Get("object_id")) - if applicationId, ok := d.GetOk("application_id"); ok { - resourceId = fmt.Sprintf( - "%s/applicationId/%s", - resourceId, - applicationId) + resourceId := fmt.Sprintf("%s/objectId/%s", *read.ID, objectId) + if applicationIdRaw != "" { + resourceId = fmt.Sprintf("%s/applicationId/%s", resourceId, applicationIdRaw) } d.SetId(resourceId) } @@ -113,10 +153,6 @@ func resourceArmKeyVaultAccessPolicyCreate(d *schema.ResourceData, meta interfac } func resourceArmKeyVaultAccessPolicyDelete(d *schema.ResourceData, meta interface{}) error { - // Lets lock the keyvault during a deletion to prevent a run updating the policies during a deletion - azureRMLockByName(d.Get("vault_name").(string), keyVaultAccessPolicyResourceName) - defer azureRMUnlockByName(d.Get("vault_name").(string), keyVaultAccessPolicyResourceName) - return resourceArmKeyVaultAccessPolicyCreateOrDelete(d, meta, keyvault.Remove) } @@ -134,96 +170,84 @@ func resourceArmKeyVaultAccessPolicyRead(d *schema.ResourceData, meta interface{ return err } resGroup := id.ResourceGroup - name := id.Path["vaults"] + vaultName := id.Path["vaults"] + objectId := id.Path["objectId"] + applicationId := id.Path["applicationId"] - resp, err := client.Get(ctx, resGroup, name) + resp, err := client.Get(ctx, resGroup, vaultName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[ERROR] Key Vault %q (Resource Group %q) was not found - removing from state", vaultName, resGroup) d.SetId("") return nil } - return fmt.Errorf("Error making Read request on Azure KeyVault %s: %+v", name, err) - } - if resp.Properties == nil { - return fmt.Errorf("Properties not returned by api for Azurue KeyVault %s", name) + return fmt.Errorf("Error making Read request on Azure KeyVault %q (Resource Group %q): %+v", vaultName, resGroup, err) } - flattenedPolicy := keyVaultHelper.FlattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies) - - policyObjectId := id.Path["objectId"] - policyApplicationId := id.Path["applicationId"] - policyId := getPolicyIdentity(&policyObjectId, &policyApplicationId) - - policy := findKeyVaultAccessPolicy(policyId, flattenedPolicy) + policy, err := findKeyVaultAccessPolicy(resp.Properties.AccessPolicies, objectId, applicationId) + if err != nil { + return fmt.Errorf("Error locating Access Policy (Object ID %q / Application ID %q) in Key Vault %q (Resource Group %q)", objectId, applicationId, vaultName, resGroup) + } if policy == nil { + log.Printf("[ERROR] Access Policy (Object ID %q / Application ID %q) was not found in Key Vault %q (Resource Group %q) - removing from state", objectId, applicationId, vaultName, resGroup) d.SetId("") - return fmt.Errorf("Policy for was not found for vault: %s", name) + return nil } d.Set("vault_name", resp.Name) d.Set("resource_group_name", resGroup) - d.Set("object_id", policyObjectId) - d.Set("tenant_id", resp.Properties.TenantID.String()) - d.Set("application_id", policyApplicationId) - d.Set("key_permissions", policy["key_permissions"]) - d.Set("secret_permissions", policy["secret_permissions"]) - d.Set("certificate_permissions", policy["certificate_permissions"]) - - flattenAndSetTags(d, resp.Tags) - - return nil -} - -func getPolicyIdentity(objectId *string, applicationId *string) string { + d.Set("object_id", objectId) - if applicationId != nil && *applicationId != "" { - return fmt.Sprintf("%s/%s", *objectId, *applicationId) - } else { - return fmt.Sprintf("%s", *objectId) + if tid := policy.TenantID; tid != nil { + d.Set("tenant_id", tid.String()) } -} -func matchAccessPolicy(policyString string, policy map[string]interface{}) bool { + if aid := policy.ApplicationID; aid != nil { + d.Set("application_id", aid.String()) + } - policyObjectId := policy["object_id"].(string) + if permissions := policy.Permissions; permissions != nil { + certificatePermissions := azschema.FlattenCertificatePermissions(permissions.Certificates) + if err := d.Set("certificate_permissions", certificatePermissions); err != nil { + return fmt.Errorf("Error flattening `certificate_permissions`: %+v", err) + } - if policyApplicationId, ok := policy["application_id"]; ok { - return policyString == fmt.Sprintf("%s/%s", policyObjectId, policyApplicationId) - } else { - return policyString == policyObjectId - } -} + keyPermissions := azschema.FlattenKeyPermissions(permissions.Keys) + if err := d.Set("key_permissions", keyPermissions); err != nil { + return fmt.Errorf("Error flattening `key_permissions`: %+v", err) + } -func findKeyVaultAccessPolicy(policyString string, policies []map[string]interface{}) map[string]interface{} { - for _, policy := range policies { - if matchAccessPolicy(policyString, policy) { - return policy + secretPermissions := azschema.FlattenSecretPermissions(permissions.Secrets) + if err := d.Set("secret_permissions", secretPermissions); err != nil { + return fmt.Errorf("Error flattening `secret_permissions`: %+v", err) } } + return nil } -func expandKeyVaultAccessPolicy(d *schema.ResourceData) keyvault.AccessPolicyEntry { - - policy := keyvault.AccessPolicyEntry{ - Permissions: &keyvault.Permissions{ - Certificates: keyVaultHelper.ExpandKeyVaultAccessPolicyCertificatePermissions(d.Get("certificate_permissions").([]interface{})), - Keys: keyVaultHelper.ExpandKeyVaultAccessPolicyKeyPermissions(d.Get("key_permissions").([]interface{})), - Secrets: keyVaultHelper.ExpandKeyVaultAccessPolicySecretPermissions(d.Get("secret_permissions").([]interface{})), - }, +func findKeyVaultAccessPolicy(policies *[]keyvault.AccessPolicyEntry, objectId string, applicationId string) (*keyvault.AccessPolicyEntry, error) { + if policies == nil { + return nil, nil } - tenantUUID := uuid.FromStringOrNil(d.Get("tenant_id").(string)) - policy.TenantID = &tenantUUID - objectUUID := d.Get("object_id").(string) - policy.ObjectID = &objectUUID - - if v := d.Get("application_id"); v != "" { - applicationUUID := uuid.FromStringOrNil(v.(string)) - policy.ApplicationID = &applicationUUID + for _, policy := range *policies { + if id := policy.ObjectID; id != nil { + if strings.EqualFold(*id, objectId) { + if applicationId == "" { + return &policy, nil + } + + if aid := policy.ApplicationID; aid != nil { + if strings.EqualFold(aid.String(), applicationId) { + return &policy, nil + } + } + } + } } - return policy + return nil, nil } diff --git a/azurerm/resource_arm_key_vault_access_policy_test.go b/azurerm/resource_arm_key_vault_access_policy_test.go index 8ab2185cf8ce..c68535ef875c 100644 --- a/azurerm/resource_arm_key_vault_access_policy_test.go +++ b/azurerm/resource_arm_key_vault_access_policy_test.go @@ -7,7 +7,6 @@ import ( "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" - keyVaultHelper "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/keyvault" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -24,7 +23,7 @@ func TestAccAzureRMKeyVaultAccessPolicy_basic(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id", "application_id"), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "set"), @@ -34,11 +33,11 @@ func TestAccAzureRMKeyVaultAccessPolicy_basic(t *testing.T) { }) } -func TestAccAzureRMKeyVaultAccessPolicy_complete(t *testing.T) { +func TestAccAzureRMKeyVaultAccessPolicy_multiple(t *testing.T) { resourceName1 := "azurerm_key_vault_access_policy.test_with_application_id" resourceName2 := "azurerm_key_vault_access_policy.test_no_application_id" rs := acctest.RandString(6) - config := testAccAzureRMKeyVaultAccessPolicy_complete(rs, testLocation()) + config := testAccAzureRMKeyVaultAccessPolicy_multiple(rs, testLocation()) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -48,7 +47,7 @@ func TestAccAzureRMKeyVaultAccessPolicy_complete(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(resourceName1, "object_id", "application_id"), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName1), resource.TestCheckResourceAttr(resourceName1, "key_permissions.0", "create"), resource.TestCheckResourceAttr(resourceName1, "key_permissions.1", "get"), resource.TestCheckResourceAttr(resourceName1, "secret_permissions.0", "get"), @@ -56,7 +55,7 @@ func TestAccAzureRMKeyVaultAccessPolicy_complete(t *testing.T) { resource.TestCheckResourceAttr(resourceName1, "certificate_permissions.0", "create"), resource.TestCheckResourceAttr(resourceName1, "certificate_permissions.1", "delete"), - testCheckAzureRMKeyVaultAccessPolicyExists(resourceName2, "object_id", "application_id"), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName2), resource.TestCheckResourceAttr(resourceName2, "key_permissions.0", "list"), resource.TestCheckResourceAttr(resourceName2, "key_permissions.1", "encrypt"), resource.TestCheckResourceAttr(resourceName2, "secret_permissions.0", "list"), @@ -76,15 +75,14 @@ func TestAccAzureRMKeyVaultAccessPolicy_update(t *testing.T) { postConfig := testAccAzureRMKeyVaultAccessPolicy_update(rs, testLocation()) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - // Using the KeyVaultDestroy checker since that ensures the policy is gone. + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, CheckDestroy: testCheckAzureRMKeyVaultDestroy, Steps: []resource.TestStep{ { Config: preConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id", "application_id"), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.0", "get"), resource.TestCheckResourceAttr(resourceName, "secret_permissions.1", "set"), @@ -93,7 +91,7 @@ func TestAccAzureRMKeyVaultAccessPolicy_update(t *testing.T) { { Config: postConfig, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(resourceName, "object_id", "application_id"), + testCheckAzureRMKeyVaultAccessPolicyExists(resourceName), resource.TestCheckResourceAttr(resourceName, "key_permissions.0", "list"), resource.TestCheckResourceAttr(resourceName, "key_permissions.1", "encrypt"), ), @@ -102,103 +100,34 @@ func TestAccAzureRMKeyVaultAccessPolicy_update(t *testing.T) { }) } -func TestAccAzureRMKeyVaultAccessPolicy_policyRemoved(t *testing.T) { - rs := acctest.RandString(6) - policyResourceName := "azurerm_key_vault_access_policy.test" - vaultResourceName := "azurerm_key_vault.test" - preConfig := testAccAzureRMKeyVaultAccessPolicy_basic(rs, testLocation()) - postConfig := testAccAzureRMKeyVaultAccessPolicy_policyRemoved(rs, testLocation()) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - // Using the KeyVaultDestroy checker since that ensures the policy is gone. - CheckDestroy: testCheckAzureRMKeyVaultDestroy, - Steps: []resource.TestStep{ - { - Config: preConfig, - Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyExists(policyResourceName, "object_id", "application_id"), - resource.TestCheckResourceAttr(policyResourceName, "key_permissions.0", "get"), - resource.TestCheckResourceAttr(policyResourceName, "secret_permissions.0", "get"), - resource.TestCheckResourceAttr(policyResourceName, "secret_permissions.1", "set"), - ), - }, - { - Config: postConfig, - Check: resource.ComposeTestCheckFunc( - testCheckAzureRMKeyVaultAccessPolicyMissing(vaultResourceName, "tags.policy_object_id"), - ), - }, - }, - }) -} - -func testCheckAzureRMKeyVaultAccessPolicyExists(name string, policyObjectTag string, policyApplicationTag string) resource.TestCheckFunc { +func testCheckAzureRMKeyVaultAccessPolicyExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure we have enough information in state to look up in API rs, ok := s.RootModule().Resources[name] if !ok { return fmt.Errorf("Not found: %s", name) } - name := rs.Primary.Attributes["vault_name"] - resGroup := rs.Primary.Attributes["resource_group_name"] - - client := testAccProvider.Meta().(*ArmClient).keyVaultClient - ctx := testAccProvider.Meta().(*ArmClient).StopContext - - resp, err := client.Get(ctx, resGroup, name) - if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Bad: Key Vault %q (resource group: %q) does not exist", name, resGroup) - } - - return fmt.Errorf("Bad: Get on keyVaultClient: %+v", err) - } - - objectId := rs.Primary.Attributes[policyObjectTag] - applicationId := rs.Primary.Attributes[policyApplicationTag] - - policyIdentity := getPolicyIdentity(&objectId, &applicationId) - - policy := findKeyVaultAccessPolicy(policyIdentity, keyVaultHelper.FlattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) - - if policy == nil { - return fmt.Errorf("Bad: Key Vault Policy %q (resource group: %q, object_id: %s) does not exist", name, resGroup, objectId) - } - return nil - } -} - -func testCheckAzureRMKeyVaultAccessPolicyMissing(name string, policyObjectTag string) resource.TestCheckFunc { - return func(s *terraform.State) error { - // Ensure we have enough information in state to look up in API - rs, ok := s.RootModule().Resources[name] - if !ok { - return fmt.Errorf("Not found: %s", name) - } - name := rs.Primary.Attributes["name"] + vaultName := rs.Primary.Attributes["vault_name"] resGroup := rs.Primary.Attributes["resource_group_name"] + objectId := rs.Primary.Attributes["object_id"] + applicationId := rs.Primary.Attributes["application_id"] client := testAccProvider.Meta().(*ArmClient).keyVaultClient ctx := testAccProvider.Meta().(*ArmClient).StopContext - resp, err := client.Get(ctx, resGroup, name) + resp, err := client.Get(ctx, resGroup, vaultName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Bad: Key Vault %q (resource group: %q) does not exist", name, resGroup) + return fmt.Errorf("Bad: Key Vault %q (resource group: %q) does not exist", vaultName, resGroup) } return fmt.Errorf("Bad: Get on keyVaultClient: %+v", err) } - objectId := rs.Primary.Attributes[policyObjectTag] - - policy := findKeyVaultAccessPolicy(objectId, keyVaultHelper.FlattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies)) - - if policy != nil { - return fmt.Errorf("Bad: Key Vault Policy %q (resource group: %q, object_id: %s) exists", name, resGroup, objectId) + policy, err := findKeyVaultAccessPolicy(resp.Properties.AccessPolicies, objectId, applicationId) + if policy == nil { + return fmt.Errorf("Bad: Key Vault Policy %q (resource group: %q, object_id: %s) does not exist", vaultName, resGroup, objectId) } return nil @@ -249,7 +178,7 @@ resource "azurerm_key_vault_access_policy" "test" { `, rString, location, rString) } -func testAccAzureRMKeyVaultAccessPolicy_complete(rString string, location string) string { +func testAccAzureRMKeyVaultAccessPolicy_multiple(rString string, location string) string { return fmt.Sprintf(` data "azurerm_client_config" "current" {} From 50e2837715beead1e5ccc27d93bba1e7dd3bb205 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 6 Jul 2018 18:13:58 +0200 Subject: [PATCH 20/23] Adding import tests / clarifying the import docs Tests pass: ``` $ acctests azurerm TestAccAzureRMKeyVaultAccessPolicy_import === RUN TestAccAzureRMKeyVaultAccessPolicy_importBasic --- PASS: TestAccAzureRMKeyVaultAccessPolicy_importBasic (225.81s) === RUN TestAccAzureRMKeyVaultAccessPolicy_importMultiple --- PASS: TestAccAzureRMKeyVaultAccessPolicy_importMultiple (218.71s) PASS ok github.com/terraform-providers/terraform-provider-azurerm/azurerm 444.557s ``` --- ...import_arm_key_vault_access_policy_test.go | 57 +++++++++++++++++++ .../r/key_vault_access_policy.html.markdown | 23 ++++++-- 2 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 azurerm/import_arm_key_vault_access_policy_test.go diff --git a/azurerm/import_arm_key_vault_access_policy_test.go b/azurerm/import_arm_key_vault_access_policy_test.go new file mode 100644 index 000000000000..c5920b466a56 --- /dev/null +++ b/azurerm/import_arm_key_vault_access_policy_test.go @@ -0,0 +1,57 @@ +package azurerm + +import ( + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccAzureRMKeyVaultAccessPolicy_importBasic(t *testing.T) { + resourceName := "azurerm_key_vault_access_policy.test" + + rs := acctest.RandString(5) + config := testAccAzureRMKeyVaultAccessPolicy_basic(rs, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMKeyVaultDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMKeyVaultAccessPolicy_importMultiple(t *testing.T) { + rs := acctest.RandString(5) + config := testAccAzureRMKeyVaultAccessPolicy_multiple(rs, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMKeyVaultDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: "azurerm_key_vault_access_policy.test_with_application_id", + ImportState: true, + ImportStateVerify: true, + }, + { + ResourceName: "azurerm_key_vault_access_policy.test_no_application_id", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} diff --git a/website/docs/r/key_vault_access_policy.html.markdown b/website/docs/r/key_vault_access_policy.html.markdown index 620b3178a08b..dcc1225112b9 100644 --- a/website/docs/r/key_vault_access_policy.html.markdown +++ b/website/docs/r/key_vault_access_policy.html.markdown @@ -98,15 +98,28 @@ The following attributes are exported: * `id` - Key Vault Access Policy ID. +-> **NOTE:** This Identifier is unique to Terraform and doesn't map to an existing object within Azure. + ## Import -Routes can be imported using the `resource id` of the keyvault with additional metadata containing -the service principal objectId and the applicationId if applicable, e.g. +Key Vault Access Policies can be imported using the Resource ID of the Key Vault, plus some additional metadata. + +If both an `object_id` and `application_id` are specified, then the Access Policy can be imported using the following code: ```shell -terraform import azurerm_key_vault_access_policy.testPolicy /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.KeyVault/vaults/test-vault/objectId/11111111-1111-1111-1111-111111111111 +terraform import azurerm_key_vault_access_policy.test /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.KeyVault/vaults/test-vault/objectId/11111111-1111-1111-1111-111111111111/applicationId/22222222-2222-2222-2222-222222222222 ``` +where `11111111-1111-1111-1111-111111111111` is the `object_id` and `22222222-2222-2222-2222-222222222222` is the `application_id`. + +--- + +Access Policies with an `object_id` but no `application_id` can be imported using the following command: + ```shell -terraform import azurerm_key_vault_access_policy.testPolicy /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.KeyVault/vaults/test-vault/objectId/11111111-1111-1111-1111-111111111111/applicationId/22222222-2222-2222-2222-222222222222 -``` \ No newline at end of file +terraform import azurerm_key_vault_access_policy.test /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.KeyVault/vaults/test-vault/objectId/11111111-1111-1111-1111-111111111111 +``` + +where `11111111-1111-1111-1111-111111111111` is the `object_id`. + +-> **NOTE:** Both Identifiers are unique to Terraform and don't map to an existing object within Azure. \ No newline at end of file From 0ea420ab9c0ddabbeb340ea39583657d5424cf40 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 9 Jul 2018 09:21:30 +0200 Subject: [PATCH 21/23] Handling the case of an AppID and no AppID being specified / refactoring tests --- .../resource_arm_key_vault_access_policy.go | 11 +- ...source_arm_key_vault_access_policy_test.go | 204 ++++++------------ 2 files changed, 76 insertions(+), 139 deletions(-) diff --git a/azurerm/resource_arm_key_vault_access_policy.go b/azurerm/resource_arm_key_vault_access_policy.go index 608af361ee41..530d165d3dbe 100644 --- a/azurerm/resource_arm_key_vault_access_policy.go +++ b/azurerm/resource_arm_key_vault_access_policy.go @@ -236,14 +236,13 @@ func findKeyVaultAccessPolicy(policies *[]keyvault.AccessPolicyEntry, objectId s for _, policy := range *policies { if id := policy.ObjectID; id != nil { if strings.EqualFold(*id, objectId) { - if applicationId == "" { - return &policy, nil + aid := "" + if policy.ApplicationID != nil { + aid = policy.ApplicationID.String() } - if aid := policy.ApplicationID; aid != nil { - if strings.EqualFold(aid.String(), applicationId) { - return &policy, nil - } + if strings.EqualFold(aid, applicationId) { + return &policy, nil } } } diff --git a/azurerm/resource_arm_key_vault_access_policy_test.go b/azurerm/resource_arm_key_vault_access_policy_test.go index c68535ef875c..d9b1976ba4b1 100644 --- a/azurerm/resource_arm_key_vault_access_policy_test.go +++ b/azurerm/resource_arm_key_vault_access_policy_test.go @@ -135,167 +135,107 @@ func testCheckAzureRMKeyVaultAccessPolicyExists(name string) resource.TestCheckF } func testAccAzureRMKeyVaultAccessPolicy_basic(rString string, location string) string { + template := testAccAzureRMKeyVaultAccessPolicy_template(rString, location) return fmt.Sprintf(` -data "azurerm_client_config" "current" {} - -resource "azurerm_resource_group" "test" { - name = "acctestRG-%s" - location = "%s" -} - -resource "azurerm_key_vault" "test" { - name = "acctestkv-%s" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - tenant_id = "${data.azurerm_client_config.current.tenant_id}" - - sku { - name = "premium" - } - - tags { - environment = "Production" - policy_object_id = "${data.azurerm_client_config.current.service_principal_object_id}" - } -} +%s resource "azurerm_key_vault_access_policy" "test" { - vault_name = "${azurerm_key_vault.test.name}" - resource_group_name = "${azurerm_resource_group.test.name}" + vault_name = "${azurerm_key_vault.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" - key_permissions = [ - "get" - ] + key_permissions = [ + "get", + ] - secret_permissions = [ - "get", - "set" - ] + secret_permissions = [ + "get", + "set", + ] - tenant_id = "${data.azurerm_client_config.current.tenant_id}" - object_id = "${data.azurerm_client_config.current.service_principal_object_id}" + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + object_id = "${data.azurerm_client_config.current.service_principal_object_id}" } -`, rString, location, rString) +`, template) } func testAccAzureRMKeyVaultAccessPolicy_multiple(rString string, location string) string { + template := testAccAzureRMKeyVaultAccessPolicy_template(rString, location) return fmt.Sprintf(` -data "azurerm_client_config" "current" {} - -resource "azurerm_resource_group" "test" { - name = "acctestRG-%s" - location = "%s" -} - -resource "azurerm_key_vault" "test" { - name = "acctestkv-%s" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - tenant_id = "${data.azurerm_client_config.current.tenant_id}" - - - sku { - name = "premium" - } - - tags { - environment = "Production" - } -} +%s resource "azurerm_key_vault_access_policy" "test_with_application_id" { - vault_name = "${azurerm_key_vault.test.name}" - resource_group_name = "${azurerm_resource_group.test.name}" - - key_permissions = [ - "create", - "get" - ] - - secret_permissions = [ - "get", - "delete" - ] - - certificate_permissions = [ - "create", - "delete" - ] - - application_id = "${data.azurerm_client_config.current.service_principal_application_id}" - tenant_id = "${data.azurerm_client_config.current.tenant_id}" - object_id = "${data.azurerm_client_config.current.service_principal_object_id}" -} + vault_name = "${azurerm_key_vault.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" -resource "azurerm_key_vault_access_policy" "test_no_application_id" { - vault_name = "${azurerm_key_vault.test.name}" - resource_group_name = "${azurerm_resource_group.test.name}" - - key_permissions = [ - "list", - "encrypt" - ] - - secret_permissions = [ - "list", - "delete" - ] - - certificate_permissions = [ - "list", - "delete" - ] - - tenant_id = "${data.azurerm_client_config.current.tenant_id}" - object_id = "${data.azurerm_client_config.current.service_principal_object_id}" -} -`, rString, location, rString) -} + key_permissions = [ + "create", + "get", + ] -func testAccAzureRMKeyVaultAccessPolicy_update(rString string, location string) string { - return fmt.Sprintf(` -data "azurerm_client_config" "current" {} + secret_permissions = [ + "get", + "delete", + ] -resource "azurerm_resource_group" "test" { - name = "acctestRG-%s" - location = "%s" + certificate_permissions = [ + "create", + "delete", + ] + + application_id = "${data.azurerm_client_config.current.service_principal_application_id}" + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + object_id = "${data.azurerm_client_config.current.service_principal_object_id}" } -resource "azurerm_key_vault" "test" { - name = "acctestkv-%s" - location = "${azurerm_resource_group.test.location}" +resource "azurerm_key_vault_access_policy" "test_no_application_id" { + vault_name = "${azurerm_key_vault.test.name}" resource_group_name = "${azurerm_resource_group.test.name}" - tenant_id = "${data.azurerm_client_config.current.tenant_id}" - sku { - name = "premium" - } + key_permissions = [ + "list", + "encrypt", + ] - tags { - environment = "Production" - policy_object_id = "${data.azurerm_client_config.current.service_principal_object_id}" - } + secret_permissions = [ + "list", + "delete", + ] + + certificate_permissions = [ + "list", + "delete", + ] + + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + object_id = "${data.azurerm_client_config.current.service_principal_object_id}" } +`, template) +} + +func testAccAzureRMKeyVaultAccessPolicy_update(rString string, location string) string { + template := testAccAzureRMKeyVaultAccessPolicy_template(rString, location) + return fmt.Sprintf(` +%s resource "azurerm_key_vault_access_policy" "test" { - vault_name = "${azurerm_key_vault.test.name}" - resource_group_name = "${azurerm_resource_group.test.name}" + vault_name = "${azurerm_key_vault.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" - key_permissions = [ - "list", - "encrypt" - ] + key_permissions = [ + "list", + "encrypt", + ] - secret_permissions = [ - ] + secret_permissions = [] - tenant_id = "${data.azurerm_client_config.current.tenant_id}" - object_id = "${data.azurerm_client_config.current.service_principal_object_id}" + tenant_id = "${data.azurerm_client_config.current.tenant_id}" + object_id = "${data.azurerm_client_config.current.service_principal_object_id}" } -`, rString, location, rString) + +`, template) } -func testAccAzureRMKeyVaultAccessPolicy_policyRemoved(rString string, location string) string { +func testAccAzureRMKeyVaultAccessPolicy_template(rString string, location string) string { return fmt.Sprintf(` data "azurerm_client_config" "current" {} @@ -316,9 +256,7 @@ resource "azurerm_key_vault" "test" { tags { environment = "Production" - policy_object_id = "${data.azurerm_client_config.current.service_principal_object_id}" } } - `, rString, location, rString) } From 56ae66ba31fda90406f85b633218467442527a57 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 9 Jul 2018 11:30:16 +0200 Subject: [PATCH 22/23] Fixing the error message --- azurerm/resource_arm_key_vault.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azurerm/resource_arm_key_vault.go b/azurerm/resource_arm_key_vault.go index 6388086e621e..3be569735fff 100644 --- a/azurerm/resource_arm_key_vault.go +++ b/azurerm/resource_arm_key_vault.go @@ -164,7 +164,7 @@ func resourceArmKeyVaultCreateUpdate(d *schema.ResourceData, meta interface{}) e _, err = client.CreateOrUpdate(ctx, resGroup, name, parameters) if err != nil { - return fmt.Errorf("Error updating Key Vault (Key Vault %q / Resource Group %q): %+v", name, resGroup, err) + return fmt.Errorf("Error updating Key Vault %q (Resource Group %q): %+v", name, resGroup, err) } read, err := client.Get(ctx, resGroup, name) @@ -172,7 +172,7 @@ func resourceArmKeyVaultCreateUpdate(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("Error retrieving Key Vault %q (Resource Group %q): %+v", name, resGroup, err) } if read.ID == nil { - return fmt.Errorf("Cannot read KeyVault %s (resource group %s) ID", name, resGroup) + return fmt.Errorf("Cannot read KeyVault %s (resource Group %q) ID", name, resGroup) } d.SetId(*read.ID) @@ -218,7 +218,7 @@ func resourceArmKeyVaultRead(d *schema.ResourceData, meta interface{}) error { d.SetId("") return nil } - return fmt.Errorf("Error making Read request on Azure KeyVault %s: %+v", name, err) + return fmt.Errorf("Error making Read request on KeyVault %q (Resource Group %q): %+v", name, resGroup, err) } d.Set("name", resp.Name) From aa2d2b044782971404e4a58332fc2d4b8576e4fd Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 9 Jul 2018 11:43:59 +0200 Subject: [PATCH 23/23] Documentation fixes --- website/docs/r/key_vault.html.markdown | 6 +++--- website/docs/r/key_vault_access_policy.html.markdown | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/website/docs/r/key_vault.html.markdown b/website/docs/r/key_vault.html.markdown index b5170427096f..b672109071f0 100644 --- a/website/docs/r/key_vault.html.markdown +++ b/website/docs/r/key_vault.html.markdown @@ -10,6 +10,8 @@ description: |- Manages a Key Vault. +~> **NOTE:** It's possible to define Key Vault Access Policies both within [the `azurerm_key_vault` resource](key_vault.html) via the `access_policy` block and by using [the `azurerm_key_vault_access_policy` resource](key_vault_access_policy.html). However it's not possible to use both methods to manage Access Policies within a KeyVault, since there'll be conflicts. + ## Example Usage ```hcl @@ -71,9 +73,7 @@ The following arguments are supported: * `access_policy` - (Optional) An access policy block as described below. A maximum of 16 may be declared. -~> **Please Note:** Access Policies can also be defined using the [Key Vault Access Policy Resource](key_vault_access_policy.html) -resource (however you cannot use the independent resource and the built-in access_policy -field together, since they'll conflict). +~> **NOTE:** It's possible to define Key Vault Access Policies both within [the `azurerm_key_vault` resource](key_vault.html) via the `access_policy` block and by using [the `azurerm_key_vault_access_policy` resource](key_vault_access_policy.html). However it's not possible to use both methods to manage Access Policies within a KeyVault, since there'll be conflicts. * `enabled_for_deployment` - (Optional) Boolean flag to specify whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key diff --git a/website/docs/r/key_vault_access_policy.html.markdown b/website/docs/r/key_vault_access_policy.html.markdown index dcc1225112b9..c957a0987102 100644 --- a/website/docs/r/key_vault_access_policy.html.markdown +++ b/website/docs/r/key_vault_access_policy.html.markdown @@ -10,10 +10,9 @@ description: |- Manages a Key Vault Access Policy. -~> **NOTE on Key Vaults and Key Vault Policies:** Terraform currently -provides both a standalone [Key Vault Policy Resource](key_vault_access_policy.html), and allows for Key Vault Access Polcies to be defined in-line within the [Key Vault Resource](key_vault.html). -At this time you cannot define Key Vault Policy with in-line Key Vault in conjunction with any Key Vault Policy resources. Doing so may cause a conflict of Access Policies and will overwrite Access Policies. +~> **NOTE:** It's possible to define Key Vault Access Policies both within [the `azurerm_key_vault` resource](key_vault.html) via the `access_policy` block and by using [the `azurerm_key_vault_access_policy` resource](key_vault_access_policy.html). However it's not possible to use both methods to manage Access Policies within a KeyVault, since there'll be conflicts. +-> **NOTE:** Azure permits a maximum of 16 Access Policies per Key Vault - [more information can be found in this document](https://docs.microsoft.com/en-us/azure/key-vault/key-vault-secure-your-key-vault#data-plane-access-control). ## Example Usage