Skip to content

Commit

Permalink
New Resource: Key Vault Access Policy (#1149)
Browse files Browse the repository at this point in the history
* Initial support for Azure Key Vault Policy resource

* 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

* Addressed PR comments

* Return nil on a delete for the shared delete/update function

* Removed reference to old code

* Starting to address PR comments

* Starting to address PR comments

* Working my way through the PR comments

* Fixed some of the tests

* Ran make fmt

* Fixed website links

* Updated route test to fail

* Updated to support importing an access policy

* Updated to support importing of the resource and some enhanced tests

* Reverted route_test to not fail for this pr

* Working through pr comments

* Updated for PR comments as well as added several unittests for the key_vault_access_policy shared helper library

* Ran make fmt

* 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
```

* 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
```

* Handling the case of an AppID and no AppID being specified / refactoring tests

* Fixing the error message

* Documentation fixes
  • Loading branch information
sophos-jeff authored and tombuildsstuff committed Jul 9, 2018
1 parent 167d001 commit 1e9f067
Show file tree
Hide file tree
Showing 10 changed files with 968 additions and 235 deletions.
55 changes: 4 additions & 51 deletions azurerm/data_source_key_vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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)
Expand All @@ -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
}
224 changes: 224 additions & 0 deletions azurerm/helpers/schema/key_vault_access_policy.go
Original file line number Diff line number Diff line change
@@ -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
}
57 changes: 57 additions & 0 deletions azurerm/import_arm_key_vault_access_policy_test.go
Original file line number Diff line number Diff line change
@@ -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,
},
},
})
}
1 change: 1 addition & 0 deletions azurerm/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +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_certificate": resourceArmKeyVaultCertificate(),
"azurerm_key_vault_key": resourceArmKeyVaultKey(),
"azurerm_key_vault_secret": resourceArmKeyVaultSecret(),
Expand Down
Loading

0 comments on commit 1e9f067

Please sign in to comment.