Skip to content

Commit

Permalink
feat: parameterize customer_managed_policies path
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
cilindrox committed Feb 5, 2025
1 parent 067084a commit 87b3195
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 11 deletions.
40 changes: 40 additions & 0 deletions examples/customer-managed-policies/.header.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
This directory contains examples of using the module to create users and groups and assign permissions with **Inline Policies**.

**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':

```hcl
sso_groups = {
Admin : {
group_name = "Admin"
group_description = "Admin IAM Identity Center Group"
},
}
// Create desired USERS in IAM Identity Center
sso_users = {
nuzumaki : {
group_membership = ["Admin",]
user_name = "nuzumaki"
given_name = "Naruto"
family_name = "Uzumaki"
email = "[email protected]"
},
}
```

These names are referenced throughout the module. Failure to do this may lead to unintentional errors such as the following:

```
Error: Invalid index
│ on ../../main.tf line 141, in resource "aws_identitystore_group_membership" "sso_group_membership":
│ 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)
│ ├────────────────
│ │ aws_identitystore_user.sso_users is object with 2 attributes
│ │ each.value.user_name is "nuzumaki"
│ The given key does not identify an element in this collection value.
```

To resolve this, ensure your object and principal names are the same and re-run `terraform plan` and `terraform apply`.
72 changes: 72 additions & 0 deletions examples/customer-managed-policies/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<!-- BEGIN_TF_DOCS -->
This directory contains examples of using the module to create users and groups and assign permissions with **Inline Policies**.

**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':

```hcl
sso_groups = {
Admin : {
group_name = "Admin"
group_description = "Admin IAM Identity Center Group"
},
}
// Create desired USERS in IAM Identity Center
sso_users = {
nuzumaki : {
group_membership = ["Admin",]
user_name = "nuzumaki"
given_name = "Naruto"
family_name = "Uzumaki"
email = "[email protected]"
},
}
```

These names are referenced throughout the module. Failure to do this may lead to unintentional errors such as the following:

```
Error: Invalid index
│ on ../../main.tf line 141, in resource "aws_identitystore_group_membership" "sso_group_membership":
│ 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)
│ ├────────────────
│ │ aws_identitystore_user.sso_users is object with 2 attributes
│ │ each.value.user_name is "nuzumaki"
│ The given key does not identify an element in this collection value.
```

To resolve this, ensure your object and principal names are the same and re-run `terraform plan` and `terraform apply`.

## Requirements

No requirements.

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | n/a |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_aws-iam-identity-center"></a> [aws-iam-identity-center](#module\_aws-iam-identity-center) | ../.. | n/a |

## Resources

| Name | Type |
|------|------|
| [aws_organizations_organization.org](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/organizations_organization) | data source |

## Inputs

No inputs.

## Outputs

No outputs.
<!-- END_TF_DOCS -->
14 changes: 14 additions & 0 deletions examples/customer-managed-policies/locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Fetch Account Id from SSM Parameter Store
data "aws_ssm_parameter" "account1_account_id" {
name = "tf-aws-iam-idc-module-testing-account1-account-id" // replace with your SSM Parameter Key
}

locals {
# Account IDs
account1_account_id = nonsensitive(data.aws_ssm_parameter.account1_account_id.value)
# account1_account_id = "111111111111"
# account2_account_id = "222222222222"
# account3_account_id = "333333333333"
# account4_account_id = "444444444444"

}
112 changes: 112 additions & 0 deletions examples/customer-managed-policies/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
data "aws_organizations_organization" "org" {}

