Skip to content

Commit

Permalink
IAM Policy Assignment: S2S Policy Assignments ET and AG (IBM-Cloud#5624)
Browse files Browse the repository at this point in the history
* IAM Policy Assignment: S2S Policy Assignments ET and AG

Signed-off-by: Alluri-Varma <alluri.varma@ibm.com>

* resolving CVE's for EPAP

* IAM Policy Assignment: S2S Policy Assignments ET and AG

* IAM Policy Assignment: S2S Policy Assignments ET and AG

* IAM Policy Assignment: S2S Policy Assignments ET and AG

* IAM Policy Assignment: S2S Policy Assignments ET and AG

* IAM Policy Assignment: S2S Policy Assignments ET and AG

* IAM Policy Assignment: S2S Policy Assignments ET and AG

* IAM Policy Assignment: S2S Policy Assignments ET and AG

---------

Signed-off-by: Alluri-Varma <alluri.varma@ibm.com>
Co-authored-by: Alluri-Varma <alluri.varma@ibm.com>
  • Loading branch information
siddhuvarma1997 and siddhualluri authored Sep 18, 2024
1 parent 54c8962 commit 2aa2176
Show file tree
Hide file tree
Showing 6 changed files with 300 additions and 17 deletions.
7 changes: 7 additions & 0 deletions ibm/acctest/acctest.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ var (
// For IAM Access Management
var (
TargetAccountId string
TargetEnterpriseId string
)

// For Partner Center Sell
Expand Down Expand Up @@ -1870,6 +1871,12 @@ func init() {
fmt.Println("[INFO] Set the environment variable IBM_POLICY_ASSIGNMENT_TARGET_ACCOUNT_ID for testing ibm_iam_policy_assignment resource else tests will fail if this is not set correctly")
}


TargetEnterpriseId = os.Getenv("IBM_POLICY_ASSIGNMENT_TARGET_ENTERPRISE_ID")
if TargetEnterpriseId == "" {
fmt.Println("[INFO] Set the environment variable IBM_POLICY_ASSIGNMENT_TARGET_ENTERPRISE_ID for testing ibm_iam_policy_assignment resource else tests will fail if this is not set correctly")
}

PcsRegistrationAccountId = os.Getenv("PCS_REGISTRATION_ACCOUNT_ID")
if PcsRegistrationAccountId == "" {
fmt.Println("[WARN] Set the environment variable PCS_REGISTRATION_ACCOUNT_ID for testing iam_onboarding resource else tests will fail if this is not set correctly")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,6 @@ resource "ibm_iam_policy_assignment" "policy_assignment" {
id = "%s"
}
options {
root {
requester_id = "orchestrator"
assignment_id = "test"
}
}
templates{
id = ibm_iam_policy_template.policy_s2s_template.template_id
version = ibm_iam_policy_template.policy_s2s_template.version
Expand Down
194 changes: 186 additions & 8 deletions ibm/service/iampolicy/resource_ibm_iam_policy_assignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import (
"context"
"fmt"
"log"
"strings"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns"
Expand All @@ -17,14 +20,24 @@ import (
"github.com/IBM/platform-services-go-sdk/iampolicymanagementv1"
)

const (
InProgress = "in_progress"
complete = "complete"
failed = "failed"
)

func ResourceIBMIAMPolicyAssignment() *schema.Resource {
return &schema.Resource{
CreateContext: resourceIBMPolicyAssignmentCreate,
ReadContext: resourceIBMPolicyAssignmentRead,
UpdateContext: resourceIBMPolicyAssignmentUpdate,
DeleteContext: resourceIBMPolicyAssignmentDelete,
Importer: &schema.ResourceImporter{},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(30 * time.Minute),
Update: schema.DefaultTimeout(30 * time.Minute),
Delete: schema.DefaultTimeout(30 * time.Minute),
},
Schema: map[string]*schema.Schema{
"version": {
Type: schema.TypeString,
Expand Down Expand Up @@ -251,9 +264,9 @@ func resourceIBMPolicyAssignmentCreate(context context.Context, d *schema.Resour
createPolicyTemplateAssignmentOptions := &iampolicymanagementv1.CreatePolicyTemplateAssignmentOptions{}

createPolicyTemplateAssignmentOptions.SetVersion(d.Get("version").(string))
targetModel, err := ResourceIBMPolicyAssignmentMapToAssignmentTargetDetails(d.Get("target").(map[string]interface{}))
if err != nil {
return diag.FromErr(err)
targetModel, diags := GetTargetModel(d)
if diags.HasError() {
return diags
}
createPolicyTemplateAssignmentOptions.SetTarget(targetModel)
var templates []iampolicymanagementv1.AssignmentTemplateDetails
Expand All @@ -278,6 +291,14 @@ func resourceIBMPolicyAssignmentCreate(context context.Context, d *schema.Resour

d.SetId(*policyAssignmentV1Collection.Assignments[0].ID)

if targetModel.Type != nil && (*targetModel.Type == "Account") {
log.Printf("[DEBUG] Skipping waitForAssignment for target type: %s", *targetModel.Type)
} else {
_, err = waitForAssignment(d.Timeout(schema.TimeoutCreate), meta, d, isAccessPolicyAssigned)
if err != nil {
return diag.FromErr(fmt.Errorf("error assigning: %s", err))
}
}
return resourceIBMPolicyAssignmentRead(context, d, meta)
}

Expand Down Expand Up @@ -385,6 +406,12 @@ func resourceIBMPolicyAssignmentUpdate(context context.Context, d *schema.Resour

updatePolicyAssignmentOptions.SetAssignmentID(d.Id())

targetModel, diags := GetTargetModel(d)

if diags.HasError() {
return diags
}

hasChange := false

if d.HasChange("template_version") {
Expand Down Expand Up @@ -416,6 +443,16 @@ func resourceIBMPolicyAssignmentUpdate(context context.Context, d *schema.Resour
log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage())
return tfErr.GetDiag()
}

if targetModel.Type != nil && (*targetModel.Type == "Account") {
log.Printf("[DEBUG] Skipping waitForAssignment for target type: %s", *targetModel.Type)
} else {
_, err = waitForAssignment(d.Timeout(schema.TimeoutUpdate), meta, d, isAccessPolicyAssigned)
if err != nil {
return diag.FromErr(fmt.Errorf("error assigning: %s", err))
}
}

}

return resourceIBMPolicyAssignmentRead(context, d, meta)
Expand All @@ -433,11 +470,34 @@ func resourceIBMPolicyAssignmentDelete(context context.Context, d *schema.Resour

deletePolicyAssignmentOptions.SetAssignmentID(d.Id())

_, err = iamPolicyManagementClient.DeletePolicyAssignmentWithContext(context, deletePolicyAssignmentOptions)

response, err := iamPolicyManagementClient.DeletePolicyAssignmentWithContext(context, deletePolicyAssignmentOptions)
if err != nil {
tfErr := flex.TerraformErrorf(err, fmt.Sprintf("DeletePolicyAssignmentWithContext failed: %s", err.Error()), "ibm_policy_assignment", "delete")
log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage())
return tfErr.GetDiag()
if response != nil && response.StatusCode == 404 {
return nil
} else {
tfErr := flex.TerraformErrorf(err, fmt.Sprintf("DeletePolicyAssignmentWithContext failed: %s", err.Error()), "ibm_policy_assignment", "delete")
log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage())
return tfErr.GetDiag()
}
}

targetModel, diags := GetTargetModel(d)
if diags.HasError() {
return diags
}

if targetModel.Type != nil && (*targetModel.Type == "Account") {
log.Printf("[DEBUG] Skipping waitForAssignment for target type: %s", *targetModel.Type)
} else {
_, err = waitForAssignment(d.Timeout(schema.TimeoutDelete), meta, d, isAccessPolicyAssignedDeleted)
if err != nil {
if strings.Contains(err.Error(), "not found") {
return nil
} else {
return diag.FromErr(fmt.Errorf("error assigning: %s", err))
}
}
}

d.SetId("")
Expand Down Expand Up @@ -477,3 +537,121 @@ func ResourceIBMPolicyAssignmentAssignmentTemplateDetailsToMap(model *iampolicym
}
return modelMap, nil
}

func GetTargetModel(d *schema.ResourceData) (*iampolicymanagementv1.AssignmentTargetDetails, diag.Diagnostics) {
targetModel, err := ResourceIBMPolicyAssignmentMapToAssignmentTargetDetails(d.Get("target").(map[string]interface{}))

if err != nil {
return targetModel, diag.FromErr(err)
}

return targetModel, nil
}


func waitForAssignment(timeout time.Duration, meta interface{}, d *schema.ResourceData, refreshFn func(string, interface{}) resource.StateRefreshFunc) (interface{}, error) {

stateConf := &resource.StateChangeConf{
Pending: []string{InProgress},
Target: []string{complete},
Refresh: refreshFn(d.Id(), meta),
Delay: 30 * time.Second,
PollInterval: time.Minute,
Timeout: timeout,
}

return stateConf.WaitForState()
}

func isAccessPolicyAssigned(id string, meta interface{}) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API()
if err != nil {
return nil, failed, err
}

getAssignmentPolicyOptions := &iampolicymanagementv1.GetPolicyAssignmentOptions{
AssignmentID: core.StringPtr(id),
Version: core.StringPtr("1.0"),
}

getAssignmentPolicyOptions.SetAssignmentID(id)

assignmentDetails, response, err := iamPolicyManagementClient.GetPolicyAssignment(getAssignmentPolicyOptions)

if err != nil {
if response != nil && response.StatusCode == 404 {
return nil, failed, err
}
return nil, failed, err
}

assignment, ok := assignmentDetails.(*iampolicymanagementv1.GetPolicyAssignmentResponse)

if !ok {
return nil, failed, fmt.Errorf("[ERROR] Type assertion failed for assignment details : %s", id)
}

if assignment != nil {
if *assignment.Status == "accepted" || *assignment.Status == "in_progress" {
log.Printf("Assignment still in progress\n")
return assignment, InProgress, nil
}

if *assignment.Status == "succeeded" {
return assignment, complete, nil
}

if *assignment.Status == "failed" {
return assignment, failed, fmt.Errorf("[ERROR] The assignment %s did not complete successfully and has a 'failed' status. Please check assignment resource for detailed errors: %s\n", id, response)
}
}

return assignment, failed, fmt.Errorf("[ERROR] Unexpected status reached for assignment %s.: %s\n", id, response)
}
}

func isAccessPolicyAssignedDeleted(id string, meta interface{}) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API()
if err != nil {
return nil, failed, err
}

getAssignmentPolicyOptions := &iampolicymanagementv1.GetPolicyAssignmentOptions{
AssignmentID: core.StringPtr(id),
Version: core.StringPtr("1.0"),
}

getAssignmentPolicyOptions.SetAssignmentID(id)

assignmentDetails, response, err := iamPolicyManagementClient.GetPolicyAssignment(getAssignmentPolicyOptions)

if err != nil {
if response != nil && response.StatusCode == 404 {
return nil, failed, err
}
return nil, failed, err
}

assignment, ok := assignmentDetails.(*iampolicymanagementv1.GetPolicyAssignmentResponse)

if !ok {
return nil, failed, fmt.Errorf("[ERROR] Type assertion failed for assignment details : %s", id)
}


if assignment != nil {
if *assignment.Status == "accepted" || *assignment.Status == "in_progress" {
log.Printf("Assignment still in progress\n")
return assignment, InProgress, nil
}

if *assignment.Status == "failed" {
return assignment, failed, fmt.Errorf("[ERROR] The assignment %s did not complete successfully and has a 'failed' status. Please check assignment resource for detailed errors: %s\n", id, response)
}
}

return assignment, failed, fmt.Errorf("[ERROR] Unexpected status reached for assignment %s.: %s\n", id, response)
}
}
64 changes: 62 additions & 2 deletions ibm/service/iampolicy/resource_ibm_iam_policy_assignment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func TestAccIBMPolicyAssignmentBasic(t *testing.T) {
})
}


func TestAccIBMPolicyAssignmentS2SBasic(t *testing.T) {
var conf iampolicymanagementv1.GetPolicyAssignmentResponse
var name string = fmt.Sprintf("TerraformTemplateTest%d", acctest.RandIntRange(10, 100))
Expand All @@ -70,6 +71,27 @@ func TestAccIBMPolicyAssignmentS2SBasic(t *testing.T) {
})
}

func TestAccIBMPolicyAssignmentEnterprise(t *testing.T) {
var conf iampolicymanagementv1.GetPolicyAssignmentResponse
var name string = fmt.Sprintf("TerraformTemplateTest%d", acctest.RandIntRange(10, 100))
resource.Test(t, resource.TestCase{
PreCheck: func() { acc.TestAccPreCheck(t) },
Providers: acc.TestAccProviders,
CheckDestroy: testAccCheckIBMPolicyAssignmentDestroy,
Steps: []resource.TestStep{
{
Config: testAccCheckIBMPolicyAssignmentConfigEnterprise(name, acc.TargetEnterpriseId),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckIBMPolicyAssignmentExists("ibm_iam_policy_assignment.policy_assignment", conf),
resource.TestCheckResourceAttr("ibm_iam_policy_template.policy_s2s_template", "name", name),
resource.TestCheckResourceAttr("ibm_iam_policy_template.policy_s2s_template", "policy.0.resource.0.attributes.0.value", resourceServiceName),
resource.TestCheckResourceAttr("ibm_iam_policy_template.policy_s2s_template", "policy.0.subject.0.attributes.0.value", "compliance"),
),
},
},
})
}

