diff --git a/azurerm/resource_arm_key_vault.go b/azurerm/resource_arm_key_vault.go index a9b19cc7860b6..98eef136d2b94 100644 --- a/azurerm/resource_arm_key_vault.go +++ b/azurerm/resource_arm_key_vault.go @@ -26,6 +26,8 @@ func resourceArmKeyVault() *schema.Resource { Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, + MigrateState: resourceAzureRMKeyVaultMigrateState, + SchemaVersion: 1, Schema: map[string]*schema.Schema{ "name": { diff --git a/azurerm/resource_arm_key_vault_migration.go b/azurerm/resource_arm_key_vault_migration.go new file mode 100644 index 0000000000000..11e08275c894f --- /dev/null +++ b/azurerm/resource_arm_key_vault_migration.go @@ -0,0 +1,167 @@ +package azurerm + +import ( + "fmt" + "log" + "strings" + + "github.com/Azure/azure-sdk-for-go/arm/keyvault" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/terraform" +) + +func resourceAzureRMKeyVaultMigrateState(v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) { + switch v { + case 0: + log.Println("[INFO] Found AzureRM Key Vault State v0; migrating to v1") + return migrateAzureRMKeyVaultStateV0toV1(is) + default: + return is, fmt.Errorf("Unexpected schema version: %d", v) + } +} + +func migrateAzureRMKeyVaultStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) { + if is.Empty() { + log.Println("[DEBUG] Empty InstanceState; nothing to migrate.") + return is, nil + } + + log.Printf("[DEBUG] ARM Key Vault Attributes before Migration: %#v", is.Attributes) + + err := migrateAzureRMKeyVaultStateV0toV1AccessPolicies(is) + if err != nil { + return nil, err + } + + log.Printf("[DEBUG] ARM Key Vault Attributes after State Migration: %#v", is.Attributes) + + return is, nil +} + +func migrateAzureRMKeyVaultStateV0toV1AccessPolicies(is *terraform.InstanceState) error { + keyVaultSchema := resourceArmKeyVault().Schema + reader := &schema.MapFieldReader{ + Schema: keyVaultSchema, + Map: schema.BasicMapReader(is.Attributes), + } + + // parse and update the existing data + result, err := reader.ReadField([]string{"access_policy"}) + if err != nil { + return err + } + + inputAccessPolicies := result.Value.([]interface{}) + + if len(inputAccessPolicies) == 0 { + return nil + } + + outputAccessPolicies := make([]interface{}, 0) + for _, accessPolicy := range inputAccessPolicies { + policy := accessPolicy.(map[string]interface{}) + + if v, ok := policy["certificate_permissions"]; ok { + inputCertificatePermissions := v.([]interface{}) + outputCertificatePermissions := make([]string, 0) + for _, p := range inputCertificatePermissions { + permission := p.(string) + if strings.ToLower(permission) == "all" { + outputCertificatePermissions = append(outputCertificatePermissions, string(keyvault.Create)) + outputCertificatePermissions = append(outputCertificatePermissions, string(keyvault.Delete)) + outputCertificatePermissions = append(outputCertificatePermissions, string(keyvault.Deleteissuers)) + outputCertificatePermissions = append(outputCertificatePermissions, string(keyvault.Get)) + outputCertificatePermissions = append(outputCertificatePermissions, string(keyvault.Getissuers)) + outputCertificatePermissions = append(outputCertificatePermissions, string(keyvault.Import)) + outputCertificatePermissions = append(outputCertificatePermissions, string(keyvault.List)) + outputCertificatePermissions = append(outputCertificatePermissions, string(keyvault.Listissuers)) + outputCertificatePermissions = append(outputCertificatePermissions, string(keyvault.Managecontacts)) + outputCertificatePermissions = append(outputCertificatePermissions, string(keyvault.Manageissuers)) + outputCertificatePermissions = append(outputCertificatePermissions, string(keyvault.Setissuers)) + outputCertificatePermissions = append(outputCertificatePermissions, string(keyvault.Update)) + break + } + } + + if len(outputCertificatePermissions) > 0 { + policy["certificate_permissions"] = outputCertificatePermissions + } + } + + if v, ok := policy["key_permissions"]; ok { + inputKeyPermissions := v.([]interface{}) + outputKeyPermissions := make([]string, 0) + for _, p := range inputKeyPermissions { + permission := p.(string) + if strings.ToLower(permission) == "all" { + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsBackup)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsCreate)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsDecrypt)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsDelete)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsEncrypt)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsGet)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsImport)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsList)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsPurge)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsRecover)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsRestore)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsSign)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsUnwrapKey)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsUpdate)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsVerify)) + outputKeyPermissions = append(outputKeyPermissions, string(keyvault.KeyPermissionsWrapKey)) + break + } + } + + if len(outputKeyPermissions) > 0 { + policy["key_permissions"] = outputKeyPermissions + } + } + + if v, ok := policy["secret_permissions"]; ok { + inputSecretPermissions := v.([]interface{}) + outputSecretPermissions := make([]string, 0) + for _, p := range inputSecretPermissions { + permission := p.(string) + if strings.ToLower(permission) == "all" { + outputSecretPermissions = append(outputSecretPermissions, string(keyvault.SecretPermissionsBackup)) + outputSecretPermissions = append(outputSecretPermissions, string(keyvault.SecretPermissionsDelete)) + outputSecretPermissions = append(outputSecretPermissions, string(keyvault.SecretPermissionsGet)) + outputSecretPermissions = append(outputSecretPermissions, string(keyvault.SecretPermissionsList)) + outputSecretPermissions = append(outputSecretPermissions, string(keyvault.SecretPermissionsPurge)) + outputSecretPermissions = append(outputSecretPermissions, string(keyvault.SecretPermissionsRecover)) + outputSecretPermissions = append(outputSecretPermissions, string(keyvault.SecretPermissionsRestore)) + outputSecretPermissions = append(outputSecretPermissions, string(keyvault.SecretPermissionsSet)) + break + } + } + + if len(outputSecretPermissions) > 0 { + policy["secret_permissions"] = outputSecretPermissions + } + } + + outputAccessPolicies = append(outputAccessPolicies, policy) + } + + // remove the existing fields + for k := range is.Attributes { + if strings.HasPrefix(k, "access_policy.") { + delete(is.Attributes, k) + } + } + + // write this out + writer := schema.MapFieldWriter{ + Schema: keyVaultSchema, + } + if err := writer.WriteField([]string{"access_policy"}, outputAccessPolicies); err != nil { + return err + } + for k, v := range writer.Map() { + is.Attributes[k] = v + } + + return nil +} diff --git a/azurerm/resource_arm_key_vault_migration_test.go b/azurerm/resource_arm_key_vault_migration_test.go new file mode 100644 index 0000000000000..b8ede42dba769 --- /dev/null +++ b/azurerm/resource_arm_key_vault_migration_test.go @@ -0,0 +1,362 @@ +package azurerm + +import ( + "reflect" + "testing" + + "github.com/hashicorp/terraform/terraform" +) + +func TestAzureRMKeyVaultMigrateState(t *testing.T) { + cases := map[string]struct { + StateVersion int + ID string + Attributes map[string]string + Expected map[string]string + Meta interface{} + }{ + "v0_1_empty": { + StateVersion: 0, + ID: "some_id", + Attributes: map[string]string{}, + Expected: map[string]string{}, + }, + "v0_1_read_only": { + StateVersion: 0, + ID: "some_id", + Attributes: map[string]string{ + "access_policy.#": "1", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.application_id": "", + "access_policy.0.certificate_permissions.#": "1", + "access_policy.0.certificate_permissions.0": "Get", + "access_policy.0.key_permissions.#": "1", + "access_policy.0.key_permissions.0": "Get", + "access_policy.0.secret_permissions.#": "1", + "access_policy.0.secret_permissions.0": "Get", + }, + Expected: map[string]string{ + "access_policy.#": "1", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.application_id": "", + "access_policy.0.certificate_permissions.#": "1", + "access_policy.0.certificate_permissions.0": "Get", + "access_policy.0.key_permissions.#": "1", + "access_policy.0.key_permissions.0": "Get", + "access_policy.0.secret_permissions.#": "1", + "access_policy.0.secret_permissions.0": "Get", + }, + }, + "v0_1_certificates": { + StateVersion: 0, + ID: "some_id", + Attributes: map[string]string{ + "access_policy.#": "1", + "access_policy.0.application_id": "", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.certificate_permissions.#": "1", + "access_policy.0.certificate_permissions.0": "All", + "access_policy.0.key_permissions.#": "1", + "access_policy.0.key_permissions.0": "Get", + "access_policy.0.secret_permissions.#": "1", + "access_policy.0.secret_permissions.0": "Get", + }, + Expected: map[string]string{ + "access_policy.#": "1", + "access_policy.0.application_id": "", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.certificate_permissions.#": "12", + "access_policy.0.certificate_permissions.0": "create", + "access_policy.0.certificate_permissions.1": "delete", + "access_policy.0.certificate_permissions.2": "deleteissuers", + "access_policy.0.certificate_permissions.3": "get", + "access_policy.0.certificate_permissions.4": "getissuers", + "access_policy.0.certificate_permissions.5": "import", + "access_policy.0.certificate_permissions.6": "list", + "access_policy.0.certificate_permissions.7": "listissuers", + "access_policy.0.certificate_permissions.8": "managecontacts", + "access_policy.0.certificate_permissions.9": "manageissuers", + "access_policy.0.certificate_permissions.10": "setissuers", + "access_policy.0.certificate_permissions.11": "update", + "access_policy.0.key_permissions.#": "1", + "access_policy.0.key_permissions.0": "Get", + "access_policy.0.secret_permissions.#": "1", + "access_policy.0.secret_permissions.0": "Get", + }, + }, + "v0_1_certificates_multiple": { + StateVersion: 0, + ID: "some_id", + Attributes: map[string]string{ + // an All and a Get should be replaced by all of the values + "access_policy.#": "1", + "access_policy.0.application_id": "", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.certificate_permissions.#": "2", + "access_policy.0.certificate_permissions.0": "Get", + "access_policy.0.certificate_permissions.1": "All", + "access_policy.0.key_permissions.#": "1", + "access_policy.0.key_permissions.0": "Get", + "access_policy.0.secret_permissions.#": "1", + "access_policy.0.secret_permissions.0": "Get", + }, + Expected: map[string]string{ + "access_policy.#": "1", + "access_policy.0.application_id": "", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.certificate_permissions.#": "12", + "access_policy.0.certificate_permissions.0": "create", + "access_policy.0.certificate_permissions.1": "delete", + "access_policy.0.certificate_permissions.2": "deleteissuers", + "access_policy.0.certificate_permissions.3": "get", + "access_policy.0.certificate_permissions.4": "getissuers", + "access_policy.0.certificate_permissions.5": "import", + "access_policy.0.certificate_permissions.6": "list", + "access_policy.0.certificate_permissions.7": "listissuers", + "access_policy.0.certificate_permissions.8": "managecontacts", + "access_policy.0.certificate_permissions.9": "manageissuers", + "access_policy.0.certificate_permissions.10": "setissuers", + "access_policy.0.certificate_permissions.11": "update", + "access_policy.0.key_permissions.#": "1", + "access_policy.0.key_permissions.0": "Get", + "access_policy.0.secret_permissions.#": "1", + "access_policy.0.secret_permissions.0": "Get", + }, + }, + "v0_1_keys": { + StateVersion: 0, + ID: "some_id", + Attributes: map[string]string{ + "access_policy.#": "1", + "access_policy.0.application_id": "", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.certificate_permissions.#": "0", + "access_policy.0.key_permissions.#": "1", + "access_policy.0.key_permissions.0": "All", + "access_policy.0.secret_permissions.#": "1", + "access_policy.0.secret_permissions.0": "Get", + }, + Expected: map[string]string{ + "access_policy.#": "1", + "access_policy.0.application_id": "", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.certificate_permissions.#": "0", + "access_policy.0.key_permissions.#": "16", + "access_policy.0.key_permissions.0": "backup", + "access_policy.0.key_permissions.1": "create", + "access_policy.0.key_permissions.2": "decrypt", + "access_policy.0.key_permissions.3": "delete", + "access_policy.0.key_permissions.4": "encrypt", + "access_policy.0.key_permissions.5": "get", + "access_policy.0.key_permissions.6": "import", + "access_policy.0.key_permissions.7": "list", + "access_policy.0.key_permissions.8": "purge", + "access_policy.0.key_permissions.9": "recover", + "access_policy.0.key_permissions.10": "restore", + "access_policy.0.key_permissions.11": "sign", + "access_policy.0.key_permissions.12": "unwrapKey", + "access_policy.0.key_permissions.13": "update", + "access_policy.0.key_permissions.14": "verify", + "access_policy.0.key_permissions.15": "wrapKey", + "access_policy.0.secret_permissions.#": "1", + "access_policy.0.secret_permissions.0": "Get", + }, + }, + "v0_1_keys_multiple": { + StateVersion: 0, + ID: "some_id", + Attributes: map[string]string{ + // an All and a Get should be replaced by all of the values + "access_policy.#": "1", + "access_policy.0.application_id": "", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.certificate_permissions.#": "0", + "access_policy.0.key_permissions.#": "2", + "access_policy.0.key_permissions.0": "all", + "access_policy.0.key_permissions.1": "create", + "access_policy.0.secret_permissions.#": "1", + "access_policy.0.secret_permissions.0": "Get", + }, + Expected: map[string]string{ + "access_policy.#": "1", + "access_policy.0.application_id": "", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.certificate_permissions.#": "0", + "access_policy.0.key_permissions.#": "16", + "access_policy.0.key_permissions.0": "backup", + "access_policy.0.key_permissions.1": "create", + "access_policy.0.key_permissions.2": "decrypt", + "access_policy.0.key_permissions.3": "delete", + "access_policy.0.key_permissions.4": "encrypt", + "access_policy.0.key_permissions.5": "get", + "access_policy.0.key_permissions.6": "import", + "access_policy.0.key_permissions.7": "list", + "access_policy.0.key_permissions.8": "purge", + "access_policy.0.key_permissions.9": "recover", + "access_policy.0.key_permissions.10": "restore", + "access_policy.0.key_permissions.11": "sign", + "access_policy.0.key_permissions.12": "unwrapKey", + "access_policy.0.key_permissions.13": "update", + "access_policy.0.key_permissions.14": "verify", + "access_policy.0.key_permissions.15": "wrapKey", + "access_policy.0.secret_permissions.#": "1", + "access_policy.0.secret_permissions.0": "Get", + }, + }, + "v0_1_secrets": { + StateVersion: 0, + ID: "some_id", + Attributes: map[string]string{ + "access_policy.#": "1", + "access_policy.0.application_id": "", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.certificate_permissions.#": "0", + "access_policy.0.key_permissions.#": "1", + "access_policy.0.key_permissions.0": "create", + "access_policy.0.secret_permissions.#": "1", + "access_policy.0.secret_permissions.0": "All", + }, + Expected: map[string]string{ + "access_policy.#": "1", + "access_policy.0.application_id": "", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.certificate_permissions.#": "0", + "access_policy.0.key_permissions.#": "1", + "access_policy.0.key_permissions.0": "create", + "access_policy.0.secret_permissions.#": "8", + "access_policy.0.secret_permissions.0": "backup", + "access_policy.0.secret_permissions.1": "delete", + "access_policy.0.secret_permissions.2": "get", + "access_policy.0.secret_permissions.3": "list", + "access_policy.0.secret_permissions.4": "purge", + "access_policy.0.secret_permissions.5": "recover", + "access_policy.0.secret_permissions.6": "restore", + "access_policy.0.secret_permissions.7": "set", + }, + }, + "v0_1_secrets_multiple": { + StateVersion: 0, + ID: "some_id", + Attributes: map[string]string{ + // an All and a Get should be replaced by all of the values + "access_policy.#": "1", + "access_policy.0.application_id": "", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.certificate_permissions.#": "0", + "access_policy.0.key_permissions.#": "1", + "access_policy.0.key_permissions.0": "create", + "access_policy.0.secret_permissions.#": "2", + "access_policy.0.secret_permissions.0": "backup", + "access_policy.0.secret_permissions.1": "all", + }, + Expected: map[string]string{ + "access_policy.#": "1", + "access_policy.0.application_id": "", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.certificate_permissions.#": "0", + "access_policy.0.key_permissions.#": "1", + "access_policy.0.key_permissions.0": "create", + "access_policy.0.secret_permissions.#": "8", + "access_policy.0.secret_permissions.0": "backup", + "access_policy.0.secret_permissions.1": "delete", + "access_policy.0.secret_permissions.2": "get", + "access_policy.0.secret_permissions.3": "list", + "access_policy.0.secret_permissions.4": "purge", + "access_policy.0.secret_permissions.5": "recover", + "access_policy.0.secret_permissions.6": "restore", + "access_policy.0.secret_permissions.7": "set", + }, + }, + "v0_1_all": { + StateVersion: 0, + ID: "some_id", + Attributes: map[string]string{ + "access_policy.#": "1", + "access_policy.0.application_id": "", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.certificate_permissions.#": "1", + "access_policy.0.certificate_permissions.0": "all", + "access_policy.0.key_permissions.#": "1", + "access_policy.0.key_permissions.0": "all", + "access_policy.0.secret_permissions.#": "1", + "access_policy.0.secret_permissions.0": "all", + }, + Expected: map[string]string{ + "access_policy.#": "1", + "access_policy.0.application_id": "", + "access_policy.0.tenant_id": "abc123", + "access_policy.0.object_id": "bcd234", + "access_policy.0.certificate_permissions.#": "12", + "access_policy.0.certificate_permissions.0": "create", + "access_policy.0.certificate_permissions.1": "delete", + "access_policy.0.certificate_permissions.2": "deleteissuers", + "access_policy.0.certificate_permissions.3": "get", + "access_policy.0.certificate_permissions.4": "getissuers", + "access_policy.0.certificate_permissions.5": "import", + "access_policy.0.certificate_permissions.6": "list", + "access_policy.0.certificate_permissions.7": "listissuers", + "access_policy.0.certificate_permissions.8": "managecontacts", + "access_policy.0.certificate_permissions.9": "manageissuers", + "access_policy.0.certificate_permissions.10": "setissuers", + "access_policy.0.certificate_permissions.11": "update", + "access_policy.0.key_permissions.#": "16", + "access_policy.0.key_permissions.0": "backup", + "access_policy.0.key_permissions.1": "create", + "access_policy.0.key_permissions.2": "decrypt", + "access_policy.0.key_permissions.3": "delete", + "access_policy.0.key_permissions.4": "encrypt", + "access_policy.0.key_permissions.5": "get", + "access_policy.0.key_permissions.6": "import", + "access_policy.0.key_permissions.7": "list", + "access_policy.0.key_permissions.8": "purge", + "access_policy.0.key_permissions.9": "recover", + "access_policy.0.key_permissions.10": "restore", + "access_policy.0.key_permissions.11": "sign", + "access_policy.0.key_permissions.12": "unwrapKey", + "access_policy.0.key_permissions.13": "update", + "access_policy.0.key_permissions.14": "verify", + "access_policy.0.key_permissions.15": "wrapKey", + "access_policy.0.secret_permissions.#": "8", + "access_policy.0.secret_permissions.0": "backup", + "access_policy.0.secret_permissions.1": "delete", + "access_policy.0.secret_permissions.2": "get", + "access_policy.0.secret_permissions.3": "list", + "access_policy.0.secret_permissions.4": "purge", + "access_policy.0.secret_permissions.5": "recover", + "access_policy.0.secret_permissions.6": "restore", + "access_policy.0.secret_permissions.7": "set", + }, + }, + } + + for tn, tc := range cases { + is := &terraform.InstanceState{ + ID: tc.ID, + Attributes: tc.Attributes, + } + is, err := resourceAzureRMKeyVaultMigrateState(tc.StateVersion, is, tc.Meta) + + if err != nil { + t.Fatalf("bad: %q, err: %+v", tn, err) + } + + if !reflect.DeepEqual(tc.Expected, is.Attributes) { + t.Fatalf("Bad Key Vault Migrate\n\n. Got: %+v\n\n expected: %+v", is.Attributes, tc.Expected) + } + } +}