module "aws-iam-identity-center" {
source = "../.." // local example
# source = "aws-ia/iam-identity-center/aws" // remote example

existing_sso_groups = {
AWSControlTowerAdmins : {
group_name = "AWSControlTowerAdmins" # this must be the name of a sso group that already exists in your AWS account
}
}

sso_groups = {
Admin : {
group_name = "Admin"
group_description = "Admin Group"
},
Dev : {
group_name = "Dev"
group_description = "Dev Group"
},
}
sso_users = {
nuzumaki : {
group_membership = ["Admin", "Dev", "AWSControlTowerAdmins"]
user_name = "nuzumaki"
given_name = "Naruto"
family_name = "Uzumaki"
email = "[email protected]"
},
suchiha : {
group_membership = ["Dev", "AWSControlTowerAdmins"]
user_name = "suchiha"
given_name = "Sasuke"
family_name = "Uchiha"
email = "[email protected]"
},
}

existing_permission_sets = {
AWSAdministratorAccess : {
permission_set_name = "AWSAdministratorAccess" # this must be the name of a permission set that already exists in your AWS account
},
}

permission_sets = {
AdministratorAccess = {
description = "Provides full access to AWS services and resources",
session_duration = "PT3H",
aws_managed_policies = ["arn:aws:iam::aws:policy/AdministratorAccess"]

customer_managed_policies = [
"MyExampleOrgAdminAccess",
]

tags = { ManagedBy = "Terraform" }
},
ViewOnlyAccess = {
description = "This policy grants permissions to view resources and basic metadata across all AWS services",
session_duration = "PT3H",
aws_managed_policies = ["arn:aws:iam::aws:policy/job-function/ViewOnlyAccess"]
managed_policy_arn = "arn:aws:iam::aws:policy/job-function/ViewOnlyAccess"

customer_managed_policies = [
{
name = "MyExampleOrgViewOnlyAccess"
path = "/foo/example/"
}
]

permissions_boundary = {
managed_policy_arn = "arn:aws:iam::aws:policy/job-function/ViewOnlyAccess"
}
tags = { ManagedBy = "Terraform" }
},
}
account_assignments = {
Admin : {
principal_name = "Admin"
principal_type = "GROUP"
principal_idp = "INTERNAL"
permission_sets = [
"AdministratorAccess",
"ViewOnlyAccess",
// existing permission set
"AWSAdministratorAccess",
]
account_ids = [
// replace with your own account id
local.account1_account_id,
# local.account2_account_id
# local.account3_account_id
# local.account4_account_id
]
},
Dev : {
principal_name = "Dev"
principal_type = "GROUP"
principal_idp = "INTERNAL"
permission_sets = [
"ViewOnlyAccess",
]
account_ids = [
// replace with your own account id
local.account1_account_id,
# local.account2_account_id
# local.account3_account_id
# local.account4_account_id
]
},
}
}
6 changes: 3 additions & 3 deletions locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ locals {
for pset_name, pset_index in local.customer_managed_permission_sets : [
for policy in pset_index.customer_managed_policies : {
pset_name = pset_name
policy_name = policy
# path = path
policy_name = try(policy.name, policy)
policy_path = try(policy.path, "/")
} if pset_index.customer_managed_policies != null && can(pset_index.customer_managed_policies)
]
])
Expand Down Expand Up @@ -207,7 +207,7 @@ locals {
])

# Creating a local variable by flattening the complex type related to Applications to extract a simple structure representing
# app assignments access scopes
# app assignments access scopes
apps_assignments_access_scopes = flatten([
for app in var.sso_applications : [
for ass_acc_scope in app.assignments_access_scope : {
Expand Down
16 changes: 8 additions & 8 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ resource "aws_ssoadmin_customer_managed_policy_attachment" "pset_customer_manage
permission_set_arn = aws_ssoadmin_permission_set.pset[each.value.pset_name].arn
customer_managed_policy_reference {
name = each.value.policy_name
path = "/"
path = each.value.policy_path
}

}
Expand Down Expand Up @@ -271,7 +271,7 @@ resource "aws_ssoadmin_application" "sso_apps" {
tags = each.value.tags
}

# SSO - Applications Assigments Configuration
# SSO - Applications Assigments Configuration
resource "aws_ssoadmin_application_assignment_configuration" "sso_apps_assignments_configs" {
for_each = {
for idx, assignment_config in local.apps_assignments_configs :
Expand All @@ -281,28 +281,28 @@ resource "aws_ssoadmin_application_assignment_configuration" "sso_apps_assignmen
assignment_required = each.value.assignment_required
}

# SSO - Application Assignments access scope
# SSO - Application Assignments access scope
resource "aws_ssoadmin_application_access_scope" "sso_apps_assignments_access_scope" {
for_each = {
for idx, app_access_scope in local.apps_assignments_access_scopes :
"${app_access_scope.app_name}-${app_access_scope.scope}" => app_access_scope
}
application_arn = aws_ssoadmin_application.sso_apps[each.value.app_name].application_arn
authorized_targets = [
for target in each.value.authorized_targets : aws_ssoadmin_application.sso_apps[target].application_arn
for target in each.value.authorized_targets : aws_ssoadmin_application.sso_apps[target].application_arn
]
#authorized_targets = each.value.authorized_targets
scope = each.value.scope
}

# SSO - Applications Assignments
# SSO - Applications Assignments
# Groups assignments
resource "aws_ssoadmin_application_assignment" "sso_apps_groups_assignments" {
for_each = {
for idx, assignment in local.apps_groups_assignments :
"${assignment.app_name}-${assignment.group_name}" => assignment
}
application_arn = aws_ssoadmin_application.sso_apps[each.value.app_name].application_arn
application_arn = aws_ssoadmin_application.sso_apps[each.value.app_name].application_arn
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)
principal_type = each.value.principal_type
}
Expand All @@ -313,7 +313,7 @@ resource "aws_ssoadmin_application_assignment" "sso_apps_users_assignments" {
for idx, assignment in local.apps_users_assignments :
"${assignment.app_name}-${assignment.user_name}" => assignment
}
application_arn = aws_ssoadmin_application.sso_apps[each.value.app_name].application_arn
application_arn = aws_ssoadmin_application.sso_apps[each.value.app_name].application_arn
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)
principal_type = each.value.principal_type
}
Expand All @@ -331,4 +331,4 @@ resource "aws_ssoadmin_instance_access_control_attributes" "sso_access_control_
}
}
}
}
}
13 changes: 13 additions & 0 deletions tests/08_customer_managed_policies.tftest.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
run "unit_test" {
command = plan
module {
source = "./examples/customer-managed-policies"
}
}

run "e2e_test" {
command = apply
module {
source = "./examples/customer-managed-policies"
}
}

0 comments on commit 87b3195

Please sign in to comment.