Skip to content

Commit

Permalink
add encryption in automation account
Browse files Browse the repository at this point in the history
  • Loading branch information
wuxu92 committed Jun 30, 2022
1 parent c037938 commit ec65a09
Show file tree
Hide file tree
Showing 3 changed files with 287 additions and 0 deletions.
130 changes: 130 additions & 0 deletions internal/services/automation/automation_account_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ 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"
Expand Down Expand Up @@ -58,6 +60,48 @@ func resourceAutomationAccount() *pluginsdk.Resource {

"identity": commonschema.SystemAssignedUserAssignedIdentityOptional(),

"encryption": {
Type: pluginsdk.TypeList,
Optional: true,
Elem: &pluginsdk.Resource{
Schema: map[string]*schema.Schema{
"user_identity_id": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: commonids.ValidateUserAssignedIdentityID,
},
"key_source": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice(
automationaccount.PossibleValuesForEncryptionKeySourceType(),
false,
),
},
"key_name": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsNotEmpty,
},
"key_version": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsNotEmpty,
},
"key_vault_uri": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsNotEmpty,
},
},
},
},

"disable_local_auth": {
Type: pluginsdk.TypeBool,
Optional: true,
},

"tags": tags.Schema(),

"dsc_server_endpoint": {
Expand Down Expand Up @@ -111,9 +155,17 @@ func resourceAutomationAccountCreate(d *pluginsdk.ResourceData, meta interface{}
Name: automationaccount.SkuNameEnum(d.Get("sku_name").(string)),
},
PublicNetworkAccess: utils.Bool(d.Get("public_network_access_enabled").(bool)),
DisableLocalAuth: utils.Bool(d.Get("disable_local_auth").(bool)),
},
Location: utils.String(location.Normalize(d.Get("location").(string))),
}
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 @@ -149,11 +201,20 @@ func resourceAutomationAccountUpdate(d *pluginsdk.ResourceData, meta interface{}
Name: automationaccount.SkuNameEnum(d.Get("sku_name").(string)),
},
PublicNetworkAccess: utils.Bool(d.Get("public_network_access_enabled").(bool)),
DisableLocalAuth: utils.Bool(d.Get("disable_local_auth").(bool)),
},
Location: utils.String(location.Normalize(d.Get("location").(string))),
Identity: identity,
}

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 @@ -217,6 +278,16 @@ func resourceAutomationAccountRead(d *pluginsdk.ResourceData, meta interface{})
}
d.Set("sku_name", skuName)

if prop.DisableLocalAuth != nil {
d.Set("disable_local_auth", *prop.DisableLocalAuth)
}

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

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 @@ -258,3 +329,62 @@ 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_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)
}
var keyProp automationaccount.KeyVaultProperties
var hasKeyProp bool
if val, ok := encMap["key_name"].(string); ok && val != "" {
keyProp.KeyName = &val
hasKeyProp = true
}
if val, ok := encMap["key_version"].(string); ok && val != "" {
keyProp.KeyVersion = &val
hasKeyProp = true
}
if val, ok := encMap["key_vault_uri"].(string); ok && val != "" {
keyProp.KeyvaultUri = &val
hasKeyProp = true
}
if hasKeyProp {
prop.KeyVaultProperties = &keyProp
}
return prop, nil
}

func flattenEncryption(encryption *automationaccount.EncryptionProperties) (res []interface{}, err error) {
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_identity_id"] = (*encryption.Identity.UserAssignedIdentity).(string)
}
if keyProp := encryption.KeyVaultProperties; keyProp != nil {
if keyProp.KeyName != nil {
item["key_name"] = *keyProp.KeyName
}
if keyProp.KeyVersion != nil {
item["key_version"] = *keyProp.KeyVersion
}
if keyProp.KeyName != nil {
item["key_vault_uri"] = *keyProp.KeyvaultUri
}
}
return []interface{}{item}, nil
}
139 changes: 139 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,23 @@ 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("disable_local_auth").HasValue("true"),
),
},
data.ImportStep(),
})
}

func TestAccAutomationAccount_identityUpdate(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_automation_account", "test")
r := AutomationAccountResource{}
Expand Down Expand Up @@ -257,6 +274,128 @@ 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
}
data "azurerm_key_vault_key" "test" {
name = azurerm_key_vault_key.test.name
key_vault_id = azurerm_key_vault.test.id
}
resource "azurerm_key_vault_key" "test" {
name = "key-%[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
]
}
disable_local_auth = true
encryption {
key_source = "Microsoft.Keyvault"
user_identity_id = azurerm_user_assigned_identity.test.id
key_vault_uri = azurerm_key_vault.test.vault_uri
key_name = azurerm_key_vault_key.test.name
key_version = azurerm_key_vault_key.test.version
}
}
`, data.RandomInteger, data.Locations.Primary)
}

func (AutomationAccountResource) userAssignedIdentity(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
Expand Down
18 changes: 18 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.

* `disable_local_auth` - (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,20 @@ 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_identity_id` - (Optional) The user identity used for CMK. It will be an ARM resource id.

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

* `key_name` - (Optional) The name of the key used to encrypt data.

* `key_version` - (Optional) The version of the key used to encrypt data.

* `key_vault_uri` - (Optional) The URI of the Key Vault key used to encrypt data.

---

## Attributes Reference
Expand Down

0 comments on commit ec65a09

Please sign in to comment.