diff --git a/azurerm/internal/services/containers/kubernetes_cluster_pod_identity_resource.go b/azurerm/internal/services/containers/kubernetes_cluster_pod_identity_resource.go new file mode 100644 index 000000000000..b7d11e91d4ce --- /dev/null +++ b/azurerm/internal/services/containers/kubernetes_cluster_pod_identity_resource.go @@ -0,0 +1,351 @@ +package containers + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2021-03-01/containerservice" + "github.com/Azure/azure-sdk-for-go/services/msi/mgmt/2018-11-30/msi" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/containers/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/containers/validate" + msiParse "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/msi/parse" + msiValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/msi/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/pluginsdk" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceKubernetesClusterPodIdentity() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceKubernetesClusterPodIdentityCreateUpdate, + Read: resourceKubernetesClusterPodIdentityRead, + Update: resourceKubernetesClusterPodIdentityCreateUpdate, + Delete: resourceKubernetesClusterPodIdentityDelete, + + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.ClusterID(id) + return err + }), + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(30 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "cluster_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ClusterID, + }, + + "pod_identity": { + Type: pluginsdk.TypeSet, + Optional: true, + AtLeastOneOf: []string{"pod_identity", "exception"}, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "namespace": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "identity_id": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: msiValidate.UserAssignedIdentityID, + }, + }, + }, + }, + + "exception": { + Type: pluginsdk.TypeSet, + Optional: true, + AtLeastOneOf: []string{"pod_identity", "exception"}, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "namespace": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "pod_labels": { + Type: pluginsdk.TypeMap, + Required: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + }, + }, + }, + }, + } +} + +func resourceKubernetesClusterPodIdentityCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Containers.KubernetesClustersClient + userAssignedIdentitiesClient := meta.(*clients.Client).MSI.UserAssignedIdentitiesClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + log.Printf("[INFO] preparing arguments for Managed Kubernetes Cluster Pod Identity.") + + clusterId, err := parse.ClusterID(d.Get("cluster_id").(string)) + if err != nil { + return err + } + + existing, err := client.Get(ctx, clusterId.ResourceGroup, clusterId.ManagedClusterName) + if err != nil { + return fmt.Errorf("checking for presence of existing %s: %s", clusterId, err) + } + + if existing.ManagedClusterProperties == nil { + return fmt.Errorf("`ManagedClusterProperties` is nil for %s: %s", clusterId, err) + } + + if d.IsNewResource() { + if existing.ManagedClusterProperties.PodIdentityProfile != nil && + existing.ManagedClusterProperties.PodIdentityProfile.Enabled != nil && + *existing.ManagedClusterProperties.PodIdentityProfile.Enabled { + return tf.ImportAsExistsError("azurerm_kubernetes_cluster_pod_identity", clusterId.ID()) + } + } + + podIdentities, err := expandKubernetesPodIdentities(ctx, userAssignedIdentitiesClient, d.Get("pod_identity").(*pluginsdk.Set).List()) + if err != nil { + return err + } + existing.ManagedClusterProperties.PodIdentityProfile = &containerservice.ManagedClusterPodIdentityProfile{ + Enabled: utils.Bool(true), + UserAssignedIdentities: podIdentities, + UserAssignedIdentityExceptions: expandKubernetesPodIdentityExceptions(d.Get("exception").(*pluginsdk.Set).List()), + } + + if existing.NetworkProfile != nil && existing.NetworkProfile.NetworkPlugin == containerservice.NetworkPluginKubenet { + existing.ManagedClusterProperties.PodIdentityProfile.AllowNetworkPluginKubenet = utils.Bool(true) + } + + future, err := client.CreateOrUpdate(ctx, clusterId.ResourceGroup, clusterId.ManagedClusterName, existing) + if err != nil { + return fmt.Errorf("creating/updating Pod Identity within %s: %+v", clusterId, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for creation/updation of Pod Identity within %s: %+v", clusterId, err) + } + + d.SetId(clusterId.ID()) + + return resourceKubernetesClusterPodIdentityRead(d, meta) +} + +func resourceKubernetesClusterPodIdentityRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Containers.KubernetesClustersClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ClusterID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.ManagedClusterName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[DEBUG] Managed Kubernetes Cluster %q was not found in Resource Group %q - removing from state!", id.ManagedClusterName, id.ResourceGroup) + d.SetId("") + return nil + } + + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + if resp.ManagedClusterProperties == nil || + resp.ManagedClusterProperties.PodIdentityProfile == nil || + resp.ManagedClusterProperties.PodIdentityProfile.Enabled == nil || + !*resp.ManagedClusterProperties.PodIdentityProfile.Enabled { + log.Printf("[DEBUG] Pod Identity Managed Kubernetes Cluster %q was not found in Resource Group %q - removing from state!", id.ManagedClusterName, id.ResourceGroup) + d.SetId("") + return nil + } + + d.Set("cluster_id", resp.ID) + if err := d.Set("pod_identity", flattenKubernetesPodIdentities(resp.ManagedClusterProperties.PodIdentityProfile.UserAssignedIdentities)); err != nil { + return fmt.Errorf("setting `pod_identity`: %+v", err) + } + + if err := d.Set("exception", flattenKubernetesPodIdentityException(resp.ManagedClusterProperties.PodIdentityProfile.UserAssignedIdentityExceptions)); err != nil { + return fmt.Errorf("setting `exception`: %+v", err) + } + + return nil +} + +func resourceKubernetesClusterPodIdentityDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Containers.KubernetesClustersClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ClusterID(d.Id()) + if err != nil { + return err + } + + existing, err := client.Get(ctx, id.ResourceGroup, id.ManagedClusterName) + if err != nil { + return fmt.Errorf("checking for presence of existing %s: %s", id, err) + } + + if existing.ManagedClusterProperties == nil { + return fmt.Errorf("`ManagedClusterProperties` is nil for %s: %s", id, err) + } + + existing.ManagedClusterProperties.PodIdentityProfile = &containerservice.ManagedClusterPodIdentityProfile{ + Enabled: utils.Bool(false), + } + + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ManagedClusterName, existing) + if err != nil { + return fmt.Errorf("deleting Pod Identity for %s: %+v", id, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for deletion of Pod Identity for %s: %+v", id, err) + } + + return nil +} + +func expandKubernetesPodIdentities(ctx context.Context, userAssignedIdentitiesClient *msi.UserAssignedIdentitiesClient, input []interface{}) (*[]containerservice.ManagedClusterPodIdentity, error) { + if len(input) == 0 { + return nil, nil + } + result := make([]containerservice.ManagedClusterPodIdentity, 0) + for _, raw := range input { + v := raw.(map[string]interface{}) + + identityId, err := msiParse.UserAssignedIdentityID(v["identity_id"].(string)) + if err != nil { + return nil, err + } + resp, err := userAssignedIdentitiesClient.Get(ctx, identityId.ResourceGroup, identityId.Name) + if err != nil { + return nil, err + } + if resp.UserAssignedIdentityProperties == nil || + resp.UserAssignedIdentityProperties.ClientID == nil || + resp.UserAssignedIdentityProperties.PrincipalID == nil { + return nil, fmt.Errorf("clientId or principalId is nil for %s", identityId) + } + result = append(result, containerservice.ManagedClusterPodIdentity{ + Name: utils.String(v["name"].(string)), + Namespace: utils.String(v["namespace"].(string)), + Identity: &containerservice.UserAssignedIdentity{ + ResourceID: utils.String(identityId.ID()), + ClientID: utils.String(resp.UserAssignedIdentityProperties.ClientID.String()), + ObjectID: utils.String(resp.UserAssignedIdentityProperties.PrincipalID.String()), + }, + }) + } + return &result, nil +} + +func expandKubernetesPodIdentityExceptions(input []interface{}) *[]containerservice.ManagedClusterPodIdentityException { + if len(input) == 0 { + return nil + } + result := make([]containerservice.ManagedClusterPodIdentityException, 0) + for _, raw := range input { + v := raw.(map[string]interface{}) + + // issue https://github.com/hashicorp/terraform-plugin-sdk/issues/588 + // once it's resolved, we could remove the check empty logic + name := v["name"].(string) + namespace := v["namespace"].(string) + if name == "" || namespace == "" { + continue + } + + result = append(result, containerservice.ManagedClusterPodIdentityException{ + Name: utils.String(name), + Namespace: utils.String(namespace), + PodLabels: utils.ExpandMapStringPtrString(v["pod_labels"].(map[string]interface{})), + }) + } + return &result +} + +func flattenKubernetesPodIdentities(inputs *[]containerservice.ManagedClusterPodIdentity) []interface{} { + if inputs == nil { + return []interface{}{} + } + + result := make([]interface{}, 0) + for _, v := range *inputs { + var name, namespace, identityId string + if v.Name != nil { + name = *v.Name + } + if v.Namespace != nil { + namespace = *v.Namespace + } + if v.Identity != nil && v.Identity.ResourceID != nil { + identityId = *v.Identity.ResourceID + } + result = append(result, map[string]interface{}{ + "name": name, + "namespace": namespace, + "identity_id": identityId, + }) + } + return result +} + +func flattenKubernetesPodIdentityException(inputs *[]containerservice.ManagedClusterPodIdentityException) []interface{} { + if inputs == nil { + return []interface{}{} + } + result := make([]interface{}, 0) + for _, v := range *inputs { + var name, namespace string + if v.Name != nil { + name = *v.Name + } + if v.Namespace != nil { + namespace = *v.Namespace + } + + result = append(result, map[string]interface{}{ + "name": name, + "namespace": namespace, + "pod_labels": utils.FlattenMapStringPtrString(v.PodLabels), + }) + } + return result +} diff --git a/azurerm/internal/services/containers/kubernetes_cluster_pod_identity_resource_test.go b/azurerm/internal/services/containers/kubernetes_cluster_pod_identity_resource_test.go new file mode 100644 index 000000000000..bfce088fe55e --- /dev/null +++ b/azurerm/internal/services/containers/kubernetes_cluster_pod_identity_resource_test.go @@ -0,0 +1,271 @@ +package containers_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/containers/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type KubernetesClusterPodIdentityResource struct { +} + +func TestAccKubernetesClusterPodIdentity_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster_pod_identity", "test") + r := KubernetesClusterPodIdentityResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccKubernetesClusterPodIdentity_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster_pod_identity", "test") + r := KubernetesClusterPodIdentityResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccKubernetesClusterPodIdentity_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster_pod_identity", "test") + r := KubernetesClusterPodIdentityResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccKubernetesClusterPodIdentity_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster_pod_identity", "test") + r := KubernetesClusterPodIdentityResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.onlyPodException(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (t KubernetesClusterPodIdentityResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.ClusterID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.Containers.KubernetesClustersClient.Get(ctx, id.ResourceGroup, id.ManagedClusterName) + if err != nil { + return nil, fmt.Errorf("reading %s: %+v", id, err) + } + + if resp.ManagedClusterProperties == nil || + resp.ManagedClusterProperties.PodIdentityProfile == nil || + resp.ManagedClusterProperties.PodIdentityProfile.Enabled == nil || + !*resp.ManagedClusterProperties.PodIdentityProfile.Enabled { + return utils.Bool(false), nil + } + + return utils.Bool(true), nil +} + +func (r KubernetesClusterPodIdentityResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_kubernetes_cluster_pod_identity" "test" { + cluster_id = azurerm_kubernetes_cluster.test.id + + pod_identity { + name = "name1" + namespace = "ns1" + identity_id = azurerm_user_assigned_identity.test.id + } + + depends_on = [ + azurerm_role_assignment.test + ] +} +`, r.template(data)) +} + +func (r KubernetesClusterPodIdentityResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_kubernetes_cluster_pod_identity" "import" { + cluster_id = azurerm_kubernetes_cluster_pod_identity.test.cluster_id + + dynamic "pod_identity" { + for_each = azurerm_kubernetes_cluster_pod_identity.test.pod_identity + content { + name = pod_identity.value.name + namespace = pod_identity.value.namespace + identity_id = pod_identity.value.identity_id + } + } +} +`, r.basic(data)) +} + +func (r KubernetesClusterPodIdentityResource) onlyPodException(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_kubernetes_cluster_pod_identity" "test" { + cluster_id = azurerm_kubernetes_cluster.test.id + + exception { + name = "exception1" + namespace = "exception-ns1" + pod_labels = { + "env" : "test" + } + } + + depends_on = [ + azurerm_role_assignment.test + ] +} +`, r.template(data)) +} + +func (r KubernetesClusterPodIdentityResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_kubernetes_cluster_pod_identity" "test" { + cluster_id = azurerm_kubernetes_cluster.test.id + + pod_identity { + name = "name1" + namespace = "ns1" + identity_id = azurerm_user_assigned_identity.test.id + } + + exception { + name = "exception1" + namespace = "exception-ns1" + pod_labels = { + "env" : "test" + } + } + + depends_on = [ + azurerm_role_assignment.test + ] +} +`, r.template(data)) +} + +func (r KubernetesClusterPodIdentityResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-aks-%d" + location = "%s" +} + +resource "azurerm_kubernetes_cluster" "test" { + name = "acctestaks%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + dns_prefix = "acctestaks%d" + + linux_profile { + admin_username = "acctestuser%d" + + ssh_key { + key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld" + } + } + + default_node_pool { + name = "default" + node_count = 1 + vm_size = "Standard_DS2_v2" + } + + identity { + type = "SystemAssigned" + } + + network_profile { + network_plugin = "azure" + load_balancer_sku = "standard" + } +} + +resource "azurerm_user_assigned_identity" "test" { + name = "acctestRG-aks-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location +} + +resource "azurerm_role_assignment" "test" { + scope = azurerm_user_assigned_identity.test.id + role_definition_name = "Managed Identity Operator" + principal_id = azurerm_kubernetes_cluster.test.identity.0.principal_id +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} diff --git a/azurerm/internal/services/containers/registration.go b/azurerm/internal/services/containers/registration.go index 857f1a0b7e1c..460258a0ce59 100644 --- a/azurerm/internal/services/containers/registration.go +++ b/azurerm/internal/services/containers/registration.go @@ -33,12 +33,13 @@ func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { // SupportedResources returns the supported Resources supported by this Service func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { return map[string]*pluginsdk.Resource{ - "azurerm_container_group": resourceContainerGroup(), - "azurerm_container_registry_webhook": resourceContainerRegistryWebhook(), - "azurerm_container_registry": resourceContainerRegistry(), - "azurerm_container_registry_token": resourceContainerRegistryToken(), - "azurerm_container_registry_scope_map": resourceContainerRegistryScopeMap(), - "azurerm_kubernetes_cluster": resourceKubernetesCluster(), - "azurerm_kubernetes_cluster_node_pool": resourceKubernetesClusterNodePool(), + "azurerm_container_group": resourceContainerGroup(), + "azurerm_container_registry_webhook": resourceContainerRegistryWebhook(), + "azurerm_container_registry": resourceContainerRegistry(), + "azurerm_container_registry_token": resourceContainerRegistryToken(), + "azurerm_container_registry_scope_map": resourceContainerRegistryScopeMap(), + "azurerm_kubernetes_cluster": resourceKubernetesCluster(), + "azurerm_kubernetes_cluster_node_pool": resourceKubernetesClusterNodePool(), + "azurerm_kubernetes_cluster_pod_identity": resourceKubernetesClusterPodIdentity(), } } diff --git a/website/docs/r/kubernetes_cluster_pod_identity.html.markdown b/website/docs/r/kubernetes_cluster_pod_identity.html.markdown new file mode 100644 index 000000000000..cc988893bb35 --- /dev/null +++ b/website/docs/r/kubernetes_cluster_pod_identity.html.markdown @@ -0,0 +1,123 @@ +--- +subcategory: "Container" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_kubernetes_cluster_pod_identity" +description: |- + Manages the Pod Identities within an Azure Kubernetes Cluster. +--- + +# azurerm_kubernetes_cluster_pod_identity + +Manages the Pod Identities within an Azure Kubernetes Cluster. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +resource "azurerm_kubernetes_cluster" "example" { + name = "example-aks1" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + dns_prefix = "exampleaks1" + + linux_profile { + admin_username = "acctestuser1" + + ssh_key { + key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld" + } + } + + default_node_pool { + name = "default" + node_count = 1 + vm_size = "Standard_D2_v2" + } + + identity { + type = "SystemAssigned" + } + + network_profile { + network_plugin = "azure" + load_balancer_sku = "standard" + } +} + +resource "azurerm_user_assigned_identity" "example" { + name = "example-uai" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location +} + +resource "azurerm_role_assignment" "example" { + scope = azurerm_user_assigned_identity.example.id + role_definition_name = "Managed Identity Operator" + principal_id = azurerm_kubernetes_cluster.example.identity.0.principal_id +} + +resource "azurerm_kubernetes_cluster_pod_identity" "example" { + cluster_id = azurerm_kubernetes_cluster.example.id + + pod_identity { + name = "name" + namespace = "ns" + identity_id = azurerm_user_assigned_identity.example.id + } + + depends_on = [ + azurerm_role_assignment.example + ] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `cluster_id` - (Required) The ID of the Managed Kubernetes Cluster in which to create the Pod Identity. Changing this forces a new resource to be created. + +* `pod_identity` - (Optional) One or more `pod_identity` blocks as defined below. At least one of `pod_identity` and `exception` should be specified. + +* `exception` - (Optional) One or more `exception` blocks as defined below. At least one of `pod_identity` and `exception` should be specified. + +--- + +A `pod_identity` block supports the following: + +* `name` - (Required) The name of the Pod Identity. + +* `namespace` - (Required) The namespace where the Pod Identity should be created. + +* `identity_id` - (Required) The ID of the user assigned identity. + +--- + +An `exception` block supports the following: + +* `name` - (Required) The name of the Pod Identity Exception. + +* `namespace` - (Required) The namespace where the Pod Identity Exception should be created. + +* `pod_labels` - (Required) A map of Pod labels, the Pod Identity Exception will take effect only if Pod labels match. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Kubernetes Cluster Pod Identity. +* `update` - (Defaults to 30 minutes) Used when updating the Kubernetes Cluster Pod Identity. +* `read` - (Defaults to 5 minutes) Used when retrieving the Kubernetes Cluster Pod Identity. +* `delete` - (Defaults to 30 minutes) Used when deleting the Kubernetes Cluster Pod Identity. + +## Import + +Kubernetes Clusters Pod Identity can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_kubernetes_cluster_pod_identity.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.ContainerService/managedClusters/cluster1 +```