Skip to content

Commit

Permalink
azurerm_automation_account - support for the encryption and `loca…
Browse files Browse the repository at this point in the history
…l_authentication_enabled` property (hashicorp#17454)

Co-authored-by: xuwu1 <[email protected]>
  • Loading branch information
wuxu92 and wuxu92 authored Aug 16, 2022
1 parent 9d74747 commit 0673a30
Show file tree
Hide file tree
Showing 3 changed files with 271 additions and 0 deletions.
122 changes: 122 additions & 0 deletions internal/services/automation/automation_account_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ import (
"time"

"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
"github.com/hashicorp/go-azure-helpers/resourcemanager/identity"
"github.com/hashicorp/go-azure-helpers/resourcemanager/location"
"github.com/hashicorp/go-azure-sdk/resource-manager/automation/2021-06-22/automationaccount"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-azurerm/helpers/tf"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/automation/validate"
keyVaultParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/parse"
keyVaultValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/tags"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
Expand Down Expand Up @@ -58,6 +62,43 @@ func resourceAutomationAccount() *pluginsdk.Resource {

"identity": commonschema.SystemAssignedUserAssignedIdentityOptional(),

"encryption": {
Type: pluginsdk.TypeList,
Optional: true,
Computed: true,
Elem: &pluginsdk.Resource{
Schema: map[string]*schema.Schema{
"user_assigned_identity_id": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: commonids.ValidateUserAssignedIdentityID,
},

"key_source": {
Type: pluginsdk.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringInSlice(
automationaccount.PossibleValuesForEncryptionKeySourceType(),
false,
),
},

"key_vault_key_id": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: keyVaultValidate.NestedItemIdWithOptionalVersion,
},
},
},
},

"local_authentication_enabled": {
Type: pluginsdk.TypeBool,
Optional: true,
Default: true,
},

"tags": tags.Schema(),

"dsc_server_endpoint": {
Expand Down Expand Up @@ -130,6 +171,17 @@ func resourceAutomationAccountCreate(d *pluginsdk.ResourceData, meta interface{}
},
Location: utils.String(location.Normalize(d.Get("location").(string))),
}

if localAuth := d.Get("local_authentication_enabled").(bool); localAuth == false {
parameters.Properties.DisableLocalAuth = utils.Bool(true)
}
if encryption := d.Get("encryption").([]interface{}); len(encryption) > 0 {
enc, err := expandEncryption(encryption[0].(map[string]interface{}))
if err != nil {
return fmt.Errorf("expanding `encryption`: %v", err)
}
parameters.Properties.Encryption = enc
}
// for create account do not set identity property (even TypeNone is not allowed), or api will response error
if identityVal.Type != identity.TypeNone {
parameters.Identity = identityVal
Expand Down Expand Up @@ -170,6 +222,18 @@ func resourceAutomationAccountUpdate(d *pluginsdk.ResourceData, meta interface{}
Identity: identity,
}

if localAuth := d.Get("local_authentication_enabled").(bool); localAuth == false {
parameters.Properties.DisableLocalAuth = utils.Bool(true)
}

if encryption := d.Get("encryption").([]interface{}); len(encryption) > 0 {
enc, err := expandEncryption(encryption[0].(map[string]interface{}))
if err != nil {
return fmt.Errorf("expanding `encryption`: %v", err)
}
parameters.Properties.Encryption = enc
}

if tagsVal := expandTags(d.Get("tags").(map[string]interface{})); tagsVal != nil {
parameters.Tags = &tagsVal
}
Expand Down Expand Up @@ -233,6 +297,16 @@ func resourceAutomationAccountRead(d *pluginsdk.ResourceData, meta interface{})
}
d.Set("sku_name", skuName)

localAuthEnabled := true
if val := prop.DisableLocalAuth; val != nil && *val == true {
localAuthEnabled = false
}
d.Set("local_authentication_enabled", localAuthEnabled)

if err := d.Set("encryption", flattenEncryption(prop.Encryption)); err != nil {
return fmt.Errorf("setting `encryption`: %+v", err)
}

d.Set("dsc_server_endpoint", keysResp.Endpoint)
if keys := keysResp.Keys; keys != nil {
d.Set("dsc_primary_access_key", keys.Primary)
Expand Down Expand Up @@ -278,3 +352,51 @@ func resourceAutomationAccountDelete(d *pluginsdk.ResourceData, meta interface{}

return nil
}

func expandEncryption(encMap map[string]interface{}) (*automationaccount.EncryptionProperties, error) {
var id interface{}
id, ok := encMap["user_assigned_identity_id"].(string)
if !ok {
return nil, fmt.Errorf("read encryption user identity id error")
}
prop := &automationaccount.EncryptionProperties{
Identity: &automationaccount.EncryptionPropertiesIdentity{
UserAssignedIdentity: &id,
},
}
if val, ok := encMap["key_source"].(string); ok && val != "" {
prop.KeySource = (*automationaccount.EncryptionKeySourceType)(&val)
}
if keyIdStr := encMap["key_vault_key_id"].(string); keyIdStr != "" {
keyId, err := keyVaultParse.ParseOptionallyVersionedNestedItemID(keyIdStr)
if err != nil {
return nil, err
}
prop.KeyVaultProperties = &automationaccount.KeyVaultProperties{
KeyName: utils.String(keyId.Name),
KeyVersion: utils.String(keyId.Version),
KeyvaultUri: utils.String(keyId.KeyVaultBaseUrl),
}
}
return prop, nil
}

func flattenEncryption(encryption *automationaccount.EncryptionProperties) (res []interface{}) {
if encryption == nil {
return
}
item := map[string]interface{}{}
if encryption.KeySource != nil {
item["key_source"] = (string)(*encryption.KeySource)
}
if encryption.Identity != nil && encryption.Identity.UserAssignedIdentity != nil {
item["user_assigned_identity_id"] = (*encryption.Identity.UserAssignedIdentity).(string)
}
if keyProp := encryption.KeyVaultProperties; keyProp != nil {
keyVaultKeyId, err := keyVaultParse.NewNestedItemID(*keyProp.KeyvaultUri, "keys", *keyProp.KeyName, *keyProp.KeyVersion)
if err == nil {
item["key_vault_key_id"] = keyVaultKeyId.ID()
}
}
return []interface{}{item}
}
135 changes: 135 additions & 0 deletions internal/services/automation/automation_account_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,24 @@ func TestAccAutomationAccount_complete(t *testing.T) {
})
}