func testAccCheckIBMPolicyAssignmentConfigBasic(name string, targetId string) string {
return fmt.Sprintf(`
resource "ibm_iam_policy_template" "policy_s2s_template" {
Expand Down Expand Up @@ -215,8 +237,46 @@ func testAccCheckIBMPolicyAssignmentConfigUpdate(name string, targetId string) s
}
templates{
id = ibm_iam_policy_template.policy_s2stemplate.template_id
version = ibm_iam_policy_template.policy_s2stemplate.version
id = ibm_iam_policy_template_version.template_version.template_id
version = ibm_iam_policy_template_version.template_version.version
}
}`, name, targetId)
}

func testAccCheckIBMPolicyAssignmentConfigEnterprise(name string, targetId string) string {
return fmt.Sprintf(`
resource "ibm_iam_policy_template" "policy_s2s_template" {
name = "%s"
policy {
type = "authorization"
description = "description"
resource {
attributes {
key = "serviceName"
operator = "stringEquals"
value = "kms"
}
}
subject {
attributes {
key = "serviceName"
operator = "stringEquals"
value = "compliance"
}
}
roles = ["Reader"]
}
committed=true
}
resource "ibm_iam_policy_assignment" "policy_assignment" {
version = "1.0"
target ={
type = "Enterprise"
id = "%s"
}
templates{
id = ibm_iam_policy_template.policy_s2s_template.template_id
version = ibm_iam_policy_template.policy_s2s_template.version
}
}`, name, targetId)
}
Expand Down
8 changes: 8 additions & 0 deletions website/docs/d/iam_policy_assignment.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ data "ibm_iam_policy_assignments" "policy_assignment" {

## Argument Reference

## Timeouts section

The resource includes default timeout settings for the following operations:

* `create` - (Timeout) Defaults to 30 minutes.
* `update` - (Timeout) Defaults to 30 minutes.
* `delete` - (Timeout) Defaults to 30 minutes.


## Attribute Reference

Expand Down
Loading

0 comments on commit 2aa2176

Please sign in to comment.