Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ab11e7a

Browse files
committedFeb 5, 2025
feat: parameterize customer_managed_policies path
Make customer-managed policies configurable using a custom path instead of the current hard-coded "/" value. Retains the current behavior, so these entries can either be a set of strings or a set of objects with `name` and `path` (new behavior).
1 parent 067084a commit ab11e7a

File tree

8 files changed

+263
-12
lines changed

8 files changed

+263
-12
lines changed
 

‎README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -300,4 +300,4 @@ No modules.
300300
| <a name="output_sso_applications_group_assignments"></a> [sso\_applications\_group\_assignments](#output\_sso\_applications\_group\_assignments) | A map of SSO Applications assignments with groups created by this module |
301301
| <a name="output_sso_applications_user_assignments"></a> [sso\_applications\_user\_assignments](#output\_sso\_applications\_user\_assignments) | A map of SSO Applications assignments with users created by this module |
302302
| <a name="output_sso_groups_ids"></a> [sso\_groups\_ids](#output\_sso\_groups\_ids) | A map of SSO groups ids created by this module |
303-
<!-- END_TF_DOCS -->
303+
<!-- END_TF_DOCS -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
This directory contains examples of using the module to create users and groups and assign permissions with **Inline Policies**.
2+
3+
**IMPORTANT:** Ensure that the name of your object matches the name of your principal (e.g. user name or group name). See the following example with object/principal names 'Admin' and 'nuzumaki':
4+
5+
```hcl
6+
sso_groups = {
7+
Admin : {
8+
group_name = "Admin"
9+
group_description = "Admin IAM Identity Center Group"
10+
},
11+
}
12+
13+
// Create desired USERS in IAM Identity Center
14+
sso_users = {
15+
nuzumaki : {
16+
group_membership = ["Admin",]
17+
user_name = "nuzumaki"
18+
given_name = "Naruto"
19+
family_name = "Uzumaki"
20+
email = "nuzumaki@hiddenleaf.village"
21+
},
22+
}
23+
24+
```
25+
26+
These names are referenced throughout the module. Failure to do this may lead to unintentional errors such as the following:
27+
28+
```
29+
Error: Invalid index
30+
31+
│ on ../../main.tf line 141, in resource "aws_identitystore_group_membership" "sso_group_membership":
32+
│ 141: member_id = (contains(local.this_users, each.value.user_name) ? aws_identitystore_user.sso_users[each.value.user_name].user_id : data.aws_identitystore_user.existing_sso_users[each.value.user_name].id)
33+
│ ├────────────────
34+
│ │ aws_identitystore_user.sso_users is object with 2 attributes
35+
│ │ each.value.user_name is "nuzumaki"
36+
37+
│ The given key does not identify an element in this collection value.
38+
```
39+
40+
To resolve this, ensure your object and principal names are the same and re-run `terraform plan` and `terraform apply`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<!-- BEGIN_TF_DOCS -->
2+
This directory contains examples of using the module to create users and groups and assign permissions with **Inline Policies**.
3+
4+
**IMPORTANT:** Ensure that the name of your object matches the name of your principal (e.g. user name or group name). See the following example with object/principal names 'Admin' and 'nuzumaki':
5+
6+
```hcl
7+
sso_groups = {
8+
Admin : {
9+
group_name = "Admin"
10+
group_description = "Admin IAM Identity Center Group"
11+
},
12+
}
13+
14+
// Create desired USERS in IAM Identity Center
15+
sso_users = {
16+
nuzumaki : {
17+
group_membership = ["Admin",]
18+
user_name = "nuzumaki"
19+
given_name = "Naruto"
20+
family_name = "Uzumaki"
21+
email = "nuzumaki@hiddenleaf.village"
22+
},
23+
}
24+
25+
```
26+
27+
These names are referenced throughout the module. Failure to do this may lead to unintentional errors such as the following:
28+
29+
```
30+
Error: Invalid index
31+
32+
│ on ../../main.tf line 141, in resource "aws_identitystore_group_membership" "sso_group_membership":
33+
│ 141: member_id = (contains(local.this_users, each.value.user_name) ? aws_identitystore_user.sso_users[each.value.user_name].user_id : data.aws_identitystore_user.existing_sso_users[each.value.user_name].id)
34+
│ ├────────────────
35+
│ │ aws_identitystore_user.sso_users is object with 2 attributes
36+
│ │ each.value.user_name is "nuzumaki"
37+
38+
│ The given key does not identify an element in this collection value.
39+
```
40+
41+
To resolve this, ensure your object and principal names are the same and re-run `terraform plan` and `terraform apply`.
42+
43+
## Requirements
44+
45+
No requirements.
46+
47+
## Providers
48+
49+
| Name | Version |
50+
|------|---------|
51+
| <a name="provider_aws"></a> [aws](#provider\_aws) | n/a |
52+
53+
## Modules
54+
55+
| Name | Source | Version |
56+
|------|--------|---------|
57+
| <a name="module_aws-iam-identity-center"></a> [aws-iam-identity-center](#module\_aws-iam-identity-center) | ../.. | n/a |
58+
59+
## Resources
60+
61+
| Name | Type |
62+
|------|------|
63+
| [aws_organizations_organization.org](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/organizations_organization) | data source |
64+
65+
## Inputs
66+
67+
No inputs.
68+
69+
## Outputs
70+
71+
No outputs.
72+
<!-- END_TF_DOCS -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Fetch Account Id from SSM Parameter Store
2+
data "aws_ssm_parameter" "account1_account_id" {
3+
name = "tf-aws-iam-idc-module-testing-account1-account-id" // replace with your SSM Parameter Key
4+
}
5+
6+
locals {
7+
# Account IDs
8+
account1_account_id = nonsensitive(data.aws_ssm_parameter.account1_account_id.value)
9+
# account1_account_id = "111111111111"
10+
# account2_account_id = "222222222222"
11+
# account3_account_id = "333333333333"
12+
# account4_account_id = "444444444444"
13+
14+
}
+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
data "aws_organizations_organization" "org" {}
2+
3+
module "aws-iam-identity-center" {
4+
source = "../.." // local example
5+
# source = "aws-ia/iam-identity-center/aws" // remote example
6+
7+
existing_sso_groups = {
8+
AWSControlTowerAdmins : {
9+
group_name = "AWSControlTowerAdmins" # this must be the name of a sso group that already exists in your AWS account
10+
}
11+
}
12+
13+
sso_groups = {
14+
Admin : {
15+
group_name = "Admin"
16+
group_description = "Admin Group"
17+
},
18+
Dev : {
19+
group_name = "Dev"
20+
group_description = "Dev Group"
21+
},
22+
}
23+
sso_users = {
24+
nuzumaki : {
25+
group_membership = ["Admin", "Dev", "AWSControlTowerAdmins"]
26+
user_name = "nuzumaki"
27+
given_name = "Naruto"
28+
family_name = "Uzumaki"
29+
email = "nuzumaki@hiddenleaf.village"
30+
},
31+
suchiha : {
32+
group_membership = ["Dev", "AWSControlTowerAdmins"]
33+
user_name = "suchiha"
34+
given_name = "Sasuke"
35+
family_name = "Uchiha"
36+
email = "suchiha@hiddenleaf.village"
37+
},
38+
}
39+
40+
existing_permission_sets = {
41+
AWSAdministratorAccess : {
42+
permission_set_name = "AWSAdministratorAccess" # this must be the name of a permission set that already exists in your AWS account
43+
},
44+
}
45+
46+
permission_sets = {
47+
AdministratorAccess = {
48+
description = "Provides full access to AWS services and resources",
49+
session_duration = "PT3H",
50+
aws_managed_policies = ["arn:aws:iam::aws:policy/AdministratorAccess"]
51+
52+
customer_managed_policies = [
53+
"MyExampleOrgAdminAccess",
54+
]
55+
56+
tags = { ManagedBy = "Terraform" }
57+
},
58+
ViewOnlyAccess = {
59+
description = "This policy grants permissions to view resources and basic metadata across all AWS services",
60+
session_duration = "PT3H",
61+
aws_managed_policies = ["arn:aws:iam::aws:policy/job-function/ViewOnlyAccess"]
62+
managed_policy_arn = "arn:aws:iam::aws:policy/job-function/ViewOnlyAccess"
63+
64+
customer_managed_policies = [
65+
{
66+
name = "MyExampleOrgViewOnlyAccess"
67+
path = "/foo/example/"
68+
}
69+
]
70+
71+
permissions_boundary = {
72+
managed_policy_arn = "arn:aws:iam::aws:policy/job-function/ViewOnlyAccess"
73+
}
74+
tags = { ManagedBy = "Terraform" }
75+
},
76+
}
77+
account_assignments = {
78+
Admin : {
79+
principal_name = "Admin"
80+
principal_type = "GROUP"
81+
principal_idp = "INTERNAL"
82+
permission_sets = [
83+
"AdministratorAccess",
84+
"ViewOnlyAccess",
85+
// existing permission set
86+
"AWSAdministratorAccess",
87+
]
88+
account_ids = [
89+
// replace with your own account id
90+
local.account1_account_id,
91+
# local.account2_account_id
92+
# local.account3_account_id
93+
# local.account4_account_id
94+
]
95+
},
96+
Dev : {
97+
principal_name = "Dev"
98+
principal_type = "GROUP"
99+
principal_idp = "INTERNAL"
100+
permission_sets = [
101+
"ViewOnlyAccess",
102+
]
103+
account_ids = [
104+
// replace with your own account id
105+
local.account1_account_id,
106+
# local.account2_account_id
107+
# local.account3_account_id
108+
# local.account4_account_id
109+
]
110+
},
111+
}
112+
}

‎locals.tf

+3-3
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ locals {
7878
for pset_name, pset_index in local.customer_managed_permission_sets : [
7979
for policy in pset_index.customer_managed_policies : {
8080
pset_name = pset_name
81-
policy_name = policy
82-
# path = path
81+
policy_name = try(policy.name, policy)
82+
policy_path = try(policy.path, "/")
8383
} if pset_index.customer_managed_policies != null && can(pset_index.customer_managed_policies)
8484
]
8585
])
@@ -207,7 +207,7 @@ locals {
207207
])
208208

209209
# Creating a local variable by flattening the complex type related to Applications to extract a simple structure representing
210-
# app assignments access scopes
210+
# app assignments access scopes
211211
apps_assignments_access_scopes = flatten([
212212
for app in var.sso_applications : [
213213
for ass_acc_scope in app.assignments_access_scope : {

‎main.tf

+8-8
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ resource "aws_ssoadmin_customer_managed_policy_attachment" "pset_customer_manage
191191
permission_set_arn = aws_ssoadmin_permission_set.pset[each.value.pset_name].arn
192192
customer_managed_policy_reference {
193193
name = each.value.policy_name
194-
path = "/"
194+
path = each.value.policy_path
195195
}
196196

197197
}
@@ -271,7 +271,7 @@ resource "aws_ssoadmin_application" "sso_apps" {
271271
tags = each.value.tags
272272
}
273273

274-
# SSO - Applications Assigments Configuration
274+
# SSO - Applications Assigments Configuration
275275
resource "aws_ssoadmin_application_assignment_configuration" "sso_apps_assignments_configs" {
276276
for_each = {
277277
for idx, assignment_config in local.apps_assignments_configs :
@@ -281,28 +281,28 @@ resource "aws_ssoadmin_application_assignment_configuration" "sso_apps_assignmen
281281
assignment_required = each.value.assignment_required
282282
}
283283

284-
# SSO - Application Assignments access scope
284+
# SSO - Application Assignments access scope
285285
resource "aws_ssoadmin_application_access_scope" "sso_apps_assignments_access_scope" {
286286
for_each = {
287287
for idx, app_access_scope in local.apps_assignments_access_scopes :
288288
"${app_access_scope.app_name}-${app_access_scope.scope}" => app_access_scope
289289
}
290290
application_arn = aws_ssoadmin_application.sso_apps[each.value.app_name].application_arn
291291
authorized_targets = [
292-
for target in each.value.authorized_targets : aws_ssoadmin_application.sso_apps[target].application_arn
292+
for target in each.value.authorized_targets : aws_ssoadmin_application.sso_apps[target].application_arn
293293
]
294294
#authorized_targets = each.value.authorized_targets
295295
scope = each.value.scope
296296
}
297297

298-
# SSO - Applications Assignments
298+
# SSO - Applications Assignments
299299
# Groups assignments
300300
resource "aws_ssoadmin_application_assignment" "sso_apps_groups_assignments" {
301301
for_each = {
302302
for idx, assignment in local.apps_groups_assignments :
303303
"${assignment.app_name}-${assignment.group_name}" => assignment
304304
}
305-
application_arn = aws_ssoadmin_application.sso_apps[each.value.app_name].application_arn
305+
application_arn = aws_ssoadmin_application.sso_apps[each.value.app_name].application_arn
306306
principal_id = (contains(local.this_groups, each.value.group_name) ? aws_identitystore_group.sso_groups[each.value.group_name].group_id : data.aws_identitystore_group.existing_sso_groups[each.value.group_name].group_id)
307307
principal_type = each.value.principal_type
308308
}
@@ -313,7 +313,7 @@ resource "aws_ssoadmin_application_assignment" "sso_apps_users_assignments" {
313313
for idx, assignment in local.apps_users_assignments :
314314
"${assignment.app_name}-${assignment.user_name}" => assignment
315315
}
316-
application_arn = aws_ssoadmin_application.sso_apps[each.value.app_name].application_arn
316+
application_arn = aws_ssoadmin_application.sso_apps[each.value.app_name].application_arn
317317
principal_id = (contains(local.this_users, each.value.user_name) ? aws_identitystore_user.sso_users[each.value.user_name].user_id : data.aws_identitystore_user.existing_sso_users[each.value.user_name].user_id)
318318
principal_type = each.value.principal_type
319319
}
@@ -331,4 +331,4 @@ resource "aws_ssoadmin_instance_access_control_attributes" "sso_access_control_
331331
}
332332
}
333333
}
334-
}
334+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
run "unit_test" {
2+
command = plan
3+
module {
4+
source = "./examples/customer-managed-policies"
5+
}
6+
}
7+
8+
run "e2e_test" {
9+
command = apply
10+
module {
11+
source = "./examples/customer-managed-policies"
12+
}
13+
}

0 commit comments

Comments
 (0)
Please sign in to comment.