From 9e394848a4e9c3e11c0fddba77a349033e0eb003 Mon Sep 17 00:00:00 2001 From: kavya498 Date: Wed, 10 Mar 2021 13:56:22 +0530 Subject: [PATCH] Support: Cross Account iam_service_policy --- ibm/data_source_ibm_iam_service_policy.go | 60 ++++++++--- ibm/resource_ibm_iam_service_policy.go | 100 ++++++++++++------ .../docs/d/iam_service_policy.html.markdown | 5 +- .../docs/r/iam_service_policy.html.markdown | 34 +++++- 4 files changed, 143 insertions(+), 56 deletions(-) diff --git a/ibm/data_source_ibm_iam_service_policy.go b/ibm/data_source_ibm_iam_service_policy.go index 0ac1917749..a268647799 100644 --- a/ibm/data_source_ibm_iam_service_policy.go +++ b/ibm/data_source_ibm_iam_service_policy.go @@ -6,8 +6,9 @@ package ibm import ( "fmt" - "github.com/IBM-Cloud/bluemix-go/api/iampap/iampapv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/bluemix-go/api/iampap/iampapv1" ) // Data source to find all the policies for a serviceID @@ -17,9 +18,16 @@ func dataSourceIBMIAMServicePolicy() *schema.Resource { Schema: map[string]*schema.Schema{ "iam_service_id": { - Description: "UUID of ServiceID", - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"iam_service_id", "iam_id"}, + Description: "UUID of ServiceID", + }, + "iam_id": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"iam_service_id", "iam_id"}, + Description: "IAM ID of ServiceID", }, "sort": { Description: "Sort query for policies", @@ -88,19 +96,26 @@ func dataSourceIBMIAMServicePolicy() *schema.Resource { } func dataSourceIBMIAMServicePolicyRead(d *schema.ResourceData, meta interface{}) error { - iamClient, err := meta.(ClientSession).IAMAPI() - if err != nil { - return err - } - serviceIDUUID := d.Get("iam_service_id").(string) + var iamID string + if v, ok := d.GetOk("iam_service_id"); ok && v != nil { - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err + serviceIDUUID := v.(string) + iamClient, err := meta.(ClientSession).IAMAPI() + if err != nil { + return err + } + serviceID, err := iamClient.ServiceIds().Get(serviceIDUUID) + if err != nil { + return err + } + iamID = serviceID.IAMID + } + if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID = v.(string) } - serviceID, err := iamClient.ServiceIds().Get(serviceIDUUID) + userDetails, err := meta.(ClientSession).BluemixUserDetails() if err != nil { return err } @@ -113,7 +128,7 @@ func dataSourceIBMIAMServicePolicyRead(d *schema.ResourceData, meta interface{}) query := iampapv1.SearchParams{ AccountID: userDetails.userAccount, Type: iampapv1.AccessPolicyType, - IAMID: serviceID.IAMID, + IAMID: iamID, } if v, ok := d.GetOk("sort"); ok { @@ -133,13 +148,26 @@ func dataSourceIBMIAMServicePolicyRead(d *schema.ResourceData, meta interface{}) } resources := flattenPolicyResource(policy.Resources) p := map[string]interface{}{ - "id": fmt.Sprintf("%s/%s", serviceIDUUID, policy.ID), "roles": roles, "resources": resources, } + if v, ok := d.GetOk("iam_service_id"); ok && v != nil { + serviceIDUUID := v.(string) + p["id"] = fmt.Sprintf("%s/%s", serviceIDUUID, policy.ID) + } else if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID := v.(string) + p["id"] = fmt.Sprintf("%s/%s", iamID, policy.ID) + } servicePolicies = append(servicePolicies, p) } - d.SetId(serviceIDUUID) + + if v, ok := d.GetOk("iam_service_id"); ok && v != nil { + serviceIDUUID := v.(string) + d.SetId(serviceIDUUID) + } else if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID := v.(string) + d.SetId(iamID) + } d.Set("policies", servicePolicies) return nil } diff --git a/ibm/resource_ibm_iam_service_policy.go b/ibm/resource_ibm_iam_service_policy.go index f7f4657d25..ab2b91e513 100644 --- a/ibm/resource_ibm_iam_service_policy.go +++ b/ibm/resource_ibm_iam_service_policy.go @@ -5,6 +5,7 @@ package ibm import ( "fmt" + "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -24,12 +25,19 @@ func resourceIBMIAMServicePolicy() *schema.Resource { Schema: map[string]*schema.Schema{ "iam_service_id": { - Type: schema.TypeString, - Required: true, - Description: "UUID of ServiceID", - ForceNew: true, + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"iam_service_id", "iam_id"}, + Description: "UUID of ServiceID", + ForceNew: true, + }, + "iam_id": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"iam_service_id", "iam_id"}, + Description: "IAM ID of ServiceID", + ForceNew: true, }, - "roles": { Type: schema.TypeList, Required: true, @@ -115,11 +123,24 @@ func resourceIBMIAMServicePolicy() *schema.Resource { } func resourceIBMIAMServicePolicyCreate(d *schema.ResourceData, meta interface{}) error { - iamClient, err := meta.(ClientSession).IAMAPI() - if err != nil { - return err + + var iamID string + if v, ok := d.GetOk("iam_service_id"); ok && v != nil { + serviceIDUUID := v.(string) + + iamClient, err := meta.(ClientSession).IAMAPI() + if err != nil { + return err + } + serviceID, err := iamClient.ServiceIds().Get(serviceIDUUID) + if err != nil { + return err + } + iamID = serviceID.IAMID + } + if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID = v.(string) } - serviceIDUUID := d.Get("iam_service_id").(string) userDetails, err := meta.(ClientSession).BluemixUserDetails() if err != nil { @@ -132,17 +153,6 @@ func resourceIBMIAMServicePolicyCreate(d *schema.ResourceData, meta interface{}) if err != nil { return err } - - serviceID, err := iamClient.ServiceIds().Get(serviceIDUUID) - if err != nil { - return err - } - - iampapClient, err := meta.(ClientSession).IAMPAPAPI() - if err != nil { - return err - } - policy.Resources[0].SetAccountID(userDetails.userAccount) policy.Subjects = []iampapv1.Subject{ @@ -150,7 +160,7 @@ func resourceIBMIAMServicePolicyCreate(d *schema.ResourceData, meta interface{}) Attributes: []iampapv1.Attribute{ { Name: "iam_id", - Value: serviceID.IAMID, + Value: iamID, }, }, }, @@ -158,13 +168,22 @@ func resourceIBMIAMServicePolicyCreate(d *schema.ResourceData, meta interface{}) policy.Type = iampapv1.AccessPolicyType + iampapClient, err := meta.(ClientSession).IAMPAPAPI() + if err != nil { + return err + } servicePolicy, err := iampapClient.V1Policy().Create(policy) if err != nil { return fmt.Errorf("Error creating servicePolicy: %s", err) } - - d.SetId(fmt.Sprintf("%s/%s", serviceIDUUID, servicePolicy.ID)) + if v, ok := d.GetOk("iam_service_id"); ok && v != nil { + serviceIDUUID := v.(string) + d.SetId(fmt.Sprintf("%s/%s", serviceIDUUID, servicePolicy.ID)) + } else if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID := v.(string) + d.SetId(fmt.Sprintf("%s/%s", iamID, servicePolicy.ID)) + } return resourceIBMIAMServicePolicyRead(d, meta) } @@ -187,8 +206,12 @@ func resourceIBMIAMServicePolicyRead(d *schema.ResourceData, meta interface{}) e if err != nil { return fmt.Errorf("Error retrieving servicePolicy: %s", err) } + if strings.HasPrefix(serviceIDUUID, "iam-") { + d.Set("iam_id", serviceIDUUID) + } else { + d.Set("iam_service_id", serviceIDUUID) + } - d.Set("iam_service_id", serviceIDUUID) roles := make([]string, len(servicePolicy.Roles)) for i, role := range servicePolicy.Roles { roles[i] = role.Name @@ -212,27 +235,34 @@ func resourceIBMIAMServicePolicyUpdate(d *schema.ResourceData, meta interface{}) if d.HasChange("roles") || d.HasChange("resources") || d.HasChange("account_management") { - iamClient, err := meta.(ClientSession).IAMAPI() - if err != nil { - return err - } parts, err := idParts(d.Id()) if err != nil { return err } - serviceIDUUID := parts[0] servicePolicyID := parts[1] - userDetails, err := meta.(ClientSession).BluemixUserDetails() - if err != nil { - return err + var iamID string + if v, ok := d.GetOk("iam_service_id"); ok && v != nil { + serviceIDUUID := v.(string) + + iamClient, err := meta.(ClientSession).IAMAPI() + if err != nil { + return err + } + serviceID, err := iamClient.ServiceIds().Get(serviceIDUUID) + if err != nil { + return err + } + iamID = serviceID.IAMID + } + if v, ok := d.GetOk("iam_id"); ok && v != nil { + iamID = v.(string) } - serviceID, err := iamClient.ServiceIds().Get(serviceIDUUID) + userDetails, err := meta.(ClientSession).BluemixUserDetails() if err != nil { return err } - var policy iampapv1.Policy policy, err = generateAccountPolicyV2(d, meta) @@ -247,7 +277,7 @@ func resourceIBMIAMServicePolicyUpdate(d *schema.ResourceData, meta interface{}) Attributes: []iampapv1.Attribute{ { Name: "iam_id", - Value: serviceID.IAMID, + Value: iamID, }, }, }, diff --git a/website/docs/d/iam_service_policy.html.markdown b/website/docs/d/iam_service_policy.html.markdown index 569b7006c6..05ecae0bdc 100644 --- a/website/docs/d/iam_service_policy.html.markdown +++ b/website/docs/d/iam_service_policy.html.markdown @@ -34,7 +34,8 @@ data "ibm_iam_service_policy" "testacc_ds_service_policy" { The following arguments are supported: -* `iam_service_id` - (Required, string) The UUID of the serviceID. +* `iam_service_id` - (Optional, string) UUID of the serviceID. Exactly one of `iam_service_id`, `iam_id` is required. +* `iam_id` - (Optional, string) IAM ID of the serviceID. Exactly one of `iam_service_id`, `iam_id` is required. Can be used to get cross account service ID Policy. * `sort` - (Optional, string) Single field sort query for policies. ## Attribute Reference @@ -42,7 +43,7 @@ The following arguments are supported: The following attributes are exported: * `policies` - A nested block describing IAM Policies assigned to serviceID. Nested `policies` blocks have the following structure: - * `id` - The unique identifier of the IAM service policy.The id is composed of \/\ + * `id` - The unique identifier of the IAM service policy.The id is composed of \/\ if policy is created using . The id is composed of \/\ if policy is created using . * `roles` - Roles assigned to the policy. * `resources` - A nested block describing the resources in the policy. * `service` - Service name of the policy definition. diff --git a/website/docs/r/iam_service_policy.html.markdown b/website/docs/r/iam_service_policy.html.markdown index 93953be2ba..39700a91f7 100644 --- a/website/docs/r/iam_service_policy.html.markdown +++ b/website/docs/r/iam_service_policy.html.markdown @@ -140,13 +140,40 @@ resource "ibm_iam_service_policy" "policy" { } } +``` +### Cross account Service policy using iam_id + +```hcl +provider "ibm" { + alias = "accA" + ibmcloud_api_key = "Account A Api Key" +} +resource "ibm_iam_service_id" "serviceID" { + provider = ibm.accA + name = "test" +} + +provider "ibm" { + alias = "accB" + ibmcloud_api_key = "Account B Api Key" +} +resource "ibm_iam_service_policy" "policy" { + provider = ibm.accB + iam_id = ibm_iam_service_id.serviceID.iam_id + roles = ["Reader"] + resources { + service = "cloud-object-storage" + } +} + ``` ## Argument Reference The following arguments are supported: -* `iam_service_id` - (Required, Forces new resource, string) UUID of the serviceID. +* `iam_service_id` - (Optional, Forces new resource, string) UUID of the serviceID. Exactly one of `iam_service_id`, `iam_id` is required. +* `iam_id` - (Optional, Forces new resource, string) IAM ID of the serviceID. Exactly one of `iam_service_id`, `iam_id` is required. Can be used to assign cross account service ID Policy. * `roles` - (Required, list) comma separated list of roles. Valid roles are Writer, Reader, Manager, Administrator, Operator, Viewer, Editor. * `resources` - (Optional, list) A nested block describing the resource of this policy. Nested `resources` blocks have the following structure: @@ -167,15 +194,16 @@ Nested `resources` blocks have the following structure: The following attributes are exported: -* `id` - The unique identifier of the service policy. The id is composed of \/\ +* `id` - The unique identifier of the service policy. The id is composed of \/\ if policy is created using . The id is composed of \/\ if policy is created using . * `version` - Version of the service policy. ## Import -ibm_iam_service_policy can be imported using serviceID and service policy id, eg +ibm_iam_service_policy can be imported using serviceID and service policy id or iamID and service policy id, eg ``` $ terraform import ibm_iam_service_policy.example ServiceId-d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb +$ terraform import ibm_iam_service_policy.example iam-ServiceId-d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb ```