Skip to content

Commit f399dc9

Browse files
authored
Merge pull request #221 from philips-software/feature/220
IAM: Add IAM Role Sharing Policy resource. Refs #220
2 parents 91f521a + 5fa371e commit f399dc9

File tree

13 files changed

+672
-21
lines changed

13 files changed

+672
-21
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*.exe
77
b.sh
88
.swp
9+
.*.run
910
.DS_Store
1011
terraform-provider-hsdp
1112
build/
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
subcategory: "Identity and Access Management (IAM)"
3+
---
4+
5+
# hsdp_iam_role_sharing_policies
6+
7+
Lists defined IAM Role Sharing Policies
8+
9+
## Example Usage
10+
11+
```hcl
12+
data "hsdp_iam_role_sharing_policies" "all" {
13+
role_id = var.role_id
14+
}
15+
```
16+
17+
```hcl
18+
output "policy_ids" {
19+
value = data.hsdp_iam_role_sharing_policies.all.ids
20+
}
21+
```
22+
23+
## Argument Reference
24+
25+
The following arguments are supported:
26+
27+
* `role_id` - (Required) The role ID to search for policies
28+
* `sharing_policy` - (Optional) Only list results with this policy sharing
29+
* `target_organization_id` - (Optional) Only list policies targetting the given organization
30+
31+
## Attributes Reference
32+
33+
The following attributes are exported:
34+
35+
* `ids` - The IDS of the sharing policies
36+
* `role_names` - The role names
37+
* `sharing_policies` - The sharing policies
38+
* `target_organization_ids` - The target organization IDs
39+
* `source_organization_ids` - The source organization IDs
40+
* `purposes` - The purposes
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
subcategory: "Identity and Access Management (IAM)"
3+
---
4+
5+
# hsdp_iam_role_sharing_policy
6+
7+
Provides a resource for managing HSDP IAM Role Sharing Policies, introduced in the
8+
March 2022 release.
9+
10+
A principal (user / identity) with any of the following permissions can create/update the policy:
11+
12+
* `HSDP_IAM_ROLE_SHARE.WRITE`
13+
* `HSDP_IAM_ORGANIZATION.MGMT`
14+
15+
!> Changing any permissions assigned to a shared role impacts the application behavior across organizations and sometimes may result in application downtime.
16+
Applying a restrictive sharing policy to an organization automatically and recursively removes any existing assignments from all its children - unless the child organization has an overriding policy to retain the assignments. Removal of assignments are permanent and requires re-assignments by the organization administrators
17+
18+
## Example Usage
19+
20+
The following example creates a role sharing policy
21+
22+
```hcl
23+
# Create the role
24+
resource "hsdp_iam_role" "shared" {
25+
name = "SOME Role"
26+
description = "A role we want to share across ORGs"
27+
28+
permissions = [
29+
"PATIENT.READ",
30+
"PRACTITIONER.READ",
31+
]
32+
33+
managing_organization = hsdp_iam_org.my_org.id
34+
}
35+
36+
# Share the role
37+
resource "hsdp_iam_role_sharing_policy" "policy" {
38+
role_id = hsdp_iam_role.shared.id
39+
sharing_policy = "AllowChildren"
40+
purpose = "Share SOME role with another organization"
41+
42+
target_organization_id = hsdp_iam_org.another_org.id
43+
}
44+
```
45+
46+
## Argument Reference
47+
48+
The following arguments are supported:
49+
50+
* `role_id` - (Required) The ID of the role to share
51+
* `sharing_policy` - (Required) The policy to use
52+
Sharing of a role with a tenant organization can be in one of the following modes:
53+
* Restricted: - The assignment role to group operation shall check and allow assignment to the groups present in the target organizations. Any assignment operation - both upward and downward organization
54+
hierarchy - shall fail the API.
55+
* AllowChildren: - The assignment role to group operations shall check to restrict the assignment to any group in the target or its children organization. Any assignment operation in the parent organization hierarchy shall fail the API.
56+
* Denied: - The tenant organization cannot make use of this role. Any attempt to assign the role shall fail the API.
57+
* `target_organization_id` - (Required) The target organization UUID to apply this policy for. This can either be a root IAM Org or a subOrg in an existing hierarchy
58+
* `purpose` - (Optional) The purpose of this role sharing policy mapping
59+
60+
## Attributes Reference
61+
62+
In addition to all arguments above, the following attributes are exported:
63+
64+
* `id` - The GUID of the role sharing policy (also known as `internalId` at the API level)
65+
* `source_organization_id` - The source organization ID
66+
* `role_name` - The role name
67+
68+
## Import
69+
70+
An existing role sharing policy can be imported using `terraform import hsdp_iam_role_sharing_policy`, e.g.
71+
72+
```shell
73+
> terraform import hsdp_iam_role_sharing_policy.mypolicy a-guid
74+
```

