Skip to content

Commit

Permalink
azurerm_synapse_workspace - add support for `user_assigned_identity…
Browse files Browse the repository at this point in the history
…_id` within `customer_managed_key` (hashicorp#25027)
  • Loading branch information
mbfrahry authored and rizkybiz committed Feb 29, 2024
1 parent e4f090b commit 4ebe910
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 27 deletions.
67 changes: 42 additions & 25 deletions internal/services/synapse/synapse_workspace_resource.go
Expand Up @@ -116,12 +116,11 @@ func resourceSynapseWorkspace() *pluginsdk.Resource {
},

"aad_admin": {
Type: pluginsdk.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
ConfigMode: pluginsdk.SchemaConfigModeAttr,
ConflictsWith: []string{"customer_managed_key"},
Type: pluginsdk.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
ConfigMode: pluginsdk.SchemaConfigModeAttr,
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"login": {
Expand Down Expand Up @@ -294,7 +293,7 @@ func resourceSynapseWorkspace() *pluginsdk.Resource {
Type: pluginsdk.TypeList,
Optional: true,
MaxItems: 1,
ConflictsWith: []string{"aad_admin", "sql_aad_admin"},
ConflictsWith: []string{"sql_aad_admin"},
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"key_versionless_id": {
Expand All @@ -309,6 +308,11 @@ func resourceSynapseWorkspace() *pluginsdk.Resource {
Optional: true,
Default: "cmk",
},

"user_assigned_identity_id": {
Type: pluginsdk.TypeString,
Optional: true,
},
},
},
},
Expand Down Expand Up @@ -528,7 +532,10 @@ func resourceSynapseWorkspaceRead(d *pluginsdk.ResourceData, meta interface{}) e
d.Set("connectivity_endpoints", utils.FlattenMapStringPtrString(props.ConnectivityEndpoints))
d.Set("public_network_access_enabled", resp.PublicNetworkAccess == synapse.WorkspacePublicNetworkAccessEnabled)
d.Set("azuread_authentication_only", props.AzureADOnlyAuthentication)
cmk := flattenEncryptionDetails(props.Encryption)
cmk, err := flattenEncryptionDetails(props.Encryption)
if err != nil {
return fmt.Errorf("flattening `customer_managed_key`: %+v", err)
}
if err := d.Set("customer_managed_key", cmk); err != nil {
return fmt.Errorf("setting `customer_managed_key`: %+v", err)
}
Expand Down Expand Up @@ -894,14 +901,24 @@ func expandIdentityControlSQLSettings(enabled bool) *synapse.ManagedIdentitySQLC
func expandEncryptionDetails(d *pluginsdk.ResourceData) *synapse.EncryptionDetails {
if cmkList, ok := d.GetOk("customer_managed_key"); ok {
cmk := cmkList.([]interface{})[0].(map[string]interface{})
return &synapse.EncryptionDetails{

encryptionDetails := &synapse.EncryptionDetails{
Cmk: &synapse.CustomerManagedKeyDetails{
Key: &synapse.WorkspaceKeyDetails{
Name: utils.String(cmk["key_name"].(string)),
KeyVaultURL: utils.String(cmk["key_versionless_id"].(string)),
},
},
}

if v, ok := cmk["user_assigned_identity_id"]; ok && v.(string) != "" {
encryptionDetails.Cmk.KekIdentity = &synapse.KekIdentityProperties{
UserAssignedIdentity: pointer.To(v.(string)),
UseSystemAssignedIdentity: false,
}
}

return encryptionDetails
}

return nil
Expand Down Expand Up @@ -992,25 +1009,25 @@ func flattenIdentityControlSQLSettings(settings synapse.ManagedIdentitySQLContro
return false
}

func flattenEncryptionDetails(encryption *synapse.EncryptionDetails) []interface{} {
if encryption != nil {
if cmk := encryption.Cmk; cmk != nil {
if cmk.Key != nil {
resultMap := map[string]interface{}{}
resultMap["key_name"] = *cmk.Key.Name
resultMap["key_versionless_id"] = *cmk.Key.KeyVaultURL
return []interface{}{resultMap}
}
}
func flattenEncryptionDetails(encryption *synapse.EncryptionDetails) ([]interface{}, error) {
output := make([]interface{}, 0)
if encryption == nil || encryption.Cmk == nil || encryption.Cmk.Key == nil {
return output, nil
}
resultMap := map[string]interface{}{}

resultMap["key_name"] = pointer.From(encryption.Cmk.Key.Name)
resultMap["key_versionless_id"] = pointer.From(encryption.Cmk.Key.KeyVaultURL)

// if cmk := encryption.Cmk; cmk != nil {
// if key := cmk.Key; key != nil {
// return key.Name, key.KeyVaultURL
// }
// }
if encryption.Cmk.KekIdentity != nil && encryption.Cmk.KekIdentity.UserAssignedIdentity != nil {
parsed, err := commonids.ParseUserAssignedIdentityIDInsensitively(pointer.From(encryption.Cmk.KekIdentity.UserAssignedIdentity))
if err != nil {
return nil, fmt.Errorf("parsing %q: %+v", pointer.From(encryption.Cmk.KekIdentity.UserAssignedIdentity), err)
}
resultMap["user_assigned_identity_id"] = parsed.ID()
}

return make([]interface{}, 0)
return append(output, resultMap), nil
}

func expandIdentity(input []interface{}) (*synapse.ManagedIdentity, error) {
Expand Down
98 changes: 98 additions & 0 deletions internal/services/synapse/synapse_workspace_resource_test.go
Expand Up @@ -216,6 +216,21 @@ func TestAccSynapseWorkspace_azureAdOnlyAuthentication(t *testing.T) {
})
}

func TestAccSynapseWorkspace_cmkWithAADAdmin(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_synapse_workspace", "test")
r := SynapseWorkspaceResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.cmkWithAADAdmin(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep("sql_administrator_login_password"),
})
}

func (r SynapseWorkspaceResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) {
id, err := parse.WorkspaceID(state.ID)
if err != nil {
Expand Down Expand Up @@ -676,3 +691,86 @@ resource "azurerm_storage_data_lake_gen2_filesystem" "test" {
}
`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomInteger)
}

func (r SynapseWorkspaceResource) cmkWithAADAdmin(data acceptance.TestData) string {
template := r.template(data)
return fmt.Sprintf(`
%s
data "azurerm_client_config" "current" {}
resource "azurerm_user_assigned_identity" "test" {
name = "acctestuaid%[2]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
}
resource "azurerm_key_vault" "test" {
name = "acckv%[2]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"
purge_protection_enabled = true
access_policy {
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = data.azurerm_client_config.current.object_id
key_permissions = [
"Create",
"Get",
"Delete",
"Purge",
"GetRotationPolicy",
]
}
access_policy {
tenant_id = azurerm_user_assigned_identity.test.tenant_id
object_id = azurerm_user_assigned_identity.test.principal_id
key_permissions = [
"Get",
"WrapKey",
"UnwrapKey",
]
}
}
resource "azurerm_key_vault_key" "test" {
name = "key"
key_vault_id = azurerm_key_vault.test.id
key_type = "RSA"
key_size = 2048
key_opts = [
"unwrapKey",
"wrapKey"
]
}
resource "azurerm_synapse_workspace" "test" {
name = "acctestsw%[2]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
storage_data_lake_gen2_filesystem_id = azurerm_storage_data_lake_gen2_filesystem.test.id
sql_administrator_login = "sqladminuser"
sql_administrator_login_password = "H@Sh1CoR3!"
azuread_authentication_only = true
customer_managed_key {
key_versionless_id = azurerm_key_vault_key.test.versionless_id
user_assigned_identity_id = azurerm_user_assigned_identity.test.id
}
aad_admin {
login = "AzureAD Admin"
object_id = data.azurerm_client_config.current.object_id
tenant_id = data.azurerm_client_config.current.tenant_id
}
identity {
type = "SystemAssigned, UserAssigned"
identity_ids = [azurerm_user_assigned_identity.test.id]
}
}
`, template, data.RandomInteger)
}
6 changes: 4 additions & 2 deletions website/docs/r/synapse_workspace.html.markdown
Expand Up @@ -187,15 +187,15 @@ The following arguments are supported:

---

* `aad_admin` - (Optional) An `aad_admin` block as defined below. Conflicts with `customer_managed_key`.
* `aad_admin` - (Optional) An `aad_admin` block as defined below.

* `compute_subnet_id` - (Optional) Subnet ID used for computes in workspace Changing this forces a new resource to be created.

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

* `data_exfiltration_protection_enabled` - (Optional) Is data exfiltration protection enabled in this workspace? If set to `true`, `managed_virtual_network_enabled` must also be set to `true`. Changing this forces a new resource to be created.

* `customer_managed_key` - (Optional) A `customer_managed_key` block as defined below. Conflicts with `aad_admin`.
* `customer_managed_key` - (Optional) A `customer_managed_key` block as defined below.

* `github_repo` - (Optional) A `github_repo` block as defined below.

Expand Down Expand Up @@ -251,6 +251,8 @@ A `customer_managed_key` block supports the following:

* `key_name` - (Optional) An identifier for the key. Name needs to match the name of the key used with the `azurerm_synapse_workspace_key` resource. Defaults to "cmk" if not specified.

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

---

The `identity` block supports the following:
Expand Down

0 comments on commit 4ebe910

Please sign in to comment.