Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api_managment - support user assigned managed identities #6783

Merged
merged 14 commits into from May 13, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -52,6 +52,36 @@ func dataSourceApiManagementService() *schema.Resource {
Computed: true,
},

"identity": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
sirlatrom marked this conversation as resolved.
Show resolved Hide resolved
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"type": {
Type: schema.TypeString,
Computed: true,
},
"principal_id": {
Type: schema.TypeString,
Computed: true,
},
"tenant_id": {
Type: schema.TypeString,
Computed: true,
},
"identity_ids": {
Type: schema.TypeList,
Computed: true,
MinItems: 1,
sirlatrom marked this conversation as resolved.
Show resolved Hide resolved
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},

"notification_sender_email": {
Type: schema.TypeString,
Computed: true,
Expand Down
54 changes: 49 additions & 5 deletions azurerm/internal/services/apimanagement/api_management_resource.go
Expand Up @@ -89,7 +89,9 @@ func resourceArmApiManagementService() *schema.Resource {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
"SystemAssigned",
string(apimanagement.SystemAssigned),
sirlatrom marked this conversation as resolved.
Show resolved Hide resolved
string(apimanagement.UserAssigned),
string(apimanagement.SystemAssignedUserAssigned),
}, false),
},
"principal_id": {
Expand All @@ -100,6 +102,15 @@ func resourceArmApiManagementService() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"identity_ids": {
Type: schema.TypeSet,
Optional: true,
MinItems: 1,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.NoZeroValues,
},
},
},
},
},
Expand Down Expand Up @@ -470,7 +481,11 @@ func resourceArmApiManagementServiceCreateUpdate(d *schema.ResourceData, meta in
}

if _, ok := d.GetOk("identity"); ok {
properties.Identity = expandAzureRmApiManagementIdentity(d)
identity, err := expandAzureRmApiManagementIdentity(d)
if err != nil {
return fmt.Errorf("Error expanding `identity`: %+v", err)
}
properties.Identity = identity
}

if _, ok := d.GetOk("additional_location"); ok {
Expand Down Expand Up @@ -899,17 +914,38 @@ func flattenApiManagementAdditionalLocations(input *[]apimanagement.AdditionalLo
return results
}

func expandAzureRmApiManagementIdentity(d *schema.ResourceData) *apimanagement.ServiceIdentity {
func expandAzureRmApiManagementIdentity(d *schema.ResourceData) (*apimanagement.ServiceIdentity, error) {
vs := d.Get("identity").([]interface{})
if len(vs) == 0 {
return nil
return &apimanagement.ServiceIdentity{
Type: apimanagement.None,
}, nil
sirlatrom marked this conversation as resolved.
Show resolved Hide resolved
}

v := vs[0].(map[string]interface{})
identityType := v["type"].(string)
return &apimanagement.ServiceIdentity{

managedServiceIdentity := apimanagement.ServiceIdentity{
Type: apimanagement.ApimIdentityType(identityType),
}

identityIdSet := (v["identity_ids"].(*schema.Set))
if managedServiceIdentity.Type == apimanagement.UserAssigned || managedServiceIdentity.Type == apimanagement.SystemAssignedUserAssigned {
if identityIdSet.Len() == 0 {
return nil, fmt.Errorf("`identity_ids` must have at least 1 element when `type` includes `UserAssigned`")
}
sirlatrom marked this conversation as resolved.
Show resolved Hide resolved

identityIds := make(map[string]*apimanagement.UserIdentityProperties)
for _, id := range identityIdSet.List() {
identityIds[id.(string)] = &apimanagement.UserIdentityProperties{}
}

managedServiceIdentity.UserAssignedIdentities = identityIds
} else if identityIdSet.Len() > 0 {
return nil, fmt.Errorf("`identity_ids` can only be specified when `type` includes `UserAssigned`")
}

return &managedServiceIdentity, nil
}

func flattenAzureRmApiManagementMachineIdentity(identity *apimanagement.ServiceIdentity) []interface{} {
Expand All @@ -929,6 +965,14 @@ func flattenAzureRmApiManagementMachineIdentity(identity *apimanagement.ServiceI
result["tenant_id"] = identity.TenantID.String()
}

identityIds := make([]interface{}, 0)
if identity.UserAssignedIdentities != nil {
for key := range identity.UserAssignedIdentities {
identityIds = append(identityIds, key)
}
result["identity_ids"] = schema.NewSet(schema.HashString, identityIds)
}

return []interface{}{result}
}

Expand Down
Expand Up @@ -272,6 +272,27 @@ func TestAccAzureRMApiManagementApi_complete(t *testing.T) {
})
}

func TestAccAzureRMApiManagement_identityUserAssigned(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_api_management", "test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acceptance.PreCheck(t) },
Providers: acceptance.SupportedProviders,
CheckDestroy: testCheckAzureRMApiManagementDestroy,
Steps: []resource.TestStep{
{
Config: testAccAzureRMApiManagement_identityUserAssigned(data),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMApiManagementExists(data.ResourceName),
resource.TestCheckResourceAttr(data.ResourceName, "identity.type", "UserAssigned"),
resource.TestCheckResourceAttr(data.ResourceName, "identity.identity_ids.#", "1"),
),
},
data.ImportStep(),
},
})
}
sirlatrom marked this conversation as resolved.
Show resolved Hide resolved

func testCheckAzureRMApiManagementApiDestroy(s *terraform.State) error {
conn := acceptance.AzureProvider.Meta().(*clients.Client).ApiManagement.ApiClient
ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext
Expand Down Expand Up @@ -581,3 +602,39 @@ resource "azurerm_api_management" "test" {
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger)
}

func testAccAzureRMApiManagement_identityUserAssigned(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}

resource "azurerm_resource_group" "test" {
name = "acctestRG-%d"
location = "%s"
}

resource "azurerm_user_assigned_identity" "test" {
name = "acctestUAI-%d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
}

resource "azurerm_api_management" "test" {
name = "acctestAM-%d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
publisher_name = "pub1"
publisher_email = "pub1@email.com"

sku_name = "Developer_1"

identity {
type = "UserAssigned"
identity_ids = [
azurerm_user_assigned_identity.test.id,
]
}
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger)
}
12 changes: 12 additions & 0 deletions website/docs/d/api_management.html.markdown
Expand Up @@ -41,6 +41,8 @@ output "api_management_id" {

* `gateway_regional_url` - The URL for the Gateway in the Default Region.

* `identity` - (Optional) An `identity` block as defined below.
sirlatrom marked this conversation as resolved.
Show resolved Hide resolved

* `hostname_configuration` - A `hostname_configuration` block as defined below.

* `management_api_url` - The URL for the Management API.
Expand Down Expand Up @@ -73,6 +75,16 @@ A `additional_location` block exports the following:

---

A `identity` block exports the following:

~> **Note:** User Assigned Managed Identities are in Preview

* `type` - Specifies the type of Managed Service Identity that is configured on this API Management Service.

* `identity_ids` - A list of IDs for User Assigned Managed Identity resources to be assigned.

sirlatrom marked this conversation as resolved.
Show resolved Hide resolved
---

A `hostname_configuration` block exports the following:

* `management` - One or more `management` blocks as documented below.
Expand Down
8 changes: 7 additions & 1 deletion website/docs/r/api_management.html.markdown
Expand Up @@ -118,7 +118,13 @@ A `hostname_configuration` block supports the following:

A `identity` block supports the following:

* `type` - (Required) Specifies the type of Managed Service Identity that should be configured on this API Management Service. At this time the only supported value is`SystemAssigned`.
~> **Note:** User Assigned Managed Identities are in Preview

* `type` - (Required) Specifies the type of Managed Service Identity that should be configured on this API Management Service. Possible values are `SystemAssigned`, `UserAssigned` or `SystemAssigned, UserAssigned` (to enable both).

* `identity_ids` - (Optional) A list of IDs for User Assigned Managed Identity resources to be assigned.
sirlatrom marked this conversation as resolved.
Show resolved Hide resolved

~> **NOTE:** This is required when `type` is set to `UserAssigned` or `SystemAssigned, UserAssigned`.

---

Expand Down