internal/provider/provider.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"github.com/philips-software/terraform-provider-hsdp/internal/services/iam"
2828
"github.com/philips-software/terraform-provider-hsdp/internal/services/iam/client"
2929
"github.com/philips-software/terraform-provider-hsdp/internal/services/iam/group"
30+
"github.com/philips-software/terraform-provider-hsdp/internal/services/iam/role_sharing_policy"
3031
"github.com/philips-software/terraform-provider-hsdp/internal/services/iam/service"
3132
"github.com/philips-software/terraform-provider-hsdp/internal/services/metrics"
3233
"github.com/philips-software/terraform-provider-hsdp/internal/services/notification"
@@ -297,6 +298,7 @@ func Provider(build string) *schema.Provider {
297298
"hsdp_iam_group_membership": iam.ResourceIAMGroupMembership(),
298299
"hsdp_dicom_notification": dicom.ResourceDICOMNotification(),
299300
"hsdp_cdr_practitioner": practitioner.ResourceCDRPractitioner(),
301+
"hsdp_iam_role_sharing_policy": role_sharing_policy.ResourceRoleSharingPolicy(),
300302
},
301303
DataSourcesMap: map[string]*schema.Resource{
302304
"hsdp_iam_introspect": iam.DataSourceIAMIntrospect(),
@@ -368,6 +370,7 @@ func Provider(build string) *schema.Provider {
368370
"hsdp_iam_permission": iam.DataSourceIAMPermission(),
369371
"hsdp_cdr_practitioner": practitioner.DataSourceCDRPractitioner(),
370372
"hsdp_cdr_org": org.DataSourceCDROrg(),
373+
"hsdp_iam_role_sharing_policies": iam.DataSourceIAMRoleSharingPolicies(),
371374
},
372375
ConfigureContextFunc: providerConfigure(build),
373376
}

internal/services/cdr/org/r4.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func r4Create(ctx context.Context, c *config.Config, client *cdr.Client, d *sche
5252
return nil, err
5353
}
5454
return resp.Response, err
55-
})
55+
}, append(tools.StandardRetryOnCodes, http.StatusNotFound)...) // CDR weirdness
5656

