Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: parameterize customer_managed_policies path #54

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
22 changes: 11 additions & 11 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,22 +313,22 @@ 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
}

# SSO Instance Access Control Attributes
resource "aws_ssoadmin_instance_access_control_attributes" "sso_access_control_attributes" {
count = length(var.sso_instance_access_control_attributes) <= 0 ? 0 : 1
resource "aws_ssoadmin_instance_access_control_attributes" "sso_access_control_attributes" {
count = length(var.sso_instance_access_control_attributes) <= 0 ? 0 : 1
instance_arn = local.ssoadmin_instance_arn
dynamic "attribute" {
for_each = var.sso_instance_access_control_attributes
content {
key = attribute.key
key = attribute.key
value {
source = attribute.value.source
}
}
}
}
}
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"
}
}
4 changes: 2 additions & 2 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ variable "sso_instance_access_control_attributes" {
description = "List of attributes for access control. This is used to create the enable and use attributes for access control."
type = list(object({
attribute_name = string
source = set(string)
source = set(string)
}))
default = []
validation {
Expand All @@ -166,7 +166,7 @@ variable "sso_instance_access_control_attributes" {
condition = alltrue([
for attr in var.sso_instance_access_control_attributes :
attr.source != null &&
length(attr.source) > 0 && # checks if the set is not empty
length(attr.source) > 0 && # checks if the set is not empty
alltrue([for s in attr.source : s != ""]) # checks no empty strings in set
])
error_message = "The attribute source is mandatory and must contain non-empty strings."
Expand Down