func TestAccAutomationAccount_encryption(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_automation_account", "test")
r := AutomationAccountResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.encryption(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("sku_name").HasValue("Basic"),
check.That(data.ResourceName).Key("local_authentication_enabled").HasValue("false"),
check.That(data.ResourceName).Key("encryption.0.key_source").HasValue("Microsoft.Keyvault"),
),
},
data.ImportStep(),
})
}

func TestAccAutomationAccount_identityUpdate(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_automation_account", "test")
r := AutomationAccountResource{}
Expand Down Expand Up @@ -257,6 +275,123 @@ resource "azurerm_automation_account" "test" {
`, data.RandomInteger, data.Locations.Primary)
}

func (AutomationAccountResource) encryption(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {
key_vault {
purge_soft_delete_on_destroy = false
purge_soft_deleted_keys_on_destroy = false
}
}
}
data "azurerm_client_config" "current" {
}
resource "azurerm_resource_group" "test" {
name = "acctestRG-auto-%[1]d"
location = "%[2]s"
}
resource "azurerm_user_assigned_identity" "test" {
name = "acctestUAI-%[1]d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
}
resource "azurerm_key_vault" "test" {
name = "vault%[1]d"
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 = "standard"
soft_delete_retention_days = 7
purge_protection_enabled = true
access_policy {
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = data.azurerm_client_config.current.object_id
certificate_permissions = [
"ManageContacts",
]
key_permissions = [
"Create",
"Get",
"List",
"Delete",
"Purge",
]
secret_permissions = [
"Set",
]
}
access_policy {
tenant_id = azurerm_user_assigned_identity.test.tenant_id
object_id = azurerm_user_assigned_identity.test.principal_id
certificate_permissions = []
key_permissions = [
"Get",
"Recover",
"WrapKey",
"UnwrapKey",
]
secret_permissions = []
}
}
data "azurerm_key_vault" "test" {
name = azurerm_key_vault.test.name
resource_group_name = azurerm_key_vault.test.resource_group_name
}
resource "azurerm_key_vault_key" "test" {
name = "acckvkey-%[1]d"
key_vault_id = azurerm_key_vault.test.id
key_type = "RSA"
key_size = 2048
key_opts = [
"decrypt",
"encrypt",
"sign",
"unwrapKey",
"verify",
"wrapKey",
]
}
resource "azurerm_automation_account" "test" {
name = "acctest-%[1]d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
sku_name = "Basic"
identity {
type = "UserAssigned"
identity_ids = [
azurerm_user_assigned_identity.test.id
]
}
local_authentication_enabled = false
encryption {
key_source = "Microsoft.Keyvault"
user_assigned_identity_id = azurerm_user_assigned_identity.test.id
key_vault_key_id = azurerm_key_vault_key.test.id
}
}
`, data.RandomInteger, data.Locations.Primary)
}

func (AutomationAccountResource) userAssignedIdentity(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
Expand Down
14 changes: 14 additions & 0 deletions website/docs/r/automation_account.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,16 @@ The following arguments are supported:

* `sku_name` - (Required) The SKU of the account - only `Basic` is supported at this time.

* `local_authentication_enabled` - (Optional) Whether requests using non-AAD authentication are blocked.

---

* `identity` - (Optional) An `identity` block as defined below.

* `tags` - (Optional) A mapping of tags to assign to the resource.

* `encryption` - (Optional) An `encryption` block as defined below.

---

An `identity` block supports the following:
Expand All @@ -60,6 +64,16 @@ An `identity` block supports the following:

-> **Note:** `identity_ids` is required when `type` is set to `UserAssigned` or `SystemAssigned, UserAssigned`.

--

An `encryption` block supports the following:

* `user_assigned_identity_id` - (Optional) The User Assigned Managed Identity ID to be used for accessing the Customer Managed Key for encryption.

* `key_source` - (Optional) The source of the encryption key. Possible values are `Microsoft.Keyvault` and `Microsoft.Storage`.

* `key_vault_key_id` - (Required) The ID of the Key Vault Key which should be used to Encrypt the data in this Automation Account.

---

## Attributes Reference
Expand Down

0 comments on commit 0673a30

Please sign in to comment.