5757
if err != nil {
5858
return diag.FromErr(err)

internal/services/cdr/org/stu3.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func stu3Read(ctx context.Context, client *cdr.Client, d *schema.ResourceData) d
7979
return nil, err
8080
}
8181
return resp.Response, err
82-
})
82+
}, append(tools.StandardRetryOnCodes, http.StatusNotFound)...) // CDR weirdness
8383
if err != nil {
8484
if resp != nil && (resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusGone) {
8585
d.SetId("")

internal/services/cdr/practitioner/stu3.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func stu3Create(ctx context.Context, c *config.Config, client *cdr.Client, d *sc
7575
return diag.FromErr(err)
7676
}
7777

78-
err = tools.TryHTTPCall(ctx, 5, func() (*http.Response, error) {
78+
err = tools.TryHTTPCall(ctx, 8, func() (*http.Response, error) {
7979
var resp *cdr.Response
8080
var err error
8181

@@ -101,7 +101,7 @@ func stu3Read(ctx context.Context, _ *config.Config, client *cdr.Client, d *sche
101101
var resp *cdr.Response
102102
var contained *resources_go_proto.ContainedResource
103103

104-
err := tools.TryHTTPCall(ctx, 5, func() (*http.Response, error) {
104+
err := tools.TryHTTPCall(ctx, 8, func() (*http.Response, error) {
105105
var err error
106106

107107
contained, resp, err = client.OperationsSTU3.Get("Practitioner/" + d.Id())
@@ -112,7 +112,7 @@ func stu3Read(ctx context.Context, _ *config.Config, client *cdr.Client, d *sche
112112
return nil, fmt.Errorf("OperationsSTU3.Get: response is nil")
113113
}
114114
return resp.Response, err
115-
})
115+
}, append(tools.StandardRetryOnCodes, http.StatusNotFound)...) // CDR weirdness
116116
if err != nil {
117117
if resp != nil && (resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusGone) {
118118
d.SetId("")
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package iam
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8+
"github.com/philips-software/go-hsdp-api/iam"
9+
"github.com/philips-software/terraform-provider-hsdp/internal/config"
10+
)
11+
12+
func DataSourceIAMRoleSharingPolicies() *schema.Resource {
13+
return &schema.Resource{
14+
ReadContext: dataSourceIAMRoleSharingPoliciesRead,
15+
Schema: map[string]*schema.Schema{
16+
"role_id": {
17+
Type: schema.TypeString,
18+
Required: true,
19+
},
20+
"target_organization_id": {
21+
Type: schema.TypeString,
22+
Optional: true,
23+
},
24+
"sharing_policy": {
25+
Type: schema.TypeString,
26+
Optional: true,
27+
},
28+
"ids": {
29+
Type: schema.TypeList,
30+
Computed: true,
31+
Elem: &schema.Schema{Type: schema.TypeString},
32+
},
33+
"sharing_policies": {
34+
Type: schema.TypeList,
35+
Computed: true,
36+
Elem: &schema.Schema{Type: schema.TypeString},
37+
},
38+
"target_organization_ids": {
39+
Type: schema.TypeList,
40+
Computed: true,
41+
Elem: &schema.Schema{Type: schema.TypeString},
42+
},
43+
"source_organization_ids": {
44+
Type: schema.TypeList,
45+
Computed: true,
46+
Elem: &schema.Schema{Type: schema.TypeString},
47+
},
48+
"role_names": {
49+
Type: schema.TypeList,
50+
Computed: true,
51+
Elem: &schema.Schema{Type: schema.TypeString},
52+
},
53+
"purposes": {
54+
Type: schema.TypeList,
55+
Computed: true,
56+
Elem: &schema.Schema{Type: schema.TypeString},
57+
},
58+
},
59+
}
60+
61+
}
62+
63+
func dataSourceIAMRoleSharingPoliciesRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
64+
c := meta.(*config.Config)
65+
66+
var diags diag.Diagnostics
67+
68+
client, err := c.IAMClient()
69+
if err != nil {
70+
return diag.FromErr(err)
71+
}
72+
73+
roleID := d.Get("role_id").(string)
74+
sharingPolicy := d.Get("sharing_policy").(string)
75+
targetOrganizationID := d.Get("target_organization_id").(string)
76+
77+
listOptions := &iam.ListSharingPoliciesOptions{}
78+
if sharingPolicy != "" {
79+
listOptions.SharingPolicy = &sharingPolicy
80+
}
81+
if targetOrganizationID != "" {
82+
listOptions.TargetOrganizationID = &targetOrganizationID
83+
}
84+
85+
policies, _, err := client.Roles.ListSharingPolicies(iam.Role{ID: roleID}, listOptions)
86+
if err != nil {
87+
return diag.FromErr(err)
88+
}
89+
90+
var ids []string
91+
var sharingPolicies []string
92+
var targetOrganizationIDs []string
93+
var sourceOrganizationIDs []string
94+
var roleNames []string
95+
var purposes []string
96+
97+
for _, policy := range *policies {
98+
ids = append(ids, policy.InternalID)
99+
sharingPolicies = append(sharingPolicies, policy.SharingPolicy)
100+
targetOrganizationIDs = append(targetOrganizationIDs, policy.TargetOrganizationID)
101+
sourceOrganizationIDs = append(sourceOrganizationIDs, policy.TargetOrganizationID)
102+
roleNames = append(roleNames, policy.RoleName)
103+
purposes = append(purposes, policy.Purpose)
104+
}
105+
_ = d.Set("ids", ids)
106+
_ = d.Set("sharing_policies", sharingPolicies)
107+
_ = d.Set("target_organization_ids", targetOrganizationIDs)
108+
_ = d.Set("source_organization_ids", sourceOrganizationIDs)
109+
_ = d.Set("role_names", roleNames)
110+
_ = d.Set("purposes", purposes)
111+
112+
d.SetId(roleID + targetOrganizationID)
113+
return diags
114+
}

0 commit comments

Comments
 (0)